Skip to content

Commit e7af83e

Browse files
committed
Extensions: analyzer actions
1 parent 9233fa3 commit e7af83e

File tree

2 files changed

+166
-1
lines changed

2 files changed

+166
-1
lines changed

src/Compilers/CSharp/CSharpAnalyzerDriver/CSharpDeclarationComputer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ private static void ComputeDeclarations(
102102
case SyntaxKind.StructDeclaration:
103103
case SyntaxKind.RecordDeclaration:
104104
case SyntaxKind.RecordStructDeclaration:
105-
// Tracked by https://github.com/dotnet/roslyn/issues/76130 : likely needs work for analyzers
106105
{
107106
if (associatedSymbol is IMethodSymbol ctor)
108107
{
@@ -123,6 +122,7 @@ private static void ComputeDeclarations(
123122
goto case SyntaxKind.InterfaceDeclaration;
124123
}
125124
case SyntaxKind.InterfaceDeclaration:
125+
case SyntaxKind.ExtensionDeclaration:
126126
{
127127
var t = (TypeDeclarationSyntax)node;
128128
foreach (var decl in t.Members)

src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55

66
using System;
77
using System.Collections;
8+
using System.Collections.Concurrent;
89
using System.Collections.Generic;
10+
using System.Collections.Immutable;
911
using System.Linq;
1012
using Microsoft.CodeAnalysis.CSharp.Symbols;
1113
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
1214
using Microsoft.CodeAnalysis.CSharp.Syntax;
1315
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
16+
using Microsoft.CodeAnalysis.Diagnostics;
1417
using Microsoft.CodeAnalysis.Emit;
1518
using Microsoft.CodeAnalysis.Test.Utilities;
1619
using Microsoft.CodeAnalysis.VisualBasic;
@@ -36601,4 +36604,166 @@ static unsafe class E
3660136604
Assert.False(verifier.HasLocalsInit("E.M"));
3660236605
Assert.True(verifier.HasLocalsInit("E.M2"));
3660336606
}
36607+
36608+
[Fact]
36609+
public void AnalyzerActions_01()
36610+
{
36611+
var src = """
36612+
static class E
36613+
{
36614+
extension<T>([Attr] T t)
36615+
{
36616+
[Attr2]
36617+
public void M() { }
36618+
36619+
[Attr3]
36620+
public int P => 0;
36621+
}
36622+
}
36623+
""";
36624+
36625+
var analyzer = new AnalyzerActions_01_Analyzer();
36626+
var comp = CreateCompilation(src);
36627+
comp.GetAnalyzerDiagnostics([analyzer], null).Verify();
36628+
36629+
AssertEx.SetEqual([
36630+
"Attr2 -> void E.<>E__0<T>.M()",
36631+
"M -> void E.<>E__0<T>.M()",
36632+
"Attr3 -> System.Int32 E.<>E__0<T>.P { get; }",
36633+
"P -> System.Int32 E.<>E__0<T>.P { get; }",
36634+
"T -> E.<>E__0<T>",
36635+
"Attr -> E.<>E__0<T>",
36636+
"extension -> E.<>E__0<T>"],
36637+
analyzer._results.ToArray());
36638+
}
36639+
36640+
private class AnalyzerActions_01_Analyzer : DiagnosticAnalyzer
36641+
{
36642+
public ConcurrentQueue<string> _results = new ConcurrentQueue<string>();
36643+
36644+
private static readonly DiagnosticDescriptor Descriptor =
36645+
new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test");
36646+
36647+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Descriptor];
36648+
36649+
public override void Initialize(AnalysisContext context)
36650+
{
36651+
context.RegisterSyntaxNodeAction(handle, SyntaxKind.ExtensionDeclaration);
36652+
context.RegisterSyntaxNodeAction(handle, SyntaxKind.IdentifierName);
36653+
context.RegisterSyntaxNodeAction(handle, SyntaxKind.MethodDeclaration);
36654+
context.RegisterSyntaxNodeAction(handle, SyntaxKind.PropertyDeclaration);
36655+
36656+
void handle(SyntaxNodeAnalysisContext context)
36657+
{
36658+
_results.Enqueue(print(context));
36659+
Assert.Same(context.Node.SyntaxTree, context.ContainingSymbol!.DeclaringSyntaxReferences.Single().SyntaxTree);
36660+
}
36661+
36662+
static string print(SyntaxNodeAnalysisContext context)
36663+
{
36664+
var syntaxString = context.Node switch
36665+
{
36666+
ExtensionDeclarationSyntax => "extension",
36667+
MethodDeclarationSyntax method => method.Identifier.ValueText,
36668+
PropertyDeclarationSyntax property => property.Identifier.ValueText,
36669+
_ => context.Node.ToString()
36670+
};
36671+
36672+
return $"{syntaxString} -> {context.ContainingSymbol.ToTestDisplayString()}";
36673+
}
36674+
}
36675+
}
36676+
36677+
[Fact]
36678+
public void AnalyzerActions_02()
36679+
{
36680+
var src = """
36681+
static class E
36682+
{
36683+
extension<T>(T t)
36684+
{
36685+
public void M() { }
36686+
public int P => 0;
36687+
}
36688+
}
36689+
""";
36690+
36691+
var analyzer = new AnalyzerActions_02_Analyzer();
36692+
var comp = CreateCompilation(src);
36693+
comp.GetAnalyzerDiagnostics([analyzer], null).Verify();
36694+
36695+
AssertEx.SetEqual([
36696+
"System.Int32 E.<>E__0<T>.P.get",
36697+
"void E.<>E__0<T>.M()",
36698+
"E.<>E__0<T>",
36699+
"System.Int32 E.<>E__0<T>.P { get; }",
36700+
"E"],
36701+
analyzer._results.ToArray());
36702+
}
36703+
36704+
private class AnalyzerActions_02_Analyzer : DiagnosticAnalyzer
36705+
{
36706+
public ConcurrentQueue<string> _results = new ConcurrentQueue<string>();
36707+
36708+
private static readonly DiagnosticDescriptor Descriptor =
36709+
new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test");
36710+
36711+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Descriptor];
36712+
36713+
public override void Initialize(AnalysisContext context)
36714+
{
36715+
context.RegisterSymbolAction(handle, SymbolKind.NamedType);
36716+
context.RegisterSymbolAction(handle, SymbolKind.Method);
36717+
context.RegisterSymbolAction(handle, SymbolKind.Property);
36718+
36719+
void handle(SymbolAnalysisContext context)
36720+
{
36721+
_results.Enqueue(context.Symbol.ToTestDisplayString());
36722+
}
36723+
}
36724+
}
36725+
36726+
[Fact]
36727+
public void AnalyzerActions_03()
36728+
{
36729+
var src = """
36730+
static class E
36731+
{
36732+
extension<T>(T t)
36733+
{
36734+
public void M() { }
36735+
public int P { get { return 0; } }
36736+
}
36737+
}
36738+
""";
36739+
36740+
var analyzer = new AnalyzerActions_03_Analyzer();
36741+
var comp = CreateCompilation(src);
36742+
comp.GetAnalyzerDiagnostics([analyzer], null).Verify();
36743+
36744+
AssertEx.SetEqual([
36745+
"public void M() { } -> void E.<>E__0<T>.M()",
36746+
"get { return 0; } -> System.Int32 E.<>E__0<T>.P.get"],
36747+
analyzer._results.ToArray());
36748+
}
36749+
36750+
private class AnalyzerActions_03_Analyzer : DiagnosticAnalyzer
36751+
{
36752+
public ConcurrentQueue<string> _results = new ConcurrentQueue<string>();
36753+
36754+
private static readonly DiagnosticDescriptor Descriptor =
36755+
new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test");
36756+
36757+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Descriptor];
36758+
36759+
public override void Initialize(AnalysisContext context)
36760+
{
36761+
context.RegisterOperationAction(handle, OperationKind.MethodBody);
36762+
36763+
void handle(OperationAnalysisContext context)
36764+
{
36765+
_results.Enqueue($"{context.Operation.Syntax.ToString()} -> {context.ContainingSymbol.ToTestDisplayString()}");
36766+
}
36767+
}
36768+
}
3660436769
}

0 commit comments

Comments
 (0)