Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MakeTypesInternalAnalyzer #6820

Merged
merged 10 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System.Composition;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeQuality.Analyzers.Maintainability;

namespace Microsoft.CodeQuality.CSharp.Analyzers.Maintainability
{
[ExportCodeFixProvider(LanguageNames.CSharp), Shared]
public sealed class CSharpMakeTypesInternalFixer : MakeTypesInternalFixer
{
protected override SyntaxNode? MakeInternal(SyntaxNode node)
{
if (node is TypeDeclarationSyntax type)
{
var publicKeyword = type.Modifiers.First(m => m.IsKind(SyntaxKind.PublicKeyword));
var modifiers = type.Modifiers.Replace(publicKeyword, SyntaxFactory.Token(SyntaxKind.InternalKeyword));

return type.WithModifiers(modifiers);
buyaa-n marked this conversation as resolved.
Show resolved Hide resolved
}

if (node is EnumDeclarationSyntax @enum)
{
var publicKeyword = @enum.Modifiers.First(m => m.IsKind(SyntaxKind.PublicKeyword));
var modifiers = @enum.Modifiers.Replace(publicKeyword, SyntaxFactory.Token(SyntaxKind.InternalKeyword));

return @enum.WithModifiers(modifiers);
}

return null;
buyaa-n marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System.Collections.Immutable;
using Analyzer.Utilities.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeQuality.Analyzers.Maintainability;

namespace Microsoft.CodeQuality.CSharp.Analyzers.Maintainability
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class CSharpMakeTypesInternal : MakeTypesInternal<SyntaxKind>
{
protected override ImmutableArray<SyntaxKind> TypeKinds { get; } =
ImmutableArray.Create(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration, SyntaxKind.InterfaceDeclaration, SyntaxKind.RecordDeclaration);

protected override SyntaxKind EnumKind { get; } = SyntaxKind.EnumDeclaration;

protected override void AnalyzeTypeDeclaration(SyntaxNodeAnalysisContext context)
{
var type = (TypeDeclarationSyntax)context.Node;
if (type.Modifiers.Any(SyntaxKind.PublicKeyword))
{
context.ReportDiagnostic(type.Identifier.CreateDiagnostic(Rule));
}
}

protected override void AnalyzeEnumDeclaration(SyntaxNodeAnalysisContext context)
{
var @enum = (EnumDeclarationSyntax)context.Node;
if (@enum.Modifiers.Any(SyntaxKind.PublicKeyword))
{
context.ReportDiagnostic(@enum.Identifier.CreateDiagnostic(Rule));
}
}
}
}
1 change: 1 addition & 0 deletions src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

Rule ID | Category | Severity | Notes
--------|----------|----------|-------
CA1514 | Maintainability | Disabled | MakeTypesInternal, [Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1514)
CA1865 | Performance | Info | UseStringMethodCharOverloadWithSingleCharacters, [Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1865)
CA1866 | Performance | Info | UseStringMethodCharOverloadWithSingleCharacters, [Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1866)
CA1867 | Performance | Disabled | UseStringMethodCharOverloadWithSingleCharacters, [Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1867)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System.Collections.Immutable;
using System.Threading.Tasks;
using Analyzer.Utilities;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;

namespace Microsoft.CodeQuality.Analyzers.Maintainability
{
public abstract class MakeTypesInternalFixer : CodeFixProvider
{
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
var node = root.FindNode(context.Span);
var newNode = MakeInternal(node);
buyaa-n marked this conversation as resolved.
Show resolved Hide resolved
if (newNode is null)
{
return;
}

root = root.ReplaceNode(node, newNode.WithTriviaFrom(node));

var codeAction = CodeAction.Create(
MicrosoftCodeQualityAnalyzersResources.MakeTypesInternalCodeFixTitle,
_ => Task.FromResult(context.Document.WithSyntaxRoot(root)),
MicrosoftCodeQualityAnalyzersResources.MakeTypesInternalCodeFixTitle);
context.RegisterCodeFix(codeAction, context.Diagnostics);
}

public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;

protected abstract SyntaxNode? MakeInternal(SyntaxNode node);

public override ImmutableArray<string> FixableDiagnosticIds { get; } = ImmutableArray.Create(MakeTypesInternal<SymbolKind>.RuleId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System;
using System.Collections.Immutable;
using Analyzer.Utilities;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;

namespace Microsoft.CodeQuality.Analyzers.Maintainability
{
using static MicrosoftCodeQualityAnalyzersResources;

public abstract class MakeTypesInternal<TSyntaxKind> : DiagnosticAnalyzer
where TSyntaxKind : struct, Enum
{
internal const string RuleId = "CA1514";

protected static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create(
RuleId,
CreateLocalizableResourceString(nameof(MakeTypesInternalTitle)),
CreateLocalizableResourceString(nameof(MakeTypesInternalMessage)),
DiagnosticCategory.Maintainability,
RuleLevel.Disabled,
description: CreateLocalizableResourceString(nameof(MakeTypesInternalDescription)),
isPortedFxCopRule: false,
isDataflowRule: false);

public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterCompilationStartAction(compilationStartContext =>
{
var compilation = compilationStartContext.Compilation;
if (compilation.Options.OutputKind is not (OutputKind.ConsoleApplication or OutputKind.WindowsApplication or OutputKind.WindowsRuntimeApplication))
{
return;
}

compilationStartContext.RegisterSyntaxNodeAction(AnalyzeTypeDeclaration, TypeKinds);
compilationStartContext.RegisterSyntaxNodeAction(AnalyzeEnumDeclaration, EnumKind);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delegate declaration as well?

});
buyaa-n marked this conversation as resolved.
Show resolved Hide resolved
}

protected abstract ImmutableArray<TSyntaxKind> TypeKinds { get; }

protected abstract TSyntaxKind EnumKind { get; }

protected abstract void AnalyzeTypeDeclaration(SyntaxNodeAnalysisContext context);

protected abstract void AnalyzeEnumDeclaration(SyntaxNodeAnalysisContext context);

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(Rule);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1281,4 +1281,16 @@
<data name="CollectionsShouldImplementGenericInterfaceMultipleMessage" xml:space="preserve">
<value>Type '{0}' directly or indirectly inherits '{1}' without implementing any of '{2}'. Publicly-visible types should implement the generic version to broaden usability.</value>
</data>
<data name="MakeTypesInternalCodeFixTitle" xml:space="preserve">
<value>Make all public types internal</value>
buyaa-n marked this conversation as resolved.
Show resolved Hide resolved
</data>
<data name="MakeTypesInternalDescription" xml:space="preserve">
<value>Different than libraries, applications aren't referenced and thus all types can be made internal.</value>
buyaa-n marked this conversation as resolved.
Show resolved Hide resolved
</data>
<data name="MakeTypesInternalMessage" xml:space="preserve">
<value>Since applications' code isn't referenced, all types can be made internal</value>
buyaa-n marked this conversation as resolved.
Show resolved Hide resolved
</data>
<data name="MakeTypesInternalTitle" xml:space="preserve">
<value>Make all public types internal</value>
buyaa-n marked this conversation as resolved.
Show resolved Hide resolved
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,26 @@
<target state="translated">Používat PascalCase pro pojmenované zástupné objekty</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalCodeFixTitle">
<source>Make all public types internal</source>
<target state="new">Make all public types internal</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalDescription">
<source>Different than libraries, applications aren't referenced and thus all types can be made internal.</source>
<target state="new">Different than libraries, applications aren't referenced and thus all types can be made internal.</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalMessage">
<source>Since applications' code isn't referenced, all types can be made internal</source>
<target state="new">Since applications' code isn't referenced, all types can be made internal</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalTitle">
<source>Make all public types internal</source>
<target state="new">Make all public types internal</target>
<note />
</trans-unit>
<trans-unit id="MarkAttributesWithAttributeUsageCodeFix">
<source>Apply 'AttributeUsageAttribute'</source>
<target state="translated">Použít AttributeUsageAttribute</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,26 @@
<target state="translated">PascalCase für benannte Platzhalter verwenden</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalCodeFixTitle">
<source>Make all public types internal</source>
<target state="new">Make all public types internal</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalDescription">
<source>Different than libraries, applications aren't referenced and thus all types can be made internal.</source>
<target state="new">Different than libraries, applications aren't referenced and thus all types can be made internal.</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalMessage">
<source>Since applications' code isn't referenced, all types can be made internal</source>
<target state="new">Since applications' code isn't referenced, all types can be made internal</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalTitle">
<source>Make all public types internal</source>
<target state="new">Make all public types internal</target>
<note />
</trans-unit>
<trans-unit id="MarkAttributesWithAttributeUsageCodeFix">
<source>Apply 'AttributeUsageAttribute'</source>
<target state="translated">"AttributeUsageAttribute" anwenden</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,26 @@
<target state="translated">Usar PascalCase para marcadores de posición con nombre</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalCodeFixTitle">
<source>Make all public types internal</source>
<target state="new">Make all public types internal</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalDescription">
<source>Different than libraries, applications aren't referenced and thus all types can be made internal.</source>
<target state="new">Different than libraries, applications aren't referenced and thus all types can be made internal.</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalMessage">
<source>Since applications' code isn't referenced, all types can be made internal</source>
<target state="new">Since applications' code isn't referenced, all types can be made internal</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalTitle">
<source>Make all public types internal</source>
<target state="new">Make all public types internal</target>
<note />
</trans-unit>
<trans-unit id="MarkAttributesWithAttributeUsageCodeFix">
<source>Apply 'AttributeUsageAttribute'</source>
<target state="translated">Aplicar "AttributeUsageAttribute"</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,26 @@
<target state="translated">Utiliser casse Pascal pour les espaces réservés nommés</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalCodeFixTitle">
<source>Make all public types internal</source>
<target state="new">Make all public types internal</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalDescription">
<source>Different than libraries, applications aren't referenced and thus all types can be made internal.</source>
<target state="new">Different than libraries, applications aren't referenced and thus all types can be made internal.</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalMessage">
<source>Since applications' code isn't referenced, all types can be made internal</source>
<target state="new">Since applications' code isn't referenced, all types can be made internal</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalTitle">
<source>Make all public types internal</source>
<target state="new">Make all public types internal</target>
<note />
</trans-unit>
<trans-unit id="MarkAttributesWithAttributeUsageCodeFix">
<source>Apply 'AttributeUsageAttribute'</source>
<target state="translated">Appliquer 'AttributeUsageAttribute'</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,26 @@
<target state="translated">Usare la notazione Pascal per i segnaposto denominati</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalCodeFixTitle">
<source>Make all public types internal</source>
<target state="new">Make all public types internal</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalDescription">
<source>Different than libraries, applications aren't referenced and thus all types can be made internal.</source>
<target state="new">Different than libraries, applications aren't referenced and thus all types can be made internal.</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalMessage">
<source>Since applications' code isn't referenced, all types can be made internal</source>
<target state="new">Since applications' code isn't referenced, all types can be made internal</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalTitle">
<source>Make all public types internal</source>
<target state="new">Make all public types internal</target>
<note />
</trans-unit>
<trans-unit id="MarkAttributesWithAttributeUsageCodeFix">
<source>Apply 'AttributeUsageAttribute'</source>
<target state="translated">Applica 'AttributeUsageAttribute'</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,26 @@
<target state="translated">名前付きプレースホルダーに PascalCase を使用してください</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalCodeFixTitle">
<source>Make all public types internal</source>
<target state="new">Make all public types internal</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalDescription">
<source>Different than libraries, applications aren't referenced and thus all types can be made internal.</source>
<target state="new">Different than libraries, applications aren't referenced and thus all types can be made internal.</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalMessage">
<source>Since applications' code isn't referenced, all types can be made internal</source>
<target state="new">Since applications' code isn't referenced, all types can be made internal</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalTitle">
<source>Make all public types internal</source>
<target state="new">Make all public types internal</target>
<note />
</trans-unit>
<trans-unit id="MarkAttributesWithAttributeUsageCodeFix">
<source>Apply 'AttributeUsageAttribute'</source>
<target state="translated">'AttributeUsageAttribute' の適用</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,26 @@
<target state="translated">명명된 자리 표시자에 대해 PascalCase 사용</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalCodeFixTitle">
<source>Make all public types internal</source>
<target state="new">Make all public types internal</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalDescription">
<source>Different than libraries, applications aren't referenced and thus all types can be made internal.</source>
<target state="new">Different than libraries, applications aren't referenced and thus all types can be made internal.</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalMessage">
<source>Since applications' code isn't referenced, all types can be made internal</source>
<target state="new">Since applications' code isn't referenced, all types can be made internal</target>
<note />
</trans-unit>
<trans-unit id="MakeTypesInternalTitle">
<source>Make all public types internal</source>
<target state="new">Make all public types internal</target>
<note />
</trans-unit>
<trans-unit id="MarkAttributesWithAttributeUsageCodeFix">
<source>Apply 'AttributeUsageAttribute'</source>
<target state="translated">'AttributeUsageAttribute' 적용</target>
Expand Down
Loading