Skip to content

Commit 40d2ffa

Browse files
committed
Extensions: analyzer actions
1 parent c3fc0f0 commit 40d2ffa

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;
@@ -36055,4 +36058,166 @@ .method public hidebysig specialname static int32 get_P2 ( int32 '' ) cil manage
3605536058
var comp = CreateCompilationWithIL(source, ilSrc);
3605636059
comp.VerifyEmitDiagnostics();
3605736060
}
36061+
36062+
[Fact]
36063+
public void AnalyzerActions_01()
36064+
{
36065+
var src = """
36066+
static class E
36067+
{
36068+
extension<T>([Attr] T t)
36069+
{
36070+
[Attr2]
36071+
public void M() { }
36072+
36073+
[Attr3]
36074+
public int P => 0;
36075+
}
36076+
}
36077+
""";
36078+
36079+
var analyzer = new AnalyzerActions_01_Analyzer();
36080+
var comp = CreateCompilation(src);
36081+
comp.GetAnalyzerDiagnostics([analyzer], null).Verify();
36082+
36083+
AssertEx.SetEqual([
36084+
"Attr2 -> void E.<>E__0<T>.M()",
36085+
"M -> void E.<>E__0<T>.M()",
36086+
"Attr3 -> System.Int32 E.<>E__0<T>.P { get; }",
36087+
"P -> System.Int32 E.<>E__0<T>.P { get; }",
36088+
"T -> E.<>E__0<T>",
36089+
"Attr -> E.<>E__0<T>",
36090+
"extension -> E.<>E__0<T>"],
36091+
analyzer._results.ToArray());
36092+
}
36093+
36094+
private class AnalyzerActions_01_Analyzer : DiagnosticAnalyzer
36095+
{
36096+
public ConcurrentQueue<string> _results = new ConcurrentQueue<string>();
36097+
36098+
private static readonly DiagnosticDescriptor Descriptor =
36099+
new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test");
36100+
36101+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Descriptor];
36102+
36103+
public override void Initialize(AnalysisContext context)
36104+
{
36105+
context.RegisterSyntaxNodeAction(handle, SyntaxKind.ExtensionDeclaration);
36106+
context.RegisterSyntaxNodeAction(handle, SyntaxKind.IdentifierName);
36107+
context.RegisterSyntaxNodeAction(handle, SyntaxKind.MethodDeclaration);
36108+
context.RegisterSyntaxNodeAction(handle, SyntaxKind.PropertyDeclaration);
36109+
36110+
void handle(SyntaxNodeAnalysisContext context)
36111+
{
36112+
_results.Enqueue(print(context));
36113+
Assert.Same(context.Node.SyntaxTree, context.ContainingSymbol!.DeclaringSyntaxReferences.Single().SyntaxTree);
36114+
}
36115+
36116+
static string print(SyntaxNodeAnalysisContext context)
36117+
{
36118+
var syntaxString = context.Node switch
36119+
{
36120+
ExtensionDeclarationSyntax => "extension",
36121+
MethodDeclarationSyntax method => method.Identifier.ValueText,
36122+
PropertyDeclarationSyntax property => property.Identifier.ValueText,
36123+
_ => context.Node.ToString()
36124+
};
36125+
36126+
return $"{syntaxString} -> {context.ContainingSymbol.ToTestDisplayString()}";
36127+
}
36128+
}
36129+
}
36130+
36131+
[Fact]
36132+
public void AnalyzerActions_02()
36133+
{
36134+
var src = """
36135+
static class E
36136+
{
36137+
extension<T>(T t)
36138+
{
36139+
public void M() { }
36140+
public int P => 0;
36141+
}
36142+
}
36143+
""";
36144+
36145+
var analyzer = new AnalyzerActions_02_Analyzer();
36146+
var comp = CreateCompilation(src);
36147+
comp.GetAnalyzerDiagnostics([analyzer], null).Verify();
36148+
36149+
AssertEx.SetEqual([
36150+
"System.Int32 E.<>E__0<T>.P.get",
36151+
"void E.<>E__0<T>.M()",
36152+
"E.<>E__0<T>",
36153+
"System.Int32 E.<>E__0<T>.P { get; }",
36154+
"E"],
36155+
analyzer._results.ToArray());
36156+
}
36157+
36158+
private class AnalyzerActions_02_Analyzer : DiagnosticAnalyzer
36159+
{
36160+
public ConcurrentQueue<string> _results = new ConcurrentQueue<string>();
36161+
36162+
private static readonly DiagnosticDescriptor Descriptor =
36163+
new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test");
36164+
36165+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Descriptor];
36166+
36167+
public override void Initialize(AnalysisContext context)
36168+
{
36169+
context.RegisterSymbolAction(handle, SymbolKind.NamedType);
36170+
context.RegisterSymbolAction(handle, SymbolKind.Method);
36171+
context.RegisterSymbolAction(handle, SymbolKind.Property);
36172+
36173+
void handle(SymbolAnalysisContext context)
36174+
{
36175+
_results.Enqueue(context.Symbol.ToTestDisplayString());
36176+
}
36177+
}
36178+
}
36179+
36180+
[Fact]
36181+
public void AnalyzerActions_03()
36182+
{
36183+
var src = """
36184+
static class E
36185+
{
36186+
extension<T>(T t)
36187+
{
36188+
public void M() { }
36189+
public int P { get { return 0; } }
36190+
}
36191+
}
36192+
""";
36193+
36194+
var analyzer = new AnalyzerActions_03_Analyzer();
36195+
var comp = CreateCompilation(src);
36196+
comp.GetAnalyzerDiagnostics([analyzer], null).Verify();
36197+
36198+
AssertEx.SetEqual([
36199+
"public void M() { } -> void E.<>E__0<T>.M()",
36200+
"get { return 0; } -> System.Int32 E.<>E__0<T>.P.get"],
36201+
analyzer._results.ToArray());
36202+
}
36203+
36204+
private class AnalyzerActions_03_Analyzer : DiagnosticAnalyzer
36205+
{
36206+
public ConcurrentQueue<string> _results = new ConcurrentQueue<string>();
36207+
36208+
private static readonly DiagnosticDescriptor Descriptor =
36209+
new DiagnosticDescriptor("XY0000", "Test", "Test", "Test", DiagnosticSeverity.Warning, true, "Test", "Test");
36210+
36211+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Descriptor];
36212+
36213+
public override void Initialize(AnalysisContext context)
36214+
{
36215+
context.RegisterOperationAction(handle, OperationKind.MethodBody);
36216+
36217+
void handle(OperationAnalysisContext context)
36218+
{
36219+
_results.Enqueue($"{context.Operation.Syntax.ToString()} -> {context.ContainingSymbol.ToTestDisplayString()}");
36220+
}
36221+
}
36222+
}
3605836223
}

0 commit comments

Comments
 (0)