5
5
using Microsoft . CodeAnalysis . CSharp ;
6
6
using Microsoft . CodeAnalysis . CSharp . Syntax ;
7
7
using Microsoft . CodeAnalysis . Text ;
8
+ using OmniSharp . Extensions . JsonRpc . Generators . Cache ;
8
9
using OmniSharp . Extensions . JsonRpc . Generators . Contexts ;
9
10
using static Microsoft . CodeAnalysis . CSharp . SyntaxFactory ;
10
11
using static OmniSharp . Extensions . JsonRpc . Generators . CommonElements ;
11
12
12
13
namespace OmniSharp . Extensions . JsonRpc . Generators
13
14
{
14
15
[ Generator ]
15
- public class AutoImplementParamsGenerator : ISourceGenerator
16
+ public class AutoImplementParamsGenerator : CachedSourceGenerator < AutoImplementParamsGenerator . SyntaxReceiver , ClassDeclarationSyntax >
16
17
{
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 )
24
19
{
25
- if ( ! ( context . SyntaxReceiver is SyntaxReceiver syntaxReceiver ) )
26
- {
27
- return ;
28
- }
29
-
30
20
foreach ( var candidate in syntaxReceiver . Candidates )
31
21
{
32
22
var members = new List < MemberDeclarationSyntax > ( ) ;
@@ -49,9 +39,7 @@ public void Execute(GeneratorExecutionContext context)
49
39
50
40
if ( ! candidate . Modifiers . Any ( z => z . IsKind ( SyntaxKind . PartialKeyword ) ) )
51
41
{
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 ) ) ;
55
43
}
56
44
57
45
var cu = CompilationUnit (
@@ -61,64 +49,77 @@ public void Execute(GeneratorExecutionContext context)
61
49
SingletonList < MemberDeclarationSyntax > (
62
50
NamespaceDeclaration ( ParseName ( symbol . ContainingNamespace . ToDisplayString ( ) ) )
63
51
. WithMembers ( List ( members ) )
64
- )
52
+ )
65
53
)
66
54
. AddUsings ( UsingDirective ( ParseName ( "OmniSharp.Extensions.LanguageServer.Protocol.Serialization" ) ) )
67
55
. WithLeadingTrivia ( )
68
56
. WithTrailingTrivia ( )
69
57
. WithLeadingTrivia ( Comment ( Preamble . GeneratedByATool ) , Trivia ( NullableDirectiveTrivia ( Token ( SyntaxKind . EnableKeyword ) , true ) ) )
70
58
. WithTrailingTrivia ( Trivia ( NullableDirectiveTrivia ( Token ( SyntaxKind . RestoreKeyword ) , true ) ) , CarriageReturnLineFeed ) ;
71
59
72
- context . AddSource (
60
+ addCacheSource (
73
61
$ "{ candidate . Identifier . Text } { ( candidate . Arity > 0 ? candidate . Arity . ToString ( ) : "" ) } .cs",
62
+ candidate ,
74
63
cu . NormalizeWhitespace ( ) . GetText ( Encoding . UTF8 )
75
64
) ;
76
65
}
77
66
}
78
67
79
68
private static IEnumerable < MemberDeclarationSyntax > AutoImplementInterfaces ( ClassDeclarationSyntax syntax , INamedTypeSymbol symbol )
80
69
{
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
82
71
&& symbol . GetMembers ( "WorkDoneToken" ) . IsEmpty )
83
72
{
84
73
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 ) ;
88
77
}
89
78
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
91
80
&& symbol . GetMembers ( "PartialResultToken" ) . IsEmpty )
92
81
{
93
82
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 ) ;
97
86
}
98
87
}
99
88
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 >
104
94
{
105
95
private string _attributes ;
106
- public List < ClassDeclarationSyntax > Candidates { get ; } = new ( ) ;
96
+ public List < ClassDeclarationSyntax > Candidates { get ; } = new ( ) ;
107
97
108
- public SyntaxReceiver ( )
98
+ public SyntaxReceiver ( CacheContainer < ClassDeclarationSyntax > cacheContainer ) : base ( cacheContainer )
109
99
{
110
100
_attributes = "Method,RegistrationOptions" ;
111
101
}
112
102
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
+
113
114
/// <summary>
114
115
/// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation
115
116
/// </summary>
116
- public void OnVisitSyntaxNode ( SyntaxNode syntaxNode )
117
+ public override void OnVisitNode ( ClassDeclarationSyntax syntaxNode )
117
118
{
118
119
// 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 ) )
120
121
{
121
- Candidates . Add ( tds ) ;
122
+ Candidates . Add ( syntaxNode ) ;
122
123
}
123
124
}
124
125
}
0 commit comments