55using Microsoft . CodeAnalysis . CSharp ;
66using Microsoft . CodeAnalysis . CSharp . Syntax ;
77using Microsoft . CodeAnalysis . Text ;
8+ using OmniSharp . Extensions . JsonRpc . Generators . Cache ;
89using OmniSharp . Extensions . JsonRpc . Generators . Contexts ;
910using static Microsoft . CodeAnalysis . CSharp . SyntaxFactory ;
1011using static OmniSharp . Extensions . JsonRpc . Generators . CommonElements ;
1112
1213namespace OmniSharp . Extensions . JsonRpc . Generators
1314{
1415 [ Generator ]
15- public class AutoImplementParamsGenerator : ISourceGenerator
16+ public class AutoImplementParamsGenerator : CachedSourceGenerator < AutoImplementParamsGenerator . SyntaxReceiver , ClassDeclarationSyntax >
1617 {
17-
18- public void Initialize ( GeneratorInitializationContext context )
19- {
20- context . RegisterForSyntaxNotifications ( ( ) => new SyntaxReceiver ( ) ) ;
21- }
22-
23- public void Execute ( GeneratorExecutionContext context )
18+ protected override void Execute ( GeneratorExecutionContext context , SyntaxReceiver syntaxReceiver , AddCacheSource < ClassDeclarationSyntax > addCacheSource , ReportCacheDiagnostic < ClassDeclarationSyntax > cacheDiagnostic )
2419 {
25- if ( ! ( context . SyntaxReceiver is SyntaxReceiver syntaxReceiver ) )
26- {
27- return ;
28- }
29-
3020 foreach ( var candidate in syntaxReceiver . Candidates )
3121 {
3222 var members = new List < MemberDeclarationSyntax > ( ) ;
@@ -49,9 +39,7 @@ public void Execute(GeneratorExecutionContext context)
4939
5040 if ( ! candidate . Modifiers . Any ( z => z . IsKind ( SyntaxKind . PartialKeyword ) ) )
5141 {
52- context . ReportDiagnostic (
53- Diagnostic . Create ( GeneratorDiagnostics . MustBePartial , candidate . Identifier . GetLocation ( ) , candidate . Identifier . Text )
54- ) ;
42+ cacheDiagnostic ( candidate , static c => Diagnostic . Create ( GeneratorDiagnostics . MustBePartial , c . Identifier . GetLocation ( ) , c . Identifier . Text ) ) ;
5543 }
5644
5745 var cu = CompilationUnit (
@@ -61,64 +49,77 @@ public void Execute(GeneratorExecutionContext context)
6149 SingletonList < MemberDeclarationSyntax > (
6250 NamespaceDeclaration ( ParseName ( symbol . ContainingNamespace . ToDisplayString ( ) ) )
6351 . WithMembers ( List ( members ) )
64- )
52+ )
6553 )
6654 . AddUsings ( UsingDirective ( ParseName ( "OmniSharp.Extensions.LanguageServer.Protocol.Serialization" ) ) )
6755 . WithLeadingTrivia ( )
6856 . WithTrailingTrivia ( )
6957 . WithLeadingTrivia ( Comment ( Preamble . GeneratedByATool ) , Trivia ( NullableDirectiveTrivia ( Token ( SyntaxKind . EnableKeyword ) , true ) ) )
7058 . WithTrailingTrivia ( Trivia ( NullableDirectiveTrivia ( Token ( SyntaxKind . RestoreKeyword ) , true ) ) , CarriageReturnLineFeed ) ;
7159
72- context . AddSource (
60+ addCacheSource (
7361 $ "{ candidate . Identifier . Text } { ( candidate . Arity > 0 ? candidate . Arity . ToString ( ) : "" ) } .cs",
62+ candidate ,
7463 cu . NormalizeWhitespace ( ) . GetText ( Encoding . UTF8 )
7564 ) ;
7665 }
7766 }
7867
7968 private static IEnumerable < MemberDeclarationSyntax > AutoImplementInterfaces ( ClassDeclarationSyntax syntax , INamedTypeSymbol symbol )
8069 {
81- if ( syntax . BaseList ? . Types . Any ( z => z . Type . GetSyntaxName ( ) is "IWorkDoneProgressParams" ) == true
70+ if ( syntax . BaseList ? . Types . Any ( z => z . Type . GetSyntaxName ( ) is "IWorkDoneProgressParams" ) == true
8271 && symbol . GetMembers ( "WorkDoneToken" ) . IsEmpty )
8372 {
8473 yield return PropertyDeclaration ( NullableType ( IdentifierName ( "ProgressToken" ) ) , Identifier ( "WorkDoneToken" ) )
85- . WithAttributeLists ( SingletonList ( AttributeList ( SingletonSeparatedList ( Attribute ( IdentifierName ( "Optional" ) ) ) ) ) )
86- . WithModifiers ( TokenList ( Token ( SyntaxKind . PublicKeyword ) ) )
87- . WithAccessorList ( GetSetAccessor ) ;
74+ . WithAttributeLists ( SingletonList ( AttributeList ( SingletonSeparatedList ( Attribute ( IdentifierName ( "Optional" ) ) ) ) ) )
75+ . WithModifiers ( TokenList ( Token ( SyntaxKind . PublicKeyword ) ) )
76+ . WithAccessorList ( GetSetAccessor ) ;
8877 }
8978
90- if ( syntax . BaseList ? . Types . Any ( z => z . Type . GetSyntaxName ( ) is "IPartialItemsRequest" or "IPartialItemRequest" ) == true
79+ if ( syntax . BaseList ? . Types . Any ( z => z . Type . GetSyntaxName ( ) is "IPartialItemsRequest" or "IPartialItemRequest" ) == true
9180 && symbol . GetMembers ( "PartialResultToken" ) . IsEmpty )
9281 {
9382 yield return PropertyDeclaration ( NullableType ( IdentifierName ( "ProgressToken" ) ) , Identifier ( "PartialResultToken" ) )
94- . WithAttributeLists ( SingletonList ( AttributeList ( SingletonSeparatedList ( Attribute ( IdentifierName ( "Optional" ) ) ) ) ) )
95- . WithModifiers ( TokenList ( Token ( SyntaxKind . PublicKeyword ) ) )
96- . WithAccessorList ( GetSetAccessor ) ;
83+ . WithAttributeLists ( SingletonList ( AttributeList ( SingletonSeparatedList ( Attribute ( IdentifierName ( "Optional" ) ) ) ) ) )
84+ . WithModifiers ( TokenList ( Token ( SyntaxKind . PublicKeyword ) ) )
85+ . WithAccessorList ( GetSetAccessor ) ;
9786 }
9887 }
9988
100- /// <summary>
101- /// Created on demand before each generation pass
102- /// </summary>
103- internal class SyntaxReceiver : ISyntaxReceiver
89+ public AutoImplementParamsGenerator ( ) : base ( ( ) => new SyntaxReceiver ( Cache ) ) { }
90+
91+ public static CacheContainer < ClassDeclarationSyntax > Cache = new ( ) ;
92+
93+ public class SyntaxReceiver : SyntaxReceiverCache < ClassDeclarationSyntax >
10494 {
10595 private string _attributes ;
106- public List < ClassDeclarationSyntax > Candidates { get ; } = new ( ) ;
96+ public List < ClassDeclarationSyntax > Candidates { get ; } = new ( ) ;
10797
108- public SyntaxReceiver ( )
98+ public SyntaxReceiver ( CacheContainer < ClassDeclarationSyntax > cacheContainer ) : base ( cacheContainer )
10999 {
110100 _attributes = "Method,RegistrationOptions" ;
111101 }
112102
103+ public override string ? GetKey ( ClassDeclarationSyntax syntax )
104+ {
105+ var hasher = new CacheKeyHasher ( ) ;
106+ hasher . Append ( syntax . SyntaxTree . FilePath ) ;
107+ hasher . Append ( syntax . Identifier . Text ) ;
108+ hasher . Append ( syntax . TypeParameterList ) ;
109+ hasher . Append ( syntax . AttributeLists ) ;
110+ hasher . Append ( syntax . BaseList ) ;
111+ return hasher ;
112+ }
113+
113114 /// <summary>
114115 /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation
115116 /// </summary>
116- public void OnVisitSyntaxNode ( SyntaxNode syntaxNode )
117+ public override void OnVisitNode ( ClassDeclarationSyntax syntaxNode )
117118 {
118119 // any field with at least one attribute is a candidate for property generation
119- if ( syntaxNode is ClassDeclarationSyntax tds && tds . AttributeLists . ContainsAttribute ( _attributes ) )
120+ if ( syntaxNode . AttributeLists . ContainsAttribute ( _attributes ) )
120121 {
121- Candidates . Add ( tds ) ;
122+ Candidates . Add ( syntaxNode ) ;
122123 }
123124 }
124125 }
0 commit comments