forked from dotnet/roslyn-analyzers
/
ConfigureGeneratedCodeAnalysisAnalyzer.cs
138 lines (114 loc) · 6.03 KB
/
ConfigureGeneratedCodeAnalysisAnalyzer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Analyzer.Utilities;
using Analyzer.Utilities.Extensions;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
namespace Microsoft.CodeAnalysis.Analyzers.MetaAnalyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public class ConfigureGeneratedCodeAnalysisAnalyzer : DiagnosticAnalyzerCorrectnessAnalyzer
{
private static readonly LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(CodeAnalysisDiagnosticsResources.ConfigureGeneratedCodeAnalysisTitle), CodeAnalysisDiagnosticsResources.ResourceManager, typeof(CodeAnalysisDiagnosticsResources));
private static readonly LocalizableString s_localizableMessage = new LocalizableResourceString(nameof(CodeAnalysisDiagnosticsResources.ConfigureGeneratedCodeAnalysisMessage), CodeAnalysisDiagnosticsResources.ResourceManager, typeof(CodeAnalysisDiagnosticsResources));
private static readonly LocalizableString s_localizableDescription = new LocalizableResourceString(nameof(CodeAnalysisDiagnosticsResources.ConfigureGeneratedCodeAnalysisDescription), CodeAnalysisDiagnosticsResources.ResourceManager, typeof(CodeAnalysisDiagnosticsResources));
public static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(
DiagnosticIds.ConfigureGeneratedCodeAnalysisRuleId,
s_localizableTitle,
s_localizableMessage,
DiagnosticCategory.MicrosoftCodeAnalysisCorrectness,
DiagnosticHelpers.DefaultDiagnosticSeverity,
isEnabledByDefault: DiagnosticHelpers.EnabledByDefaultIfNotBuildingVSIX,
description: s_localizableDescription,
customTags: WellKnownDiagnosticTags.Telemetry);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
#pragma warning disable RS1025 // Configure generated code analysis
public override void Initialize(AnalysisContext context)
#pragma warning restore RS1025 // Configure generated code analysis
{
context.EnableConcurrentExecution();
base.Initialize(context);
}
[SuppressMessage("AnalyzerPerformance", "RS1012:Start action has no registered actions.", Justification = "Method returns an analyzer that is registered by the caller.")]
protected override DiagnosticAnalyzerSymbolAnalyzer? GetDiagnosticAnalyzerSymbolAnalyzer(CompilationStartAnalysisContext compilationContext, INamedTypeSymbol diagnosticAnalyzer, INamedTypeSymbol diagnosticAnalyzerAttribute)
{
var compilation = compilationContext.Compilation;
var analysisContext = compilation.GetOrCreateTypeByMetadataName(AnalysisContextFullName);
if (analysisContext is null)
{
return null;
}
compilationContext.RegisterOperationBlockStartAction(context =>
{
if (context.OwningSymbol?.Kind != SymbolKind.Method)
{
return;
}
var method = (IMethodSymbol)context.OwningSymbol;
if (method.Name != nameof(DiagnosticAnalyzer.Initialize))
{
return;
}
IParameterSymbol? analysisContextParameter = null;
foreach (var parameter in method.Parameters)
{
if (!Equals(parameter.Type, analysisContext))
{
continue;
}
analysisContextParameter = parameter;
break;
}
if (analysisContextParameter is null)
{
return;
}
var analyzer = new ConfigureGeneratedCodeAnalyzer(analysisContextParameter);
context.RegisterOperationAction(analyzer.HandleInvocationOperation, OperationKind.Invocation);
context.RegisterOperationBlockEndAction(analyzer.HandleOperationBlockEnd);
});
// This analyzer only performs operation block analysis
return null;
}
private sealed class ConfigureGeneratedCodeAnalyzer
{
private readonly IParameterSymbol _analysisContextParameter;
public ConfigureGeneratedCodeAnalyzer(IParameterSymbol analysisContextParameter)
{
_analysisContextParameter = analysisContextParameter;
}
public bool ConfiguredGeneratedCodeAnalysis { get; private set; }
internal void HandleInvocationOperation(OperationAnalysisContext context)
{
if (ConfiguredGeneratedCodeAnalysis)
{
return;
}
var invocation = (IInvocationOperation)context.Operation;
if (invocation.TargetMethod?.Name != nameof(AnalysisContext.ConfigureGeneratedCodeAnalysis))
{
return;
}
if (invocation.Instance?.Kind != OperationKind.ParameterReference)
{
return;
}
var parameterReference = (IParameterReferenceOperation)invocation.Instance;
if (!Equals(parameterReference.Parameter, _analysisContextParameter))
{
return;
}
ConfiguredGeneratedCodeAnalysis = true;
}
internal void HandleOperationBlockEnd(OperationBlockAnalysisContext context)
{
if (!ConfiguredGeneratedCodeAnalysis)
{
context.ReportDiagnostic(Diagnostic.Create(Rule, _analysisContextParameter.Locations.FirstOrDefault()));
}
}
}
}
}