-
Notifications
You must be signed in to change notification settings - Fork 480
Add analyzer for banning APIs in analyzers #6115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c59b0de
484e7fb
d5114f5
39c440c
14aa4b4
90cd8ee
0c6e336
b7fec78
1026880
137d484
31b97a7
a144be8
e55b206
3eeb0db
c74aa15
72b4bd9
2935495
6738a96
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. | ||
|
|
||
| using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
| using Microsoft.CodeAnalysis.Diagnostics; | ||
| using Microsoft.CodeAnalysis.Analyzers; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.Analyzers | ||
| { | ||
| [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
| public sealed class CSharpSymbolIsBannedInAnalyzersAnalyzer : SymbolIsBannedInAnalyzersAnalyzer<SyntaxKind> | ||
| { | ||
| protected override SyntaxKind XmlCrefSyntaxKind => SyntaxKind.XmlCrefAttribute; | ||
|
|
||
| protected override SymbolDisplayFormat SymbolDisplayFormat => SymbolDisplayFormat.CSharpShortErrorMessageFormat; | ||
|
|
||
| protected override SyntaxNode GetReferenceSyntaxNodeFromXmlCref(SyntaxNode syntaxNode) => ((XmlCrefAttributeSyntax)syntaxNode).Cref; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| T:System.IO.File; Do not do file IO in analyzers | ||
| T:System.IO.Directory; Do not do file IO in analyzers | ||
| M:System.IO.Path.GetTempPath; Do not do file IO in analyzers | ||
| T:System.Environment; Analyzers should not read their settings directly from environment variables | ||
| M:System.Reflection.Assembly.Load(System.Byte[]); Analyzers should only load their dependencies via standard runtime mechanisms | ||
| M:System.Reflection.Assembly.Load(System.String); Analyzers should only load their dependencies via standard runtime mechanisms | ||
| M:System.Reflection.Assembly.Load(System.Reflection.AssemblyName); Analyzers should only load their dependencies via standard runtime mechanisms | ||
| M:System.Reflection.Assembly.Load(System.Byte[],System.Byte[]); Analyzers should only load their dependencies via standard runtime mechanisms | ||
| P:System.Globalization.CultureInfo.CurrentCulture; Analyzers should use the locale given by the compiler command line arguments, not the CurrentCulture | ||
| P:System.Globalization.CultureInfo.CurrentUICulture; Analyzers should use the locale given by the compiler command line arguments, not the CurrentUICulture | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,8 @@ | ||
| ; Please do not edit this file manually, it should only be updated through code fix application. | ||
|
|
||
| ### New Rules | ||
|
|
||
| Rule ID | Category | Severity | Notes | ||
| --------|----------|----------|------- | ||
| RS1035 | MicrosoftCodeAnalysisCorrectness | Error | SymbolIsBannedInAnalyzersAnalyzer | ||
| RS1036 | MicrosoftCodeAnalysisCorrectness | Warning | SymbolIsBannedInAnalyzersAnalyzer |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. | ||
|
|
||
| using System.Collections.Generic; | ||
| using System.Collections.Immutable; | ||
| using System.Linq; | ||
| using Analyzer.Utilities; | ||
| using Analyzer.Utilities.Extensions; | ||
| using Microsoft.CodeAnalysis.BannedApiAnalyzers; | ||
| using Microsoft.CodeAnalysis.Diagnostics; | ||
| using Microsoft.CodeAnalysis.Text; | ||
|
|
||
| namespace Microsoft.CodeAnalysis.Analyzers | ||
| { | ||
| using static CodeAnalysisDiagnosticsResources; | ||
|
|
||
| internal static class SymbolIsBannedInAnalyzersAnalyzer | ||
| { | ||
| public static readonly DiagnosticDescriptor SymbolIsBannedRule = new( | ||
| id: DiagnosticIds.SymbolIsBannedInAnalyzersRuleId, | ||
| title: CreateLocalizableResourceString(nameof(SymbolIsBannedInAnalyzersTitle)), | ||
| messageFormat: CreateLocalizableResourceString(nameof(SymbolIsBannedInAnalyzersMessage)), | ||
| category: DiagnosticCategory.MicrosoftCodeAnalysisCorrectness, | ||
| defaultSeverity: DiagnosticSeverity.Error, | ||
| isEnabledByDefault: true, | ||
| description: CreateLocalizableResourceString(nameof(SymbolIsBannedInAnalyzersDescription)), | ||
| helpLinkUri: null, | ||
| customTags: WellKnownDiagnosticTagsExtensions.Telemetry); | ||
|
|
||
| public static readonly DiagnosticDescriptor NoSettingSpecifiedSymbolIsBannedRule = new( | ||
| id: DiagnosticIds.NoSettingSpecifiedSymbolIsBannedInAnalyzersRuleId, | ||
| title: CreateLocalizableResourceString(nameof(NoSettingSpecifiedSymbolIsBannedInAnalyzersTitle)), | ||
| messageFormat: CreateLocalizableResourceString(nameof(NoSettingSpecifiedSymbolIsBannedInAnalyzersMessage)), | ||
| category: DiagnosticCategory.MicrosoftCodeAnalysisCorrectness, | ||
| defaultSeverity: DiagnosticSeverity.Warning, | ||
| isEnabledByDefault: true, | ||
| description: CreateLocalizableResourceString(nameof(NoSettingSpecifiedSymbolIsBannedInAnalyzersDescription)), | ||
| helpLinkUri: null, | ||
| customTags: WellKnownDiagnosticTagsExtensions.Telemetry); | ||
| } | ||
|
|
||
| public abstract class SymbolIsBannedInAnalyzersAnalyzer<TSyntaxKind> : SymbolIsBannedAnalyzerBase<TSyntaxKind> | ||
| where TSyntaxKind : struct | ||
| { | ||
| public sealed override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(SymbolIsBannedInAnalyzersAnalyzer.SymbolIsBannedRule, SymbolIsBannedInAnalyzersAnalyzer.NoSettingSpecifiedSymbolIsBannedRule); | ||
|
|
||
| protected sealed override DiagnosticDescriptor SymbolIsBannedRule => SymbolIsBannedInAnalyzersAnalyzer.SymbolIsBannedRule; | ||
|
|
||
| #pragma warning disable RS1025, RS1026 // Configure generated code analysis, Enable concurrent execution. Base Initialize handles these. | ||
| public sealed override void Initialize(AnalysisContext context) | ||
| { | ||
| base.Initialize(context); | ||
|
|
||
| context.RegisterCompilationStartAction(analyzeAnalyzersAndGeneratorsIfPropertyNotSpecified); | ||
| void analyzeAnalyzersAndGeneratorsIfPropertyNotSpecified(CompilationStartAnalysisContext context) | ||
| { | ||
| var propertyValue = context.Options.GetMSBuildPropertyValue(MSBuildPropertyOptionNames.EnforceExtendedAnalyzerRules, context.Compilation); | ||
| // Note: in absence of any value for this property in the project, the generated editorconfig will have an entry like: | ||
| // `build_property.EnforceExtendedAnalyzerRules = ` | ||
| if (!string.IsNullOrEmpty(propertyValue)) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| var provider = WellKnownTypeProvider.GetOrCreate(context.Compilation); | ||
| var diagnosticAnalyzerAttributeType = provider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftCodeAnalysisDiagnosticsDiagnosticAnalyzerAttribute); | ||
| var generatorAttributeType = provider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftCodeAnalysisGeneratorAttribute); | ||
| context.RegisterSymbolAction(analyzePossibleAnalyzerOrGenerator, SymbolKind.NamedType); | ||
|
|
||
| void analyzePossibleAnalyzerOrGenerator(SymbolAnalysisContext symbolAnalysisContext) | ||
| { | ||
| var symbol = symbolAnalysisContext.Symbol; | ||
|
|
||
| var attributes = symbol.GetAttributes(); | ||
| if (attributes.Any(shouldReportNotSpecifiedEnforceAnalyzerBannedApisSetting)) | ||
| { | ||
| symbolAnalysisContext.ReportDiagnostic(symbol.Locations.CreateDiagnostic(SymbolIsBannedInAnalyzersAnalyzer.NoSettingSpecifiedSymbolIsBannedRule, symbol)); | ||
| } | ||
|
|
||
| bool shouldReportNotSpecifiedEnforceAnalyzerBannedApisSetting(AttributeData attributeData) | ||
| { | ||
| return attributeData.AttributeClass.Equals(diagnosticAnalyzerAttributeType, SymbolEqualityComparer.Default) | ||
| || attributeData.AttributeClass.Equals(generatorAttributeType, SymbolEqualityComparer.Default); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #pragma warning disable RS1012 // 'compilationContext' does not register any analyzer actions. Consider moving actions registered in 'Initialize' that depend on this start action to 'compilationContext'. | ||
| protected sealed override Dictionary<ISymbol, BanFileEntry>? ReadBannedApis(CompilationStartAnalysisContext compilationContext) | ||
| { | ||
| var propertyValue = compilationContext.Options.GetMSBuildPropertyValue(MSBuildPropertyOptionNames.EnforceExtendedAnalyzerRules, compilationContext.Compilation); | ||
| if (propertyValue != "true") | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| const string fileName = "Microsoft.CodeAnalysis.Analyzers.AnalyzerBannedSymbols.txt"; | ||
| using var stream = typeof(SymbolIsBannedInAnalyzersAnalyzer<>).Assembly.GetManifestResourceStream(fileName); | ||
| var source = SourceText.From(stream); | ||
| var result = new Dictionary<ISymbol, BanFileEntry>(SymbolEqualityComparer.Default); | ||
| foreach (var line in source.Lines) | ||
| { | ||
| var text = line.ToString(); | ||
| if (string.IsNullOrWhiteSpace(text)) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| var entry = new BanFileEntry(text, line.Span, source, fileName); | ||
| var symbols = DocumentationCommentId.GetSymbolsForDeclarationId(entry.DeclarationId, compilationContext.Compilation); | ||
| if (!symbols.IsDefaultOrEmpty) | ||
| { | ||
| foreach (var symbol in symbols) | ||
| { | ||
| result.Add(symbol, entry); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,9 @@ | |
| <PackageId>*$(MSBuildProjectFile)*</PackageId> | ||
| </PropertyGroup> | ||
| <ItemGroup> | ||
| <Compile Include="..\..\Microsoft.CodeAnalysis.BannedApiAnalyzers\Core\SymbolIsBannedAnalyzerBase.cs" Link="SymbolIsBannedAnalyzerBase.cs" /> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another option is to move this file into the shared utilities project, similar to the common base type shared across analyzer packages here: https://github.com/dotnet/roslyn-analyzers/blob/main/src/Utilities/Compiler/DoNotCatchGeneralUnlessRethrown.cs
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wasn't able to make this work. I might not have gotten the configuration of the shproj or some |
||
| <EmbeddedResource Include="AnalyzerBannedSymbols.txt" /> | ||
|
|
||
| <InternalsVisibleTo Include="Microsoft.CodeAnalysis.CSharp.Analyzers" /> | ||
| <InternalsVisibleTo Include="Microsoft.CodeAnalysis.VisualBasic.Analyzers" /> | ||
| <InternalsVisibleTo Include="Microsoft.CodeAnalysis.Analyzers.UnitTests" /> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@RikkiGibson Should all "analyzers" in these messages be updated to "analyzers or generators"