提交 cf49294c 编写于 作者: D David Poeschl 提交者: GitHub

Merge pull request #13931 from dpoeschl/RegisterSymbolActionForLocals

Make RegisterSymbolAction work on Parameters
...@@ -1655,5 +1655,233 @@ public partial class C33 { } ...@@ -1655,5 +1655,233 @@ public partial class C33 { }
Diagnostic("UniqueTextFileDiagnostic").WithArguments("Source3_File5.designer.cs").WithLocation(1, 1), Diagnostic("UniqueTextFileDiagnostic").WithArguments("Source3_File5.designer.cs").WithLocation(1, 1),
Diagnostic("NumberOfUniqueTextFileDescriptor").WithArguments("3").WithLocation(1, 1)); Diagnostic("NumberOfUniqueTextFileDescriptor").WithArguments("3").WithLocation(1, 1));
} }
[Fact, WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")]
public void TestParametersAnalyzer_InConstructor()
{
string source = @"
public class C
{
public C(int a, int b)
{
}
}
";
var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs");
var compilation = CreateCompilationWithMscorlib45(new[] { tree });
compilation.VerifyDiagnostics();
var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() };
compilation.VerifyAnalyzerDiagnostics(analyzers, null, null, true,
Diagnostic("Parameter_ID", "a").WithLocation(4, 18),
Diagnostic("Parameter_ID", "b").WithLocation(4, 25));
}
[Fact, WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")]
public void TestParametersAnalyzer_InRegularMethod()
{
string source = @"
public class C
{
void M1(string a, string b)
{
}
}
";
var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs");
var compilation = CreateCompilationWithMscorlib45(new[] { tree });
compilation.VerifyDiagnostics();
var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() };
compilation.VerifyAnalyzerDiagnostics(analyzers, null, null, true,
Diagnostic("Parameter_ID", "a").WithLocation(4, 20),
Diagnostic("Parameter_ID", "b").WithLocation(4, 30));
}
[Fact, WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")]
public void TestParametersAnalyzer_InIndexers()
{
string source = @"
public class C
{
public int this[int index]
{
get { return 0; }
set { }
}
}
";
var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs");
var compilation = CreateCompilationWithMscorlib45(new[] { tree });
compilation.VerifyDiagnostics();
var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() };
compilation.VerifyAnalyzerDiagnostics(analyzers, null, null, true,
Diagnostic("Parameter_ID", "index").WithLocation(4, 25));
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/14061"), WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")]
public void TestParametersAnalyzer_Lambdas()
{
string source = @"
public class C
{
void M2()
{
System.Func<int, int, int> x = (int a, int b) => b;
}
}
";
var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs");
var compilation = CreateCompilationWithMscorlib45(new[] { tree });
compilation.VerifyDiagnostics();
var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() };
compilation.VerifyAnalyzerDiagnostics(analyzers, null, null, true,
Diagnostic("Local_ID", "x").WithLocation(6, 36),
Diagnostic("Parameter_ID", "a").WithLocation(6, 45),
Diagnostic("Parameter_ID", "b").WithLocation(6, 52));
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/14061"), WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")]
public void TestParametersAnalyzer_InAnonymousMethods()
{
string source = @"
public class C
{
void M3()
{
M4(delegate (int x, int y) { });
}
void M4(System.Action<int, int> a) { }
}
";
var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs");
var compilation = CreateCompilationWithMscorlib45(new[] { tree });
compilation.VerifyDiagnostics();
var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() };
compilation.VerifyAnalyzerDiagnostics(analyzers, null, null, true,
Diagnostic("Parameter_ID", "a").WithLocation(9, 37),
Diagnostic("Parameter_ID", "x").WithLocation(6, 26),
Diagnostic("Parameter_ID", "y").WithLocation(6, 33));
}
[Fact, WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")]
public void TestParametersAnalyzer_InDelegateTypes()
{
string source = @"
public class C
{
delegate void D(int x, string y);
}
";
var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs");
var compilation = CreateCompilationWithMscorlib45(new[] { tree });
compilation.VerifyDiagnostics();
var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() };
compilation.VerifyAnalyzerDiagnostics(analyzers, null, null, true,
Diagnostic("Parameter_ID", "x").WithLocation(4, 25),
Diagnostic("Parameter_ID", "y").WithLocation(4, 35));
}
[Fact, WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")]
public void TestParametersAnalyzer_InOperators()
{
string source = @"
public class C
{
public static implicit operator int (C c) { return 0; }
}
";
var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs");
var compilation = CreateCompilationWithMscorlib45(new[] { tree });
compilation.VerifyDiagnostics();
var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() };
compilation.VerifyAnalyzerDiagnostics(analyzers, null, null, true,
Diagnostic("Parameter_ID", "c").WithLocation(4, 44));
}
[Fact, WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")]
public void TestParametersAnalyzer_InExplicitInterfaceImplementations()
{
string source = @"
interface I
{
void M(int a, int b);
}
public class C : I
{
void I.M(int c, int d) { }
}
";
var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs");
var compilation = CreateCompilationWithMscorlib45(new[] { tree });
compilation.VerifyDiagnostics();
var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() };
compilation.VerifyAnalyzerDiagnostics(analyzers, null, null, true,
Diagnostic("Parameter_ID", "c").WithLocation(9, 18),
Diagnostic("Parameter_ID", "d").WithLocation(9, 25),
Diagnostic("Parameter_ID", "a").WithLocation(4, 16),
Diagnostic("Parameter_ID", "b").WithLocation(4, 23));
}
[Fact, WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")]
public void TestParametersAnalyzer_InExtensionMethods()
{
string source = @"
public static class C
{
static void M(this int x, int y) { }
}
";
var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs");
var compilation = CreateCompilationWithMscorlib45(new[] { tree });
compilation.VerifyDiagnostics();
var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() };
compilation.VerifyAnalyzerDiagnostics(analyzers, null, null, true,
Diagnostic("Parameter_ID", "x").WithLocation(4, 28),
Diagnostic("Parameter_ID", "y").WithLocation(4, 35));
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/14061"), WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")]
public void TestParametersAnalyzer_InLocalFunctions()
{
string source = @"
public class C
{
void M1()
{
M2(1, 2);
void M2(int a, int b)
{
}
}
}
";
var tree = CSharpSyntaxTree.ParseText(source, path: "Source.cs");
var compilation = CreateCompilationWithMscorlib45(new[] { tree });
compilation.VerifyDiagnostics();
var analyzers = new DiagnosticAnalyzer[] { new AnalyzerForParameters() };
compilation.VerifyAnalyzerDiagnostics(analyzers, null, null, true,
Diagnostic("Parameter_ID", "a").WithLocation(4, 18), // ctor
Diagnostic("Parameter_ID", "b").WithLocation(4, 25),
Diagnostic("Local_ID", "c").WithLocation(6, 13),
Diagnostic("Local_ID", "d").WithLocation(6, 20),
Diagnostic("Parameter_ID", "a").WithLocation(10, 20), // M1
Diagnostic("Parameter_ID", "b").WithLocation(10, 30),
Diagnostic("Local_ID", "c").WithLocation(12, 11),
Diagnostic("Local_ID", "x").WithLocation(18, 36), // M2
Diagnostic("Parameter_ID", "a").WithLocation(26, 37), // M4
Diagnostic("Parameter_ID", "index").WithLocation(28, 25)); // indexer
}
} }
} }
...@@ -701,6 +701,8 @@ public struct SymbolAnalysisContext ...@@ -701,6 +701,8 @@ public struct SymbolAnalysisContext
/// </summary> /// </summary>
public CancellationToken CancellationToken { get { return _cancellationToken; } } public CancellationToken CancellationToken { get { return _cancellationToken; } }
internal Func<Diagnostic, bool> IsSupportedDiagnostic => _isSupportedDiagnostic;
public SymbolAnalysisContext(ISymbol symbol, Compilation compilation, AnalyzerOptions options, Action<Diagnostic> reportDiagnostic, Func<Diagnostic, bool> isSupportedDiagnostic, CancellationToken cancellationToken) public SymbolAnalysisContext(ISymbol symbol, Compilation compilation, AnalyzerOptions options, Action<Diagnostic> reportDiagnostic, Func<Diagnostic, bool> isSupportedDiagnostic, CancellationToken cancellationToken)
{ {
_symbol = symbol; _symbol = symbol;
......
...@@ -608,6 +608,53 @@ public void RegisterSymbolAction(DiagnosticAnalyzer analyzer, Action<SymbolAnaly ...@@ -608,6 +608,53 @@ public void RegisterSymbolAction(DiagnosticAnalyzer analyzer, Action<SymbolAnaly
SymbolAnalyzerAction analyzerAction = new SymbolAnalyzerAction(action, symbolKinds, analyzer); SymbolAnalyzerAction analyzerAction = new SymbolAnalyzerAction(action, symbolKinds, analyzer);
this.GetOrCreateAnalyzerActions(analyzer).AddSymbolAction(analyzerAction); this.GetOrCreateAnalyzerActions(analyzer).AddSymbolAction(analyzerAction);
_symbolActions = _symbolActions.Add(analyzerAction); _symbolActions = _symbolActions.Add(analyzerAction);
// The SymbolAnalyzerAction does not handle SymbolKind.Parameter because the compiler
// does not make CompilationEvents for them. As a workaround, handle them specially by
// registering further SymbolActions (for Methods) and utilize the results to construct
// the necessary SymbolAnalysisContexts.
if (symbolKinds.Contains(SymbolKind.Parameter))
{
RegisterSymbolAction(
analyzer,
context =>
{
ImmutableArray<IParameterSymbol> parameters;
switch (context.Symbol.Kind)
{
case SymbolKind.Method:
parameters = ((IMethodSymbol)context.Symbol).Parameters;
break;
case SymbolKind.Property:
parameters = ((IPropertySymbol)context.Symbol).Parameters;
break;
case SymbolKind.NamedType:
var namedType = (INamedTypeSymbol)context.Symbol;
var delegateInvokeMethod = namedType.DelegateInvokeMethod;
parameters = delegateInvokeMethod?.Parameters ?? ImmutableArray.Create<IParameterSymbol>();
break;
default:
throw new ArgumentException(nameof(context));
}
foreach (var parameter in parameters)
{
if (!parameter.IsImplicitlyDeclared)
{
action(new SymbolAnalysisContext(
parameter,
context.Compilation,
context.Options,
context.ReportDiagnostic,
context.IsSupportedDiagnostic,
context.CancellationToken));
}
}
},
ImmutableArray.Create(SymbolKind.Method, SymbolKind.Property, SymbolKind.NamedType));
}
} }
public void RegisterCodeBlockStartAction<TLanguageKindEnum>(DiagnosticAnalyzer analyzer, Action<CodeBlockStartAnalysisContext<TLanguageKindEnum>> action) where TLanguageKindEnum : struct public void RegisterCodeBlockStartAction<TLanguageKindEnum>(DiagnosticAnalyzer analyzer, Action<CodeBlockStartAnalysisContext<TLanguageKindEnum>> action) where TLanguageKindEnum : struct
......
...@@ -981,6 +981,162 @@ End Class ...@@ -981,6 +981,162 @@ End Class
Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "12").WithLocation(12, 36)) Diagnostic(OwningSymbolTestAnalyzer.ExpressionDescriptor.Id, "12").WithLocation(12, 36))
End Sub End Sub
<Fact, WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")>
Public Sub TestParametersAnalyzer_InRegularMethods()
Dim source = <compilation>
<file name="c.vb">
<![CDATA[
Class C
Public Sub M(a As Integer, b As String)
End Sub
End Class
]]>
</file>
</compilation>
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(source)
comp.VerifyDiagnostics()
comp.VerifyAnalyzerDiagnostics({New AnalyzerForParameters}, Nothing, Nothing, False,
Diagnostic("Parameter_ID", "a").WithLocation(2, 18),
Diagnostic("Parameter_ID", "b").WithLocation(2, 32))
End Sub
<Fact, WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")>
Public Sub TestParametersAnalyzer_InConstructors()
Dim source = <compilation>
<file name="c.vb">
<![CDATA[
Class C
Public Sub New(a As Integer, b As String)
End Sub
End Class
]]>
</file>
</compilation>
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(source)
comp.VerifyDiagnostics()
comp.VerifyAnalyzerDiagnostics({New AnalyzerForParameters}, Nothing, Nothing, False,
Diagnostic("Parameter_ID", "a").WithLocation(2, 20),
Diagnostic("Parameter_ID", "b").WithLocation(2, 34))
End Sub
<Fact, WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")>
Public Sub TestParametersAnalyzer_InIndexers()
Dim source = <compilation>
<file name="c.vb">
<![CDATA[
Class C
Default Public Property Item(a As Integer, b As Integer) As Integer
Get
Return 0
End Get
Set(ByVal Value As Integer)
End Set
End Property
End Class
]]>
</file>
</compilation>
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(source)
comp.VerifyDiagnostics()
comp.VerifyAnalyzerDiagnostics({New AnalyzerForParameters}, Nothing, Nothing, False,
Diagnostic("Parameter_ID", "a").WithLocation(2, 34),
Diagnostic("Parameter_ID", "b").WithLocation(2, 48),
Diagnostic("Parameter_ID", "Value").WithLocation(6, 19))
End Sub
<Fact(Skip:="https://github.com/dotnet/roslyn/issues/14062"), WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")>
Public Sub TestParametersAnalyzer_InDelegateTypes()
Dim source = <compilation>
<file name="c.vb">
<![CDATA[
Class C
Delegate Sub DelegateType(a As Integer, b As String)
End Class
]]>
</file>
</compilation>
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(source)
comp.VerifyDiagnostics()
comp.VerifyAnalyzerDiagnostics({New AnalyzerForParameters}, Nothing, Nothing, False,
Diagnostic("Parameter_ID", "a").WithLocation(2, 34),
Diagnostic("Parameter_ID", "b").WithLocation(2, 48))
End Sub
<Fact, WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")>
Public Sub TestParametersAnalyzer_InOperators()
Dim source = <compilation>
<file name="c.vb">
<![CDATA[
Class C
Public Shared Operator +(ByVal h1 As C, ByVal h2 As C)
Return New C()
End Operator
End Class
]]>
</file>
</compilation>
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(source)
comp.VerifyDiagnostics()
comp.VerifyAnalyzerDiagnostics({New AnalyzerForParameters}, Nothing, Nothing, False,
Diagnostic("Parameter_ID", "h1").WithLocation(2, 36),
Diagnostic("Parameter_ID", "h2").WithLocation(2, 51))
End Sub
<Fact, WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")>
Public Sub TestParametersAnalyzer_InInterfaceImplementations()
Dim source = <compilation>
<file name="c.vb">
<![CDATA[
Interface I
Sub M(a As Integer, b As String)
End Interface
Class C
Implements I
Public Sub M(a As Integer, b As String) Implements I.M
End Sub
End Class
]]>
</file>
</compilation>
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(source)
comp.VerifyDiagnostics()
comp.VerifyAnalyzerDiagnostics({New AnalyzerForParameters}, Nothing, Nothing, False,
Diagnostic("Parameter_ID", "a").WithLocation(2, 11),
Diagnostic("Parameter_ID", "b").WithLocation(2, 25),
Diagnostic("Parameter_ID", "a").WithLocation(7, 18),
Diagnostic("Parameter_ID", "b").WithLocation(7, 32))
End Sub
<Fact, WorkItem(8753, "https://github.com/dotnet/roslyn/issues/8753")>
Public Sub TestParametersAnalyzer_InParameterizedProperties()
Dim source = <compilation>
<file name="c.vb">
<![CDATA[
Class C
Public ReadOnly Property Test(a As Integer, b As String) As Integer
Get
Return 1
End Get
End Property
End Class
]]>
</file>
</compilation>
Dim comp = CreateCompilationWithMscorlibAndVBRuntime(source)
comp.VerifyDiagnostics()
comp.VerifyAnalyzerDiagnostics({New AnalyzerForParameters}, Nothing, Nothing, False,
Diagnostic("Parameter_ID", "a").WithLocation(2, 35),
Diagnostic("Parameter_ID", "b").WithLocation(2, 49))
End Sub
Private Shared Sub VerifyGeneratedCodeAnalyzerDiagnostics(compilation As Compilation, isGeneratedFileName As Func(Of String, Boolean), generatedCodeAnalysisFlagsOpt As GeneratedCodeAnalysisFlags?) Private Shared Sub VerifyGeneratedCodeAnalyzerDiagnostics(compilation As Compilation, isGeneratedFileName As Func(Of String, Boolean), generatedCodeAnalysisFlagsOpt As GeneratedCodeAnalysisFlags?)
Dim expected = GetExpectedGeneratedCodeAnalyzerDiagnostics(compilation, isGeneratedFileName, generatedCodeAnalysisFlagsOpt) Dim expected = GetExpectedGeneratedCodeAnalyzerDiagnostics(compilation, isGeneratedFileName, generatedCodeAnalysisFlagsOpt)
VerifyGeneratedCodeAnalyzerDiagnostics(compilation, expected, generatedCodeAnalysisFlagsOpt) VerifyGeneratedCodeAnalyzerDiagnostics(compilation, expected, generatedCodeAnalysisFlagsOpt)
......
...@@ -1067,5 +1067,29 @@ private void OnCompilationStart(CompilationStartAnalysisContext context) ...@@ -1067,5 +1067,29 @@ private void OnCompilationStart(CompilationStartAnalysisContext context)
}); });
} }
} }
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public class AnalyzerForParameters : DiagnosticAnalyzer
{
public static readonly DiagnosticDescriptor ParameterDescriptor = new DiagnosticDescriptor(
"Parameter_ID",
"Parameter_Title",
"Parameter_Message",
"Parameter_Category",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(ParameterDescriptor);
public override void Initialize(AnalysisContext context)
{
context.RegisterSymbolAction(SymbolAction, SymbolKind.Parameter);
}
private void SymbolAction(SymbolAnalysisContext context)
{
context.ReportDiagnostic(Diagnostic.Create(ParameterDescriptor, context.Symbol.Locations[0]));
}
}
} }
} }
\ No newline at end of file
...@@ -75,7 +75,11 @@ public void VerifyAllAnalyzerMembersWereCalled() ...@@ -75,7 +75,11 @@ public void VerifyAllAnalyzerMembersWereCalled()
public void VerifyAnalyzeSymbolCalledForAllSymbolKinds() public void VerifyAnalyzeSymbolCalledForAllSymbolKinds()
{ {
var expectedSymbolKinds = new[] { SymbolKind.Event, SymbolKind.Field, SymbolKind.Method, SymbolKind.NamedType, SymbolKind.Namespace, SymbolKind.Property }; var expectedSymbolKinds = new[]
{
SymbolKind.Event, SymbolKind.Field, SymbolKind.Method, SymbolKind.NamedType, SymbolKind.Namespace, SymbolKind.Parameter, SymbolKind.Property
};
var actualSymbolKinds = _callLog.Where(a => FilterByAbstractName(a, "Symbol")).Where(e => e.SymbolKind.HasValue).Select(e => e.SymbolKind.Value).Distinct(); var actualSymbolKinds = _callLog.Where(a => FilterByAbstractName(a, "Symbol")).Where(e => e.SymbolKind.HasValue).Select(e => e.SymbolKind.Value).Distinct();
AssertSequenceEqual(expectedSymbolKinds, actualSymbolKinds); AssertSequenceEqual(expectedSymbolKinds, actualSymbolKinds);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册