From f1d9dda846036785f0ecc733bcfdf3b5055f8fde Mon Sep 17 00:00:00 2001 From: Newell Clark Date: Fri, 15 Apr 2022 10:29:22 -0400 Subject: [PATCH 1/4] Seal internal private types analyzer --- .../Core/AnalyzerReleases.Unshipped.md | 1 + .../MicrosoftNetCoreAnalyzersResources.resx | 12 + .../Runtime/SealInternalTypes.Fixer.cs | 60 +++ .../Runtime/SealInternalTypes.cs | 69 ++++ .../MicrosoftNetCoreAnalyzersResources.cs.xlf | 20 + .../MicrosoftNetCoreAnalyzersResources.de.xlf | 20 + .../MicrosoftNetCoreAnalyzersResources.es.xlf | 20 + .../MicrosoftNetCoreAnalyzersResources.fr.xlf | 20 + .../MicrosoftNetCoreAnalyzersResources.it.xlf | 20 + .../MicrosoftNetCoreAnalyzersResources.ja.xlf | 20 + .../MicrosoftNetCoreAnalyzersResources.ko.xlf | 20 + .../MicrosoftNetCoreAnalyzersResources.pl.xlf | 20 + ...crosoftNetCoreAnalyzersResources.pt-BR.xlf | 20 + .../MicrosoftNetCoreAnalyzersResources.ru.xlf | 20 + .../MicrosoftNetCoreAnalyzersResources.tr.xlf | 20 + ...osoftNetCoreAnalyzersResources.zh-Hans.xlf | 20 + ...osoftNetCoreAnalyzersResources.zh-Hant.xlf | 20 + .../Microsoft.CodeAnalysis.NetAnalyzers.md | 12 + .../Runtime/SealInternalTypesTests.cs | 376 ++++++++++++++++++ .../DiagnosticCategoryAndIdRanges.txt | 2 +- 20 files changed, 791 insertions(+), 1 deletion(-) create mode 100644 src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.Fixer.cs create mode 100644 src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.cs create mode 100644 src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypesTests.cs diff --git a/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md b/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md index 3eabb0eb21..071fbb8ff6 100644 --- a/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md +++ b/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md @@ -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) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx index ed9666ae2f..ecb7679b87 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx @@ -1906,4 +1906,16 @@ Varadic P/Invoke signatures require runtime marshalling to be enabled + + 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. + + + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + + + Seal internal types + + + Seal class + \ No newline at end of file diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.Fixer.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.Fixer.cs new file mode 100644 index 0000000000..d6365bc783 --- /dev/null +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.Fixer.cs @@ -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 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 FixableDiagnosticIds { get; } = ImmutableArray.Create(SealInternalTypes.RuleId); + + public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + } +} diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.cs new file mode 100644 index 0000000000..d0349891bd --- /dev/null +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.cs @@ -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 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.GetInstance(SymbolEqualityComparer.Default); + var baseTypes = PooledConcurrentSet.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(); + }); + } + } +} diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf index e08c223e5a..bda908ae07 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf @@ -2297,6 +2297,26 @@ Zkontrolujte dotazy SQL pro chyby zabezpečení + + Seal class + Seal class + + + + 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. + 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. + + + + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + + + + Seal internal types + Seal internal types + + Set HttpOnly to true for HttpCookie Nastavit HttpOnly na hodnotu true pro HttpCookie diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf index 35813f6313..e0c697382d 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf @@ -2297,6 +2297,26 @@ SQL-Abfragen auf Sicherheitsrisiken überprüfen + + Seal class + Seal class + + + + 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. + 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. + + + + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + + + + Seal internal types + Seal internal types + + Set HttpOnly to true for HttpCookie HttpOnly für HttpCookie auf TRUE festlegen diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf index 0b54ef9431..de09f020fc 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf @@ -2297,6 +2297,26 @@ Revisar consultas SQL para comprobar si tienen vulnerabilidades de seguridad + + Seal class + Seal class + + + + 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. + 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. + + + + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + + + + Seal internal types + Seal internal types + + Set HttpOnly to true for HttpCookie Establecer HttpOnly en true para HttpCookie diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf index 1a4dab8d3f..ac074e59e6 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf @@ -2297,6 +2297,26 @@ Vérifier si les requêtes SQL présentent des failles de sécurité + + Seal class + Seal class + + + + 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. + 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. + + + + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + + + + Seal internal types + Seal internal types + + Set HttpOnly to true for HttpCookie Affectez la valeur true à HttpOnly pour HttpCookie diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf index 934dd37391..56c77c0d05 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf @@ -2297,6 +2297,26 @@ Controllare l'eventuale vulnerabilità di sicurezza delle query SQL + + Seal class + Seal class + + + + 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. + 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. + + + + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + + + + Seal internal types + Seal internal types + + Set HttpOnly to true for HttpCookie Impostare HttpOnly su true per HttpCookie diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf index e90081a08c..7f337896c0 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf @@ -2297,6 +2297,26 @@ SQL クエリのセキュリティ脆弱性を確認 + + Seal class + Seal class + + + + 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. + 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. + + + + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + + + + Seal internal types + Seal internal types + + Set HttpOnly to true for HttpCookie HttpCookie で HttpOnly を true に設定する diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf index 88d5a98aa5..ef26d7d300 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf @@ -2297,6 +2297,26 @@ 보안상 취약한 부분이 있는지 SQL 쿼리를 검토하십시오. + + Seal class + Seal class + + + + 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. + 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. + + + + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + + + + Seal internal types + Seal internal types + + Set HttpOnly to true for HttpCookie HttpCookie에 대해 HttpOnly를 true로 설정 diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf index a93814d5b9..a553fb9cf0 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf @@ -2297,6 +2297,26 @@ Sprawdź zapytania SQL pod kątem luk w zabezpieczeniach + + Seal class + Seal class + + + + 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. + 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. + + + + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + + + + Seal internal types + Seal internal types + + Set HttpOnly to true for HttpCookie Ustaw element HttpOnly na wartość true dla elementu HttpCookie diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf index 812ea76f1a..ba496b07d0 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf @@ -2297,6 +2297,26 @@ Revisar as consultas SQL em busca de vulnerabilidades de segurança + + Seal class + Seal class + + + + 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. + 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. + + + + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + + + + Seal internal types + Seal internal types + + Set HttpOnly to true for HttpCookie Definir HttpOnly como true para HttpCookie diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf index 9d107e44e0..edbc0eb52d 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf @@ -2297,6 +2297,26 @@ Проверка запросов SQL на уязвимости безопасности + + Seal class + Seal class + + + + 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. + 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. + + + + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + + + + Seal internal types + Seal internal types + + Set HttpOnly to true for HttpCookie Установите для параметра HttpOnly объекта HttpCookie значение true diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf index 3168483791..e4b4f86f10 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf @@ -2297,6 +2297,26 @@ SQL sorgularını güvenlik açıkları için inceleyin + + Seal class + Seal class + + + + 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. + 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. + + + + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + + + + Seal internal types + Seal internal types + + Set HttpOnly to true for HttpCookie HttpCookie için HttpOnly'yi true olarak ayarlayın diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf index f87d8df7f9..e02027a819 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf @@ -2297,6 +2297,26 @@ 检查 SQL 查询是否存在安全漏洞 + + Seal class + Seal class + + + + 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. + 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. + + + + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + + + + Seal internal types + Seal internal types + + Set HttpOnly to true for HttpCookie 将 HttpCookie 的 HttpOnly 设置为 true diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf index 9bf73b818f..f27d54a728 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf @@ -2297,6 +2297,26 @@ 必須檢閱 SQL 查詢中是否有安全性弱點 + + Seal class + Seal class + + + + 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. + 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. + + + + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + Type '{0}' can be sealed because it has no subtypes in its containing assembly and is not externally visible + + + + Seal internal types + Seal internal types + + Set HttpOnly to true for HttpCookie 針對 HttpCookie 將 HttpOnly 設為 true diff --git a/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md b/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md index e02886d9e4..798fc7e64c 100644 --- a/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md +++ b/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md @@ -1524,6 +1524,18 @@ Possible multiple enumerations of 'IEnumerable' collection. Consider using an im |CodeFix|False| --- +## [CA1852](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1851): Seal internal types + +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. + +|Item|Value| +|-|-| +|Category|Performance| +|Enabled|True| +|Severity|Hidden| +|CodeFix|True| +--- + ## [CA2000](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2000): Dispose objects before losing scope If a disposable object is not explicitly disposed before all references to it are out of scope, the object will be disposed at some indeterminate time when the garbage collector runs the finalizer of the object. Because an exceptional event might occur that will prevent the finalizer of the object from running, the object should be explicitly disposed instead. diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypesTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypesTests.cs new file mode 100644 index 0000000000..d5355f45be --- /dev/null +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypesTests.cs @@ -0,0 +1,376 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Xunit; + +using VerifyCS = Test.Utilities.CSharpCodeFixVerifier< + Microsoft.NetCore.Analyzers.Runtime.SealInternalTypes, + Microsoft.NetCore.Analyzers.Runtime.SealInternalTypesFixer>; +using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier< + Microsoft.NetCore.Analyzers.Runtime.SealInternalTypes, + Microsoft.NetCore.Analyzers.Runtime.SealInternalTypesFixer>; + +namespace Microsoft.NetCore.Analyzers.Runtime.UnitTests +{ + public class SealInternalTypesTests + { + #region Diagnostic + [Theory] + [InlineData("internal ")] + [InlineData("")] + public Task TopLevelInternalClass_Diagnostic_CS(string accessModifier) + { + string source = $"{accessModifier}class {{|#0:C|}} {{ }}"; + string fixedSource = $"{accessModifier}sealed class C {{ }}"; + var diagnostic = VerifyCS.Diagnostic(Rule).WithArguments("C").WithLocation(0); + + return VerifyCS.VerifyCodeFixAsync(source, diagnostic, fixedSource); + } + + [Theory] + [InlineData("Friend ")] + [InlineData("")] + public Task TopLevelInternalClass_Diagnostic_VB(string accessModifier) + { + string source = $@" +{accessModifier}Class {{|#0:C|}} +End Class"; + string fixedSource = $@" +{accessModifier}NotInheritable Class C +End Class"; + var diagnostic = VerifyVB.Diagnostic(Rule).WithArguments("C").WithLocation(0); + + return VerifyVB.VerifyCodeFixAsync(source, diagnostic, fixedSource); + } + + [Fact] + public Task NonEmptyInternalClass_Diagnostic_CS() + { + string source = @" +internal class {|#0:C|} +{ + private int _i; +}"; + string fixedSource = @" +internal sealed class C +{ + private int _i; +}"; + var diagnostic = VerifyCS.Diagnostic(Rule).WithArguments("C").WithLocation(0); + + return VerifyCS.VerifyCodeFixAsync(source, diagnostic, fixedSource); + } + + [Theory] + [InlineData("internal ")] + [InlineData("")] + public Task InternalClassInNamespace_Diagnostic_CS(string accessModifier) + { + string source = $@" +namespace N +{{ + {accessModifier}class {{|#0:C|}} {{ }} +}}"; + string fixedSource = $@" +namespace N +{{ + {accessModifier}sealed class C {{ }} +}}"; + var diagnostic = VerifyCS.Diagnostic(Rule).WithArguments("C").WithLocation(0); + + return VerifyCS.VerifyCodeFixAsync(source, diagnostic, fixedSource); + } + + [Theory] + [InlineData("Friend ")] + [InlineData("")] + public Task InternalClassInNamespace_Diagnostic_VB(string accessModifier) + { + string source = $@" +Namespace N + {accessModifier}Class {{|#0:C|}} + End Class +End Namespace"; + string fixedSource = $@" +Namespace N + {accessModifier}NotInheritable Class C + End Class +End Namespace"; + var diagnostic = VerifyVB.Diagnostic(Rule).WithArguments("C").WithLocation(0); + + return VerifyVB.VerifyCodeFixAsync(source, diagnostic, fixedSource); + } + + [Theory] + [InlineData("public", "internal")] + [InlineData("public", "private")] + [InlineData("public", "private protected")] + [InlineData("internal", "public")] + [InlineData("internal", "internal protected")] + public Task NestedOneDeep_NotExternallyVisible_Diagnostic_CS(string outerModifiers, string innerModifiers) + { + string source = $@" +{outerModifiers} sealed class Outer +{{ + {innerModifiers} class {{|#0:C|}} {{ }} +}}"; + string fixedSource = $@" +{outerModifiers} sealed class Outer +{{ + {innerModifiers} sealed class C {{ }} +}}"; + var diagnostic = VerifyCS.Diagnostic(Rule).WithArguments("C").WithLocation(0); + + return VerifyCS.VerifyCodeFixAsync(source, diagnostic, fixedSource); + } + + [Theory] + [InlineData("Public", "Friend")] + [InlineData("Public", "Private")] + [InlineData("Public", "Private Protected")] + [InlineData("Friend", "Public")] + [InlineData("Friend", "Friend Protected")] + public Task NestedOneDeep_NotExternallyVisible_Diagnostic_VB(string outerModifiers, string innerModifiers) + { + string source = $@" +{outerModifiers} NotInheritable Class Outer + {innerModifiers} Class {{|#0:C|}} + End Class +End Class"; + string fixedSource = $@" +{outerModifiers} NotInheritable Class Outer + {innerModifiers} NotInheritable Class C + End Class +End Class"; + var diagnostic = VerifyVB.Diagnostic(Rule).WithArguments("C").WithLocation(0); + + return VerifyVB.VerifyCodeFixAsync(source, diagnostic, fixedSource); + } + + [Theory] + [InlineData("public", "public", "internal")] + [InlineData("internal", "internal protected", "public")] + [InlineData("public", "private protected", "public")] + public Task NestedTwoDeep_NotExternallyVisible_Diagnostic_CS(string outerModifiers, string middleModifiers, string innerModifiers) + { + string source = $@" +{outerModifiers} sealed class Outer +{{ + {middleModifiers} sealed class Middle + {{ + {innerModifiers} class {{|#0:C|}} {{ }} + }} +}}"; + string fixedSource = $@" +{outerModifiers} sealed class Outer +{{ + {middleModifiers} sealed class Middle + {{ + {innerModifiers} sealed class {{|#0:C|}} {{ }} + }} +}}"; + var diagnostic = VerifyCS.Diagnostic(Rule).WithArguments("C").WithLocation(0); + + return VerifyCS.VerifyCodeFixAsync(source, diagnostic, fixedSource); + } + + [Theory] + [InlineData("Public", "Public", "Friend")] + [InlineData("Friend", "Friend Protected", "Public")] + [InlineData("Public", "Private Protected", "Public")] + public Task NestedTwoDeep_NotExternallyVisible_Diagnostic_VB(string outerModifiers, string middleModifiers, string innerModifiers) + { + string source = $@" +{outerModifiers} NotInheritable Class Outer + {middleModifiers} NotInheritable Class Middle + {innerModifiers} Class {{|#0:C|}} + End Class + End Class +End Class"; + string fixedSource = $@" +{outerModifiers} NotInheritable Class Outer + {middleModifiers} NotInheritable Class Middle + {innerModifiers} NotInheritable Class C + End Class + End Class +End Class"; + var diagnostic = VerifyVB.Diagnostic(Rule).WithArguments("C").WithLocation(0); + + return VerifyVB.VerifyCodeFixAsync(source, diagnostic, fixedSource); + } + #endregion + + #region No Diagnostic + [Theory] + [InlineData("interface I { }")] + [InlineData("struct S { }")] + [InlineData("enum E { None }")] + [InlineData("delegate void D();")] + [InlineData("static class C { }")] + public Task NonClassType_NoDiagnostic_CS(string declaration) + { + string source = $"internal {declaration}"; + + return VerifyCS.VerifyCodeFixAsync(source, source); + } + + [Theory] + [InlineData("Interface I", "End Interface")] + [InlineData("Structure S", "End Structure")] + [InlineData(@"Enum E + None", "End Enum")] + [InlineData("Delegate Sub D()", "")] + [InlineData("Module M", "End Module")] + public Task NonClassType_NoDiagnostic_VB(string declaration, string endDeclaration) + { + string source = $@" +Friend {declaration} +{endDeclaration}"; + + return VerifyVB.VerifyCodeFixAsync(source, source); + } + + [Fact] + public Task ClassWithDerivedType_NoDiagnostic_CS() + { + string source = @" +internal class B { } +internal sealed class D : B { }"; + + return VerifyCS.VerifyCodeFixAsync(source, source); + } + + [Fact] + public Task ClassWithDerivedType_NoDiagnostic_VB() + { + string source = @" +Friend Class B +End Class +Friend NotInheritable Class D : Inherits B +End Class"; + + return VerifyVB.VerifyCodeFixAsync(source, source); + } + + [Fact] + public Task AbstractClass_NoDiagnostic_CS() + { + string source = "internal abstract class C { }"; + + return VerifyCS.VerifyCodeFixAsync(source, source); + } + + [Fact] + public Task AbstractClass_NoDiagnostic_VB() + { + string source = @" +Friend MustInherit Class C +End Class"; + + return VerifyVB.VerifyCodeFixAsync(source, source); + } + + [Theory] + [InlineData("B { }", "D : B { }")] + [InlineData("B { }", "D : B { }")] + [InlineData("B { }", "D : B { }")] + public Task GenericClass_WithSubclass_NoDiagnostic_CS(string baseClass, string derivedClass) + { + string source = $@" +internal class {baseClass} +internal sealed class {derivedClass}"; + + return VerifyCS.VerifyCodeFixAsync(source, source); + } + + [Theory] + [InlineData("B(Of T)", "D : Inherits B(Of Integer)")] + [InlineData("B(Of T)", "D(Of T) : Inherits B(Of T)")] + [InlineData("B(Of T, U)", "D(Of T) : Inherits B(Of T, Integer)")] + public Task GenericClass_WithSubclass_NoDiagnostic_VB(string baseClass, string derivedClass) + { + string source = $@" +Friend Class {baseClass} +End Class + +Friend NotInheritable Class {derivedClass} +End Class"; + + return VerifyVB.VerifyCodeFixAsync(source, source); + } + + [Fact] + public Task PartialClass_ReportedAndFixedAtAllLocations_CS() + { + var test = new VerifyCS.Test + { + TestState = + { + Sources = + { + @"internal class Base { }", + @"internal partial class {|#0:Derived|} : Base { }", + @"internal partial class {|#1:Derived|} : Base { }" + }, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(Rule).WithArguments("Derived").WithLocation(0).WithLocation(1) + } + }, + FixedState = + { + Sources = + { + @"internal class Base { }", + @"internal sealed partial class Derived : Base { }", + @"internal sealed partial class Derived : Base { }" + } + } + }; + return test.RunAsync(); + } + + [Fact] + public Task PartialClass_ReportedAndFixedAtAllLocations_VB() + { + var test = new VerifyVB.Test + { + TestState = + { + Sources = + { + @" +Friend Class Base +End Class", @" +Partial Friend Class {|#0:Derived|} : Inherits Base +End Class", @" +Partial Friend Class {|#1:Derived|} : Inherits Base +End Class" + }, + ExpectedDiagnostics = + { + VerifyVB.Diagnostic(Rule).WithArguments("Derived").WithLocation(0).WithLocation(1) + } + }, + FixedState = + { + Sources = + { + @" +Friend Class Base +End Class", @" +Partial Friend NotInheritable Class Derived : Inherits Base +End Class", @" +Partial Friend NotInheritable Class Derived : Inherits Base +End Class" + } + } + }; + return test.RunAsync(); + } + #endregion + + private static DiagnosticDescriptor Rule => SealInternalTypes.Rule; + } +} diff --git a/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt b/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt index 49b5edf51a..0155914e50 100644 --- a/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt +++ b/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt @@ -12,7 +12,7 @@ Design: CA2210, CA1000-CA1070 Globalization: CA2101, CA1300-CA1311 Mobility: CA1600-CA1601 -Performance: HA, CA1800-CA1851 +Performance: HA, CA1800-CA1852 Security: CA2100-CA2153, CA2300-CA2330, CA3000-CA3147, CA5300-CA5405 Usage: CA1801, CA1806, CA1816, CA2200-CA2209, CA2211-CA2259 Naming: CA1700-CA1727 From b73159341452de0c13b06ebdb8aec1df3f5ec269 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Fri, 15 Apr 2022 14:31:40 -0400 Subject: [PATCH 2/4] Address PR feedback --- .../Runtime/SealInternalTypes.cs | 17 +++++- .../Runtime/SealInternalTypesTests.cs | 55 +++++++++++++++++++ src/Utilities/Compiler/WellKnownTypeNames.cs | 1 + 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.cs index d0349891bd..14e669f6b5 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.cs @@ -36,6 +36,8 @@ public override void Initialize(AnalysisContext context) private static void OnCompilationStart(CompilationStartAnalysisContext context) { + INamedTypeSymbol? comImportAttributeType = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeInteropServicesComImportAttribute); + var candidateTypes = PooledConcurrentSet.GetInstance(SymbolEqualityComparer.Default); var baseTypes = PooledConcurrentSet.GetInstance(SymbolEqualityComparer.Default); @@ -43,17 +45,26 @@ private static void OnCompilationStart(CompilationStartAnalysisContext context) { var type = (INamedTypeSymbol)context.Symbol; - if (type.TypeKind is TypeKind.Class && !type.IsAbstract && !type.IsStatic && !type.IsSealed && !type.IsExternallyVisible()) + if (type.TypeKind is TypeKind.Class && + !type.IsAbstract && + !type.IsStatic && + !type.IsSealed && + !type.IsExternallyVisible() && + (comImportAttributeType is null || !type.HasAttribute(comImportAttributeType))) + { candidateTypes.Add(type); + } - for (var baseType = type.BaseType; baseType is not null; baseType = baseType.BaseType) + for (INamedTypeSymbol? baseType = type.BaseType; baseType is not null; baseType = baseType.BaseType) + { baseTypes.Add(baseType.OriginalDefinition); + } }, SymbolKind.NamedType); context.RegisterCompilationEndAction(context => { - foreach (var type in candidateTypes) + foreach (INamedTypeSymbol type in candidateTypes) { if (!baseTypes.Contains(type.OriginalDefinition)) { diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypesTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypesTests.cs index d5355f45be..28320ab2c0 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypesTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypesTests.cs @@ -202,6 +202,30 @@ End Class #endregion #region No Diagnostic + [Fact] + public Task PublicClassType_NoDiagnostic_CS() + { + string source = $"public class C {{ protected class P {{ }} }}"; + + return VerifyCS.VerifyCodeFixAsync(source, source); + } + + [Fact] + public Task AlreadySealedType_NoDiagnostic_CS() + { + string source = $"internal sealed class C {{ }}"; + + return VerifyCS.VerifyCodeFixAsync(source, source); + } + + [Fact] + public Task ComImportAttributedType_NoDiagnostic_CS() + { + string source = $"[System.Runtime.InteropServices.ComImport] [System.Runtime.InteropServices.Guid(\"E8D59775-E821-4D6C-B63D-BB0D969361DA\")] internal class C {{ }}"; + + return VerifyCS.VerifyCodeFixAsync(source, source); + } + [Theory] [InlineData("interface I { }")] [InlineData("struct S { }")] @@ -331,6 +355,37 @@ public Task PartialClass_ReportedAndFixedAtAllLocations_CS() return test.RunAsync(); } + [Fact(Skip = "Changes are being applied to .g.cs file")] + public Task PartialClass_OneGenerated_ReportedAndFixedAtAllNonGeneratedLocations_CS() + { + var test = new VerifyCS.Test + { + TestState = + { + Sources = + { + ("File1.cs", @"internal class Base { }"), + ("File2.cs", @"internal partial class {|#0:Derived|} : Base { }"), + ("File3.g.cs", @"internal partial class {|#1:Derived|} : Base { }") + }, + ExpectedDiagnostics = + { + VerifyCS.Diagnostic(Rule).WithArguments("Derived").WithLocation(0).WithLocation(1) + } + }, + FixedState = + { + Sources = + { + ("File1.cs", @"internal class Base { }"), + ("File2.cs", @"internal sealed partial class {|#0:Derived|} : Base { }"), + ("File3.g.cs", @"internal partial class {|#1:Derived|} : Base { }") + } + } + }; + return test.RunAsync(); + } + [Fact] public Task PartialClass_ReportedAndFixedAtAllLocations_VB() { diff --git a/src/Utilities/Compiler/WellKnownTypeNames.cs b/src/Utilities/Compiler/WellKnownTypeNames.cs index 567a1ad5cf..124128a89b 100644 --- a/src/Utilities/Compiler/WellKnownTypeNames.cs +++ b/src/Utilities/Compiler/WellKnownTypeNames.cs @@ -296,6 +296,7 @@ internal static class WellKnownTypeNames public const string SystemRuntimeExceptionServicesHandleProcessCorruptedStateExceptionsAttribute = "System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptionsAttribute"; public const string SystemRuntimeInteropServicesCharSet = "System.Runtime.InteropServices.CharSet"; public const string SystemRuntimeInteropServicesCoClassAttribute = "System.Runtime.InteropServices.CoClassAttribute"; + public const string SystemRuntimeInteropServicesComImportAttribute = "System.Runtime.InteropServices.ComImportAttribute"; public const string SystemRuntimeInteropServicesComSourceInterfacesAttribute = "System.Runtime.InteropServices.ComSourceInterfacesAttribute"; public const string SystemRuntimeInteropServicesComVisibleAttribute = "System.Runtime.InteropServices.ComVisibleAttribute"; public const string SystemRuntimeInteropServicesDefaultDllImportSearchPathsAttribute = "System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute"; From 1ac1aad8ddc9a055c85c5e13362f0e5165626a27 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Sat, 16 Apr 2022 23:19:20 -0400 Subject: [PATCH 3/4] Run pack --- .../Microsoft.CodeAnalysis.NetAnalyzers.md | 2 +- .../Microsoft.CodeAnalysis.NetAnalyzers.sarif | 21 +++++++++++++++++++ src/NetAnalyzers/RulesMissingDocumentation.md | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md b/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md index 798fc7e64c..546f45a956 100644 --- a/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md +++ b/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md @@ -1524,7 +1524,7 @@ Possible multiple enumerations of 'IEnumerable' collection. Consider using an im |CodeFix|False| --- -## [CA1852](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1851): Seal internal types +## [CA1852](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1852): Seal internal types 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. diff --git a/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.sarif b/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.sarif index 83366f0b86..9e709a3c87 100644 --- a/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.sarif +++ b/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.sarif @@ -2820,6 +2820,27 @@ ] } }, + "CA1852": { + "id": "CA1852", + "shortDescription": "Seal internal types", + "fullDescription": "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.", + "defaultLevel": "hidden", + "helpUri": "https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1852", + "properties": { + "category": "Performance", + "isEnabledByDefault": true, + "typeName": "SealInternalTypes", + "languages": [ + "C#", + "Visual Basic" + ], + "tags": [ + "Telemetry", + "EnabledRuleInAggressiveMode", + "CompilationEnd" + ] + } + }, "CA2000": { "id": "CA2000", "shortDescription": "Dispose objects before losing scope", diff --git a/src/NetAnalyzers/RulesMissingDocumentation.md b/src/NetAnalyzers/RulesMissingDocumentation.md index 0a42efdcfe..71f7836791 100644 --- a/src/NetAnalyzers/RulesMissingDocumentation.md +++ b/src/NetAnalyzers/RulesMissingDocumentation.md @@ -5,5 +5,6 @@ Rule ID | Missing Help Link | Title | CA1311 | | Specify a culture or use an invariant version | CA1420 | | Property, type, or attribute requires runtime marshalling | CA1421 | | This method uses runtime marshalling even when the 'DisableRuntimeMarshallingAttribute' is applied | +CA1852 | | Seal internal types | CA2019 | | Improper 'ThreadStatic' field initialization | CA2259 | | 'ThreadStatic' only affects static fields | From afccbbc28e819a2d1562d6fd006768f8ea7b8e54 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Sat, 16 Apr 2022 23:58:54 -0400 Subject: [PATCH 4/4] Update src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.cs Co-authored-by: Youssef Victor --- .../Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.cs index 14e669f6b5..a3f8d94d40 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/SealInternalTypes.cs @@ -50,7 +50,7 @@ private static void OnCompilationStart(CompilationStartAnalysisContext context) !type.IsStatic && !type.IsSealed && !type.IsExternallyVisible() && - (comImportAttributeType is null || !type.HasAttribute(comImportAttributeType))) + !type.HasAttribute(comImportAttributeType)) { candidateTypes.Add(type); }