Skip to content

Commit 92c03b0

Browse files
committed
Add diagnostcs and cleanup
1 parent a8313c1 commit 92c03b0

28 files changed

+535
-347
lines changed

solutions/All.sln

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{B96EA64C-2
2929
EndProject
3030
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{D8D6ED6A-EF63-48FC-B267-17FB76C5DD07}"
3131
EndProject
32-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Altinn.App.Sourcegenerator.Integration.Tests", "..\test\Altinn.App.Sourcegenerator.Integration.Tests\Altinn.App.Sourcegenerator.Integration.Tests.csproj", "{836CECBF-5518-4276-BE2C-B0F255BF19F2}"
32+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Altinn.App.SourceGenerator.Integration.Tests", "..\test\Altinn.App.SourceGenerator.Integration.Tests\Altinn.App.SourceGenerator.Integration.Tests.csproj", "{836CECBF-5518-4276-BE2C-B0F255BF19F2}"
3333
ProjectSection(ProjectDependencies) = postProject
3434
{E8F29FE8-6B62-41F1-A08C-2A318DD08BB4} = {E8F29FE8-6B62-41F1-A08C-2A318DD08BB4}
3535
EndProjectSection

src/Altinn.App.Analyzers/AnalyzerReleases.Unshipped.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
Rule ID | Category | Severity | Notes
77
--------|----------|----------|-------
88
ALTINNAPP0001 | General | Warning | Project not found
9+
ALTINNAPP0002 | Metadata | Warning | Error in applicationmetadata.json
910
ALTINNAPP9999 | General | Warning | Unknown error
1011
ALTINNAPP0500 | CodeSmells | Warning | CodeSmells

src/Altinn.App.Analyzers/Diagnostics.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,25 @@ public static class CodeSmells
2626
);
2727
}
2828

29+
public static class FormDataWrapperGenerator
30+
{
31+
public static readonly DiagnosticDescriptor AppMetadataError = Error(
32+
"ALTINNAPP0002",
33+
Category.Metadata,
34+
"Application metadata error",
35+
"Error in applicationmetadata.json: {0}"
36+
);
37+
}
38+
2939
private const string DocsRoot = "https://docs.altinn.studio/nb/altinn-studio/reference/analysis/";
3040
private const string RulesRoot = DocsRoot + "rules/";
3141

3242
private static DiagnosticDescriptor Warning(string id, string category, string title, string messageFormat) =>
3343
Create(id, title, messageFormat, category, DiagnosticSeverity.Warning);
3444

45+
private static DiagnosticDescriptor Error(string id, string category, string title, string messageFormat) =>
46+
Create(id, title, messageFormat, category, DiagnosticSeverity.Warning);
47+
3548
private static DiagnosticDescriptor Create(
3649
string id,
3750
string title,

src/Altinn.App.Analyzers/IncrementalGenerator/FormDataWrapperGenerator.cs

Lines changed: 117 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -11,52 +11,114 @@ namespace Altinn.App.Analyzers.IncrementalGenerator;
1111
[Generator]
1212
public 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");

src/Altinn.App.Analyzers/SourceTextGenerator/AddIndexToPathGenerator.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ ref pathOffset
2525
2626
return buffer[..bufferOffset];
2727
}
28-
28+
2929
"""
3030
);
3131
GenerateRecursiveMethod(builder, rootNode, []);
@@ -56,7 +56,7 @@ ref int pathOffset
5656
var segment = GetNextSegment(path, pathOffset, out pathOffset);
5757
switch (segment)
5858
{
59-
59+
6060
"""
6161
);
6262

@@ -67,7 +67,7 @@ ref int pathOffset
6767
case "{{child.JsonName}}":
6868
segment.CopyTo(buffer.Slice(bufferOffset));
6969
bufferOffset += {{child.JsonName.Length}};
70-
70+
7171
"""
7272
);
7373
if (child.ListType is not null)
@@ -113,7 +113,7 @@ ref int pathOffset
113113
ref pathOffset
114114
);
115115
break;
116-
116+
117117
"""
118118
);
119119
}
@@ -128,7 +128,7 @@ ref pathOffset
128128
pathOffset += {{child.JsonName.Length}};
129129
130130
break;
131-
131+
132132
"""
133133
);
134134
}

src/Altinn.App.Analyzers/SourceTextGenerator/AltinnRowIdsGenerator.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ HashSet<string> classes
6060
6161
private static void SetAltinnRowIds({{property.Node.TypeName}} dataModel, bool initialize)
6262
{
63-
63+
6464
"""
6565
);
6666

@@ -71,7 +71,7 @@ private static void SetAltinnRowIds({{property.Node.TypeName}} dataModel, bool i
7171
builder.Append(
7272
$$"""
7373
dataModel.{{child.Node.CSharpName}} = initialize ? Guid.NewGuid() : Guid.Empty;
74-
74+
7575
"""
7676
);
7777
}
@@ -83,7 +83,7 @@ private static void SetAltinnRowIds({{property.Node.TypeName}} dataModel, bool i
8383
{
8484
SetAltinnRowIds(dataModel.{{child.Node.CSharpName}}, initialize);
8585
}
86-
86+
8787
"""
8888
);
8989
}
@@ -101,7 +101,7 @@ private static void SetAltinnRowIds({{property.Node.TypeName}} dataModel, bool i
101101
}
102102
}
103103
}
104-
104+
105105
"""
106106
);
107107
}

src/Altinn.App.Analyzers/SourceTextGenerator/CopyGenerator.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public IFormDataWrapper Copy()
1515
{
1616
return new {{generatedWrapperClassName}}(CopyRecursive(_dataModel));
1717
}
18-
18+
1919
"""
2020
);
2121

@@ -46,7 +46,7 @@ private static void GenerateCopyRecursive(StringBuilder builder, ModelPathNode n
4646
return null;
4747
}
4848
49-
49+
5050
"""
5151
);
5252
if (node.Properties.Count == 0)
@@ -91,7 +91,7 @@ private static void GenerateCopyList(StringBuilder builder, ModelPathNode node)
9191
9292
return [.. list.Select(CopyRecursive)];
9393
}
94-
94+
9595
"""
9696
);
9797
}

0 commit comments

Comments
 (0)