Skip to content

Commit

Permalink
Error when users use a file type for things we need to load (#7501)
Browse files Browse the repository at this point in the history
* Error when users use a `file` type for things we need to load

Inspired by dotnet/roslyn#76355. `file` types can cause errors on .NET Framework hosts, and we should just prevent these from being used. The purpose of `file` types is to not be visible outside the current file, and the purpose of analyzers is to be loaded by some other plugin system. These goals are mutually exclusive.

* Seal type

* Feedback.
  • Loading branch information
333fred authored Dec 16, 2024
1 parent 7f449a5 commit 5ed3367
Show file tree
Hide file tree
Showing 22 changed files with 417 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,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
RS1043 | MicrosoftCodeAnalysisCorrectness | Error | DoNotUseFileTypesForAnalyzersOrGenerators
Original file line number Diff line number Diff line change
Expand Up @@ -605,4 +605,13 @@
<data name="ImplementationIsObsoleteTitle" xml:space="preserve">
<value>Implementations of this interface are not allowed</value>
</data>
<data name="DoNotUseFileTypesForAnalyzersOrGeneratorsDescription" xml:space="preserve">
<value>Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</value>
</data>
<data name="DoNotUseFileTypesForAnalyzersOrGeneratorsMessage" xml:space="preserve">
<value>Type '{0}' should not be marked with 'file'</value>
</data>
<data name="DoNotUseFileTypesForAnalyzersOrGeneratorsTitle" xml:space="preserve">
<value>Do not use file types for implementing analyzers, generators, and code fixers</value>
</data>
</root>
1 change: 1 addition & 0 deletions src/Microsoft.CodeAnalysis.Analyzers/Core/DiagnosticIds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ internal static class DiagnosticIds
public const string SemanticModelGetDeclaredSymbolAlwaysReturnsNullForField = "RS1040";
public const string DoNotRegisterCompilerTypesWithBadTargetFrameworkRuleId = "RS1041";
public const string ImplementationIsObsoleteRuleId = "RS1042";
public const string DoNotUseFileTypesForAnalyzersOrGenerators = "RS1043";

// Release tracking analyzer IDs
public const string DeclareDiagnosticIdInAnalyzerReleaseRuleId = "RS2000";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System.Collections.Immutable;
using Analyzer.Utilities;
using Analyzer.Utilities.Extensions;
using Microsoft.CodeAnalysis.Diagnostics;

namespace Microsoft.CodeAnalysis.Analyzers.MetaAnalyzers
{
using static CodeAnalysisDiagnosticsResources;

[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class DoNotUseFileTypesForAnalyzersOrGenerators : DiagnosticAnalyzer
{
private static readonly DiagnosticDescriptor Rule = new(
DiagnosticIds.DoNotUseFileTypesForAnalyzersOrGenerators,
CreateLocalizableResourceString(nameof(DoNotUseFileTypesForAnalyzersOrGeneratorsTitle)),
CreateLocalizableResourceString(nameof(DoNotUseFileTypesForAnalyzersOrGeneratorsMessage)),
DiagnosticCategory.MicrosoftCodeAnalysisCorrectness,
DiagnosticSeverity.Error,
isEnabledByDefault: true,
description: CreateLocalizableResourceString(nameof(DoNotUseFileTypesForAnalyzersOrGeneratorsDescription)));

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(Rule);

public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterCompilationStartAction(context =>
{
INamedTypeSymbol? diagnosticAnalyzer = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftCodeAnalysisDiagnosticsDiagnosticAnalyzer);
if (diagnosticAnalyzer == null)
{
// Does not contain any diagnostic analyzers.
return;
}

// There may or may not be a code fix provider type and generator types, depending on what this assembly depends on.
INamedTypeSymbol? codeFixProvider = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftCodeAnalysisCodeFixesCodeFixProvider);
INamedTypeSymbol? isourceGenerator = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftCodeAnalysisISourceGenerator);
INamedTypeSymbol? iincrementalGenerator = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftCodeAnalysisIIncrementalGenerator);

context.RegisterSymbolAction(symbolContext => AnalyzeSymbol(symbolContext, diagnosticAnalyzer, codeFixProvider, isourceGenerator, iincrementalGenerator), SymbolKind.NamedType);
});
}

