From ef8dad384cded496879b6c40e6ce5b9ffa111134 Mon Sep 17 00:00:00 2001 From: Fred Silberberg Date: Fri, 27 Sep 2024 12:10:04 -0700 Subject: [PATCH] Add new analyzer for deprecating implementing an interface (#7419) We're officially marking `ISourceGenerator` as deprecated, but we can't actually deprecate the interface, because it's used in several APIs like AnalyzerFileReference. So instead, we just add an analyzer to indicate that the interface should not be implemented. I've made this more general so we can do this with more interfaces in the future if necessary, based the implementation on InternalImplementationOnlyAnalyzer. --- .../Core/AnalyzerReleases.Unshipped.md | 1 + .../CodeAnalysisDiagnosticsResources.resx | 12 +- .../Core/DiagnosticIds.cs | 1 + .../Core/ImplementationIsObsoleteAnalyzer.cs | 62 +++++ .../CodeAnalysisDiagnosticsResources.cs.xlf | 15 + .../CodeAnalysisDiagnosticsResources.de.xlf | 15 + .../CodeAnalysisDiagnosticsResources.es.xlf | 15 + .../CodeAnalysisDiagnosticsResources.fr.xlf | 15 + .../CodeAnalysisDiagnosticsResources.it.xlf | 15 + .../CodeAnalysisDiagnosticsResources.ja.xlf | 15 + .../CodeAnalysisDiagnosticsResources.ko.xlf | 15 + .../CodeAnalysisDiagnosticsResources.pl.xlf | 15 + ...CodeAnalysisDiagnosticsResources.pt-BR.xlf | 15 + .../CodeAnalysisDiagnosticsResources.ru.xlf | 15 + .../CodeAnalysisDiagnosticsResources.tr.xlf | 15 + ...deAnalysisDiagnosticsResources.zh-Hans.xlf | 15 + ...deAnalysisDiagnosticsResources.zh-Hant.xlf | 15 + .../Microsoft.CodeAnalysis.Analyzers.md | 12 + .../Microsoft.CodeAnalysis.Analyzers.sarif | 15 + .../RulesMissingDocumentation.md | 1 + .../ImplementationIsObsoleteAnalyzerTests.cs | 263 ++++++++++++++++++ 21 files changed, 561 insertions(+), 1 deletion(-) create mode 100644 src/Microsoft.CodeAnalysis.Analyzers/Core/ImplementationIsObsoleteAnalyzer.cs create mode 100644 src/Microsoft.CodeAnalysis.Analyzers/UnitTests/ImplementationIsObsoleteAnalyzerTests.cs diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/AnalyzerReleases.Unshipped.md b/src/Microsoft.CodeAnalysis.Analyzers/Core/AnalyzerReleases.Unshipped.md index 80777b6c4d..8b15c08ff9 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/AnalyzerReleases.Unshipped.md +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/AnalyzerReleases.Unshipped.md @@ -6,3 +6,4 @@ Rule ID | Category | Severity | Notes --------|----------|----------|------- RS1038 | MicrosoftCodeAnalysisCorrectness | Warning | CompilerExtensionStrictApiAnalyzer RS1041 | MicrosoftCodeAnalysisCorrectness | Warning | CompilerExtensionTargetFrameworkAnalyzer, [Documentation](https://github.com/dotnet/roslyn-analyzers/blob/main/docs/rules/RS1041.md) +RS1042 | MicrosoftCodeAnalysisCompatibility | Error | ImplementationIsObsoleteAnalyzer diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx b/src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx index a10a64d1e0..e9174ddb36 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx @@ -595,4 +595,14 @@ Compiler extensions should be implemented in assemblies targeting netstandard2.0 - \ No newline at end of file + + The author of this interface has deprecated implementing this interface. + + + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + {2} is a URL + + + Implementations of this interface are not allowed + + diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/DiagnosticIds.cs b/src/Microsoft.CodeAnalysis.Analyzers/Core/DiagnosticIds.cs index 556b9f4cc6..daf31d6769 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/DiagnosticIds.cs +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/DiagnosticIds.cs @@ -45,6 +45,7 @@ internal static class DiagnosticIds public const string SemanticModelGetDeclaredSymbolAlwaysReturnsNull = "RS1039"; public const string SemanticModelGetDeclaredSymbolAlwaysReturnsNullForField = "RS1040"; public const string DoNotRegisterCompilerTypesWithBadTargetFrameworkRuleId = "RS1041"; + public const string ImplementationIsObsoleteRuleId = "RS1042"; // Release tracking analyzer IDs public const string DeclareDiagnosticIdInAnalyzerReleaseRuleId = "RS2000"; diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/ImplementationIsObsoleteAnalyzer.cs b/src/Microsoft.CodeAnalysis.Analyzers/Core/ImplementationIsObsoleteAnalyzer.cs new file mode 100644 index 0000000000..e900221e4c --- /dev/null +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/ImplementationIsObsoleteAnalyzer.cs @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. + +using System; +using System.Collections.Immutable; +using System.Linq; +using Analyzer.Utilities; +using Analyzer.Utilities.Extensions; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Microsoft.CodeAnalysis.Analyzers +{ + using static CodeAnalysisDiagnosticsResources; + + [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] + public class ImplementationIsObsoleteAnalyzer : DiagnosticAnalyzer + { + private const string ImplementationIsObsoleteAttributeName = "ImplementationIsObsoleteAttribute"; + private const string ImplementationIsObsoleteAttributeFullName = "System.Runtime.CompilerServices.ImplementationIsObsoleteAttribute"; + + public static readonly DiagnosticDescriptor Rule = new( + DiagnosticIds.ImplementationIsObsoleteRuleId, + CreateLocalizableResourceString(nameof(ImplementationIsObsoleteTitle)), + CreateLocalizableResourceString(nameof(ImplementationIsObsoleteMessage)), + DiagnosticCategory.MicrosoftCodeAnalysisCompatibility, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: CreateLocalizableResourceString(nameof(ImplementationIsObsoleteDescription))); + + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(Rule); + + public override void Initialize(AnalysisContext context) + { + context.EnableConcurrentExecution(); + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + + context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType); + } + + private static void AnalyzeSymbol(SymbolAnalysisContext context) + { + var namedTypeSymbol = (INamedTypeSymbol)context.Symbol; + + // If any interface implemented by this type has the attribute and if the interface and this type are not + // in "internals visible" context, then issue an error. + foreach (INamedTypeSymbol iface in namedTypeSymbol.AllInterfaces) + { + System.Collections.Generic.IEnumerable attributes = iface.GetAttributes(); + + // We are doing a string comparison of the name here because we don't care where the attribute comes from. + // CodeAnalysis.dll itself has this attribute and if the user assembly also had it, symbol equality will fail + // but we should still issue the error. + if (attributes.FirstOrDefault(a => a is { AttributeClass.Name: ImplementationIsObsoleteAttributeName, ConstructorArguments: [{ Value: string }] } + && a.AttributeClass.ToDisplayString().Equals(ImplementationIsObsoleteAttributeFullName, StringComparison.Ordinal)) is { } attr && + !iface.ContainingAssembly.GivesAccessTo(namedTypeSymbol.ContainingAssembly)) + { + context.ReportDiagnostic(namedTypeSymbol.CreateDiagnostic(Rule, namedTypeSymbol.Name, iface.Name, (string)attr.ConstructorArguments[0].Value!)); + break; + } + } + } + } +} diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.cs.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.cs.xlf index 213dd4a2dc..51891ff2b6 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.cs.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.cs.xlf @@ -217,6 +217,21 @@ Povolit souběžné provádění + + The author of this interface has deprecated implementing this interface. + The author of this interface has deprecated implementing this interface. + + + + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + + + + Implementations of this interface are not allowed + Implementations of this interface are not allowed + + Invalid entry in analyzer release file. Neplatná položka v souboru vydané verze analyzátoru diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.de.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.de.xlf index 6bbefefdbc..3b058c78e6 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.de.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.de.xlf @@ -217,6 +217,21 @@ Gleichzeitige Ausführung aktivieren + + The author of this interface has deprecated implementing this interface. + The author of this interface has deprecated implementing this interface. + + + + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + + + + Implementations of this interface are not allowed + Implementations of this interface are not allowed + + Invalid entry in analyzer release file. Ungültiger Eintrag in Analysetool-Releasedatei. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.es.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.es.xlf index d65ea6bd4c..dbb2c3ef96 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.es.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.es.xlf @@ -217,6 +217,21 @@ Habilitar la ejecución simultánea + + The author of this interface has deprecated implementing this interface. + The author of this interface has deprecated implementing this interface. + + + + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + + + + Implementations of this interface are not allowed + Implementations of this interface are not allowed + + Invalid entry in analyzer release file. Entrada no válida en el archivo de versión del analizador. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.fr.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.fr.xlf index 9a003770e4..2f3d2745d6 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.fr.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.fr.xlf @@ -217,6 +217,21 @@ Activer l'exécution simultanée + + The author of this interface has deprecated implementing this interface. + The author of this interface has deprecated implementing this interface. + + + + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + + + + Implementations of this interface are not allowed + Implementations of this interface are not allowed + + Invalid entry in analyzer release file. Entrée non valide dans le fichier de version d'analyseur. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.it.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.it.xlf index ef5d4e3bc7..7e06d4df30 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.it.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.it.xlf @@ -217,6 +217,21 @@ Abilita l'esecuzione simultanea + + The author of this interface has deprecated implementing this interface. + The author of this interface has deprecated implementing this interface. + + + + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + + + + Implementations of this interface are not allowed + Implementations of this interface are not allowed + + Invalid entry in analyzer release file. Voce non valida nel file di versione dell'analizzatore. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ja.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ja.xlf index c663c9fec4..5874e6923d 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ja.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ja.xlf @@ -217,6 +217,21 @@ 同時実行を有効にします + + The author of this interface has deprecated implementing this interface. + The author of this interface has deprecated implementing this interface. + + + + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + + + + Implementations of this interface are not allowed + Implementations of this interface are not allowed + + Invalid entry in analyzer release file. アナライザー リリース ファイルに無効なエントリがあります。 diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ko.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ko.xlf index 954c4355e7..a420161549 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ko.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ko.xlf @@ -217,6 +217,21 @@ 동시 실행 사용 + + The author of this interface has deprecated implementing this interface. + The author of this interface has deprecated implementing this interface. + + + + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + + + + Implementations of this interface are not allowed + Implementations of this interface are not allowed + + Invalid entry in analyzer release file. 분석기 릴리스 파일에 잘못된 항목이 있습니다. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pl.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pl.xlf index 6e1775bf65..2fc901c653 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pl.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pl.xlf @@ -217,6 +217,21 @@ Włącz wykonywanie współbieżne + + The author of this interface has deprecated implementing this interface. + The author of this interface has deprecated implementing this interface. + + + + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + + + + Implementations of this interface are not allowed + Implementations of this interface are not allowed + + Invalid entry in analyzer release file. Nieprawidłowy wpis w pliku wydania analizatora. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pt-BR.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pt-BR.xlf index 9007f2fb74..dcfa9870b2 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pt-BR.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pt-BR.xlf @@ -217,6 +217,21 @@ Habilitar execução simultânea + + The author of this interface has deprecated implementing this interface. + The author of this interface has deprecated implementing this interface. + + + + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + + + + Implementations of this interface are not allowed + Implementations of this interface are not allowed + + Invalid entry in analyzer release file. Entrada inválida no arquivo de versão do analisador. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ru.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ru.xlf index de18b6ac4d..833a128ffa 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ru.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ru.xlf @@ -217,6 +217,21 @@ Включение параллельного выполнения + + The author of this interface has deprecated implementing this interface. + The author of this interface has deprecated implementing this interface. + + + + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + + + + Implementations of this interface are not allowed + Implementations of this interface are not allowed + + Invalid entry in analyzer release file. Недопустимая запись в файле выпуска анализатора. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.tr.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.tr.xlf index 33fc28c411..5e5f5c0f01 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.tr.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.tr.xlf @@ -217,6 +217,21 @@ Eşzamanlı yürütmeyi etkinleştir + + The author of this interface has deprecated implementing this interface. + The author of this interface has deprecated implementing this interface. + + + + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + + + + Implementations of this interface are not allowed + Implementations of this interface are not allowed + + Invalid entry in analyzer release file. Çözümleyici yayın dosyasında geçersiz girdi. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hans.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hans.xlf index 49c6f6cb73..336e53ca66 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hans.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hans.xlf @@ -217,6 +217,21 @@ 启用并发执行 + + The author of this interface has deprecated implementing this interface. + The author of this interface has deprecated implementing this interface. + + + + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + + + + Implementations of this interface are not allowed + Implementations of this interface are not allowed + + Invalid entry in analyzer release file. 分析器版本文件中的条目无效。 diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hant.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hant.xlf index 81da3f6816..c3986e2d28 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hant.xlf +++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hant.xlf @@ -217,6 +217,21 @@ 啟用同時執行 + + The author of this interface has deprecated implementing this interface. + The author of this interface has deprecated implementing this interface. + + + + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + Type {0} cannot implement interface {1} because {1} is obsolete for implementation. See {2} for more details. + + + + Implementations of this interface are not allowed + Implementations of this interface are not allowed + + Invalid entry in analyzer release file. 分析器版本檔案中的項目無效。 diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.md b/src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.md index 0f945afd21..1974d81841 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.md +++ b/src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.md @@ -508,6 +508,18 @@ Types which implement compiler extension points should only be declared in assem |CodeFix|False| --- +## RS1042: Implementations of this interface are not allowed + +The author of this interface has deprecated implementing this interface. + +|Item|Value| +|-|-| +|Category|MicrosoftCodeAnalysisCompatibility| +|Enabled|True| +|Severity|Error| +|CodeFix|False| +--- + ## [RS2000](https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md): Add analyzer diagnostic IDs to analyzer release All supported analyzer diagnostic IDs should be part of an analyzer release. diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.sarif b/src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.sarif index d37ff20bff..b6c363c837 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.sarif +++ b/src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.sarif @@ -513,6 +513,21 @@ ] } }, + "RS1042": { + "id": "RS1042", + "shortDescription": "Implementations of this interface are not allowed", + "fullDescription": "The author of this interface has deprecated implementing this interface.", + "defaultLevel": "error", + "properties": { + "category": "MicrosoftCodeAnalysisCompatibility", + "isEnabledByDefault": true, + "typeName": "ImplementationIsObsoleteAnalyzer", + "languages": [ + "C#", + "Visual Basic" + ] + } + }, "RS2000": { "id": "RS2000", "shortDescription": "Add analyzer diagnostic IDs to analyzer release", diff --git a/src/Microsoft.CodeAnalysis.Analyzers/RulesMissingDocumentation.md b/src/Microsoft.CodeAnalysis.Analyzers/RulesMissingDocumentation.md index 07dab69c39..18e0e66b8d 100644 --- a/src/Microsoft.CodeAnalysis.Analyzers/RulesMissingDocumentation.md +++ b/src/Microsoft.CodeAnalysis.Analyzers/RulesMissingDocumentation.md @@ -39,3 +39,4 @@ RS1036 | | Specify analyzer banned API enforcement setting | RS1037 | | Add "CompilationEnd" custom tag to compilation end diagnostic descriptor | RS1039 | | This call to 'SemanticModel.GetDeclaredSymbol()' will always return 'null' | RS1040 | | This call to 'SemanticModel.GetDeclaredSymbol()' will always return 'null' | +RS1042 | | Implementations of this interface are not allowed | diff --git a/src/Microsoft.CodeAnalysis.Analyzers/UnitTests/ImplementationIsObsoleteAnalyzerTests.cs b/src/Microsoft.CodeAnalysis.Analyzers/UnitTests/ImplementationIsObsoleteAnalyzerTests.cs new file mode 100644 index 0000000000..477921b638 --- /dev/null +++ b/src/Microsoft.CodeAnalysis.Analyzers/UnitTests/ImplementationIsObsoleteAnalyzerTests.cs @@ -0,0 +1,263 @@ +// 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 Test.Utilities; +using Xunit; +using VerifyCS = Test.Utilities.CSharpCodeFixVerifier; +using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier; + +namespace Microsoft.CodeAnalysis.Analyzers.UnitTests +{ + public class ImplementationIsObsoleteAnalyzerTests + { + private const string AttributeStringCSharp = """ + + namespace System.Runtime.CompilerServices + { + internal class ImplementationIsObsoleteAttribute : System.Attribute { public ImplementationIsObsoleteAttribute(string url) { } } + } + + """; + [Fact] + public async Task CSharp_VerifySameAssemblyAsync() + { + string source = $$""" + {{AttributeStringCSharp}} + + [System.Runtime.CompilerServices.ImplementationIsObsoleteAttribute("https://example.com")] + public interface IMyInterface { } + + class SomeClass : IMyInterface { } + """; + + // Verify no diagnostic since interface is in the same assembly. + await new VerifyCS.Test + { + ReferenceAssemblies = AdditionalMetadataReferences.DefaultWithoutRoslynSymbols, + TestState = { Sources = { source } }, + }.RunAsync(); + } + + [Fact] + public async Task CSharp_VerifyDifferentAssemblyAsync() + { + string source1 = AttributeStringCSharp + """ + + + [System.Runtime.CompilerServices.ImplementationIsObsoleteAttribute("https://example.com")] + public interface IMyInterface { } + + public interface IMyOtherInterface : IMyInterface { } + """; + + var source2 = """ + + class SomeClass : IMyInterface { } + + class SomeOtherClass : IMyOtherInterface { } + """; + + // Verify errors since interface is not in a friend assembly. + await new VerifyCS.Test + { + ReferenceAssemblies = AdditionalMetadataReferences.DefaultWithoutRoslynSymbols, + TestState = + { + Sources = { source2 }, + AdditionalProjects = + { + ["DependencyProject"] = + { + Sources = { source1 }, + }, + }, + AdditionalProjectReferences = { "DependencyProject" }, + ExpectedDiagnostics = + { + // /0/Test0.cs(2,7): error RS1042: Type SomeClass cannot implement interface IMyInterface because IMyInterface is obsolete for implementation. See https://example.com for more details. + VerifyCS.Diagnostic().WithSpan(2, 7, 2, 16).WithArguments("SomeClass", "IMyInterface", "https://example.com"), + // /0/Test0.cs(4,7): error RS1042: Type SomeOtherClass cannot implement interface IMyInterface because IMyInterface is obsolete for implementation. See https://example.com for more details. + VerifyCS.Diagnostic().WithSpan(4, 7, 4, 21).WithArguments("SomeOtherClass", "IMyInterface", "https://example.com"), + }, + }, + }.RunAsync(); + } + + [Fact] + public async Task CSharp_VerifyDifferentFriendAssemblyAsync() + { + string source1 = $$""" + + [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("TestProject")] + + {{AttributeStringCSharp}} + + + [System.Runtime.CompilerServices.ImplementationIsObsoleteAttribute("https://example.com")] + public interface IMyInterface { } + + public interface IMyOtherInterface : IMyInterface { } + """; + + var source2 = """ + + class SomeClass : IMyInterface { } + + class SomeOtherClass : IMyOtherInterface { } + """; + + // Verify no diagnostic since interface is in a friend assembly. + await new VerifyCS.Test + { + ReferenceAssemblies = AdditionalMetadataReferences.DefaultWithoutRoslynSymbols, + TestState = + { + Sources = { source2 }, + AdditionalProjects = + { + ["DependencyProject"] = + { + Sources = { source1 }, + }, + }, + AdditionalProjectReferences = { "DependencyProject" }, + }, + }.RunAsync(); + } + + private const string AttributeStringBasic = """ + + Namespace System.Runtime.CompilerServices + Friend Class ImplementationIsObsoleteAttribute + Inherits System.Attribute + + Public Sub New(url As String) + End Sub + End Class + End Namespace + + """; + + [Fact] + public async Task Basic_VerifySameAssemblyAsync() + { + string source = $""" + {AttributeStringBasic} + + + Public Interface IMyInterface + End Interface + + Class SomeClass + Implements IMyInterface + End Class + """; + + // Verify no diagnostic since interface is in the same assembly. + await new VerifyVB.Test + { + ReferenceAssemblies = AdditionalMetadataReferences.DefaultWithoutRoslynSymbols, + TestState = { Sources = { source } }, + }.RunAsync(); + } + + [Fact] + public async Task Basic_VerifyDifferentAssemblyAsync() + { + string source1 = $""" + {AttributeStringBasic} + + + Public Interface IMyInterface + End Interface + + Public Interface IMyOtherInterface + Inherits IMyInterface + End Interface + + """; + + var source2 = """ + + Class SomeClass + Implements IMyInterface + End Class + + Class SomeOtherClass + Implements IMyOtherInterface + End Class + + """; + + // Verify errors since interface is not in a friend assembly. + await new VerifyVB.Test + { + ReferenceAssemblies = AdditionalMetadataReferences.DefaultWithoutRoslynSymbols, + TestState = + { + Sources = { source2 }, + AdditionalProjects = + { + ["DependencyProject"] = + { + Sources = { source1 }, + }, + }, + AdditionalProjectReferences = { "DependencyProject" }, + ExpectedDiagnostics = + { + // /0/Test0.vb(2,7): error RS1042: Type SomeClass cannot implement interface IMyInterface because IMyInterface is obsolete for implementation. See https://example.com for more details. + VerifyVB.Diagnostic().WithSpan(2, 7, 2, 16).WithArguments("SomeClass", "IMyInterface", "https://example.com"), + // /0/Test0.vb(6,7): error RS1042: Type SomeOtherClass cannot implement interface IMyInterface because IMyInterface is obsolete for implementation. See https://example.com for more details. + VerifyVB.Diagnostic().WithSpan(6, 7, 6, 21).WithArguments("SomeOtherClass", "IMyInterface", "https://example.com"), + }, + }, + }.RunAsync(); + } + + [Fact] + public async Task Basic_VerifyDifferentFriendAssemblyAsync() + { + string source1 = $""" + + {AttributeStringBasic} + + + Public Interface IMyInterface + End Interface + + Public Interface IMyOtherInterface + Inherits IMyInterface + End Interface + """; + + var source2 = @" +Class SomeClass + Implements IMyInterface +End Class + +Class SomeOtherClass + Implements IMyOtherInterface +End Class +"; + + // Verify no diagnostic since interface is in a friend assembly. + await new VerifyVB.Test + { + ReferenceAssemblies = AdditionalMetadataReferences.DefaultWithoutRoslynSymbols, + TestState = + { + Sources = { source2 }, + AdditionalProjects = + { + ["DependencyProject"] = + { + Sources = { source1 }, + }, + }, + AdditionalProjectReferences = { "DependencyProject" }, + }, + }.RunAsync(); + } + } +}