diff --git a/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.cs b/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.cs index 8f35075daffa4231ac73a160ac2c23507d8fdb9e..a75f0a2a63542b30662f94e19fde888ef49fef8e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.cs @@ -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 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 isGeneratedFileName, GeneratedCodeAnalysisFlags? generatedCodeAnalysisFlagsOpt) { var expected = GetExpectedGeneratedCodeAnalyzerDiagnostics(compilation, isGeneratedFileName, generatedCodeAnalysisFlagsOpt); diff --git a/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs b/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs index b34765308df6cfb536ecbcd812ffb39b0c8b587d..bdf46f0a8f4916d89aec896fbd4045d45ae73440 100644 --- a/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Diagnostics/OperationAnalyzerTests.cs @@ -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() { diff --git a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/OperationTestAnalyzer.cs b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/OperationTestAnalyzer.cs index 47eff7a4f835d9aa2ead09839043a3bac3b3fec9..4b601bbfd2a8246c4a0fff1f6c177c3b845b23a5 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Diagnostics/OperationTestAnalyzer.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Diagnostics/OperationTestAnalyzer.cs @@ -71,6 +71,37 @@ public sealed override void Initialize(AnalysisContext context) } } + /// Analyzer used to test for operations within symbols of certain names. + public class OwningSymbolTestAnalyzer : DiagnosticAnalyzer + { + public static readonly DiagnosticDescriptor ExpressionDescriptor = new DiagnosticDescriptor( + "Expression", + "Expression", + "Expression found.", + "Testing", + DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + public sealed override ImmutableArray 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); + } + } + /// Analyzer used to test for loop IOperations. public class BigForTestAnalyzer : DiagnosticAnalyzer { diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs index d33158e889cd6916a0ca829ddcfaea558df489c1..4aeea689fc5ef123ad3a0e60dd0f2094a09de176 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerExecutor.cs @@ -480,6 +480,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray( SyntaxNodeAnalyzerAction syntaxNodeAction, SyntaxNode node, + ISymbol owningSymbol, SemanticModel semanticModel, Action addDiagnostic, SyntaxNodeAnalyzerStateData analyzerStateOpt) @@ -489,7 +490,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray IsSupportedDiagnostic(syntaxNodeAction.Analyzer, d), _cancellationToken); ExecuteAndCatchIfThrows(syntaxNodeAction.Analyzer, () => syntaxNodeAction.Action(syntaxNodeContext), @@ -502,6 +503,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray addDiagnostic, OperationAnalyzerStateData analyzerStateOpt) @@ -510,7 +512,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray 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)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)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 nodesToAnalyze, IDictionary>> nodeActionsByKind, DiagnosticAnalyzer analyzer, + ISymbol owningSymbol, SemanticModel model, Func getKind, TextSpan filterSpan, @@ -846,12 +849,13 @@ private void ExecuteCompilationActionsCore(ImmutableArray( IEnumerable nodesToAnalyze, IDictionary>> nodeActionsByKind, + ISymbol owningSymbol, SemanticModel model, Func getKind, Action addDiagnostic, @@ -864,7 +868,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray( SyntaxNode node, IDictionary>> nodeActionsByKind, + ISymbol owningSymbol, SemanticModel model, Func getKind, Action addDiagnostic, @@ -892,7 +897,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray operationsToAnalyze, IDictionary> 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 operationsToAnalyze, IDictionary> operationActionsByKind, + ISymbol owningSymbol, SemanticModel model, Action addDiagnostic, OperationAnalyzerStateData analyzerStateOpt) @@ -983,7 +990,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray> operationActionsByKind, + ISymbol owningSymbol, SemanticModel model, Action addDiagnostic, OperationAnalyzerStateData analyzerStateOpt) @@ -1009,7 +1017,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray _reportDiagnostic; @@ -938,26 +939,37 @@ public struct SyntaxNodeAnalysisContext /// /// that is the subject of the analysis. /// - public SyntaxNode Node { get { return _node; } } + public SyntaxNode Node => _node; + + /// + /// for the declaration containing the syntax node. + /// + public ISymbol OwningSymbol => _owningSymbol; /// /// that can provide semantic information about the . /// - public SemanticModel SemanticModel { get { return _semanticModel; } } + public SemanticModel SemanticModel => _semanticModel; + + /// + /// containing the . + /// + public Compilation Compilation => _semanticModel?.Compilation; /// /// Options specified for the analysis. /// - public AnalyzerOptions Options { get { return _options; } } + public AnalyzerOptions Options => _options; /// /// Token to check for requested cancellation of the analysis. /// - public CancellationToken CancellationToken { get { return _cancellationToken; } } + public CancellationToken CancellationToken => _cancellationToken; - public SyntaxNodeAnalysisContext(SyntaxNode node, SemanticModel semanticModel, AnalyzerOptions options, Action reportDiagnostic, Func isSupportedDiagnostic, CancellationToken cancellationToken) + public SyntaxNodeAnalysisContext(SyntaxNode node, ISymbol owningSymbol, SemanticModel semanticModel, AnalyzerOptions options, Action reportDiagnostic, Func 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 reportDiagnostic, Func isSupportedDiagnostic, CancellationToken cancellationToken) + : this(node, null, semanticModel, options, reportDiagnostic, isSupportedDiagnostic, cancellationToken) + { + } + /// /// Report a about a . /// @@ -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 _reportDiagnostic; private readonly Func _isSupportedDiagnostic; @@ -997,6 +1016,16 @@ public struct OperationAnalysisContext /// public IOperation Operation => _operation; + /// + /// for the declaration containing the operation. + /// + public ISymbol OwningSymbol => _owningSymbol; + + /// + /// containing the . + /// + public Compilation Compilation => _compilation; + /// /// Options specified for the analysis. /// @@ -1007,17 +1036,17 @@ public struct OperationAnalysisContext /// public CancellationToken CancellationToken => _cancellationToken; - internal Compilation Compilation => _semanticModelOpt?.Compilation; - - public OperationAnalysisContext(IOperation operation, AnalyzerOptions options, Action reportDiagnostic, Func isSupportedDiagnostic, CancellationToken cancellationToken) - : this(operation, options, reportDiagnostic, isSupportedDiagnostic, semanticModel: null, cancellationToken: cancellationToken) + public OperationAnalysisContext(IOperation operation, ISymbol owningSymbol, Compilation compilation, AnalyzerOptions options, Action reportDiagnostic, Func isSupportedDiagnostic, CancellationToken cancellationToken) + : this(operation, owningSymbol, compilation, options, reportDiagnostic, isSupportedDiagnostic, semanticModel: null, cancellationToken: cancellationToken) { } - internal OperationAnalysisContext(IOperation operation, AnalyzerOptions options, Action reportDiagnostic, Func isSupportedDiagnostic, SemanticModel semanticModel, CancellationToken cancellationToken) + internal OperationAnalysisContext(IOperation operation, ISymbol owningSymbol, Compilation compilation, AnalyzerOptions options, Action reportDiagnostic, Func isSupportedDiagnostic, SemanticModel semanticModel, CancellationToken cancellationToken) { _operation = operation; + _owningSymbol = owningSymbol; _semanticModelOpt = semanticModel; + _compilation = compilation; _options = options; _reportDiagnostic = reportDiagnostic; _isSupportedDiagnostic = isSupportedDiagnostic; diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index ca1016ca733b3f4a5432e8afab4f0ff7f77d675c..18db022758f0a7c7847d52f1e7bd28d80366b213 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -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 reportDiagnostic, System.Func 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 reportDiagnostic, System.Func 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 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 reportDiagnostic, System.Func 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 diff --git a/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.vb index 1fc02aa46df6207fe954a88b6298116dc2798fd1..bba671bad18591ababc25ae7e68b5f758141a2bc 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.vb @@ -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 + + + Public Sub OwningSymbolVisualBasic() + Dim source = + + + + + + 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 diff --git a/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/OperationAnalyzerTests.vb b/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/OperationAnalyzerTests.vb index 60ee80a672d0777648d1e5b5b2130b997912dbe2..380bf3a1a424893a4f53b51c3fa841fdff9a4064 100644 --- a/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/OperationAnalyzerTests.vb +++ b/src/Compilers/VisualBasic/Test/Semantic/Diagnostics/OperationAnalyzerTests.vb @@ -1240,6 +1240,37 @@ End Class Diagnostic(EqualsValueTestAnalyzer.EqualsValueDescriptor.Id, "= 20").WithLocation(10, 84)) End Sub + + Public Sub OwningSymbolVisualBasic() + Dim source = + + + + + + 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 + Public Sub NoneOperationVisualBasic() ' BoundCaseStatement is OperationKind.None