Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make RegisterSymbolAction work on Parameters #13931

Merged
merged 2 commits into from
Oct 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1655,5 +1655,233 @@ public partial class C33 { }
Diagnostic("UniqueTextFileDiagnostic").WithArguments("Source3_File5.designer.cs").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
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,8 @@ public struct SymbolAnalysisContext
/// </summary>
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)
{
_symbol = symbol;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,53 @@ public void RegisterSymbolAction(DiagnosticAnalyzer analyzer, Action<SymbolAnaly
SymbolAnalyzerAction analyzerAction = new SymbolAnalyzerAction(action, symbolKinds, analyzer);
this.GetOrCreateAnalyzerActions(analyzer).AddSymbolAction(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
Expand Down
Loading