提交 8b7ac37b 编写于 作者: J John Hamby

Add OwningSymbol and Compilation properties to OperationAnalysisContext and...

Add OwningSymbol and Compilation properties to OperationAnalysisContext and SyntaxNodeAnalysisContext.
上级 7f527b51
......@@ -1356,6 +1356,67 @@ partial class PartialType
VerifyGeneratedCodeAnalyzerDiagnostics(compilation, expected, GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
}
internal class OwningSymbolTestAnalyzer : DiagnosticAnalyzer
{
public static readonly DiagnosticDescriptor ExpressionDescriptor = new DiagnosticDescriptor(
"Expression",
"Expression",
"Expression found.",
"Testing",
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public sealed override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get { return ImmutableArray.Create(ExpressionDescriptor); }
}
public sealed override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(
(nodeContext) =>
{
if (nodeContext.OwningSymbol.Name.StartsWith("Funky") && nodeContext.Compilation.Language == "C#")
{
nodeContext.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(ExpressionDescriptor, nodeContext.Node.GetLocation()));
}
},
SyntaxKind.IdentifierName,
SyntaxKind.NumericLiteralExpression);
}
}
[Fact]
public void OwningSymbolTest()
{
const string source = @"
class C
{
public void UnFunkyMethod()
{
int x = 0;
int y = x;
}
public void FunkyMethod()
{
int x = 0;
int y = x;
}
public int FunkyField = 12;
public int UnFunkyField = 12;
}
";
CreateCompilationWithMscorlib45(source)
.VerifyDiagnostics()
.VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new OwningSymbolTestAnalyzer() }, null, null, false,
Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "0").WithLocation(12, 17),
Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "x").WithLocation(13, 17),
Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "12").WithLocation(16, 29)
);
}
private static void VerifyGeneratedCodeAnalyzerDiagnostics(Compilation compilation, Func<string, bool> isGeneratedFileName, GeneratedCodeAnalysisFlags? generatedCodeAnalysisFlagsOpt)
{
var expected = GetExpectedGeneratedCodeAnalyzerDiagnostics(compilation, isGeneratedFileName, generatedCodeAnalysisFlagsOpt);
......
......@@ -1184,6 +1184,37 @@ class C
);
}
[Fact]
public void OwningSymbolCSharp()
{
const string source = @"
class C
{
public void UnFunkyMethod()
{
int x = 0;
int y = x;
}
public void FunkyMethod()
{
int x = 0;
int y = x;
}
public int FunkyField = 12;
public int UnFunkyField = 12;
}
";
CreateCompilationWithMscorlib45(source)
.VerifyDiagnostics()
.VerifyAnalyzerDiagnostics(new DiagnosticAnalyzer[] { new OwningSymbolTestAnalyzer() }, null, null, false,
Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "0").WithLocation(12, 17),
Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "x").WithLocation(13, 17),
Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "12").WithLocation(16, 29)
);
}
[Fact]
public void NoneOperationCSharp()
{
......
......@@ -71,6 +71,37 @@ public sealed override void Initialize(AnalysisContext context)
}
}
/// <summary>Analyzer used to test for operations within symbols of certain names.</summary>
public class OwningSymbolTestAnalyzer : DiagnosticAnalyzer
{
public static readonly DiagnosticDescriptor ExpressionDescriptor = new DiagnosticDescriptor(
"Expression",
"Expression",
"Expression found.",
"Testing",
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public sealed override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get { return ImmutableArray.Create(ExpressionDescriptor); }
}
public sealed override void Initialize(AnalysisContext context)
{
context.RegisterOperationAction(
(operationContext) =>
{
if (operationContext.OwningSymbol.Name.StartsWith("Funky") && operationContext.Compilation.Language != "Mumble")
{
operationContext.ReportDiagnostic(Diagnostic.Create(ExpressionDescriptor, operationContext.Operation.Syntax.GetLocation()));
}
},
OperationKind.LocalReferenceExpression,
OperationKind.LiteralExpression);
}
}
/// <summary>Analyzer used to test for loop IOperations.</summary>
public class BigForTestAnalyzer : DiagnosticAnalyzer
{
......
......@@ -480,6 +480,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
private void ExecuteSyntaxNodeAction<TLanguageKindEnum>(
SyntaxNodeAnalyzerAction<TLanguageKindEnum> syntaxNodeAction,
SyntaxNode node,
ISymbol owningSymbol,
SemanticModel semanticModel,
Action<Diagnostic> addDiagnostic,
SyntaxNodeAnalyzerStateData analyzerStateOpt)
......@@ -489,7 +490,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
if (ShouldExecuteAction(analyzerStateOpt, syntaxNodeAction))
{
var syntaxNodeContext = new SyntaxNodeAnalysisContext(node, semanticModel, _analyzerOptions, addDiagnostic,
var syntaxNodeContext = new SyntaxNodeAnalysisContext(node, owningSymbol, semanticModel, _analyzerOptions, addDiagnostic,
d => IsSupportedDiagnostic(syntaxNodeAction.Analyzer, d), _cancellationToken);
ExecuteAndCatchIfThrows(syntaxNodeAction.Analyzer,
() => syntaxNodeAction.Action(syntaxNodeContext),
......@@ -502,6 +503,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
private void ExecuteOperationAction(
OperationAnalyzerAction operationAction,
IOperation operation,
ISymbol owningSymbol,
SemanticModel semanticModel,
Action<Diagnostic> addDiagnostic,
OperationAnalyzerStateData analyzerStateOpt)
......@@ -510,7 +512,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
if (ShouldExecuteAction(analyzerStateOpt, operationAction))
{
var operationContext = new OperationAnalysisContext(operation, _analyzerOptions, addDiagnostic, d => IsSupportedDiagnostic(operationAction.Analyzer, d), semanticModel, _cancellationToken);
var operationContext = new OperationAnalysisContext(operation, owningSymbol, semanticModel.Compilation, _analyzerOptions, addDiagnostic, d => IsSupportedDiagnostic(operationAction.Analyzer, d), semanticModel, _cancellationToken);
ExecuteAndCatchIfThrows(operationAction.Analyzer,
() => operationAction.Action(operationContext),
new AnalysisContextInfo(_compilation, operation));
......@@ -713,13 +715,13 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
var executableNodeActionsByKind = GetNodeActionsByKind(syntaxNodeActions);
var syntaxNodesToAnalyze = (IEnumerable<SyntaxNode>)getNodesToAnalyze(executableBlocks);
ExecuteSyntaxNodeActions(syntaxNodesToAnalyze, executableNodeActionsByKind, semanticModel, getKind, addDiagnostic, analyzerStateOpt?.ExecutableNodesAnalysisState as SyntaxNodeAnalyzerStateData);
ExecuteSyntaxNodeActions(syntaxNodesToAnalyze, executableNodeActionsByKind, declaredSymbol, semanticModel, getKind, addDiagnostic, analyzerStateOpt?.ExecutableNodesAnalysisState as SyntaxNodeAnalyzerStateData);
}
else if (operationActions != null)
{
var operationActionsByKind = GetOperationActionsByKind(operationActions);
var operationsToAnalyze = (IEnumerable<IOperation>)getNodesToAnalyze(executableBlocks);
ExecuteOperationActions(operationsToAnalyze, operationActionsByKind, semanticModel, addDiagnostic, analyzerStateOpt?.ExecutableNodesAnalysisState as OperationAnalyzerStateData);
ExecuteOperationActions(operationsToAnalyze, operationActionsByKind, declaredSymbol, semanticModel, addDiagnostic, analyzerStateOpt?.ExecutableNodesAnalysisState as OperationAnalyzerStateData);
}
}
......@@ -825,7 +827,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
if (TryStartAnalyzingSyntaxRefence(declaredSymbol, declarationIndex, analyzer, analysisScope, analysisStateOpt, out analyzerStateOpt))
{
ExecuteSyntaxNodeActionsCore(nodesToAnalyze, nodeActionsByKind, analyzer, model, getKind, filterSpan, analyzerStateOpt, isGeneratedCode);
ExecuteSyntaxNodeActionsCore(nodesToAnalyze, nodeActionsByKind, analyzer, declaredSymbol, model, getKind, filterSpan, analyzerStateOpt, isGeneratedCode);
}
}
finally
......@@ -838,6 +840,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
IEnumerable<SyntaxNode> nodesToAnalyze,
IDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> nodeActionsByKind,
DiagnosticAnalyzer analyzer,
ISymbol owningSymbol,
SemanticModel model,
Func<SyntaxNode, TLanguageKindEnum> getKind,
TextSpan filterSpan,
......@@ -846,12 +849,13 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
where TLanguageKindEnum : struct
{
var addDiagnostic = GetAddDiagnostic(model.SyntaxTree, filterSpan, analyzer, isSyntaxDiagnostic: false, isGeneratedCode: isGeneratedCode);
ExecuteSyntaxNodeActions(nodesToAnalyze, nodeActionsByKind, model, getKind, addDiagnostic, analyzerStateOpt);
ExecuteSyntaxNodeActions(nodesToAnalyze, nodeActionsByKind, owningSymbol, model, getKind, addDiagnostic, analyzerStateOpt);
}
private void ExecuteSyntaxNodeActions<TLanguageKindEnum>(
IEnumerable<SyntaxNode> nodesToAnalyze,
IDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> nodeActionsByKind,
ISymbol owningSymbol,
SemanticModel model,
Func<SyntaxNode, TLanguageKindEnum> getKind,
Action<Diagnostic> addDiagnostic,
......@@ -864,7 +868,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
SyntaxNode partiallyProcessedNode = analyzerStateOpt?.CurrentNode;
if (partiallyProcessedNode != null)
{
ExecuteSyntaxNodeActions(partiallyProcessedNode, nodeActionsByKind, model, getKind, addDiagnostic, analyzerStateOpt);
ExecuteSyntaxNodeActions(partiallyProcessedNode, nodeActionsByKind, owningSymbol, model, getKind, addDiagnostic, analyzerStateOpt);
}
foreach (var child in nodesToAnalyze)
......@@ -873,7 +877,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
SetCurrentNode(analyzerStateOpt, child);
ExecuteSyntaxNodeActions(child, nodeActionsByKind, model, getKind, addDiagnostic, analyzerStateOpt);
ExecuteSyntaxNodeActions(child, nodeActionsByKind, owningSymbol, model, getKind, addDiagnostic, analyzerStateOpt);
}
}
}
......@@ -881,6 +885,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
private void ExecuteSyntaxNodeActions<TLanguageKindEnum>(
SyntaxNode node,
IDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> nodeActionsByKind,
ISymbol owningSymbol,
SemanticModel model,
Func<SyntaxNode, TLanguageKindEnum> getKind,
Action<Diagnostic> addDiagnostic,
......@@ -892,7 +897,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
foreach (var action in actionsForKind)
{
ExecuteSyntaxNodeAction(action, node, model, addDiagnostic, analyzerStateOpt);
ExecuteSyntaxNodeAction(action, node, owningSymbol, model, addDiagnostic, analyzerStateOpt);
}
}
......@@ -948,7 +953,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
if (TryStartAnalyzingOperationReference(declaredSymbol, declarationIndex, analyzer, analysisScope, analysisStateOpt, out analyzerStateOpt))
{
ExecuteOperationActionsCore(operationsToAnalyze, operationActionsByKind, analyzer, model, filterSpan, analyzerStateOpt, isGeneratedCode);
ExecuteOperationActionsCore(operationsToAnalyze, operationActionsByKind, analyzer, declaredSymbol, model, filterSpan, analyzerStateOpt, isGeneratedCode);
}
}
finally
......@@ -961,18 +966,20 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
IEnumerable<IOperation> operationsToAnalyze,
IDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> operationActionsByKind,
DiagnosticAnalyzer analyzer,
ISymbol owningSymbol,
SemanticModel model,
TextSpan filterSpan,
OperationAnalyzerStateData analyzerStateOpt,
bool isGeneratedCode)
{
var addDiagnostic = GetAddDiagnostic(model.SyntaxTree, filterSpan, analyzer, isSyntaxDiagnostic: false, isGeneratedCode: isGeneratedCode);
ExecuteOperationActions(operationsToAnalyze, operationActionsByKind, model, addDiagnostic, analyzerStateOpt);
ExecuteOperationActions(operationsToAnalyze, operationActionsByKind, owningSymbol, model, addDiagnostic, analyzerStateOpt);
}
private void ExecuteOperationActions(
IEnumerable<IOperation> operationsToAnalyze,
IDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> operationActionsByKind,
ISymbol owningSymbol,
SemanticModel model,
Action<Diagnostic> addDiagnostic,
OperationAnalyzerStateData analyzerStateOpt)
......@@ -983,7 +990,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
IOperation partiallyProcessedNode = analyzerStateOpt?.CurrentOperation;
if (partiallyProcessedNode != null)
{
ExecuteOperationActions(partiallyProcessedNode, operationActionsByKind, model, addDiagnostic, analyzerStateOpt);
ExecuteOperationActions(partiallyProcessedNode, operationActionsByKind, owningSymbol, model, addDiagnostic, analyzerStateOpt);
}
foreach (var child in operationsToAnalyze)
......@@ -992,7 +999,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
SetCurrentOperation(analyzerStateOpt, child);
ExecuteOperationActions(child, operationActionsByKind, model, addDiagnostic, analyzerStateOpt);
ExecuteOperationActions(child, operationActionsByKind, owningSymbol, model, addDiagnostic, analyzerStateOpt);
}
}
}
......@@ -1000,6 +1007,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
private void ExecuteOperationActions(
IOperation operation,
IDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> operationActionsByKind,
ISymbol owningSymbol,
SemanticModel model,
Action<Diagnostic> addDiagnostic,
OperationAnalyzerStateData analyzerStateOpt)
......@@ -1009,7 +1017,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
foreach (var action in actionsForKind)
{
ExecuteOperationAction(action, operation, model, addDiagnostic, analyzerStateOpt);
ExecuteOperationAction(action, operation, owningSymbol, model, addDiagnostic, analyzerStateOpt);
}
}
......
......@@ -929,6 +929,7 @@ public void ReportDiagnostic(Diagnostic diagnostic)
public struct SyntaxNodeAnalysisContext
{
private readonly SyntaxNode _node;
private readonly ISymbol _owningSymbol;
private readonly SemanticModel _semanticModel;
private readonly AnalyzerOptions _options;
private readonly Action<Diagnostic> _reportDiagnostic;
......@@ -938,26 +939,37 @@ public struct SyntaxNodeAnalysisContext
/// <summary>
/// <see cref="SyntaxNode"/> that is the subject of the analysis.
/// </summary>
public SyntaxNode Node { get { return _node; } }
public SyntaxNode Node => _node;
/// <summary>
/// <see cref="ISymbol"/> for the declaration containing the syntax node.
/// </summary>
public ISymbol OwningSymbol => _owningSymbol;
/// <summary>
/// <see cref="CodeAnalysis.SemanticModel"/> that can provide semantic information about the <see cref="SyntaxNode"/>.
/// </summary>
public SemanticModel SemanticModel { get { return _semanticModel; } }
public SemanticModel SemanticModel => _semanticModel;
/// <summary>
/// <see cref="CodeAnalysis.Compilation"/> containing the <see cref="SyntaxNode"/>.
/// </summary>
public Compilation Compilation => _semanticModel?.Compilation;
/// <summary>
/// Options specified for the analysis.
/// </summary>
public AnalyzerOptions Options { get { return _options; } }
public AnalyzerOptions Options => _options;
/// <summary>
/// Token to check for requested cancellation of the analysis.
/// </summary>
public CancellationToken CancellationToken { get { return _cancellationToken; } }
public CancellationToken CancellationToken => _cancellationToken;
public SyntaxNodeAnalysisContext(SyntaxNode node, SemanticModel semanticModel, AnalyzerOptions options, Action<Diagnostic> reportDiagnostic, Func<Diagnostic, bool> isSupportedDiagnostic, CancellationToken cancellationToken)
public SyntaxNodeAnalysisContext(SyntaxNode node, ISymbol owningSymbol, SemanticModel semanticModel, AnalyzerOptions options, Action<Diagnostic> reportDiagnostic, Func<Diagnostic, bool> isSupportedDiagnostic, CancellationToken cancellationToken)
{
_node = node;
_owningSymbol = owningSymbol;
_semanticModel = semanticModel;
_options = options;
_reportDiagnostic = reportDiagnostic;
......@@ -965,6 +977,11 @@ public SyntaxNodeAnalysisContext(SyntaxNode node, SemanticModel semanticModel, A
_cancellationToken = cancellationToken;
}
public SyntaxNodeAnalysisContext(SyntaxNode node, SemanticModel semanticModel, AnalyzerOptions options, Action<Diagnostic> reportDiagnostic, Func<Diagnostic, bool> isSupportedDiagnostic, CancellationToken cancellationToken)
: this(node, null, semanticModel, options, reportDiagnostic, isSupportedDiagnostic, cancellationToken)
{
}
/// <summary>
/// Report a <see cref="Diagnostic"/> about a <see cref="SyntaxNode"/>.
/// </summary>
......@@ -986,7 +1003,9 @@ public void ReportDiagnostic(Diagnostic diagnostic)
public struct OperationAnalysisContext
{
private readonly IOperation _operation;
private readonly ISymbol _owningSymbol;
private readonly SemanticModel _semanticModelOpt;
private readonly Compilation _compilation;
private readonly AnalyzerOptions _options;
private readonly Action<Diagnostic> _reportDiagnostic;
private readonly Func<Diagnostic, bool> _isSupportedDiagnostic;
......@@ -997,6 +1016,16 @@ public struct OperationAnalysisContext
/// </summary>
public IOperation Operation => _operation;
/// <summary>
/// <see cref="ISymbol"/> for the declaration containing the operation.
/// </summary>
public ISymbol OwningSymbol => _owningSymbol;
/// <summary>
/// <see cref="CodeAnalysis.Compilation"/> containing the <see cref="IOperation"/>.
/// </summary>
public Compilation Compilation => _compilation;
/// <summary>
/// Options specified for the analysis.
/// </summary>
......@@ -1007,17 +1036,17 @@ public struct OperationAnalysisContext
/// </summary>
public CancellationToken CancellationToken => _cancellationToken;
internal Compilation Compilation => _semanticModelOpt?.Compilation;
public OperationAnalysisContext(IOperation operation, AnalyzerOptions options, Action<Diagnostic> reportDiagnostic, Func<Diagnostic, bool> isSupportedDiagnostic, CancellationToken cancellationToken)
: this(operation, options, reportDiagnostic, isSupportedDiagnostic, semanticModel: null, cancellationToken: cancellationToken)
public OperationAnalysisContext(IOperation operation, ISymbol owningSymbol, Compilation compilation, AnalyzerOptions options, Action<Diagnostic> reportDiagnostic, Func<Diagnostic, bool> isSupportedDiagnostic, CancellationToken cancellationToken)
: this(operation, owningSymbol, compilation, options, reportDiagnostic, isSupportedDiagnostic, semanticModel: null, cancellationToken: cancellationToken)
{
}
internal OperationAnalysisContext(IOperation operation, AnalyzerOptions options, Action<Diagnostic> reportDiagnostic, Func<Diagnostic, bool> isSupportedDiagnostic, SemanticModel semanticModel, CancellationToken cancellationToken)
internal OperationAnalysisContext(IOperation operation, ISymbol owningSymbol, Compilation compilation, AnalyzerOptions options, Action<Diagnostic> reportDiagnostic, Func<Diagnostic, bool> isSupportedDiagnostic, SemanticModel semanticModel, CancellationToken cancellationToken)
{
_operation = operation;
_owningSymbol = owningSymbol;
_semanticModelOpt = semanticModel;
_compilation = compilation;
_options = options;
_reportDiagnostic = reportDiagnostic;
_isSupportedDiagnostic = isSupportedDiagnostic;
......
......@@ -13,9 +13,11 @@ Microsoft.CodeAnalysis.Diagnostics.GeneratedCodeAnalysisFlags.None = 0 -> Micros
Microsoft.CodeAnalysis.Diagnostics.GeneratedCodeAnalysisFlags.ReportDiagnostics = 16 -> Microsoft.CodeAnalysis.Diagnostics.GeneratedCodeAnalysisFlags
Microsoft.CodeAnalysis.Diagnostics.OperationAnalysisContext
Microsoft.CodeAnalysis.Diagnostics.OperationAnalysisContext.CancellationToken.get -> System.Threading.CancellationToken
Microsoft.CodeAnalysis.Diagnostics.OperationAnalysisContext.Compilation.get -> Microsoft.CodeAnalysis.Compilation
Microsoft.CodeAnalysis.Diagnostics.OperationAnalysisContext.Operation.get -> Microsoft.CodeAnalysis.Semantics.IOperation
Microsoft.CodeAnalysis.Diagnostics.OperationAnalysisContext.OperationAnalysisContext(Microsoft.CodeAnalysis.Semantics.IOperation operation, Microsoft.CodeAnalysis.Diagnostics.AnalyzerOptions options, System.Action<Microsoft.CodeAnalysis.Diagnostic> reportDiagnostic, System.Func<Microsoft.CodeAnalysis.Diagnostic, bool> isSupportedDiagnostic, System.Threading.CancellationToken cancellationToken) -> void
Microsoft.CodeAnalysis.Diagnostics.OperationAnalysisContext.OperationAnalysisContext(Microsoft.CodeAnalysis.Semantics.IOperation operation, Microsoft.CodeAnalysis.ISymbol owningSymbol, Microsoft.CodeAnalysis.Compilation compilation, Microsoft.CodeAnalysis.Diagnostics.AnalyzerOptions options, System.Action<Microsoft.CodeAnalysis.Diagnostic> reportDiagnostic, System.Func<Microsoft.CodeAnalysis.Diagnostic, bool> isSupportedDiagnostic, System.Threading.CancellationToken cancellationToken) -> void
Microsoft.CodeAnalysis.Diagnostics.OperationAnalysisContext.Options.get -> Microsoft.CodeAnalysis.Diagnostics.AnalyzerOptions
Microsoft.CodeAnalysis.Diagnostics.OperationAnalysisContext.OwningSymbol.get -> Microsoft.CodeAnalysis.ISymbol
Microsoft.CodeAnalysis.Diagnostics.OperationAnalysisContext.ReportDiagnostic(Microsoft.CodeAnalysis.Diagnostic diagnostic) -> void
Microsoft.CodeAnalysis.Diagnostics.OperationBlockAnalysisContext
Microsoft.CodeAnalysis.Diagnostics.OperationBlockAnalysisContext.CancellationToken.get -> System.Threading.CancellationToken
......@@ -31,6 +33,9 @@ Microsoft.CodeAnalysis.Diagnostics.OperationBlockStartAnalysisContext.OperationB
Microsoft.CodeAnalysis.Diagnostics.OperationBlockStartAnalysisContext.Options.get -> Microsoft.CodeAnalysis.Diagnostics.AnalyzerOptions
Microsoft.CodeAnalysis.Diagnostics.OperationBlockStartAnalysisContext.OwningSymbol.get -> Microsoft.CodeAnalysis.ISymbol
Microsoft.CodeAnalysis.Diagnostics.OperationBlockStartAnalysisContext.RegisterOperationAction(System.Action<Microsoft.CodeAnalysis.Diagnostics.OperationAnalysisContext> action, params Microsoft.CodeAnalysis.Semantics.OperationKind[] operationKinds) -> void
Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext.Compilation.get -> Microsoft.CodeAnalysis.Compilation
Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext.OwningSymbol.get -> Microsoft.CodeAnalysis.ISymbol
Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext.SyntaxNodeAnalysisContext(Microsoft.CodeAnalysis.SyntaxNode node, Microsoft.CodeAnalysis.ISymbol owningSymbol, Microsoft.CodeAnalysis.SemanticModel semanticModel, Microsoft.CodeAnalysis.Diagnostics.AnalyzerOptions options, System.Action<Microsoft.CodeAnalysis.Diagnostic> reportDiagnostic, System.Func<Microsoft.CodeAnalysis.Diagnostic, bool> isSupportedDiagnostic, System.Threading.CancellationToken cancellationToken) -> void
Microsoft.CodeAnalysis.Diagnostics.Telemetry.AnalyzerTelemetryInfo.OperationActionsCount.get -> int
Microsoft.CodeAnalysis.Diagnostics.Telemetry.AnalyzerTelemetryInfo.OperationBlockActionsCount.get -> int
Microsoft.CodeAnalysis.Diagnostics.Telemetry.AnalyzerTelemetryInfo.OperationBlockEndActionsCount.get -> int
......
......@@ -927,6 +927,60 @@ End Class
VerifyGeneratedCodeAnalyzerDiagnostics(compilation, expected, GeneratedCodeAnalysisFlags.Analyze Or GeneratedCodeAnalysisFlags.ReportDiagnostics)
End Sub
Friend Class OwningSymbolTestAnalyzer
Inherits DiagnosticAnalyzer
Public Shared ReadOnly ExpressionDescriptor As New DiagnosticDescriptor("Expression", "Expression", "Expression found.", "Testing", DiagnosticSeverity.Warning, isEnabledByDefault:=True)
Public NotOverridable Overrides ReadOnly Property SupportedDiagnostics As ImmutableArray(Of DiagnosticDescriptor)
Get
Return ImmutableArray.Create(ExpressionDescriptor)
End Get
End Property
Public NotOverridable Overrides Sub Initialize(context As AnalysisContext)
context.RegisterSyntaxNodeAction(
Sub(nodeContext)
If nodeContext.OwningSymbol.Name.StartsWith("Funky") AndAlso nodeContext.Compilation.Language = "Visual Basic" Then
nodeContext.ReportDiagnostic(CodeAnalysis.Diagnostic.Create(ExpressionDescriptor, nodeContext.Node.GetLocation()))
End If
End Sub,
SyntaxKind.IdentifierName,
SyntaxKind.NumericLiteralExpression)
End Sub
End Class
<Fact>
Public Sub OwningSymbolVisualBasic()
Dim source = <compilation>
<file name="c.vb">
<![CDATA[
Class C
Public Sub UnFunkyMethod()
Dim x As Integer = 0
Dim y As Integer = x
End Sub
Public Sub FunkyMethod()
Dim x As Integer = 0
Dim y As Integer = x
End Sub
Public FunkyField As Integer = 12
Public UnFunkyField As Integer = 12
End Class
]]>
</file>
</compilation>
Dim comp = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime(source)
comp.VerifyDiagnostics()
comp.VerifyAnalyzerDiagnostics({New OwningSymbolTestAnalyzer}, Nothing, Nothing, False,
Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "0").WithLocation(8, 28),
Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "x").WithLocation(9, 28),
Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "12").WithLocation(12, 36))
End Sub
Private Shared Sub VerifyGeneratedCodeAnalyzerDiagnostics(compilation As Compilation, isGeneratedFileName As Func(Of String, Boolean), generatedCodeAnalysisFlagsOpt As GeneratedCodeAnalysisFlags?)
Dim expected = GetExpectedGeneratedCodeAnalyzerDiagnostics(compilation, isGeneratedFileName, generatedCodeAnalysisFlagsOpt)
VerifyGeneratedCodeAnalyzerDiagnostics(compilation, expected, generatedCodeAnalysisFlagsOpt)
......@@ -955,71 +1009,71 @@ End Class
Dim isGeneratedCode = True
AddExpectedLocalDiagnostics(builder, isGeneratedCode, squiggledText, line, column, generatedCodeAnalysisFlagsOpt, diagnosticArgument)
' Type "Nested{0}"
squiggledText = String.Format("Nested{0}", i)
diagnosticArgument = squiggledText
line = 4
column = 16
isGeneratedCode = True
AddExpectedLocalDiagnostics(builder, isGeneratedCode, squiggledText, line, column, generatedCodeAnalysisFlagsOpt, diagnosticArgument)
' Type "NonGeneratedCode{0}"
squiggledText = String.Format("NonGeneratedCode{0}", i)
diagnosticArgument = squiggledText
line = 8
column = 7
isGeneratedCode = isGeneratedFile
AddExpectedLocalDiagnostics(builder, isGeneratedCode, squiggledText, line, column, generatedCodeAnalysisFlagsOpt, diagnosticArgument)
' Type "NestedGeneratedCode{0}"
squiggledText = String.Format("NestedGeneratedCode{0}", i)
diagnosticArgument = squiggledText
line = 10
column = 16
isGeneratedCode = True
AddExpectedLocalDiagnostics(builder, isGeneratedCode, squiggledText, line, column, generatedCodeAnalysisFlagsOpt, diagnosticArgument)
' File diagnostic
squiggledText = "Class" ' last token in file.
diagnosticArgument = file
line = 12
column = 5
isGeneratedCode = isGeneratedFile
AddExpectedLocalDiagnostics(builder, isGeneratedCode, squiggledText, line, column, generatedCodeAnalysisFlagsOpt, diagnosticArgument)
' Type "Nested{0}"
squiggledText = String.Format("Nested{0}", i)
diagnosticArgument = squiggledText
line = 4
column = 16
isGeneratedCode = True
AddExpectedLocalDiagnostics(builder, isGeneratedCode, squiggledText, line, column, generatedCodeAnalysisFlagsOpt, diagnosticArgument)
' Type "NonGeneratedCode{0}"
squiggledText = String.Format("NonGeneratedCode{0}", i)
diagnosticArgument = squiggledText
line = 8
column = 7
isGeneratedCode = isGeneratedFile
AddExpectedLocalDiagnostics(builder, isGeneratedCode, squiggledText, line, column, generatedCodeAnalysisFlagsOpt, diagnosticArgument)
' Type "NestedGeneratedCode{0}"
squiggledText = String.Format("NestedGeneratedCode{0}", i)
diagnosticArgument = squiggledText
line = 10
column = 16
isGeneratedCode = True
AddExpectedLocalDiagnostics(builder, isGeneratedCode, squiggledText, line, column, generatedCodeAnalysisFlagsOpt, diagnosticArgument)
' File diagnostic
squiggledText = "Class" ' last token in file.
diagnosticArgument = file
line = 12
column = 5
isGeneratedCode = isGeneratedFile
AddExpectedLocalDiagnostics(builder, isGeneratedCode, squiggledText, line, column, generatedCodeAnalysisFlagsOpt, diagnosticArgument)
' Compilation end summary diagnostic (verify callbacks into analyzer)
' Analyzer always called for generated code, unless generated code analysis is explicitly disabled.
If generatedCodeAnalysisFlagsOpt Is Nothing OrElse (generatedCodeAnalysisFlagsOpt And GeneratedCodeAnalysisFlags.Analyze) <> 0 Then
sortedCallbackSymbolNames.Add(String.Format("GeneratedCode{0}", i))
sortedCallbackSymbolNames.Add(String.Format("Nested{0}", i))
sortedCallbackSymbolNames.Add(String.Format("NonGeneratedCode{0}", i))
sortedCallbackSymbolNames.Add(String.Format("NestedGeneratedCode{0}", i))
sortedCallbackTreePaths.Add(file)
ElseIf Not isGeneratedFile Then
' Analyzer always called for non-generated code.
sortedCallbackSymbolNames.Add(String.Format("NonGeneratedCode{0}", i))
sortedCallbackTreePaths.Add(file)
End If
Next
' Compilation end summary diagnostic (verify callbacks into analyzer)
' Analyzer always called for generated code, unless generated code analysis is explicitly disabled.
If generatedCodeAnalysisFlagsOpt Is Nothing OrElse (generatedCodeAnalysisFlagsOpt And GeneratedCodeAnalysisFlags.Analyze) <> 0 Then
sortedCallbackSymbolNames.Add(String.Format("GeneratedCode{0}", i))
sortedCallbackSymbolNames.Add(String.Format("Nested{0}", i))
sortedCallbackSymbolNames.Add(String.Format("NonGeneratedCode{0}", i))
sortedCallbackSymbolNames.Add(String.Format("NestedGeneratedCode{0}", i))
sortedCallbackTreePaths.Add(file)
ElseIf Not isGeneratedFile Then
' Analyzer always called for non-generated code.
sortedCallbackSymbolNames.Add(String.Format("NonGeneratedCode{0}", i))
sortedCallbackTreePaths.Add(file)
Dim arg1 = sortedCallbackSymbolNames.Join(",")
Dim arg2 = sortedCallbackTreePaths.Join(",")
AddExpectedNonLocalDiagnostic(builder, {arg1, arg2})
If compilation.Options.GeneralDiagnosticOption = ReportDiagnostic.Error Then
For i As Integer = 0 To builder.Count - 1
If DirectCast(builder(i).Code, String) <> GeneratedCodeAnalyzer.Error.Id Then
builder(i) = builder(i).WithWarningAsError(True)
End If
Next
End If
Next
' Compilation end summary diagnostic (verify callbacks into analyzer)
Dim arg1 = sortedCallbackSymbolNames.Join(",")
Dim arg2 = sortedCallbackTreePaths.Join(",")
AddExpectedNonLocalDiagnostic(builder, {arg1, arg2})
If compilation.Options.GeneralDiagnosticOption = ReportDiagnostic.Error Then
For i As Integer = 0 To builder.Count - 1
If DirectCast(builder(i).Code, String) <> GeneratedCodeAnalyzer.Error.Id Then
builder(i) = builder(i).WithWarningAsError(True)
End If
Next
End If
Return builder.ToArrayAndFree()
End Function
Return builder.ToArrayAndFree()
End Function
Private Shared Sub AddExpectedLocalDiagnostics(
Private Shared Sub AddExpectedLocalDiagnostics(
builder As ArrayBuilder(Of DiagnosticDescription),
isGeneratedCode As Boolean,
squiggledText As String,
......@@ -1028,27 +1082,27 @@ End Class
generatedCodeAnalysisFlagsOpt As GeneratedCodeAnalysisFlags?,
ParamArray arguments As String())
' Always report diagnostics in generated code, unless explicitly suppressed or we are not even analyzing generated code.
Dim reportInGeneratedCode = generatedCodeAnalysisFlagsOpt Is Nothing OrElse
' Always report diagnostics in generated code, unless explicitly suppressed or we are not even analyzing generated code.
Dim reportInGeneratedCode = generatedCodeAnalysisFlagsOpt Is Nothing OrElse
((generatedCodeAnalysisFlagsOpt And GeneratedCodeAnalysisFlags.ReportDiagnostics) <> 0 AndAlso
(generatedCodeAnalysisFlagsOpt And GeneratedCodeAnalysisFlags.Analyze) <> 0)
If Not isGeneratedCode OrElse reportInGeneratedCode Then
Dim diag = Diagnostic(GeneratedCodeAnalyzer.Warning.Id, squiggledText).WithArguments(arguments).WithLocation(line, column)
builder.Add(diag)
If Not isGeneratedCode OrElse reportInGeneratedCode Then
Dim diag = Diagnostic(GeneratedCodeAnalyzer.Warning.Id, squiggledText).WithArguments(arguments).WithLocation(line, column)
builder.Add(diag)
diag = Diagnostic(GeneratedCodeAnalyzer.Error.Id, squiggledText).WithArguments(arguments).WithLocation(line, column)
builder.Add(diag)
End If
End Sub
diag = Diagnostic(GeneratedCodeAnalyzer.Error.Id, squiggledText).WithArguments(arguments).WithLocation(line, column)
builder.Add(diag)
End If
End Sub
Private Shared Sub AddExpectedNonLocalDiagnostic(builder As ArrayBuilder(Of DiagnosticDescription), ParamArray arguments As String())
AddExpectedDiagnostic(builder, GeneratedCodeAnalyzer.Summary.Id, Nothing, 1, 1, arguments)
End Sub
Private Shared Sub AddExpectedNonLocalDiagnostic(builder As ArrayBuilder(Of DiagnosticDescription), ParamArray arguments As String())
AddExpectedDiagnostic(builder, GeneratedCodeAnalyzer.Summary.Id, Nothing, 1, 1, arguments)
End Sub
Private Shared Sub AddExpectedDiagnostic(builder As ArrayBuilder(Of DiagnosticDescription), diagnosticId As String, squiggledText As String, line As Integer, column As Integer, ParamArray arguments As String())
Dim diag = Diagnostic(diagnosticId, squiggledText).WithArguments(arguments).WithLocation(line, column)
builder.Add(diag)
End Sub
End Class
Private Shared Sub AddExpectedDiagnostic(builder As ArrayBuilder(Of DiagnosticDescription), diagnosticId As String, squiggledText As String, line As Integer, column As Integer, ParamArray arguments As String())
Dim diag = Diagnostic(diagnosticId, squiggledText).WithArguments(arguments).WithLocation(line, column)
builder.Add(diag)
End Sub
End Class
End Namespace
......@@ -1240,6 +1240,37 @@ End Class
Diagnostic(EqualsValueTestAnalyzer.EqualsValueDescriptor.Id, "= 20").WithLocation(10, 84))
End Sub
<Fact>
Public Sub OwningSymbolVisualBasic()
Dim source = <compilation>
<file name="c.vb">
<![CDATA[
Class C
Public Sub UnFunkyMethod()
Dim x As Integer = 0
Dim y As Integer = x
End Sub
Public Sub FunkyMethod()
Dim x As Integer = 0
Dim y As Integer = x
End Sub
Public FunkyField As Integer = 12
Public UnFunkyField As Integer = 12
End Class
]]>
</file>
</compilation>
Dim comp = CompilationUtils.CreateCompilationWithMscorlibAndVBRuntime(source)
comp.VerifyDiagnostics()
comp.VerifyAnalyzerDiagnostics({New OwningSymbolTestAnalyzer}, Nothing, Nothing, False,
Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "0").WithLocation(8, 28),
Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "x").WithLocation(9, 28),
Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "12").WithLocation(12, 36))
End Sub
<Fact>
Public Sub NoneOperationVisualBasic()
' BoundCaseStatement is OperationKind.None
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册