From f6061f12aec213565a2716da78ecd1d764e6f4df Mon Sep 17 00:00:00 2001 From: Newell Clark Date: Fri, 15 Apr 2022 10:29:22 -0400 Subject: [PATCH] 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 ef5ad1de54..0101f9a00c 100644 --- a/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md +++ b/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md @@ -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) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx index 7bd95c59ba..6fc035de5d 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx @@ -1891,4 +1891,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 a92eeb0620..bb998b260d 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 6c4a810915..6321508276 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 07fc504139..c50411f25f 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 f4ab69718b..17f9b263f3 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 7e2b692563..596142761d 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 56b953e397..2098cdfc67 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 c08329f4b9..b49fafd059 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 dfb7308b44..615f45650d 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 805e7e2cc7..cce5ccf974 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 dced9dd7bf..24004a3522 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 157592c7a9..85c5f8edbe 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 4b38754a88..98ac56185b 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 4203b1bb08..c671c08dd5 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 d54dbfc267..720ee8d75d 100644 --- a/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md +++ b/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md @@ -1512,6 +1512,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 00047670f8..7e4a3a9549 100644 --- a/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt +++ b/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt @@ -12,7 +12,7 @@ Design: CA2210, CA1000-CA1070 Globalization: CA2101, CA1300-CA1310 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