Skip to content

Commit

Permalink
Seal internal private types analyzer
Browse files Browse the repository at this point in the history
  • Loading branch information
NewellClark authored and stephentoub committed Apr 15, 2022
1 parent 5b0b341 commit f6061f1
Show file tree
Hide file tree
Showing 20 changed files with 791 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,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 @@ -1891,4 +1891,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,69 @@
// 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)
{
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())
candidateTypes.Add(type);

for (var baseType = type.BaseType; baseType is not null; baseType = baseType.BaseType)
baseTypes.Add(baseType.OriginalDefinition);

}, SymbolKind.NamedType);

context.RegisterCompilationEndAction(context =>
{
foreach (var 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

0 comments on commit f6061f1

Please sign in to comment.