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

Seal internal private types analyzer #5594

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ CA1421 | Interoperability | Info | MethodUsesRuntimeMarshallingEvenWhenMarshalli
CA1849 | Performance | Disabled | UseAsyncMethodInAsyncContext, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1849)
CA1850 | Performance | Info | PreferHashDataOverComputeHashAnalyzer, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1850)
CA1851 | Performance | Disabled | AvoidMultipleEnumerations, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1851)
CA1852 | Performance | Hidden | SealInternalTypes, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1852)
CA2019 | Reliability | Info | UseThreadStaticCorrectly, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2019)
CA2259 | Usage | Warning | UseThreadStaticCorrectly, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2259)
CA5404 | Security | Disabled | DoNotDisableTokenValidationChecks, [Documentation](https://docs.microsoft.com/visualstudio/code-quality/ca5404)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1906,4 +1906,16 @@
<data name="FeatureUnsupportedWhenRuntimeMarshallingDisabledMessageVarargPInvokes" xml:space="preserve">
<value>Varadic P/Invoke signatures require runtime marshalling to be enabled</value>
</data>
<data name="SealInternalTypesDescription" xml:space="preserve">
<value>When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</value>
</data>
<data name="SealInternalTypesMessage" xml:space="preserve">
<value>Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</value>
</data>
<data name="SealInternalTypesTitle" xml:space="preserve">
<value>Seal internal types</value>
</data>
<data name="SealInternalTypesCodeFixTitle" xml:space="preserve">
<value>Seal class</value>
</data>
</root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// 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.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Editing;

namespace Microsoft.NetCore.Analyzers.Runtime
{
[ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic), Shared]
public sealed class SealInternalTypesFixer : CodeFixProvider
{
public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
var codeAction = CodeAction.Create(
MicrosoftNetCoreAnalyzersResources.SealInternalTypesCodeFixTitle,
SealClassDeclarationsAsync,
nameof(MicrosoftNetCoreAnalyzersResources.SealInternalTypesCodeFixTitle));
context.RegisterCodeFix(codeAction, context.Diagnostics);
return Task.CompletedTask;

// Local functions

async Task<Solution> SealClassDeclarationsAsync(CancellationToken token)
{
var solutionEditor = new SolutionEditor(context.Document.Project.Solution);
await SealDeclarationAt(solutionEditor, context.Diagnostics[0].Location, token).ConfigureAwait(false);

foreach (var location in context.Diagnostics[0].AdditionalLocations)
await SealDeclarationAt(solutionEditor, location, token).ConfigureAwait(false);

return solutionEditor.GetChangedSolution();
}

static async Task SealDeclarationAt(SolutionEditor solutionEditor, Location location, CancellationToken token)
{
var solution = solutionEditor.OriginalSolution;
var document = solution.GetDocument(location.SourceTree);

if (document is null)
return;

var documentEditor = await solutionEditor.GetDocumentEditorAsync(document.Id, token).ConfigureAwait(false);
var root = await document.GetSyntaxRootAsync(token).ConfigureAwait(false);
var declaration = root.FindNode(location.SourceSpan);
var newModifiers = documentEditor.Generator.GetModifiers(declaration).WithIsSealed(true);
var newDeclaration = documentEditor.Generator.WithModifiers(declaration, newModifiers);
documentEditor.ReplaceNode(declaration, newDeclaration);
}
}

public override ImmutableArray<string> FixableDiagnosticIds { get; } = ImmutableArray.Create(SealInternalTypes.RuleId);

public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// 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;
using Analyzer.Utilities.Extensions;
using Analyzer.Utilities.PooledObjects;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Resx = Microsoft.NetCore.Analyzers.MicrosoftNetCoreAnalyzersResources;

namespace Microsoft.NetCore.Analyzers.Runtime
{
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class SealInternalTypes : DiagnosticAnalyzer
{
internal const string RuleId = "CA1852";
internal static readonly DiagnosticDescriptor Rule = DiagnosticDescriptorHelper.Create(
RuleId,
Resx.CreateLocalizableResourceString(nameof(Resx.SealInternalTypesTitle)),
Resx.CreateLocalizableResourceString(nameof(Resx.SealInternalTypesMessage)),
DiagnosticCategory.Performance,
RuleLevel.IdeHidden_BulkConfigurable,
Resx.CreateLocalizableResourceString(nameof(Resx.SealInternalTypesDescription)),
isPortedFxCopRule: false,
isDataflowRule: false,
isReportedAtCompilationEnd: true);

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(Rule);

public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterCompilationStartAction(OnCompilationStart);
}

private static void OnCompilationStart(CompilationStartAnalysisContext context)
{
INamedTypeSymbol? comImportAttributeType = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeInteropServicesComImportAttribute);

var candidateTypes = PooledConcurrentSet<INamedTypeSymbol>.GetInstance(SymbolEqualityComparer.Default);
var baseTypes = PooledConcurrentSet<INamedTypeSymbol>.GetInstance(SymbolEqualityComparer.Default);

context.RegisterSymbolAction(context =>
{
var type = (INamedTypeSymbol)context.Symbol;

if (type.TypeKind is TypeKind.Class &&
!type.IsAbstract &&
!type.IsStatic &&
!type.IsSealed &&
!type.IsExternallyVisible() &&
!type.HasAttribute(comImportAttributeType))
{
candidateTypes.Add(type);
}

for (INamedTypeSymbol? baseType = type.BaseType; baseType is not null; baseType = baseType.BaseType)
{
baseTypes.Add(baseType.OriginalDefinition);
}

}, SymbolKind.NamedType);

context.RegisterCompilationEndAction(context =>
{
foreach (INamedTypeSymbol type in candidateTypes)
{
if (!baseTypes.Contains(type.OriginalDefinition))
{
context.ReportDiagnostic(type.CreateDiagnostic(Rule, type.Name));
}
}

candidateTypes.Dispose();
baseTypes.Dispose();
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2297,6 +2297,26 @@
<target state="translated">Zkontrolujte dotazy SQL pro chyby zabezpečení</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesCodeFixTitle">
<source>Seal class</source>
<target state="new">Seal class</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesDescription">
<source>When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</source>
<target state="new">When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesMessage">
<source>Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</source>
<target state="new">Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesTitle">
<source>Seal internal types</source>
<target state="new">Seal internal types</target>
<note />
</trans-unit>
<trans-unit id="SetHttpOnlyForHttpCookie">
<source>Set HttpOnly to true for HttpCookie</source>
<target state="translated">Nastavit HttpOnly na hodnotu true pro HttpCookie</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2297,6 +2297,26 @@
<target state="translated">SQL-Abfragen auf Sicherheitsrisiken überprüfen</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesCodeFixTitle">
<source>Seal class</source>
<target state="new">Seal class</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesDescription">
<source>When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</source>
<target state="new">When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesMessage">
<source>Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</source>
<target state="new">Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesTitle">
<source>Seal internal types</source>
<target state="new">Seal internal types</target>
<note />
</trans-unit>
<trans-unit id="SetHttpOnlyForHttpCookie">
<source>Set HttpOnly to true for HttpCookie</source>
<target state="translated">HttpOnly für HttpCookie auf TRUE festlegen</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2297,6 +2297,26 @@
<target state="translated">Revisar consultas SQL para comprobar si tienen vulnerabilidades de seguridad</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesCodeFixTitle">
<source>Seal class</source>
<target state="new">Seal class</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesDescription">
<source>When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</source>
<target state="new">When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesMessage">
<source>Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</source>
<target state="new">Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesTitle">
<source>Seal internal types</source>
<target state="new">Seal internal types</target>
<note />
</trans-unit>
<trans-unit id="SetHttpOnlyForHttpCookie">
<source>Set HttpOnly to true for HttpCookie</source>
<target state="translated">Establecer HttpOnly en true para HttpCookie</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2297,6 +2297,26 @@
<target state="translated">Vérifier si les requêtes SQL présentent des failles de sécurité</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesCodeFixTitle">
<source>Seal class</source>
<target state="new">Seal class</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesDescription">
<source>When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</source>
<target state="new">When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesMessage">
<source>Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</source>
<target state="new">Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesTitle">
<source>Seal internal types</source>
<target state="new">Seal internal types</target>
<note />
</trans-unit>
<trans-unit id="SetHttpOnlyForHttpCookie">
<source>Set HttpOnly to true for HttpCookie</source>
<target state="translated">Affectez la valeur true à HttpOnly pour HttpCookie</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2297,6 +2297,26 @@
<target state="translated">Controllare l'eventuale vulnerabilità di sicurezza delle query SQL</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesCodeFixTitle">
<source>Seal class</source>
<target state="new">Seal class</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesDescription">
<source>When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</source>
<target state="new">When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesMessage">
<source>Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</source>
<target state="new">Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesTitle">
<source>Seal internal types</source>
<target state="new">Seal internal types</target>
<note />
</trans-unit>
<trans-unit id="SetHttpOnlyForHttpCookie">
<source>Set HttpOnly to true for HttpCookie</source>
<target state="translated">Impostare HttpOnly su true per HttpCookie</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2297,6 +2297,26 @@
<target state="translated">SQL クエリのセキュリティ脆弱性を確認</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesCodeFixTitle">
<source>Seal class</source>
<target state="new">Seal class</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesDescription">
<source>When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</source>
<target state="new">When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesMessage">
<source>Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</source>
<target state="new">Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesTitle">
<source>Seal internal types</source>
<target state="new">Seal internal types</target>
<note />
</trans-unit>
<trans-unit id="SetHttpOnlyForHttpCookie">
<source>Set HttpOnly to true for HttpCookie</source>
<target state="translated">HttpCookie で HttpOnly を true に設定する</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2297,6 +2297,26 @@
<target state="translated">보안상 취약한 부분이 있는지 SQL 쿼리를 검토하십시오.</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesCodeFixTitle">
<source>Seal class</source>
<target state="new">Seal class</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesDescription">
<source>When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</source>
<target state="new">When a type is not accessible outside its assembly and has no subtypes within its containing assembly, it can be safely sealed. Sealing types can improve performance.</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesMessage">
<source>Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</source>
<target state="new">Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible</target>
<note />
</trans-unit>
<trans-unit id="SealInternalTypesTitle">
<source>Seal internal types</source>
<target state="new">Seal internal types</target>
<note />
</trans-unit>
<trans-unit id="SetHttpOnlyForHttpCookie">
<source>Set HttpOnly to true for HttpCookie</source>
<target state="translated">HttpCookie에 대해 HttpOnly를 true로 설정</target>
Expand Down
Loading