diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/AnalyzerReleases.Unshipped.md b/src/Microsoft.CodeAnalysis.Analyzers/Core/AnalyzerReleases.Unshipped.md
index 0a644588b4..59aa9d12a5 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
--------|----------|----------|-------
RS1035 | MicrosoftCodeAnalysisCorrectness | Error | SymbolIsBannedInAnalyzersAnalyzer
RS1036 | MicrosoftCodeAnalysisCorrectness | Warning | SymbolIsBannedInAnalyzersAnalyzer
+RS1037 | MicrosoftCodeAnalysisDesign | Warning | DiagnosticDescriptorCreationAnalyzer
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx b/src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx
index 18a503334d..0fa9feb98d 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/CodeAnalysisDiagnosticsResources.resx
@@ -514,6 +514,15 @@
Define diagnostic description correctly
+
+ 'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+
+ Add "CompilationEnd" custom tag to the diagnostic descriptor used to initialize field '{0}' as it is used to report a compilation end diagnostic
+
+
+ Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
Symbols should be compared for equality, not identity. An explicit call to 'GetHashCode' will likely result in the wrong behavior.
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/DiagnosticIds.cs b/src/Microsoft.CodeAnalysis.Analyzers/Core/DiagnosticIds.cs
index 7a77607ffb..24dd25557a 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/DiagnosticIds.cs
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/DiagnosticIds.cs
@@ -40,6 +40,7 @@ internal static class DiagnosticIds
public const string PreferIsKindRuleId = "RS1034";
public const string SymbolIsBannedInAnalyzersRuleId = "RS1035";
public const string NoSettingSpecifiedSymbolIsBannedInAnalyzersRuleId = "RS1036";
+ public const string AddCompilationEndCustomTagRuleId = "RS1037";
// Release tracking analyzer IDs
public const string DeclareDiagnosticIdInAnalyzerReleaseRuleId = "RS2000";
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzer.cs b/src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzer.cs
index f72ad8f129..39ad993e6c 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzer.cs
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzer.cs
@@ -12,6 +12,7 @@
using Analyzer.Utilities;
using Analyzer.Utilities.Extensions;
using Analyzer.Utilities.PooledObjects;
+using Microsoft.CodeAnalysis.Analyzers.MetaAnalyzers.Helpers;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.CodeAnalysis.ReleaseTracking;
@@ -23,6 +24,7 @@ namespace Microsoft.CodeAnalysis.Analyzers.MetaAnalyzers
using PooledLocalizabeStringsConcurrentDictionary = PooledConcurrentDictionary>;
using PooledResourcesDataValueConcurrentDictionary = PooledConcurrentDictionary>;
using PooledFieldToResourceNameAndFileNameConcurrentDictionary = PooledConcurrentDictionary;
+ using PooledFieldToCustomTagsConcurrentDictionary = PooledConcurrentDictionary>;
///
/// RS1007
@@ -45,6 +47,7 @@ public sealed partial class DiagnosticDescriptorCreationAnalyzer : DiagnosticAna
private const string IsEnabledByDefaultParameterName = "isEnabledByDefault";
private const string DefaultSeverityParameterName = "defaultSeverity";
private const string RuleLevelParameterName = "ruleLevel";
+ private const string CompilationEndWellKnownDiagnosticTag = "CompilationEnd" /*WellKnownDiagnosticTags.CompilationEnd*/;
internal const string DefineDescriptorArgumentCorrectlyFixValue = nameof(DefineDescriptorArgumentCorrectlyFixValue);
private const string DefineDescriptorArgumentCorrectlyFixAdditionalDocumentLocationInfo = nameof(DefineDescriptorArgumentCorrectlyFixAdditionalDocumentLocationInfo);
@@ -156,6 +159,16 @@ public sealed partial class DiagnosticDescriptorCreationAnalyzer : DiagnosticAna
isEnabledByDefault: true,
customTags: WellKnownDiagnosticTagsExtensions.Telemetry);
+ public static readonly DiagnosticDescriptor AddCompilationEndCustomTagRule = new(
+ DiagnosticIds.AddCompilationEndCustomTagRuleId,
+ CreateLocalizableResourceString(nameof(AddCompilationEndCustomTagTitle)),
+ CreateLocalizableResourceString(nameof(AddCompilationEndCustomTagMessage)),
+ DiagnosticCategory.MicrosoftCodeAnalysisDesign,
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ description: CreateLocalizableResourceString(nameof(AddCompilationEndCustomTagDescription)),
+ customTags: WellKnownDiagnosticTagsExtensions.Telemetry);
+
public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(
UseLocalizableStringsInDescriptorRule,
ProvideHelpUriInDescriptorRule,
@@ -180,7 +193,8 @@ public sealed partial class DiagnosticDescriptorCreationAnalyzer : DiagnosticAna
EnableAnalyzerReleaseTrackingRule,
DefineDiagnosticTitleCorrectlyRule,
DefineDiagnosticMessageCorrectlyRule,
- DefineDiagnosticDescriptionCorrectlyRule);
+ DefineDiagnosticDescriptionCorrectlyRule,
+ AddCompilationEndCustomTagRule);
public override void Initialize(AnalysisContext context)
{
@@ -191,7 +205,9 @@ public override void Initialize(AnalysisContext context)
{
if (!compilationContext.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftCodeAnalysisDiagnosticDescriptor, out var diagnosticDescriptorType) ||
!compilationContext.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftCodeAnalysisLocalizableString, out var localizableResourceType) ||
- !compilationContext.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftCodeAnalysisLocalizableResourceString, out var localizableResourceStringType))
+ !compilationContext.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftCodeAnalysisLocalizableResourceString, out var localizableResourceStringType) ||
+ !compilationContext.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftCodeAnalysisDiagnosticsCompilationEndAnalysisContext, out var compilationEndContextType) ||
+ !compilationContext.Compilation.TryGetOrCreateTypeByMetadataName(WellKnownTypeNames.MicrosoftCodeAnalysisDiagnostic, out var diagnosticType))
{
return;
}
@@ -228,6 +244,7 @@ public override void Initialize(AnalysisContext context)
var idToAnalyzerMap = new ConcurrentDictionary>>();
var seenRuleIds = PooledConcurrentSet.GetInstance();
+ var customTagsMap = PooledFieldToCustomTagsConcurrentDictionary.GetInstance(SymbolEqualityComparer.Default);
compilationContext.RegisterOperationAction(operationAnalysisContext =>
{
var fieldInitializer = (IFieldInitializerOperation)operationAnalysisContext.Operation;
@@ -244,7 +261,7 @@ public override void Initialize(AnalysisContext context)
AnalyzeDescription(operationAnalysisContext, creationArguments, containingType,
localizableDescriptions, resourcesDataValueMap, localizableResourceType, localizableResourceStringType);
AnalyzeHelpLinkUri(operationAnalysisContext, creationArguments, out var helpLink);
- AnalyzeCustomTags(operationAnalysisContext, creationArguments);
+ AnalyzeCustomTags(operationAnalysisContext, creationArguments, fieldInitializer, customTagsMap);
var (isEnabledByDefault, defaultSeverity) = GetDefaultSeverityAndEnabledByDefault(operationAnalysisContext.Compilation, creationArguments);
if (!TryAnalyzeCategory(operationAnalysisContext, creationArguments, checkCategoryAndAllowedIds,
@@ -299,6 +316,132 @@ public override void Initialize(AnalysisContext context)
}, SymbolKind.NamedType);
}
+ // Flag descriptor fields that are used to report compilation end diagnostics,
+ // but do not have the required 'WellKnownDiagnosticTags.CompilationEnd' custom tag.
+ // See https://github.com/dotnet/roslyn-analyzers/issues/6282 for details.
+ if (compilationEndContextType.GetMembers(DiagnosticWellKnownNames.ReportDiagnosticName).FirstOrDefault() is IMethodSymbol compilationEndReportDiagnosticMethod)
+ {
+ var diagnosticCreateMethods = diagnosticType.GetMembers("Create").OfType()
+ .Where(m => m.IsPublic() && m.Parameters.Length > 0 && SymbolEqualityComparer.Default.Equals(m.Parameters[0].Type, diagnosticDescriptorType))
+ .ToImmutableHashSet(SymbolEqualityComparer.Default);
+ compilationContext.RegisterSymbolStartAction(context =>
+ {
+ var localsToDescriptorsMap = PooledConcurrentDictionary>.GetInstance(SymbolEqualityComparer.Default);
+ var localsUsedForCompilationEndReportDiagnostic = PooledConcurrentSet.GetInstance(SymbolEqualityComparer.Default);
+ var fieldsUsedForCompilationEndReportDiagnostic = PooledConcurrentSet.GetInstance(SymbolEqualityComparer.Default);
+
+ context.RegisterOperationAction(context =>
+ {
+ var invocation = (IInvocationOperation)context.Operation;
+ if (invocation.Arguments.IsEmpty)
+ return;
+
+ if (SymbolEqualityComparer.Default.Equals(invocation.TargetMethod, compilationEndReportDiagnosticMethod) &&
+ invocation.Arguments[0].Value.WalkDownConversion() is ILocalReferenceOperation localReference)
+ {
+ // Code pattern such as:
+ // var diagnostic = Diagnostic.Create(field, ...);
+ // context.ReportDiagnostic(diagnostic);
+ localsUsedForCompilationEndReportDiagnostic.Add(localReference.Local);
+ }
+ else if (diagnosticCreateMethods.Contains(invocation.TargetMethod))
+ {
+ if (invocation.Arguments[0].Value.WalkDownConversion() is IFieldReferenceOperation fieldReference)
+ {
+ // Code pattern such as:
+ // 'Diagnostic.Create(field, ...)'
+ if (invocation.GetAncestor(OperationKind.Invocation,
+ inv => SymbolEqualityComparer.Default.Equals(inv.TargetMethod, compilationEndReportDiagnosticMethod)) is not null)
+ {
+ // Code pattern such as:
+ // 'context.ReportDiagnostic(Diagnostic.Create(field, ...));'
+ fieldsUsedForCompilationEndReportDiagnostic.Add(fieldReference.Field);
+ }
+ else
+ {
+ switch (invocation.Parent)
+ {
+ case IVariableInitializerOperation variableInitializer:
+ // Code pattern such as:
+ // 'var diagnostic = Diagnostic.Create(field, ...);'
+ if (variableInitializer.GetAncestor(OperationKind.VariableDeclaration) is { } variableDeclaration)
+ {
+ foreach (var local in variableDeclaration.GetDeclaredVariables())
+ {
+ AddToLocalsToDescriptorsMap(local, fieldReference.Field, localsToDescriptorsMap);
+ }
+ }
+
+ break;
+
+ case ISimpleAssignmentOperation simpleAssignment:
+ // Code pattern such as:
+ // 'diagnostic = Diagnostic.Create(field, ...);'
+ if (simpleAssignment.Target is ILocalReferenceOperation localReferenceTarget)
+ {
+ AddToLocalsToDescriptorsMap(localReferenceTarget.Local, fieldReference.Field, localsToDescriptorsMap);
+ }
+
+ break;
+ }
+ }
+ }
+
+ static void AddToLocalsToDescriptorsMap(ILocalSymbol local, IFieldSymbol field, PooledConcurrentDictionary> localsToDescriptorsMap)
+ {
+ localsToDescriptorsMap.AddOrUpdate(local,
+ addValueFactory: _ =>
+ {
+ var set = PooledConcurrentSet.GetInstance(SymbolEqualityComparer.Default);
+ set.Add(field);
+ return set;
+ },
+ updateValueFactory: (_, fields) =>
+ {
+ fields.Add(field);
+ return fields;
+ });
+ }
+ }
+ }, OperationKind.Invocation);
+
+ context.RegisterSymbolEndAction(context =>
+ {
+ foreach (var local in localsUsedForCompilationEndReportDiagnostic)
+ {
+ if (localsToDescriptorsMap.TryGetValue(local, out var fields))
+ {
+ foreach (var field in fields)
+ AnalyzeField(field);
+ }
+ }
+
+ foreach (var field in fieldsUsedForCompilationEndReportDiagnostic)
+ {
+ AnalyzeField(field);
+ }
+
+ foreach (var value in localsToDescriptorsMap.Values)
+ value.Free(context.CancellationToken);
+ localsToDescriptorsMap.Free(context.CancellationToken);
+ localsUsedForCompilationEndReportDiagnostic.Free(context.CancellationToken);
+ fieldsUsedForCompilationEndReportDiagnostic.Free(context.CancellationToken);
+
+ void AnalyzeField(IFieldSymbol field)
+ {
+ if (customTagsMap.TryGetValue(field, out var customTags) &&
+ !customTags.IsDefault &&
+ !customTags.Contains(CompilationEndWellKnownDiagnosticTag) &&
+ !field.Locations.IsEmpty &&
+ field.Locations[0].IsInSource)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(AddCompilationEndCustomTagRule, field.Locations[0], field.Name));
+ }
+ }
+ });
+ }, SymbolKind.NamedType);
+ }
+
compilationContext.RegisterCompilationEndAction(compilationEndContext =>
{
// Report any invalid additional file diagnostics.
@@ -357,6 +500,8 @@ public override void Initialize(AnalysisContext context)
FreeLocalizableStringsMap(localizableDescriptions, compilationEndContext.CancellationToken);
resourcesDataValueMap.Free(compilationEndContext.CancellationToken);
}
+
+ customTagsMap.Free(compilationEndContext.CancellationToken);
});
});
@@ -901,25 +1046,56 @@ private static void AnalyzeHelpLinkUri(
}
}
- private static void AnalyzeCustomTags(OperationAnalysisContext operationAnalysisContext, ImmutableArray creationArguments)
+ private static void AnalyzeCustomTags(
+ OperationAnalysisContext operationAnalysisContext,
+ ImmutableArray creationArguments,
+ IFieldInitializerOperation fieldInitializerOperation,
+ PooledFieldToCustomTagsConcurrentDictionary customTagsMap)
{
- // Find the matching argument for customTags
- foreach (var argument in creationArguments)
+ // Default to indicate unknown set of custom tags.
+ ImmutableArray customTags = default;
+
+ try
{
- if (argument.Parameter.Name.Equals(CustomTagsParameterName, StringComparison.OrdinalIgnoreCase))
+ // Find the matching argument for customTags
+ var argument = creationArguments.FirstOrDefault(
+ a => a.Parameter.Name.Equals(CustomTagsParameterName, StringComparison.OrdinalIgnoreCase));
+ if (argument is null ||
+ argument.Value is not IArrayCreationOperation arrayCreation ||
+ arrayCreation.DimensionSizes.Length != 1)
{
- if (argument.Value is IArrayCreationOperation arrayCreation &&
- arrayCreation.DimensionSizes.Length == 1 &&
- arrayCreation.DimensionSizes[0].ConstantValue.HasValue &&
- arrayCreation.DimensionSizes[0].ConstantValue.Value is int size &&
- size == 0)
- {
- Diagnostic diagnostic = argument.CreateDiagnostic(ProvideCustomTagsInDescriptorRule);
- operationAnalysisContext.ReportDiagnostic(diagnostic);
- }
-
return;
}
+
+ if (arrayCreation.DimensionSizes[0].ConstantValue.HasValue &&
+ arrayCreation.DimensionSizes[0].ConstantValue.Value is int size &&
+ size == 0)
+ {
+ Diagnostic diagnostic = argument.CreateDiagnostic(ProvideCustomTagsInDescriptorRule);
+ operationAnalysisContext.ReportDiagnostic(diagnostic);
+
+ customTags = ImmutableArray.Empty;
+ }
+ else if (arrayCreation.Initializer is IArrayInitializerOperation arrayInitializer &&
+ arrayInitializer.ElementValues.All(element => element.ConstantValue.HasValue && element.ConstantValue.Value is string))
+ {
+ customTags = arrayInitializer.ElementValues.Select(element => (string)element.ConstantValue.Value).ToImmutableArray();
+ }
+ }
+ finally
+ {
+ AddCustomTags(customTags, fieldInitializerOperation, customTagsMap);
+ }
+
+ static void AddCustomTags(
+ ImmutableArray customTags,
+ IFieldInitializerOperation fieldInitializerOperation,
+ PooledFieldToCustomTagsConcurrentDictionary customTagsMap)
+ {
+ foreach (var field in fieldInitializerOperation.InitializedFields)
+ {
+ customTagsMap[field] = customTags;
+ }
}
}
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.cs.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.cs.xlf
index 7c7bb71967..10b86eb770 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.cs.xlf
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.cs.xlf
@@ -2,6 +2,21 @@
+
+
+ 'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+
+
+
+ Add "CompilationEnd" custom tag to the diagnostic descriptor used to initialize field '{0}' as it is used to report a compilation end diagnostic
+
+
+
+
+ Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
+ Přidat položku pravidla k nevydanému souboru verze
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.de.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.de.xlf
index f248a7001c..bf8c8e0778 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.de.xlf
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.de.xlf
@@ -2,6 +2,21 @@
+
+
+ 'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+
+
+
+ Add "CompilationEnd" custom tag to the diagnostic descriptor used to initialize field '{0}' as it is used to report a compilation end diagnostic
+
+
+
+
+ Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
+ Regeleintrag der nicht veröffentlichten Releasedatei hinzufügen
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.es.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.es.xlf
index 00bb024171..4861c50254 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.es.xlf
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.es.xlf
@@ -2,6 +2,21 @@
+
+
+ 'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+
+
+
+ Add "CompilationEnd" custom tag to the diagnostic descriptor used to initialize field '{0}' as it is used to report a compilation end diagnostic
+
+
+
+
+ Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
+ Agregar una entrada de regla a un archivo de versión no incluido
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.fr.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.fr.xlf
index ce38e4b292..f5992632ec 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.fr.xlf
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.fr.xlf
@@ -2,6 +2,21 @@
+
+
+ 'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+
+
+
+ Add "CompilationEnd" custom tag to the diagnostic descriptor used to initialize field '{0}' as it is used to report a compilation end diagnostic
+
+
+
+
+ Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
+ Ajouter une entrée de règle au fichier de version non fourni
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.it.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.it.xlf
index f6ba0a4364..c770de1cf3 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.it.xlf
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.it.xlf
@@ -2,6 +2,21 @@
+
+
+ 'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+
+
+
+ Add "CompilationEnd" custom tag to the diagnostic descriptor used to initialize field '{0}' as it is used to report a compilation end diagnostic
+
+
+
+
+ Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
+ Aggiungere la voce della regola per il file di versione non distribuito
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ja.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ja.xlf
index a858898b70..913709b59c 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ja.xlf
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ja.xlf
@@ -2,6 +2,21 @@
+
+
+ 'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+
+
+
+ Add "CompilationEnd" custom tag to the diagnostic descriptor used to initialize field '{0}' as it is used to report a compilation end diagnostic
+
+
+
+
+ Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
+ 未出荷のリリース ファイルへのルール エントリの追加
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ko.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ko.xlf
index 6be7183fd5..3c3a713be1 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ko.xlf
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ko.xlf
@@ -2,6 +2,21 @@
+
+
+ 'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+
+
+
+ Add "CompilationEnd" custom tag to the diagnostic descriptor used to initialize field '{0}' as it is used to report a compilation end diagnostic
+
+
+
+
+ Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
+ 제공되지 않은 릴리스 파일에 규칙 항목 추가
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pl.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pl.xlf
index 75e2d1f329..25e8aea1fb 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pl.xlf
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pl.xlf
@@ -2,6 +2,21 @@
+
+
+ 'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+
+
+
+ Add "CompilationEnd" custom tag to the diagnostic descriptor used to initialize field '{0}' as it is used to report a compilation end diagnostic
+
+
+
+
+ Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
+ Dodaj wpis reguły do niedostarczonego pliku wydania
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 033aec8345..94f44805e5 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pt-BR.xlf
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.pt-BR.xlf
@@ -2,6 +2,21 @@
+
+
+ 'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+
+
+
+ Add "CompilationEnd" custom tag to the diagnostic descriptor used to initialize field '{0}' as it is used to report a compilation end diagnostic
+
+
+
+
+ Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
+ Adicionar uma entrada de regra ao arquivo de versão não enviado
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ru.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ru.xlf
index e21575c4b9..4784597e2e 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ru.xlf
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.ru.xlf
@@ -2,6 +2,21 @@
+
+
+ 'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+
+
+
+ Add "CompilationEnd" custom tag to the diagnostic descriptor used to initialize field '{0}' as it is used to report a compilation end diagnostic
+
+
+
+
+ Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
+ Добавить запись правила в неотправленный файл выпуска
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.tr.xlf b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.tr.xlf
index 25479c6c48..ae024b3f56 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.tr.xlf
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.tr.xlf
@@ -2,6 +2,21 @@
+
+
+ 'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+
+
+
+ Add "CompilationEnd" custom tag to the diagnostic descriptor used to initialize field '{0}' as it is used to report a compilation end diagnostic
+
+
+
+
+ Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
+ Gönderilmeyen yayın dosyasına kural girişi ekle
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 8f3cf4bc26..b83c25d56a 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hans.xlf
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hans.xlf
@@ -2,6 +2,21 @@
+
+
+ 'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+
+
+
+ Add "CompilationEnd" custom tag to the diagnostic descriptor used to initialize field '{0}' as it is used to report a compilation end diagnostic
+
+
+
+
+ Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
+ 将规则项添加到未提供的版本文件
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 d6cccc2f25..c13618bbbd 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hant.xlf
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Core/xlf/CodeAnalysisDiagnosticsResources.zh-Hant.xlf
@@ -2,6 +2,21 @@
+
+
+ 'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+
+
+
+ Add "CompilationEnd" custom tag to the diagnostic descriptor used to initialize field '{0}' as it is used to report a compilation end diagnostic
+
+
+
+
+ Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
+ 將規則項目新增至未送出的版本檔案
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.md b/src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.md
index 359a0932b3..ab6a5fe858 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.md
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.md
@@ -448,6 +448,18 @@ A project containing analyzers or source generators should specify the property
|CodeFix|False|
---
+## RS1037: Add "CompilationEnd" custom tag to compilation end diagnostic descriptor
+
+'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag "CompilationEnd". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.
+
+|Item|Value|
+|-|-|
+|Category|MicrosoftCodeAnalysisDesign|
+|Enabled|True|
+|Severity|Warning|
+|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 ad6219bd1f..184a1aeab4 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.sarif
+++ b/src/Microsoft.CodeAnalysis.Analyzers/Microsoft.CodeAnalysis.Analyzers.sarif
@@ -442,6 +442,24 @@
]
}
},
+ "RS1037": {
+ "id": "RS1037",
+ "shortDescription": "Add \"CompilationEnd\" custom tag to compilation end diagnostic descriptor",
+ "fullDescription": "'DiagnosticDescriptor' assigned to field is used to report a compilation end diagnostic, but the 'DiagnosticDescriptor' constructor used to initialize it does not pass in the required custom tag \"CompilationEnd\". See documentation for 'WellKnownDiagnosticTags.CompilationEnd' for details.",
+ "defaultLevel": "warning",
+ "properties": {
+ "category": "MicrosoftCodeAnalysisDesign",
+ "isEnabledByDefault": true,
+ "typeName": "DiagnosticDescriptorCreationAnalyzer",
+ "languages": [
+ "C#",
+ "Visual Basic"
+ ],
+ "tags": [
+ "Telemetry"
+ ]
+ }
+ },
"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 2bc9c82232..8c4c41815e 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/RulesMissingDocumentation.md
+++ b/src/Microsoft.CodeAnalysis.Analyzers/RulesMissingDocumentation.md
@@ -37,3 +37,4 @@ RS1033 | | Define diagnostic description correctly |
RS1034 | | Prefer 'IsKind' for checking syntax kinds |
RS1035 | | Do not use APIs banned for analyzers |
RS1036 | | Specify analyzer banned API enforcement setting |
+RS1037 | | Add "CompilationEnd" custom tag to compilation end diagnostic descriptor |
diff --git a/src/Microsoft.CodeAnalysis.Analyzers/UnitTests/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzerTests.cs b/src/Microsoft.CodeAnalysis.Analyzers/UnitTests/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzerTests.cs
index 1ad7656a24..19f7355749 100644
--- a/src/Microsoft.CodeAnalysis.Analyzers/UnitTests/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzerTests.cs
+++ b/src/Microsoft.CodeAnalysis.Analyzers/UnitTests/MetaAnalyzers/DiagnosticDescriptorCreationAnalyzerTests.cs
@@ -3855,6 +3855,382 @@ await VerifyBasicCodeFixAsync(
#endregion // RS1033 (DefineDiagnosticDescriptionCorrectlyRule)
+ #region RS1037 (AddCompilationEndCustomTagRule)
+ [Fact, WorkItem(6282, "https://github.com/dotnet/roslyn-analyzers/issues/6282")]
+ public async Task RS1037_WithRequiredCustomTag_NoDiagnostic()
+ {
+ await VerifyCSharpAnalyzerAsync(@"
+using System;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+class MyAnalyzer : DiagnosticAnalyzer
+{
+ private static readonly DiagnosticDescriptor descriptor1 =
+ {|#0:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: ""CompilationEnd"")|};
+
+ public override ImmutableArray SupportedDiagnostics
+ {
+ get
+ {
+ return ImmutableArray.Create(descriptor1);
+ }
+ }
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.RegisterCompilationStartAction(compilationStartAnalysisContext =>
+ {
+ compilationStartAnalysisContext.RegisterCompilationEndAction(compilationEndAnalysisContext =>
+ {
+ compilationEndAnalysisContext.ReportDiagnostic(Diagnostic.Create(descriptor1, Location.None));
+ });
+ });
+ }
+}",
+ GetRS1007ExpectedDiagnostic(0));
+
+ await VerifyBasicAnalyzerAsync(@"
+Imports System
+Imports System.Collections.Immutable
+Imports Microsoft.CodeAnalysis
+Imports Microsoft.CodeAnalysis.Diagnostics
+
+
+Class MyAnalyzer
+ Inherits DiagnosticAnalyzer
+
+ Private Shared ReadOnly descriptor1 As DiagnosticDescriptor = {|#0:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, description:=Nothing, helpLinkUri:=""HelpLinkUrl"", ""CompilationEnd"")|}
+
+ Public Overrides ReadOnly Property SupportedDiagnostics() As ImmutableArray(Of DiagnosticDescriptor)
+ Get
+ Return ImmutableArray.Create(descriptor1)
+ End Get
+ End Property
+
+ Public Overrides Sub Initialize(context As AnalysisContext)
+ context.RegisterCompilationStartAction(Function(compilationStartAnalysisContext)
+ compilationStartAnalysisContext.RegisterCompilationEndAction(Function(compilationEndAnalysisContext)
+ compilationEndAnalysisContext.ReportDiagnostic(Diagnostic.Create(descriptor1, Location.None))
+ End Function)
+ End Function)
+ End Sub
+End Class
+",
+ GetRS1007ExpectedDiagnostic(0));
+ }
+
+ [Fact, WorkItem(6282, "https://github.com/dotnet/roslyn-analyzers/issues/6282")]
+ public async Task RS1037_NonInlinedCustomTags_NoDiagnostic()
+ {
+ await VerifyCSharpAnalyzerAsync(@"
+using System;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+class MyAnalyzer : DiagnosticAnalyzer
+{
+ private static readonly DiagnosticDescriptor descriptor1 =
+ {|#0:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: tags)|};
+ private static readonly string[] tags = new string[] { """" };
+
+ public override ImmutableArray SupportedDiagnostics
+ {
+ get
+ {
+ return ImmutableArray.Create(descriptor1);
+ }
+ }
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.RegisterCompilationStartAction(compilationStartAnalysisContext =>
+ {
+ compilationStartAnalysisContext.RegisterCompilationEndAction(compilationEndAnalysisContext =>
+ {
+ compilationEndAnalysisContext.ReportDiagnostic(Diagnostic.Create(descriptor1, Location.None));
+ });
+ });
+ }
+}",
+ GetRS1007ExpectedDiagnostic(0));
+
+ await VerifyBasicAnalyzerAsync(@"
+Imports System
+Imports System.Collections.Immutable
+Imports Microsoft.CodeAnalysis
+Imports Microsoft.CodeAnalysis.Diagnostics
+
+
+Class MyAnalyzer
+ Inherits DiagnosticAnalyzer
+
+ Private Shared ReadOnly descriptor1 As DiagnosticDescriptor = {|#0:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, description:=Nothing, helpLinkUri:=""HelpLinkUrl"", Tags)|}
+ Private Shared ReadOnly Tags As String() = { """" }
+
+ Public Overrides ReadOnly Property SupportedDiagnostics() As ImmutableArray(Of DiagnosticDescriptor)
+ Get
+ Return ImmutableArray.Create(descriptor1)
+ End Get
+ End Property
+
+ Public Overrides Sub Initialize(context As AnalysisContext)
+ context.RegisterCompilationStartAction(Function(compilationStartAnalysisContext)
+ compilationStartAnalysisContext.RegisterCompilationEndAction(Function(compilationEndAnalysisContext)
+ compilationEndAnalysisContext.ReportDiagnostic(Diagnostic.Create(descriptor1, Location.None))
+ End Function)
+ End Function)
+ End Sub
+End Class
+",
+ GetRS1007ExpectedDiagnostic(0));
+ }
+
+ [Fact, WorkItem(6282, "https://github.com/dotnet/roslyn-analyzers/issues/6282")]
+ public async Task RS1037_WithoutRequiredCustomTag_Diagnostic()
+ {
+ await VerifyCSharpAnalyzerAsync(@"
+using System;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+class MyAnalyzer : DiagnosticAnalyzer
+{
+ private static readonly DiagnosticDescriptor {|#0:descriptor1|} =
+ {|#1:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """")|};
+ private static readonly DiagnosticDescriptor descriptor2 =
+ {|#2:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """")|};
+
+ public override ImmutableArray SupportedDiagnostics
+ {
+ get
+ {
+ return ImmutableArray.Create(descriptor1, descriptor2);
+ }
+ }
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.RegisterCompilationStartAction(compilationStartAnalysisContext =>
+ {
+ compilationStartAnalysisContext.RegisterCompilationEndAction(compilationEndAnalysisContext =>
+ {
+ compilationEndAnalysisContext.ReportDiagnostic(Diagnostic.Create(descriptor1, Location.None));
+
+ var diag2 = Diagnostic.Create(descriptor2, Location.None);
+ });
+ });
+ }
+}",
+ GetRS1037ExpectedDiagnostic(0, "descriptor1"),
+ GetRS1007ExpectedDiagnostic(1),
+ GetRS1007ExpectedDiagnostic(2));
+
+ await VerifyBasicAnalyzerAsync(@"
+Imports System
+Imports System.Collections.Immutable
+Imports Microsoft.CodeAnalysis
+Imports Microsoft.CodeAnalysis.Diagnostics
+
+
+Class MyAnalyzer
+ Inherits DiagnosticAnalyzer
+
+ Private Shared ReadOnly {|#0:descriptor1|} As DiagnosticDescriptor = {|#1:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, description:=Nothing, helpLinkUri:=""HelpLinkUrl"", ""Tag"")|}
+ Private Shared ReadOnly descriptor2 As DiagnosticDescriptor = {|#2:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, description:=Nothing, helpLinkUri:=""HelpLinkUrl"", ""Tag"")|}
+
+ Public Overrides ReadOnly Property SupportedDiagnostics() As ImmutableArray(Of DiagnosticDescriptor)
+ Get
+ Return ImmutableArray.Create(descriptor1, descriptor2)
+ End Get
+ End Property
+
+ Public Overrides Sub Initialize(context As AnalysisContext)
+ context.RegisterCompilationStartAction(Function(compilationStartAnalysisContext)
+ compilationStartAnalysisContext.RegisterCompilationEndAction(Function(compilationEndAnalysisContext)
+ compilationEndAnalysisContext.ReportDiagnostic(Diagnostic.Create(descriptor1, Location.None))
+
+ Dim diag2 = Diagnostic.Create(descriptor2, Location.None)
+ End Function)
+ End Function)
+ End Sub
+End Class
+",
+ GetRS1037ExpectedDiagnostic(0, "descriptor1"),
+ GetRS1007ExpectedDiagnostic(1),
+ GetRS1007ExpectedDiagnostic(2));
+ }
+
+ [Fact, WorkItem(6282, "https://github.com/dotnet/roslyn-analyzers/issues/6282")]
+ public async Task RS1037_DiagnosticStoredInLocal_WithInitializer_Diagnostic()
+ {
+ await VerifyCSharpAnalyzerAsync(@"
+using System;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+class MyAnalyzer : DiagnosticAnalyzer
+{
+ private static readonly DiagnosticDescriptor {|#0:descriptor1|} =
+ {|#1:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """")|};
+ private static readonly DiagnosticDescriptor descriptor2 =
+ {|#2:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """")|};
+
+ public override ImmutableArray SupportedDiagnostics
+ {
+ get
+ {
+ return ImmutableArray.Create(descriptor1, descriptor2);
+ }
+ }
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.RegisterCompilationStartAction(compilationStartAnalysisContext =>
+ {
+ compilationStartAnalysisContext.RegisterCompilationEndAction(compilationEndAnalysisContext =>
+ {
+ var diag1 = Diagnostic.Create(descriptor1, Location.None);
+ compilationEndAnalysisContext.ReportDiagnostic(diag1);
+
+ var diag2 = Diagnostic.Create(descriptor2, Location.None);
+ });
+ });
+ }
+}",
+ GetRS1037ExpectedDiagnostic(0, "descriptor1"),
+ GetRS1007ExpectedDiagnostic(1),
+ GetRS1007ExpectedDiagnostic(2));
+
+ await VerifyBasicAnalyzerAsync(@"
+Imports System
+Imports System.Collections.Immutable
+Imports Microsoft.CodeAnalysis
+Imports Microsoft.CodeAnalysis.Diagnostics
+
+
+Class MyAnalyzer
+ Inherits DiagnosticAnalyzer
+
+ Private Shared ReadOnly {|#0:descriptor1|} As DiagnosticDescriptor = {|#1:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, description:=Nothing, helpLinkUri:=""HelpLinkUrl"", ""Tag"")|}
+ Private Shared ReadOnly descriptor2 As DiagnosticDescriptor = {|#2:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, description:=Nothing, helpLinkUri:=""HelpLinkUrl"", ""Tag"")|}
+
+ Public Overrides ReadOnly Property SupportedDiagnostics() As ImmutableArray(Of DiagnosticDescriptor)
+ Get
+ Return ImmutableArray.Create(descriptor1, descriptor2)
+ End Get
+ End Property
+
+ Public Overrides Sub Initialize(context As AnalysisContext)
+ context.RegisterCompilationStartAction(Function(compilationStartAnalysisContext)
+ compilationStartAnalysisContext.RegisterCompilationEndAction(Function(compilationEndAnalysisContext)
+ Dim diag1 = Diagnostic.Create(descriptor1, Location.None)
+ compilationEndAnalysisContext.ReportDiagnostic(diag1)
+
+ Dim diag2 = Diagnostic.Create(descriptor2, Location.None)
+ End Function)
+ End Function)
+ End Sub
+End Class
+",
+ GetRS1037ExpectedDiagnostic(0, "descriptor1"),
+ GetRS1007ExpectedDiagnostic(1),
+ GetRS1007ExpectedDiagnostic(2));
+ }
+
+ [Fact, WorkItem(6282, "https://github.com/dotnet/roslyn-analyzers/issues/6282")]
+ public async Task RS1037_DiagnosticStoredInLocal_WithAssignment_Diagnostic()
+ {
+ await VerifyCSharpAnalyzerAsync(@"
+using System;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
+class MyAnalyzer : DiagnosticAnalyzer
+{
+ private static readonly DiagnosticDescriptor {|#0:descriptor1|} =
+ {|#1:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """")|};
+ private static readonly DiagnosticDescriptor {|#2:descriptor2|} =
+ {|#3:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, isEnabledByDefault: true, helpLinkUri: ""HelpLink"", customTags: """")|};
+
+ public override ImmutableArray SupportedDiagnostics
+ {
+ get
+ {
+ return ImmutableArray.Create(descriptor1, descriptor2);
+ }
+ }
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.RegisterCompilationStartAction(compilationStartAnalysisContext =>
+ {
+ compilationStartAnalysisContext.RegisterCompilationEndAction(compilationEndAnalysisContext =>
+ {
+ var diag = Diagnostic.Create(descriptor1, Location.None);
+ compilationEndAnalysisContext.ReportDiagnostic(diag);
+
+ diag = Diagnostic.Create(descriptor2, Location.None);
+ compilationEndAnalysisContext.ReportDiagnostic(diag);
+ });
+ });
+ }
+}",
+ GetRS1037ExpectedDiagnostic(0, "descriptor1"),
+ GetRS1007ExpectedDiagnostic(1),
+ GetRS1037ExpectedDiagnostic(2, "descriptor2"),
+ GetRS1007ExpectedDiagnostic(3));
+
+ await VerifyBasicAnalyzerAsync(@"
+Imports System
+Imports System.Collections.Immutable
+Imports Microsoft.CodeAnalysis
+Imports Microsoft.CodeAnalysis.Diagnostics
+
+
+Class MyAnalyzer
+ Inherits DiagnosticAnalyzer
+
+ Private Shared ReadOnly {|#0:descriptor1|} As DiagnosticDescriptor = {|#1:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, description:=Nothing, helpLinkUri:=""HelpLinkUrl"", ""Tag"")|}
+ Private Shared ReadOnly {|#2:descriptor2|} As DiagnosticDescriptor = {|#3:new DiagnosticDescriptor(""MyDiagnosticId"", ""MyDiagnosticTitle"", ""MyDiagnosticMessage"", ""MyDiagnosticCategory"", DiagnosticSeverity.Warning, True, description:=Nothing, helpLinkUri:=""HelpLinkUrl"", ""Tag"")|}
+
+ Public Overrides ReadOnly Property SupportedDiagnostics() As ImmutableArray(Of DiagnosticDescriptor)
+ Get
+ Return ImmutableArray.Create(descriptor1, descriptor2)
+ End Get
+ End Property
+
+ Public Overrides Sub Initialize(context As AnalysisContext)
+ context.RegisterCompilationStartAction(Function(compilationStartAnalysisContext)
+ compilationStartAnalysisContext.RegisterCompilationEndAction(Function(compilationEndAnalysisContext)
+ Dim diag = Diagnostic.Create(descriptor1, Location.None)
+ compilationEndAnalysisContext.ReportDiagnostic(diag)
+
+ diag = Diagnostic.Create(descriptor2, Location.None)
+ compilationEndAnalysisContext.ReportDiagnostic(diag)
+ End Function)
+ End Function)
+ End Sub
+End Class
+",
+ GetRS1037ExpectedDiagnostic(0, "descriptor1"),
+ GetRS1007ExpectedDiagnostic(1),
+ GetRS1037ExpectedDiagnostic(2, "descriptor2"),
+ GetRS1007ExpectedDiagnostic(3));
+ }
+
+ #endregion // RS1037 (AddCompilationEndCustomTagRule)
+
[Fact, WorkItem(6035, "https://github.com/dotnet/roslyn-analyzers/issues/6035")]
public async Task VerifyFieldReferenceForFieldDefinedInSeparateFile()
{
@@ -3977,6 +4353,14 @@ private static DiagnosticResult GetRS1029ResultAt(int markupKey, string ruleId)
.WithLocation(markupKey)
.WithArguments(ruleId);
+ ///
+ /// Creates an expected diagnostic for
+ ///
+ private static DiagnosticResult GetRS1037ExpectedDiagnostic(int markupKey, string fieldName) =>
+ new DiagnosticResult(DiagnosticDescriptorCreationAnalyzer.AddCompilationEndCustomTagRule)
+ .WithLocation(markupKey)
+ .WithArguments(fieldName);
+
private static async Task VerifyCSharpAnalyzerAsync(string source, params DiagnosticResult[] expected)
{
var test = new VerifyCS.Test