@@ -11,52 +11,114 @@ namespace Altinn.App.Analyzers.IncrementalGenerator;
1111[ Generator ]
1212public class FormDataWrapperGenerator : IIncrementalGenerator
1313{
14+ private record Result < T > ( T ? Value , EquatableArray < EquatableDiagnostic > Diagnostics )
15+ where T : class
16+ {
17+ public Result ( EquatableDiagnostic diagnostics )
18+ : this ( null , new EquatableArray < EquatableDiagnostic > ( [ diagnostics ] ) ) { }
19+
20+ public Result ( T value )
21+ : this ( value , EquatableArray < EquatableDiagnostic > . Empty ) { }
22+ } ;
23+
24+ private record ModelClassOrDiagnostic (
25+ string ? ClassName ,
26+ Location ? Location ,
27+ EquatableArray < EquatableDiagnostic > Diagnostics
28+ )
29+ {
30+ public ModelClassOrDiagnostic ( EquatableDiagnostic diagnostic )
31+ : this ( null , null , new ( [ diagnostic ] ) ) { }
32+
33+ public ModelClassOrDiagnostic ( string className , Location ? location )
34+ : this ( className , location , EquatableArray < EquatableDiagnostic > . Empty ) { }
35+ } ;
36+
1437 /// <inheritdoc />
1538 public void Initialize ( IncrementalGeneratorInitializationContext context )
1639 {
1740 var rootClasses = context
1841 . AdditionalTextsProvider . Where ( text =>
1942 text . Path . Replace ( '\\ ' , '/' ) . EndsWith ( "config/applicationmetadata.json" )
2043 )
21- . SelectMany (
44+ . SelectMany < AdditionalText , ModelClassOrDiagnostic > (
2245 ( text , token ) =>
2346 {
24- var textContent = text . GetText ( token ) ? . ToString ( ) ;
25- if ( textContent is null )
26- {
27- return [ ] ;
28- }
29- List < string > rootClasses = [ ] ;
30- var appMetadata = JsonValue . Parse ( textContent ) ;
31- if ( appMetadata . Type != JsonType . Object )
32- {
33- return rootClasses ;
34- }
35-
36- var dataTypes = appMetadata . GetProperty ( "dataTypes" ) ;
37- if ( dataTypes ? . Type != JsonType . Array )
38- {
39- return rootClasses ;
40- }
41- foreach ( var dataType in dataTypes . GetArrayValues ( ) )
47+ try
4248 {
43- if ( dataType . Type != JsonType . Object )
49+ var textContent = text . GetText ( token ) ? . ToString ( ) ;
50+ List < ModelClassOrDiagnostic > rootClasses = [ ] ;
51+ if ( textContent is null )
52+ {
53+ rootClasses . Add (
54+ new (
55+ new EquatableDiagnostic (
56+ Diagnostics . FormDataWrapperGenerator . AppMetadataError ,
57+ FileLocationHelper . GetLocation ( text , 0 , null ) ,
58+ [ "Failed to read applicationmetadata.json" ]
59+ )
60+ )
61+ ) ;
62+ return rootClasses ;
63+ }
64+ var appMetadata = JsonValue . Parse ( textContent ) ;
65+ if ( appMetadata . Type != JsonType . Object )
4466 {
45- continue ;
67+ rootClasses . Add (
68+ new (
69+ new EquatableDiagnostic (
70+ Diagnostics . FormDataWrapperGenerator . AppMetadataError ,
71+ FileLocationHelper . GetLocation ( text , appMetadata . Start , appMetadata . End ) ,
72+ [ "applicationmetadata.json is not a valid JSON object" ]
73+ )
74+ )
75+ ) ;
76+ return rootClasses ;
4677 }
47- var appLogic = dataType . GetProperty ( "appLogic" ) ;
48- if ( appLogic ? . Type != JsonType . Object )
78+
79+ var dataTypes = appMetadata . GetProperty ( "dataTypes" ) ;
80+ if ( dataTypes ? . Type != JsonType . Array )
4981 {
50- continue ;
82+ return rootClasses ;
5183 }
52- var classRef = appLogic . GetProperty ( "classRef" ) ;
53- if ( classRef ? . Type != JsonType . String )
84+ foreach ( var dataType in dataTypes . GetArrayValues ( ) )
5485 {
55- continue ;
86+ if ( dataType . Type != JsonType . Object )
87+ {
88+ continue ;
89+ }
90+ var appLogic = dataType . GetProperty ( "appLogic" ) ;
91+ if ( appLogic ? . Type != JsonType . Object )
92+ {
93+ continue ;
94+ }
95+ var classRef = appLogic . GetProperty ( "classRef" ) ;
96+ if ( classRef ? . Type != JsonType . String )
97+ {
98+ continue ;
99+ }
100+ rootClasses . Add (
101+ new (
102+ classRef . GetString ( ) ,
103+ FileLocationHelper . GetLocation ( text , classRef . Start , classRef . End )
104+ )
105+ ) ;
56106 }
57- rootClasses . Add ( classRef . GetString ( ) ) ;
107+ return rootClasses ;
108+ }
109+ catch ( NanoJsonException e )
110+ {
111+ return new List < ModelClassOrDiagnostic >
112+ {
113+ new (
114+ new EquatableDiagnostic (
115+ Diagnostics . FormDataWrapperGenerator . AppMetadataError ,
116+ FileLocationHelper . GetLocation ( text , e . StartIndex , e . EndIndex ) ,
117+ [ e . Message ]
118+ )
119+ ) ,
120+ } ;
58121 }
59- return rootClasses ;
60122 }
61123 ) ;
62124
@@ -65,28 +127,34 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
65127 context . RegisterSourceOutput ( modelPathNodesProvider , GenerateFromNode ) ;
66128 }
67129
68- private static ModelPathNode ? CreateNodeThree ( ( string , Compilation ) tuple , CancellationToken _ )
130+ private static Result < ModelPathNode > CreateNodeThree (
131+ ( ModelClassOrDiagnostic , Compilation ) tuple ,
132+ CancellationToken _
133+ )
69134 {
70135 var ( rootSymbolFullName , compilation ) = tuple ;
71- var rootSymbol = compilation . GetBestTypeByMetadataName ( rootSymbolFullName ) ;
136+ if ( rootSymbolFullName . ClassName is null )
137+ {
138+ return new Result < ModelPathNode > ( null , rootSymbolFullName . Diagnostics ) ;
139+ }
140+ var rootSymbol = compilation . GetBestTypeByMetadataName ( rootSymbolFullName . ClassName ) ;
72141 if ( rootSymbol == null )
73142 {
74- // TODO: this should probably cause a diagnostic
75- return null ;
143+ return new Result < ModelPathNode > (
144+ new EquatableDiagnostic (
145+ Diagnostics . FormDataWrapperGenerator . AppMetadataError ,
146+ rootSymbolFullName . Location ,
147+ [ $ "Could not find class { rootSymbolFullName . ClassName } in the compilation"]
148+ )
149+ ) ;
76150 }
77151
78- return new ModelPathNode (
79- "" ,
80- "" ,
81- SourceReaderUtils . TypeSymbolToString ( rootSymbol ) ,
82- GetNodeProperties ( rootSymbol , compilation )
152+ return new Result < ModelPathNode > (
153+ new ModelPathNode ( "" , "" , SourceReaderUtils . TypeSymbolToString ( rootSymbol ) , GetNodeProperties ( rootSymbol ) )
83154 ) ;
84155 }
85156
86- private static EquatableArray < ModelPathNode > ? GetNodeProperties (
87- INamedTypeSymbol namedTypeSymbol ,
88- Compilation compilation
89- )
157+ private static EquatableArray < ModelPathNode > ? GetNodeProperties ( INamedTypeSymbol namedTypeSymbol )
90158 {
91159 var nodeProperties = new List < ModelPathNode > ( ) ;
92160 foreach ( var property in namedTypeSymbol . GetMembers ( ) . OfType < IPropertySymbol > ( ) )
@@ -123,7 +191,7 @@ propertyTypeSymbol is INamedTypeSymbol propertyNamedTypeSymbol
123191 cSharpName ,
124192 jsonName ,
125193 typeString ,
126- GetNodeProperties ( propertyNamedTypeSymbol , compilation ) ,
194+ GetNodeProperties ( propertyNamedTypeSymbol ) ,
127195 collectionTypeString
128196 )
129197 ) ;
@@ -136,9 +204,13 @@ propertyTypeSymbol is INamedTypeSymbol propertyNamedTypeSymbol
136204 return nodeProperties ;
137205 }
138206
139- private void GenerateFromNode ( SourceProductionContext context , ModelPathNode ? node )
207+ private void GenerateFromNode ( SourceProductionContext context , Result < ModelPathNode > result )
140208 {
141- if ( node is null )
209+ foreach ( var diagnostic in result . Diagnostics )
210+ {
211+ context . ReportDiagnostic ( diagnostic . CreateDiagnostic ( ) ) ;
212+ }
213+ if ( result is not { Value : { } node } )
142214 return ;
143215 DebugTree = node ;
144216 var sourceText = SourceTextGenerator . SourceTextGenerator . GenerateSourceText ( node , "public" ) ;
0 commit comments