From 17ccf43fb3410d5e1a49ab32040f86ecfa7be70b Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Tue, 1 Aug 2023 11:16:13 -0700 Subject: [PATCH 01/18] Initial implementation of AZC0020 --- .../AZC0020Tests.cs | 63 +++++++++++++ .../BannedTypesAnalyzer.cs | 90 +++++++++++++++++++ .../Azure.ClientSdk.Analyzers/Descriptors.cs | 9 +- 3 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs create mode 100644 src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs new file mode 100644 index 00000000000..425ba61b47c --- /dev/null +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Threading.Tasks; +using Xunit; +using Verifier = Azure.ClientSdk.Analyzers.Tests.AzureAnalyzerVerifier; + +namespace Azure.ClientSdk.Analyzers.Tests +{ + public class AZC0020Tests + { + [Theory] + [InlineData("public class {|AZC0020:Class|}: System.IProgress { public void Report (JsonElement {|AZC0020:value|}) {} }")] + [InlineData("public void Report(MutableJsonDocument {|AZC0020:value|}) {}")] + [InlineData("public MutableJsonDocument {|AZC0020:Report|}() { return default; }")] + [InlineData("public IEnumerable {|AZC0020:Report|}() { return default; }")] + [InlineData("public MutableJsonDocument {|AZC0020:Report|} { get; }")] + [InlineData("public MutableJsonDocument {|AZC0020:Report|};")] + [InlineData("public event EventHandler {|AZC0020:Report|};")] + [InlineData("protected MutableJsonDocument {|AZC0020:Report|};")] + public async Task AZC0020ProducedForMutableJsonTypeUsageInPublicApi(string usage) + { + string code = $@" +using System; +using System.Threading.Tasks; +using System.Text.Json; +using System.Collections.Generic; +using Azure.Core.Json; + +namespace RandomNamespace +{{ + public class SomeClient + {{ + {usage} + }} +}}"; + await Verifier.VerifyAnalyzerAsync(code); + } + + + [Theory] + [InlineData("internal class Class: System.IProgress { public void Report (JsonElement value) {} }")] + [InlineData("public void Report(string value) {}")] + public async Task AZC0020NotProducedForNonPublicApisOrAllowedTypes(string usage) + { + string code = $@" +using System; +using System.Threading.Tasks; +using System.Text.Json; +using System.Collections.Generic; +using Azure.Core.Json; + +namespace RandomNamespace +{{ + public class SomeClient + {{ + {usage} + }} +}}"; + await Verifier.VerifyAnalyzerAsync(code); + } + } +} diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs new file mode 100644 index 00000000000..c02b6399a9e --- /dev/null +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs @@ -0,0 +1,90 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Azure.ClientSdk.Analyzers +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public sealed class BannedTypesAnalyzer : SymbolAnalyzerBase + { + private static HashSet BannedTypes = new HashSet() + { + "MutableJsonDocument", + "MutableJsonElement", + "MutableJsonChange" + }; + + private static readonly string BannedTypesMessageArgs = string.Join(", ", BannedTypes); + + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Descriptors.AZC0014); + + public override SymbolKind[] SymbolKinds { get; } = new[] + { + SymbolKind.Method, + SymbolKind.Field, + SymbolKind.Property, + SymbolKind.Parameter, + SymbolKind.Event, + SymbolKind.NamedType + }; + + public override void Analyze(ISymbolAnalysisContext context) + { + static void CheckType(ISymbolAnalysisContext context, ITypeSymbol type, ISymbol symbol) + { + if (type is INamedTypeSymbol namedTypeSymbol) + { + if (BannedTypes.Contains(type.Name)) + { + context.ReportDiagnostic(Diagnostic.Create(Descriptors.AZC0020, symbol.Locations.First(), BannedTypesMessageArgs), symbol); + } + + if (namedTypeSymbol.IsGenericType) + { + foreach (var typeArgument in namedTypeSymbol.TypeArguments) + { + CheckType(context, typeArgument, symbol); + } + } + } + } + + if (!IsPublicApi(context.Symbol)) + { + return; + } + + switch (context.Symbol) + { + case IParameterSymbol parameterSymbol: + CheckType(context, parameterSymbol.Type, parameterSymbol); + break; + case IMethodSymbol methodSymbol: + if (methodSymbol.MethodKind == MethodKind.PropertyGet || methodSymbol.MethodKind == MethodKind.PropertySet) + { + return; + } + CheckType(context, methodSymbol.ReturnType, methodSymbol); + break; + case IEventSymbol eventSymbol: + CheckType(context, eventSymbol.Type, eventSymbol); + break; + case IPropertySymbol propertySymbol: + CheckType(context, propertySymbol.Type, propertySymbol); + break; + case IFieldSymbol fieldSymbol: + CheckType(context, fieldSymbol.Type, fieldSymbol); + break; + case INamedTypeSymbol namedTypeSymbol: + CheckType(context, namedTypeSymbol.BaseType, namedTypeSymbol); + foreach (var iface in namedTypeSymbol.Interfaces) + { + CheckType(context, iface, namedTypeSymbol); + } + break; + } + } + } +} diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/Descriptors.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/Descriptors.cs index 42161acffca..5e20d20bb6c 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/Descriptors.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/Descriptors.cs @@ -122,7 +122,14 @@ internal class Descriptors nameof(AZC0018), "Do ensure protocol method take a RequestContext parameter called context and not take models as parameter type or return type.", "Protocol method should have requestContext as the last parameter and don't have model as parameter type or return type.", - "Usage", DiagnosticSeverity.Warning, isEnabledByDefault: true, description: null); + "Usage", DiagnosticSeverity.Warning, isEnabledByDefault: true, description: null); + + public static DiagnosticDescriptor AZC0020 = new DiagnosticDescriptor( + nameof(AZC0020), + "Avoid using banned types in public API", + "The Azure.Core internal shared source type {0} should not be used outside Azure.Core.", + "Usage", + DiagnosticSeverity.Warning, true); #endregion #region General From c44a581731a3c7cb489f63e6e8958566686f1e55 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Tue, 1 Aug 2023 17:18:14 -0700 Subject: [PATCH 02/18] Updates --- .../AZC0020Tests.cs | 23 ------------------- .../Shared/MutableJsonDocument.cs | 12 ++++++++++ 2 files changed, 12 insertions(+), 23 deletions(-) create mode 100644 src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/Shared/MutableJsonDocument.cs diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs index 425ba61b47c..92c99c706fa 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs @@ -27,29 +27,6 @@ public async Task AZC0020ProducedForMutableJsonTypeUsageInPublicApi(string usage using System.Collections.Generic; using Azure.Core.Json; -namespace RandomNamespace -{{ - public class SomeClient - {{ - {usage} - }} -}}"; - await Verifier.VerifyAnalyzerAsync(code); - } - - - [Theory] - [InlineData("internal class Class: System.IProgress { public void Report (JsonElement value) {} }")] - [InlineData("public void Report(string value) {}")] - public async Task AZC0020NotProducedForNonPublicApisOrAllowedTypes(string usage) - { - string code = $@" -using System; -using System.Threading.Tasks; -using System.Text.Json; -using System.Collections.Generic; -using Azure.Core.Json; - namespace RandomNamespace {{ public class SomeClient diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/Shared/MutableJsonDocument.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/Shared/MutableJsonDocument.cs new file mode 100644 index 00000000000..66b9099cb99 --- /dev/null +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/Shared/MutableJsonDocument.cs @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Core.Json +{ + /// + /// A mutable representation of a JSON value. + /// + internal sealed partial class MutableJsonDocument + { + } +} From 45252a5234565af70261369f92d8f8c78a1ba84f Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Mon, 7 Aug 2023 13:47:48 -0700 Subject: [PATCH 03/18] Update --- .../AZC0020Tests.cs | 64 ++++++++++++------- .../AzureAnalyzerVerifier.cs | 28 +++++++- .../BannedTypesAnalyzer.cs | 7 +- .../Azure.ClientSdk.Analyzers/Descriptors.cs | 4 +- 4 files changed, 70 insertions(+), 33 deletions(-) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs index 92c99c706fa..8e09b402156 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs @@ -9,31 +9,51 @@ namespace Azure.ClientSdk.Analyzers.Tests { public class AZC0020Tests { - [Theory] - [InlineData("public class {|AZC0020:Class|}: System.IProgress { public void Report (JsonElement {|AZC0020:value|}) {} }")] - [InlineData("public void Report(MutableJsonDocument {|AZC0020:value|}) {}")] - [InlineData("public MutableJsonDocument {|AZC0020:Report|}() { return default; }")] - [InlineData("public IEnumerable {|AZC0020:Report|}() { return default; }")] - [InlineData("public MutableJsonDocument {|AZC0020:Report|} { get; }")] - [InlineData("public MutableJsonDocument {|AZC0020:Report|};")] - [InlineData("public event EventHandler {|AZC0020:Report|};")] - [InlineData("protected MutableJsonDocument {|AZC0020:Report|};")] - public async Task AZC0020ProducedForMutableJsonTypeUsageInPublicApi(string usage) + [Fact] + public async Task AZC0020ProducedForMutableJsonDocumentUsage() { - string code = $@" -using System; -using System.Threading.Tasks; -using System.Text.Json; -using System.Collections.Generic; + string code = @" +using Azure.Core.Json; + +namespace LibraryNamespace +{ + public class Model + { + MutableJsonDocument {|AZC0020:_document|}; + } +}"; + await Verifier.VerifyAnalyzerAsync(code); + } + + [Fact] + public async Task AZC0020ProducedForMutableJsonElementUsage() + { + string code = @" using Azure.Core.Json; -namespace RandomNamespace -{{ - public class SomeClient - {{ - {usage} - }} -}}"; +namespace LibraryNamespace +{ + public class Model + { + MutableJsonElement {|AZC0020:_element|}; + } +}"; + await Verifier.VerifyAnalyzerAsync(code); + } + + [Fact] + public async Task AZC0020NotProducedForAllowedTypeUsage() + { + string code = @" +using System.Text.Json; + +namespace LibraryNamespace +{ + public class Model + { + JsonElement _element; + } +}"; await Verifier.VerifyAnalyzerAsync(code); } } diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs index 12a8d8e858d..b8bc1cf942a 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using System.Collections.Immutable; @@ -19,12 +19,13 @@ namespace Azure.ClientSdk.Analyzers.Tests ReferenceAssemblies.Default.AddPackages(ImmutableArray.Create( new PackageIdentity("Azure.Core", "1.26.0"), new PackageIdentity("Microsoft.Bcl.AsyncInterfaces", "1.1.0"), - new PackageIdentity("System.Text.Json", "4.6.0"), new PackageIdentity("Newtonsoft.Json", "12.0.3"), + new PackageIdentity("System.Text.Json", "4.6.0"), new PackageIdentity("System.Threading.Tasks.Extensions", "4.5.3"))); public static CSharpAnalyzerTest CreateAnalyzer(string source, LanguageVersion languageVersion = LanguageVersion.Latest) - => new CSharpAnalyzerTest + { + CSharpAnalyzerTest < TAnalyzer, XUnitVerifier > test = new CSharpAnalyzerTest { ReferenceAssemblies = DefaultReferenceAssemblies, SolutionTransforms = {(solution, projectId) => @@ -37,6 +38,27 @@ public static CSharpAnalyzerTest CreateAnalyzer(string TestBehaviors = TestBehaviors.SkipGeneratedCodeCheck }; + test.TestState.Sources.Add(("MutableJsonDocument.cs", @" + namespace Azure.Core.Json + { + internal sealed partial class MutableJsonDocument + { + } + } + ")); + + test.TestState.Sources.Add(("MutableJsonElement.cs", @" + namespace Azure.Core.Json + { + internal sealed partial class MutableJsonElement + { + } + } + ")); + + return test; + } + public static Task VerifyAnalyzerAsync(string source, LanguageVersion languageVersion = LanguageVersion.Latest) => CreateAnalyzer(source, languageVersion).RunAsync(CancellationToken.None); diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs index c02b6399a9e..3a2b606ba2c 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs @@ -18,7 +18,7 @@ public sealed class BannedTypesAnalyzer : SymbolAnalyzerBase private static readonly string BannedTypesMessageArgs = string.Join(", ", BannedTypes); - public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Descriptors.AZC0014); + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Descriptors.AZC0020); public override SymbolKind[] SymbolKinds { get; } = new[] { @@ -51,11 +51,6 @@ static void CheckType(ISymbolAnalysisContext context, ITypeSymbol type, ISymbol } } - if (!IsPublicApi(context.Symbol)) - { - return; - } - switch (context.Symbol) { case IParameterSymbol parameterSymbol: diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/Descriptors.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/Descriptors.cs index 5e20d20bb6c..0c66a620a71 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/Descriptors.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/Descriptors.cs @@ -126,8 +126,8 @@ internal class Descriptors public static DiagnosticDescriptor AZC0020 = new DiagnosticDescriptor( nameof(AZC0020), - "Avoid using banned types in public API", - "The Azure.Core internal shared source type {0} should not be used outside Azure.Core.", + "Avoid using banned types in public APIs", + "The Azure.Core internal shared source types {0} should not be used outside of the Azure.Core library.", "Usage", DiagnosticSeverity.Warning, true); #endregion From e322220b1abd7661a5c9aa4563a2a6fa2a9ef622 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Mon, 7 Aug 2023 14:03:15 -0700 Subject: [PATCH 04/18] refactor --- .../AZC0020Tests.cs | 33 +++++++++- .../AzureAnalyzerVerifier.cs | 61 ++++++++----------- .../Shared/MutableJsonDocument.cs | 12 ---- 3 files changed, 55 insertions(+), 51 deletions(-) delete mode 100644 src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/Shared/MutableJsonDocument.cs diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs index 8e09b402156..5ebd8737238 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.Collections.Generic; using System.Threading.Tasks; using Xunit; using Verifier = Azure.ClientSdk.Analyzers.Tests.AzureAnalyzerVerifier; @@ -9,6 +10,32 @@ namespace Azure.ClientSdk.Analyzers.Tests { public class AZC0020Tests { + private List<(string fileName, string source)> _sharedSourceFiles; + + public AZC0020Tests() + { + _sharedSourceFiles = new List<(string fileName, string source)>() { + + ("MutableJsonDocument.cs", @" + namespace Azure.Core.Json + { + internal sealed partial class MutableJsonDocument + { + } + } + "), + + ("MutableJsonElement.cs", @" + namespace Azure.Core.Json + { + internal sealed partial class MutableJsonElement + { + } + } + ") + }; + } + [Fact] public async Task AZC0020ProducedForMutableJsonDocumentUsage() { @@ -22,7 +49,7 @@ public class Model MutableJsonDocument {|AZC0020:_document|}; } }"; - await Verifier.VerifyAnalyzerAsync(code); + await Verifier.VerifyAnalyzerAsync(code, _sharedSourceFiles); } [Fact] @@ -38,7 +65,7 @@ public class Model MutableJsonElement {|AZC0020:_element|}; } }"; - await Verifier.VerifyAnalyzerAsync(code); + await Verifier.VerifyAnalyzerAsync(code, _sharedSourceFiles); } [Fact] @@ -54,7 +81,7 @@ public class Model JsonElement _element; } }"; - await Verifier.VerifyAnalyzerAsync(code); + await Verifier.VerifyAnalyzerAsync(code, _sharedSourceFiles); } } } diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs index b8bc1cf942a..101a33a3c9b 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; @@ -11,7 +12,7 @@ using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Testing.Verifiers; -namespace Azure.ClientSdk.Analyzers.Tests +namespace Azure.ClientSdk.Analyzers.Tests { public static class AzureAnalyzerVerifier where TAnalyzer : DiagnosticAnalyzer, new() { @@ -24,42 +25,20 @@ namespace Azure.ClientSdk.Analyzers.Tests new PackageIdentity("System.Threading.Tasks.Extensions", "4.5.3"))); public static CSharpAnalyzerTest CreateAnalyzer(string source, LanguageVersion languageVersion = LanguageVersion.Latest) - { - CSharpAnalyzerTest < TAnalyzer, XUnitVerifier > test = new CSharpAnalyzerTest - { - ReferenceAssemblies = DefaultReferenceAssemblies, - SolutionTransforms = {(solution, projectId) => - { - var project = solution.GetProject(projectId); - var parseOptions = (CSharpParseOptions)project.ParseOptions; - return solution.WithProjectParseOptions(projectId, parseOptions.WithLanguageVersion(languageVersion)); - }}, - TestCode = source, - TestBehaviors = TestBehaviors.SkipGeneratedCodeCheck - }; - - test.TestState.Sources.Add(("MutableJsonDocument.cs", @" - namespace Azure.Core.Json + => new CSharpAnalyzerTest { - internal sealed partial class MutableJsonDocument - { - } - } - ")); - - test.TestState.Sources.Add(("MutableJsonElement.cs", @" - namespace Azure.Core.Json - { - internal sealed partial class MutableJsonElement - { - } - } - ")); - - return test; - } - - public static Task VerifyAnalyzerAsync(string source, LanguageVersion languageVersion = LanguageVersion.Latest) + ReferenceAssemblies = DefaultReferenceAssemblies, + SolutionTransforms = {(solution, projectId) => + { + var project = solution.GetProject(projectId); + var parseOptions = (CSharpParseOptions)project.ParseOptions; + return solution.WithProjectParseOptions(projectId, parseOptions.WithLanguageVersion(languageVersion)); + }}, + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedCodeCheck + }; + + public static Task VerifyAnalyzerAsync(string source, LanguageVersion languageVersion = LanguageVersion.Latest) => CreateAnalyzer(source, languageVersion).RunAsync(CancellationToken.None); public static Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] diagnostics) @@ -69,6 +48,16 @@ public static Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] return test.RunAsync(CancellationToken.None); } + public static Task VerifyAnalyzerAsync(string source, List<(string fileName, string source)> files) + { + var test = CreateAnalyzer(source); + foreach (var file in files) + { + test.TestState.Sources.Add(file); + } + return test.RunAsync(CancellationToken.None); + } + public static DiagnosticResult Diagnostic(string expectedDescriptor) => AnalyzerVerifier.Diagnostic(expectedDescriptor); } } diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/Shared/MutableJsonDocument.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/Shared/MutableJsonDocument.cs deleted file mode 100644 index 66b9099cb99..00000000000 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/Shared/MutableJsonDocument.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Azure.Core.Json -{ - /// - /// A mutable representation of a JSON value. - /// - internal sealed partial class MutableJsonDocument - { - } -} From 010a6b40e25d00db10b2091fe9dfaf5a5c432be3 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Mon, 7 Aug 2023 14:04:21 -0700 Subject: [PATCH 05/18] whitespace --- .../AzureAnalyzerVerifier.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs index 101a33a3c9b..afe009f60b6 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs @@ -26,17 +26,17 @@ namespace Azure.ClientSdk.Analyzers.Tests public static CSharpAnalyzerTest CreateAnalyzer(string source, LanguageVersion languageVersion = LanguageVersion.Latest) => new CSharpAnalyzerTest - { - ReferenceAssemblies = DefaultReferenceAssemblies, - SolutionTransforms = {(solution, projectId) => + { + ReferenceAssemblies = DefaultReferenceAssemblies, + SolutionTransforms = {(solution, projectId) => { var project = solution.GetProject(projectId); var parseOptions = (CSharpParseOptions)project.ParseOptions; return solution.WithProjectParseOptions(projectId, parseOptions.WithLanguageVersion(languageVersion)); }}, - TestCode = source, - TestBehaviors = TestBehaviors.SkipGeneratedCodeCheck - }; + TestCode = source, + TestBehaviors = TestBehaviors.SkipGeneratedCodeCheck + }; public static Task VerifyAnalyzerAsync(string source, LanguageVersion languageVersion = LanguageVersion.Latest) => CreateAnalyzer(source, languageVersion).RunAsync(CancellationToken.None); From 77497254e56cff3fa3b6e11f21bb14a505671d2b Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Mon, 7 Aug 2023 14:11:02 -0700 Subject: [PATCH 06/18] updates --- .../AzureAnalyzerVerifier.cs | 10 +++++----- .../Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs | 4 ---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs index afe009f60b6..3992a80d1f0 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AzureAnalyzerVerifier.cs @@ -29,11 +29,11 @@ public static CSharpAnalyzerTest CreateAnalyzer(string { ReferenceAssemblies = DefaultReferenceAssemblies, SolutionTransforms = {(solution, projectId) => - { - var project = solution.GetProject(projectId); - var parseOptions = (CSharpParseOptions)project.ParseOptions; - return solution.WithProjectParseOptions(projectId, parseOptions.WithLanguageVersion(languageVersion)); - }}, + { + var project = solution.GetProject(projectId); + var parseOptions = (CSharpParseOptions)project.ParseOptions; + return solution.WithProjectParseOptions(projectId, parseOptions.WithLanguageVersion(languageVersion)); + }}, TestCode = source, TestBehaviors = TestBehaviors.SkipGeneratedCodeCheck }; diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs index 3a2b606ba2c..64185d16da9 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs @@ -57,10 +57,6 @@ static void CheckType(ISymbolAnalysisContext context, ITypeSymbol type, ISymbol CheckType(context, parameterSymbol.Type, parameterSymbol); break; case IMethodSymbol methodSymbol: - if (methodSymbol.MethodKind == MethodKind.PropertyGet || methodSymbol.MethodKind == MethodKind.PropertySet) - { - return; - } CheckType(context, methodSymbol.ReturnType, methodSymbol); break; case IEventSymbol eventSymbol: From 28792b42768b24f0874df71e2569d4eb440b1980 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Wed, 9 Aug 2023 13:35:29 -0700 Subject: [PATCH 07/18] Allow use of shared source types in Azure.Core --- .../Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs index 64185d16da9..03780260b5c 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs @@ -51,6 +51,11 @@ static void CheckType(ISymbolAnalysisContext context, ITypeSymbol type, ISymbol } } + if (IsAzureCore(context.Symbol.ContainingAssembly)) + { + return; + } + switch (context.Symbol) { case IParameterSymbol parameterSymbol: @@ -77,5 +82,10 @@ static void CheckType(ISymbolAnalysisContext context, ITypeSymbol type, ISymbol break; } } + + private bool IsAzureCore(IAssemblySymbol assembly) + { + return assembly.Name.Equals("Azure.Core"); + } } } From b16ca41e6650b5a32d1ea699a452aa327d1c90d7 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Wed, 9 Aug 2023 14:12:47 -0700 Subject: [PATCH 08/18] pr fb --- .../BannedTypesAnalyzer.cs | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs index 03780260b5c..4b5bcfe999c 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs @@ -13,7 +13,7 @@ public sealed class BannedTypesAnalyzer : SymbolAnalyzerBase { "MutableJsonDocument", "MutableJsonElement", - "MutableJsonChange" + "MutableJsonChange", }; private static readonly string BannedTypesMessageArgs = string.Join(", ", BannedTypes); @@ -27,30 +27,11 @@ public sealed class BannedTypesAnalyzer : SymbolAnalyzerBase SymbolKind.Property, SymbolKind.Parameter, SymbolKind.Event, - SymbolKind.NamedType + SymbolKind.NamedType, }; public override void Analyze(ISymbolAnalysisContext context) { - static void CheckType(ISymbolAnalysisContext context, ITypeSymbol type, ISymbol symbol) - { - if (type is INamedTypeSymbol namedTypeSymbol) - { - if (BannedTypes.Contains(type.Name)) - { - context.ReportDiagnostic(Diagnostic.Create(Descriptors.AZC0020, symbol.Locations.First(), BannedTypesMessageArgs), symbol); - } - - if (namedTypeSymbol.IsGenericType) - { - foreach (var typeArgument in namedTypeSymbol.TypeArguments) - { - CheckType(context, typeArgument, symbol); - } - } - } - } - if (IsAzureCore(context.Symbol.ContainingAssembly)) { return; @@ -83,6 +64,25 @@ static void CheckType(ISymbolAnalysisContext context, ITypeSymbol type, ISymbol } } + private static void CheckType(ISymbolAnalysisContext context, ITypeSymbol type, ISymbol symbol) + { + if (type is INamedTypeSymbol namedTypeSymbol) + { + if (BannedTypes.Contains(type.Name)) + { + context.ReportDiagnostic(Diagnostic.Create(Descriptors.AZC0020, symbol.Locations.First(), BannedTypesMessageArgs), symbol); + } + + if (namedTypeSymbol.IsGenericType) + { + foreach (var typeArgument in namedTypeSymbol.TypeArguments) + { + CheckType(context, typeArgument, symbol); + } + } + } + } + private bool IsAzureCore(IAssemblySymbol assembly) { return assembly.Name.Equals("Azure.Core"); From a5b78104df9c35e73fc7bdb93166d5c482b59168 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Wed, 9 Aug 2023 14:48:39 -0700 Subject: [PATCH 09/18] pr fb --- .../AZC0020Tests.cs | 17 +++++++++++++++++ .../BannedTypesAnalyzer.cs | 16 +++++++++++----- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs index 5ebd8737238..f1324da1b2b 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs @@ -80,6 +80,23 @@ public class Model { JsonElement _element; } +}"; + await Verifier.VerifyAnalyzerAsync(code, _sharedSourceFiles); + } + + [Fact] + public async Task AZC0020NotProducedForTypeWithBannedNameButAllowedNamespace() + { + string code = @" +namespace LibraryNamespace +{ + public class MutableJsonDocument + { + } + public class Model + { + MutableJsonDocument _document; + } }"; await Verifier.VerifyAnalyzerAsync(code, _sharedSourceFiles); } diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs index 4b5bcfe999c..d7ceebf58df 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs @@ -11,9 +11,10 @@ public sealed class BannedTypesAnalyzer : SymbolAnalyzerBase { private static HashSet BannedTypes = new HashSet() { - "MutableJsonDocument", - "MutableJsonElement", - "MutableJsonChange", + "Azure.Core.Json.MutableJsonDocument", + "Azure.Core.Json.MutableJsonElement", + "Azure.Core.Json.MutableJsonChange", + "Azure.Core.Json.MutableJsonChangeKind", }; private static readonly string BannedTypesMessageArgs = string.Join(", ", BannedTypes); @@ -68,7 +69,7 @@ private static void CheckType(ISymbolAnalysisContext context, ITypeSymbol type, { if (type is INamedTypeSymbol namedTypeSymbol) { - if (BannedTypes.Contains(type.Name)) + if (IsBannedType(namedTypeSymbol)) { context.ReportDiagnostic(Diagnostic.Create(Descriptors.AZC0020, symbol.Locations.First(), BannedTypesMessageArgs), symbol); } @@ -83,7 +84,12 @@ private static void CheckType(ISymbolAnalysisContext context, ITypeSymbol type, } } - private bool IsAzureCore(IAssemblySymbol assembly) + private static bool IsBannedType(INamedTypeSymbol namedTypeSymbol) + { + return BannedTypes.Contains($"{namedTypeSymbol.ContainingNamespace}.{namedTypeSymbol.Name}"); + } + + private static bool IsAzureCore(IAssemblySymbol assembly) { return assembly.Name.Equals("Azure.Core"); } From ad55b235b8f60a3af96c36daac8b3a946703d934 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Thu, 10 Aug 2023 14:46:59 -0700 Subject: [PATCH 10/18] add back change to file missed in merge --- .../Azure.ClientSdk.Analyzers/Descriptors.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/Descriptors.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/Descriptors.cs index ebcd98325ba..86d9e4d8072 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/Descriptors.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/Descriptors.cs @@ -110,9 +110,16 @@ internal class Descriptors "Invalid ServiceVersion member name.", "All parts of ServiceVersion members' names must begin with a number or uppercase letter and cannot have consecutive underscores.", "Usage", + DiagnosticSeverity.Warning, true); + + public static DiagnosticDescriptor AZC0020 = new DiagnosticDescriptor( + nameof(AZC0020), + "Avoid using banned types in public APIs", + "The Azure.Core internal shared source types {0} should not be used outside of the Azure.Core library.", + "Usage", DiagnosticSeverity.Warning, true); #endregion - + #region General public static DiagnosticDescriptor AZC0100 = new DiagnosticDescriptor( nameof(AZC0100), From c6d2f2209f86ab1986c23ceb807d9804758fbf83 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Thu, 10 Aug 2023 15:47:23 -0700 Subject: [PATCH 11/18] Update tests --- .../AZC0020Tests.cs | 36 ++++++++++++++++++- .../BannedTypesAnalyzer.cs | 9 +++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs index f1324da1b2b..cd0b1a054a0 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs @@ -40,13 +40,47 @@ internal sealed partial class MutableJsonElement public async Task AZC0020ProducedForMutableJsonDocumentUsage() { string code = @" +using System; using Azure.Core.Json; namespace LibraryNamespace { public class Model { - MutableJsonDocument {|AZC0020:_document|}; + private MutableJsonDocument {|AZC0020:_document|}; + internal MutableJsonDocument {|AZC0020:Document|} => {|AZC0020:_document|}; + internal event EventHandler {|AZC0020:_docEvent|}; + + internal MutableJsonDocument {|AZC0020:GetDocument|}(MutableJsonDocument {|AZC0020:value|}) + { + MutableJsonDocument mdoc = new MutableJsonDocument(); + return mdoc; + } + } +}"; + await Verifier.VerifyAnalyzerAsync(code, _sharedSourceFiles); + } + + [Fact] + public async Task AZC0020ProducedForMutableJsonDocumentUsage2() + { + string code = @" +using System; +using Azure.Core.Json; + +namespace LibraryNamespace +{ + public class Model + { + private MutableJsonDocument {|AZC0020:_document|}; + internal MutableJsonDocument {|AZC0020:Document|} => {| AZC0020:_document |}; + internal event EventHandler {|AZC0020:_docEvent|}; + + internal MutableJsonDocument {|AZC0020:GetDocument|}(MutableJsonDocument {|AZC0020:value|}) + { + MutableJsonDocument {|AZC0020:mdoc|} = new MutableJsonDocument(); + return mdoc; + } } }"; await Verifier.VerifyAnalyzerAsync(code, _sharedSourceFiles); diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs index d7ceebf58df..6d992a585f6 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Diagnostics; @@ -29,10 +30,13 @@ public sealed class BannedTypesAnalyzer : SymbolAnalyzerBase SymbolKind.Parameter, SymbolKind.Event, SymbolKind.NamedType, + SymbolKind.Local, }; public override void Analyze(ISymbolAnalysisContext context) { + Debug.WriteLine($"{context.Symbol}"); + if (IsAzureCore(context.Symbol.ContainingAssembly)) { return; @@ -55,6 +59,9 @@ public override void Analyze(ISymbolAnalysisContext context) case IFieldSymbol fieldSymbol: CheckType(context, fieldSymbol.Type, fieldSymbol); break; + case ILocalSymbol localSymbol: + CheckType(context, localSymbol.Type, localSymbol); + break; case INamedTypeSymbol namedTypeSymbol: CheckType(context, namedTypeSymbol.BaseType, namedTypeSymbol); foreach (var iface in namedTypeSymbol.Interfaces) @@ -63,6 +70,8 @@ public override void Analyze(ISymbolAnalysisContext context) } break; } + + Debug.WriteLine($"done"); } private static void CheckType(ISymbolAnalysisContext context, ITypeSymbol type, ISymbol symbol) From e22b67875a8dc38396d93db039b37618dcf08dcd Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Fri, 11 Aug 2023 09:56:38 -0700 Subject: [PATCH 12/18] pr fb; + WIP for local variables --- .../AZC0020Tests.cs | 7 +--- .../BannedTypesAnalyzer.cs | 42 ++++++++++++++++--- .../SymbolAnalyzerBase.cs | 8 +++- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs index cd0b1a054a0..68d86cac279 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs @@ -65,20 +65,15 @@ public class Model public async Task AZC0020ProducedForMutableJsonDocumentUsage2() { string code = @" -using System; using Azure.Core.Json; namespace LibraryNamespace { public class Model { - private MutableJsonDocument {|AZC0020:_document|}; - internal MutableJsonDocument {|AZC0020:Document|} => {| AZC0020:_document |}; - internal event EventHandler {|AZC0020:_docEvent|}; - internal MutableJsonDocument {|AZC0020:GetDocument|}(MutableJsonDocument {|AZC0020:value|}) { - MutableJsonDocument {|AZC0020:mdoc|} = new MutableJsonDocument(); + {|AZC0020:MutableJsonDocument mdoc = new MutableJsonDocument();|} return mdoc; } } diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs index 6d992a585f6..56e1eb70ca1 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; namespace Azure.ClientSdk.Analyzers @@ -24,13 +25,13 @@ public sealed class BannedTypesAnalyzer : SymbolAnalyzerBase public override SymbolKind[] SymbolKinds { get; } = new[] { - SymbolKind.Method, - SymbolKind.Field, - SymbolKind.Property, - SymbolKind.Parameter, SymbolKind.Event, - SymbolKind.NamedType, + SymbolKind.Field, SymbolKind.Local, + SymbolKind.Method, + SymbolKind.NamedType, + SymbolKind.Parameter, + SymbolKind.Property, }; public override void Analyze(ISymbolAnalysisContext context) @@ -49,6 +50,8 @@ public override void Analyze(ISymbolAnalysisContext context) break; case IMethodSymbol methodSymbol: CheckType(context, methodSymbol.ReturnType, methodSymbol); + + //foreach (var typeSymbol in methodSymbol.) break; case IEventSymbol eventSymbol: CheckType(context, eventSymbol.Type, eventSymbol); @@ -74,6 +77,31 @@ public override void Analyze(ISymbolAnalysisContext context) Debug.WriteLine($"done"); } + public override void AnalyzeNode(SyntaxNodeAnalysisContext context) + { + Debug.WriteLine($"{context.Node}"); + + if (IsAzureCore(context.ContainingSymbol.ContainingAssembly)) + { + return; + } + + LocalDeclarationStatementSyntax declaration = context.Node as LocalDeclarationStatementSyntax; + + TypeInfo info = context.SemanticModel.GetTypeInfo(declaration.Declaration.Type); + + ISymbol symbol = info.Type; + ITypeSymbol type = info.Type; + + if (type is INamedTypeSymbol namedTypeSymbol) + { + if (IsBannedType(namedTypeSymbol)) + { + context.ReportDiagnostic(Diagnostic.Create(Descriptors.AZC0020, context.Node.GetLocation(), BannedTypesMessageArgs)); + } + } + } + private static void CheckType(ISymbolAnalysisContext context, ITypeSymbol type, ISymbol symbol) { if (type is INamedTypeSymbol namedTypeSymbol) @@ -100,7 +128,9 @@ private static bool IsBannedType(INamedTypeSymbol namedTypeSymbol) private static bool IsAzureCore(IAssemblySymbol assembly) { - return assembly.Name.Equals("Azure.Core"); + return + assembly.Name.Equals("Azure.Core") || + assembly.Name.Equals("Azure.Core.Experimental"); } } } diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs index c3030310f61..d4c52bc5cda 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; namespace Azure.ClientSdk.Analyzers @@ -14,14 +15,17 @@ public abstract class SymbolAnalyzerBase : DiagnosticAnalyzer public abstract SymbolKind[] SymbolKinds { get; } public abstract void Analyze(ISymbolAnalysisContext context); + public virtual void AnalyzeNode(SyntaxNodeAnalysisContext context) { } + protected INamedTypeSymbol ClientOptionsType { get; private set; } public sealed override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); - context.EnableConcurrentExecution(); + //context.EnableConcurrentExecution(); context.RegisterCompilationStartAction(CompilationStart); context.RegisterSymbolAction(c => Analyze(new RoslynSymbolAnalysisContext(c)), SymbolKinds); + context.RegisterSyntaxNodeAction(c => AnalyzeNode(c), SyntaxKind.LocalDeclarationStatement); } #pragma warning disable RS1012 // Start action has no registered actions. @@ -81,4 +85,4 @@ public void ReportDiagnostic(Diagnostic diagnostic, ISymbol symbol) } } } -} \ No newline at end of file +} From eda6cd83e671ca3430c9c28154d8243a92ce3e60 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Fri, 11 Aug 2023 10:44:54 -0700 Subject: [PATCH 13/18] clean up --- .../AZC0020Tests.cs | 33 ++++++------------- .../BannedTypesAnalyzer.cs | 26 +++++++++------ .../SymbolAnalyzerBase.cs | 6 ++-- 3 files changed, 28 insertions(+), 37 deletions(-) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs index 68d86cac279..f2e2ad16873 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers.Tests/AZC0020Tests.cs @@ -28,7 +28,7 @@ internal sealed partial class MutableJsonDocument ("MutableJsonElement.cs", @" namespace Azure.Core.Json { - internal sealed partial class MutableJsonElement + internal partial struct MutableJsonElement { } } @@ -51,26 +51,6 @@ public class Model internal MutableJsonDocument {|AZC0020:Document|} => {|AZC0020:_document|}; internal event EventHandler {|AZC0020:_docEvent|}; - internal MutableJsonDocument {|AZC0020:GetDocument|}(MutableJsonDocument {|AZC0020:value|}) - { - MutableJsonDocument mdoc = new MutableJsonDocument(); - return mdoc; - } - } -}"; - await Verifier.VerifyAnalyzerAsync(code, _sharedSourceFiles); - } - - [Fact] - public async Task AZC0020ProducedForMutableJsonDocumentUsage2() - { - string code = @" -using Azure.Core.Json; - -namespace LibraryNamespace -{ - public class Model - { internal MutableJsonDocument {|AZC0020:GetDocument|}(MutableJsonDocument {|AZC0020:value|}) { {|AZC0020:MutableJsonDocument mdoc = new MutableJsonDocument();|} @@ -91,7 +71,14 @@ namespace LibraryNamespace { public class Model { - MutableJsonElement {|AZC0020:_element|}; + private MutableJsonElement {|AZC0020:_element|}; + internal MutableJsonElement {|AZC0020:Element|} => {|AZC0020:_element|}; + + internal MutableJsonElement {|AZC0020:GetDocument|}(MutableJsonElement {|AZC0020:value|}) + { + {|AZC0020:MutableJsonElement element = new MutableJsonElement();|} + return element; + } } }"; await Verifier.VerifyAnalyzerAsync(code, _sharedSourceFiles); @@ -114,7 +101,7 @@ public class Model } [Fact] - public async Task AZC0020NotProducedForTypeWithBannedNameButAllowedNamespace() + public async Task AZC0020NotProducedForTypeWithBannedNameInAllowedNamespace() { string code = @" namespace LibraryNamespace diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs index 56e1eb70ca1..c81b8ad7504 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; @@ -34,6 +35,13 @@ public sealed class BannedTypesAnalyzer : SymbolAnalyzerBase SymbolKind.Property, }; + public override void Initialize(AnalysisContext context) + { + base.Initialize(context); + + context.RegisterSyntaxNodeAction(c => AnalyzeNode(c), SyntaxKind.LocalDeclarationStatement); + } + public override void Analyze(ISymbolAnalysisContext context) { Debug.WriteLine($"{context.Symbol}"); @@ -86,18 +94,16 @@ public override void AnalyzeNode(SyntaxNodeAnalysisContext context) return; } - LocalDeclarationStatementSyntax declaration = context.Node as LocalDeclarationStatementSyntax; - - TypeInfo info = context.SemanticModel.GetTypeInfo(declaration.Declaration.Type); - - ISymbol symbol = info.Type; - ITypeSymbol type = info.Type; - - if (type is INamedTypeSymbol namedTypeSymbol) + if (context.Node is LocalDeclarationStatementSyntax declaration) { - if (IsBannedType(namedTypeSymbol)) + ITypeSymbol type = context.SemanticModel.GetTypeInfo(declaration.Declaration.Type).Type; + + if (type is INamedTypeSymbol namedTypeSymbol) { - context.ReportDiagnostic(Diagnostic.Create(Descriptors.AZC0020, context.Node.GetLocation(), BannedTypesMessageArgs)); + if (IsBannedType(namedTypeSymbol)) + { + context.ReportDiagnostic(Diagnostic.Create(Descriptors.AZC0020, context.Node.GetLocation(), BannedTypesMessageArgs)); + } } } } diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs index d4c52bc5cda..f04d800ca15 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; namespace Azure.ClientSdk.Analyzers @@ -19,13 +18,12 @@ public virtual void AnalyzeNode(SyntaxNodeAnalysisContext context) { } protected INamedTypeSymbol ClientOptionsType { get; private set; } - public sealed override void Initialize(AnalysisContext context) + public override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); - //context.EnableConcurrentExecution(); + context.EnableConcurrentExecution(); context.RegisterCompilationStartAction(CompilationStart); context.RegisterSymbolAction(c => Analyze(new RoslynSymbolAnalysisContext(c)), SymbolKinds); - context.RegisterSyntaxNodeAction(c => AnalyzeNode(c), SyntaxKind.LocalDeclarationStatement); } #pragma warning disable RS1012 // Start action has no registered actions. From 2a7c508dcbca844f3ace406fc0883ae48d84fbe7 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Fri, 11 Aug 2023 10:46:33 -0700 Subject: [PATCH 14/18] missed cleanup --- .../Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs index f04d800ca15..4062c38c03b 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs @@ -14,8 +14,6 @@ public abstract class SymbolAnalyzerBase : DiagnosticAnalyzer public abstract SymbolKind[] SymbolKinds { get; } public abstract void Analyze(ISymbolAnalysisContext context); - public virtual void AnalyzeNode(SyntaxNodeAnalysisContext context) { } - protected INamedTypeSymbol ClientOptionsType { get; private set; } public override void Initialize(AnalysisContext context) @@ -51,9 +49,9 @@ protected bool IsClientOptionsType(ITypeSymbol typeSymbol) { return false; } - + ITypeSymbol baseType = typeSymbol.BaseType; - while (baseType != null) + while (baseType != null) { if (SymbolEqualityComparer.Default.Equals(baseType, ClientOptionsType)) { From bc5bc51f53f80431cf29b2149ffab5c0fe18ae09 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Fri, 11 Aug 2023 10:51:39 -0700 Subject: [PATCH 15/18] missed file --- .../Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs index c81b8ad7504..dc4fbb53853 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs @@ -85,7 +85,7 @@ public override void Analyze(ISymbolAnalysisContext context) Debug.WriteLine($"done"); } - public override void AnalyzeNode(SyntaxNodeAnalysisContext context) + public void AnalyzeNode(SyntaxNodeAnalysisContext context) { Debug.WriteLine($"{context.Node}"); From ce000574deef1b3707f0e0b91c74f575efe60b40 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Fri, 11 Aug 2023 10:57:14 -0700 Subject: [PATCH 16/18] Address warnings --- .../Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs index dc4fbb53853..74795495973 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs @@ -35,7 +35,12 @@ public sealed class BannedTypesAnalyzer : SymbolAnalyzerBase SymbolKind.Property, }; + // Note: suppressing warnings because they are handled in base.Initialize(). +#pragma warning disable RS1025 // Configure generated code analysis +#pragma warning disable RS1026 // Enable concurrent execution public override void Initialize(AnalysisContext context) +#pragma warning restore RS1026 // Enable concurrent execution +#pragma warning restore RS1025 // Configure generated code analysis { base.Initialize(context); From 1453cbe35a887e6fa36f004f57679d6c26245cb3 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Fri, 11 Aug 2023 11:53:23 -0700 Subject: [PATCH 17/18] Updates --- .../Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs index 74795495973..6e989a07850 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -49,8 +48,6 @@ public override void Initialize(AnalysisContext context) public override void Analyze(ISymbolAnalysisContext context) { - Debug.WriteLine($"{context.Symbol}"); - if (IsAzureCore(context.Symbol.ContainingAssembly)) { return; @@ -86,14 +83,10 @@ public override void Analyze(ISymbolAnalysisContext context) } break; } - - Debug.WriteLine($"done"); } public void AnalyzeNode(SyntaxNodeAnalysisContext context) { - Debug.WriteLine($"{context.Node}"); - if (IsAzureCore(context.ContainingSymbol.ContainingAssembly)) { return; From 1b7eb5a81fd26ed461517c702c9667f772c1c1c9 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Fri, 11 Aug 2023 12:25:29 -0700 Subject: [PATCH 18/18] refactor --- .../BannedTypesAnalyzer.cs | 61 ++++++++----------- .../SymbolAnalyzerBase.cs | 8 +-- 2 files changed, 28 insertions(+), 41 deletions(-) diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs index 6e989a07850..2c981a34a23 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/BannedTypesAnalyzer.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -9,7 +10,7 @@ namespace Azure.ClientSdk.Analyzers { [DiagnosticAnalyzer(LanguageNames.CSharp)] - public sealed class BannedTypesAnalyzer : SymbolAnalyzerBase + public sealed class BannedTypesAnalyzer : DiagnosticAnalyzer { private static HashSet BannedTypes = new HashSet() { @@ -23,30 +24,25 @@ public sealed class BannedTypesAnalyzer : SymbolAnalyzerBase public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Descriptors.AZC0020); - public override SymbolKind[] SymbolKinds { get; } = new[] + public SymbolKind[] SymbolKinds { get; } = new[] { SymbolKind.Event, SymbolKind.Field, - SymbolKind.Local, SymbolKind.Method, SymbolKind.NamedType, SymbolKind.Parameter, SymbolKind.Property, }; - // Note: suppressing warnings because they are handled in base.Initialize(). -#pragma warning disable RS1025 // Configure generated code analysis -#pragma warning disable RS1026 // Enable concurrent execution public override void Initialize(AnalysisContext context) -#pragma warning restore RS1026 // Enable concurrent execution -#pragma warning restore RS1025 // Configure generated code analysis { - base.Initialize(context); - + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); + context.EnableConcurrentExecution(); + context.RegisterSymbolAction(c => Analyze(c), SymbolKinds); context.RegisterSyntaxNodeAction(c => AnalyzeNode(c), SyntaxKind.LocalDeclarationStatement); } - public override void Analyze(ISymbolAnalysisContext context) + public void Analyze(SymbolAnalysisContext context) { if (IsAzureCore(context.Symbol.ContainingAssembly)) { @@ -56,30 +52,25 @@ public override void Analyze(ISymbolAnalysisContext context) switch (context.Symbol) { case IParameterSymbol parameterSymbol: - CheckType(context, parameterSymbol.Type, parameterSymbol); + CheckType(parameterSymbol.Type, parameterSymbol, context.ReportDiagnostic); break; case IMethodSymbol methodSymbol: - CheckType(context, methodSymbol.ReturnType, methodSymbol); - - //foreach (var typeSymbol in methodSymbol.) + CheckType(methodSymbol.ReturnType, methodSymbol, context.ReportDiagnostic); break; case IEventSymbol eventSymbol: - CheckType(context, eventSymbol.Type, eventSymbol); + CheckType(eventSymbol.Type, eventSymbol, context.ReportDiagnostic); break; case IPropertySymbol propertySymbol: - CheckType(context, propertySymbol.Type, propertySymbol); + CheckType(propertySymbol.Type, propertySymbol, context.ReportDiagnostic); break; case IFieldSymbol fieldSymbol: - CheckType(context, fieldSymbol.Type, fieldSymbol); - break; - case ILocalSymbol localSymbol: - CheckType(context, localSymbol.Type, localSymbol); + CheckType(fieldSymbol.Type, fieldSymbol, context.ReportDiagnostic); break; case INamedTypeSymbol namedTypeSymbol: - CheckType(context, namedTypeSymbol.BaseType, namedTypeSymbol); + CheckType(namedTypeSymbol.BaseType, namedTypeSymbol, context.ReportDiagnostic); foreach (var iface in namedTypeSymbol.Interfaces) { - CheckType(context, iface, namedTypeSymbol); + CheckType(iface, namedTypeSymbol, context.ReportDiagnostic); } break; } @@ -96,38 +87,29 @@ public void AnalyzeNode(SyntaxNodeAnalysisContext context) { ITypeSymbol type = context.SemanticModel.GetTypeInfo(declaration.Declaration.Type).Type; - if (type is INamedTypeSymbol namedTypeSymbol) - { - if (IsBannedType(namedTypeSymbol)) - { - context.ReportDiagnostic(Diagnostic.Create(Descriptors.AZC0020, context.Node.GetLocation(), BannedTypesMessageArgs)); - } - } + CheckType(type, type, context.ReportDiagnostic, context.Node.GetLocation()); } } - private static void CheckType(ISymbolAnalysisContext context, ITypeSymbol type, ISymbol symbol) + private static Diagnostic CheckType(ITypeSymbol type, ISymbol symbol, Action reportDiagnostic, Location location = default) { if (type is INamedTypeSymbol namedTypeSymbol) { if (IsBannedType(namedTypeSymbol)) { - context.ReportDiagnostic(Diagnostic.Create(Descriptors.AZC0020, symbol.Locations.First(), BannedTypesMessageArgs), symbol); + reportDiagnostic(Diagnostic.Create(Descriptors.AZC0020, location ?? symbol.Locations.First(), BannedTypesMessageArgs)); } if (namedTypeSymbol.IsGenericType) { foreach (var typeArgument in namedTypeSymbol.TypeArguments) { - CheckType(context, typeArgument, symbol); + CheckType(typeArgument, symbol, reportDiagnostic); } } } - } - private static bool IsBannedType(INamedTypeSymbol namedTypeSymbol) - { - return BannedTypes.Contains($"{namedTypeSymbol.ContainingNamespace}.{namedTypeSymbol.Name}"); + return null; } private static bool IsAzureCore(IAssemblySymbol assembly) @@ -136,5 +118,10 @@ private static bool IsAzureCore(IAssemblySymbol assembly) assembly.Name.Equals("Azure.Core") || assembly.Name.Equals("Azure.Core.Experimental"); } + + private static bool IsBannedType(INamedTypeSymbol namedTypeSymbol) + { + return BannedTypes.Contains($"{namedTypeSymbol.ContainingNamespace}.{namedTypeSymbol.Name}"); + } } } diff --git a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs index 4062c38c03b..c3030310f61 100644 --- a/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs +++ b/src/dotnet/Azure.ClientSdk.Analyzers/Azure.ClientSdk.Analyzers/SymbolAnalyzerBase.cs @@ -16,7 +16,7 @@ public abstract class SymbolAnalyzerBase : DiagnosticAnalyzer protected INamedTypeSymbol ClientOptionsType { get; private set; } - public override void Initialize(AnalysisContext context) + public sealed override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.EnableConcurrentExecution(); @@ -49,9 +49,9 @@ protected bool IsClientOptionsType(ITypeSymbol typeSymbol) { return false; } - + ITypeSymbol baseType = typeSymbol.BaseType; - while (baseType != null) + while (baseType != null) { if (SymbolEqualityComparer.Default.Equals(baseType, ClientOptionsType)) { @@ -81,4 +81,4 @@ public void ReportDiagnostic(Diagnostic diagnostic, ISymbol symbol) } } } -} +} \ No newline at end of file