private static void AnalyzeSymbol(SymbolAnalysisContext context, INamedTypeSymbol diagnosticAnalyzer, INamedTypeSymbol? codeFixProvider, INamedTypeSymbol? isourceGenerator, INamedTypeSymbol? iincrementalGenerator)
{
var namedTypeSymbol = (INamedTypeSymbol)context.Symbol;

if (!namedTypeSymbol.IsFileLocal())
{
return;
}

if (namedTypeSymbol.Inherits(diagnosticAnalyzer) ||
namedTypeSymbol.Inherits(codeFixProvider) ||
namedTypeSymbol.Inherits(isourceGenerator) ||
namedTypeSymbol.Inherits(iincrementalGenerator))
{
var diagnostic = Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], namedTypeSymbol.Name);
context.ReportDiagnostic(diagnostic);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@
<target state="translated">Nevolejte metodu Compilation.GetSemanticModel() v diagnostickém analyzátoru</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsDescription">
<source>Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</source>
<target state="new">Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsMessage">
<source>Type '{0}' should not be marked with 'file'</source>
<target state="new">Type '{0}' should not be marked with 'file'</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsTitle">
<source>Do not use file types for implementing analyzers, generators, and code fixers</source>
<target state="new">Do not use file types for implementing analyzers, generators, and code fixers</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseReservedDiagnosticIdDescription">
<source>DiagnosticId for analyzers should not use reserved IDs.</source>
<target state="translated">Hodnoty DiagnosticId pro analyzátory by neměly používat rezervovaná ID.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@
<target state="translated">Compilation.GetSemanticModel()-Methode nicht innerhalb eines Diagnoseanalysetools aufrufen</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsDescription">
<source>Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</source>
<target state="new">Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsMessage">
<source>Type '{0}' should not be marked with 'file'</source>
<target state="new">Type '{0}' should not be marked with 'file'</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsTitle">
<source>Do not use file types for implementing analyzers, generators, and code fixers</source>
<target state="new">Do not use file types for implementing analyzers, generators, and code fixers</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseReservedDiagnosticIdDescription">
<source>DiagnosticId for analyzers should not use reserved IDs.</source>
<target state="translated">Die DiagnosticId für Analysetools darf keine reservierten IDs verwenden.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@
<target state="translated">No invoque el método Compilation.GetSemanticModel() en un analizador de diagnóstico</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsDescription">
<source>Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</source>
<target state="new">Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsMessage">
<source>Type '{0}' should not be marked with 'file'</source>
<target state="new">Type '{0}' should not be marked with 'file'</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsTitle">
<source>Do not use file types for implementing analyzers, generators, and code fixers</source>
<target state="new">Do not use file types for implementing analyzers, generators, and code fixers</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseReservedDiagnosticIdDescription">
<source>DiagnosticId for analyzers should not use reserved IDs.</source>
<target state="translated">El valor DiagnosticId para los analizadores no debe usar identificadores reservados.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@
<target state="translated">N'appelez pas la méthode Compilation.GetSemanticModel() dans un analyseur de diagnostic</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsDescription">
<source>Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</source>
<target state="new">Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsMessage">
<source>Type '{0}' should not be marked with 'file'</source>
<target state="new">Type '{0}' should not be marked with 'file'</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsTitle">
<source>Do not use file types for implementing analyzers, generators, and code fixers</source>
<target state="new">Do not use file types for implementing analyzers, generators, and code fixers</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseReservedDiagnosticIdDescription">
<source>DiagnosticId for analyzers should not use reserved IDs.</source>
<target state="translated">DiagnosticId pour les analyseurs ne doit pas utiliser d'ID réservés.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@
<target state="translated">Non richiamare il metodo Compilation.GetSemanticModel() in un analizzatore diagnostico</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsDescription">
<source>Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</source>
<target state="new">Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsMessage">
<source>Type '{0}' should not be marked with 'file'</source>
<target state="new">Type '{0}' should not be marked with 'file'</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsTitle">
<source>Do not use file types for implementing analyzers, generators, and code fixers</source>
<target state="new">Do not use file types for implementing analyzers, generators, and code fixers</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseReservedDiagnosticIdDescription">
<source>DiagnosticId for analyzers should not use reserved IDs.</source>
<target state="translated">L'ID diagnostica per gli analizzatori non deve usare ID riservati.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@
<target state="translated">診断アナライザー内での Compilation.GetSemanticModel() メソッドの呼び出し禁止</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsDescription">
<source>Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</source>
<target state="new">Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsMessage">
<source>Type '{0}' should not be marked with 'file'</source>
<target state="new">Type '{0}' should not be marked with 'file'</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsTitle">
<source>Do not use file types for implementing analyzers, generators, and code fixers</source>
<target state="new">Do not use file types for implementing analyzers, generators, and code fixers</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseReservedDiagnosticIdDescription">
<source>DiagnosticId for analyzers should not use reserved IDs.</source>
<target state="translated">アナライザーの診断 ID には、予約済み ID を使用しないでください。</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@
<target state="translated">진단 분석기 내에서 Compilation.GetSemanticModel() 메서드를 호출하지 마세요.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsDescription">
<source>Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</source>
<target state="new">Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsMessage">
<source>Type '{0}' should not be marked with 'file'</source>
<target state="new">Type '{0}' should not be marked with 'file'</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsTitle">
<source>Do not use file types for implementing analyzers, generators, and code fixers</source>
<target state="new">Do not use file types for implementing analyzers, generators, and code fixers</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseReservedDiagnosticIdDescription">
<source>DiagnosticId for analyzers should not use reserved IDs.</source>
<target state="translated">분석기의 DiagnosticId에는 예약된 ID를 사용해서는 안 됩니다.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@
<target state="translated">Nie wywołuj metody Compilation.GetSemanticModel() w analizatorze diagnostycznym</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsDescription">
<source>Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</source>
<target state="new">Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsMessage">
<source>Type '{0}' should not be marked with 'file'</source>
<target state="new">Type '{0}' should not be marked with 'file'</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsTitle">
<source>Do not use file types for implementing analyzers, generators, and code fixers</source>
<target state="new">Do not use file types for implementing analyzers, generators, and code fixers</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseReservedDiagnosticIdDescription">
<source>DiagnosticId for analyzers should not use reserved IDs.</source>
<target state="translated">W elemencie DiagnosticId dla analizatorów nie należy używać zastrzeżonych identyfikatorów.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@
<target state="translated">Não invocar o método Compilation.GetSemanticModel() em um analisador de diagnóstico</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsDescription">
<source>Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</source>
<target state="new">Using a 'file' type is not allowed for implementing analyzers, generators, or code fixers. This can break analyzer loading on some platforms.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsMessage">
<source>Type '{0}' should not be marked with 'file'</source>
<target state="new">Type '{0}' should not be marked with 'file'</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseFileTypesForAnalyzersOrGeneratorsTitle">
<source>Do not use file types for implementing analyzers, generators, and code fixers</source>
<target state="new">Do not use file types for implementing analyzers, generators, and code fixers</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseReservedDiagnosticIdDescription">
<source>DiagnosticId for analyzers should not use reserved IDs.</source>
<target state="translated">A DiagnosticId dos analisadores não deve usar IDs reservadas.</target>
Expand Down
Loading

0 comments on commit 5ed3367

Please sign in to comment.