diff --git a/.gitignore b/.gitignore index 1b53fa2..0471d4e 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,6 @@ DeviceDependentGenerator.Tests/obj/* PerfectNumbers.Core.Tests/bin/* PerfectNumbers.Core.Tests/obj/* .DS_Store -.vs/* \ No newline at end of file +.vs/* +*.generated.cs +PerfectNumbers.Core/generated/* diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e42a24f..9d9e96e 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -11,7 +11,8 @@ "--configuration", "Debug", "--framework", - "net8.0" + "net8.0", + "/p:DeviceDependentGenerator_CopyGeneratedToProjectDir=true" ], "group": { "kind": "build", @@ -29,7 +30,8 @@ "--configuration", "Release", "--framework", - "net8.0" + "net8.0", + "/p:DeviceDependentGenerator_CopyGeneratedToProjectDir=true" ], "group": "build", "problemMatcher": "$msCompile" diff --git a/DeviceDependentGenerator/DeviceDependentGenerator.cs b/DeviceDependentGenerator/DeviceDependentGenerator.cs index 379fea4..814862b 100644 --- a/DeviceDependentGenerator/DeviceDependentGenerator.cs +++ b/DeviceDependentGenerator/DeviceDependentGenerator.cs @@ -54,9 +54,12 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator IncrementalValueProvider options = context.AnalyzerConfigOptionsProvider.Select( static (provider, _) => new GeneratorOptions(provider.GlobalOptions)); - context.RegisterSourceOutput(templates.Combine(options), static (productionContext, pair) => + IncrementalValueProvider<(Compilation Compilation, GeneratorOptions Options)> compilationAndOptions = + context.CompilationProvider.Combine(options).Select(static (pair, _) => (pair.Left, pair.Right)); + + context.RegisterSourceOutput(templates.Combine(compilationAndOptions), static (productionContext, pair) => { - GenerateForTemplate(productionContext, pair.Left, pair.Right); + GenerateForTemplate(productionContext, pair.Left, pair.Right.Compilation, pair.Right.Options); }); } @@ -119,7 +122,7 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator return TemplateInfo.CreateValid(templateSymbol, enumTypeSymbol, attributeLocation, enumValues, suffix); } - private static void GenerateForTemplate(SourceProductionContext context, TemplateInfo template, GeneratorOptions options) + private static void GenerateForTemplate(SourceProductionContext context, TemplateInfo template, Compilation compilation, GeneratorOptions options) { if (!template.Valid) { @@ -146,6 +149,7 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator SourceText fileText = templateSyntax.SyntaxTree.GetText(context.CancellationToken); string filePath = templateSyntax.SyntaxTree.FilePath; CSharpParseOptions baseParseOptions = (CSharpParseOptions)templateSyntax.SyntaxTree.Options; + SyntaxTree originalTree = templateSyntax.SyntaxTree; foreach (string enumValueName in template.EnumValues) { @@ -166,6 +170,8 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator continue; } + ReportDeviceSpecificTemplateErrors(context, compilation, originalTree, deviceTree, templateSyntax.Identifier.GetLocation(), enumValueName); + string generatedTypeName = baseName + enumValueName + template.Suffix; TypeDeclarationSyntax generatedTypeSyntax = TransformTemplateType(deviceTemplateSyntax, generatedTypeName); @@ -186,6 +192,45 @@ public sealed class DeviceDependentGenerator : IIncrementalGenerator } } + private static void ReportDeviceSpecificTemplateErrors( + SourceProductionContext context, + Compilation compilation, + SyntaxTree originalTree, + SyntaxTree deviceTree, + Location fallbackLocation, + string enumValueName) + { + foreach (Diagnostic diagnostic in deviceTree.GetDiagnostics(context.CancellationToken)) + { + if (diagnostic.Severity == DiagnosticSeverity.Error) + { + context.ReportDiagnostic(diagnostic); + } + } + + if (compilation is not CSharpCompilation csharpCompilation) + { + return; + } + + CSharpCompilation deviceCompilation = csharpCompilation.ReplaceSyntaxTree(originalTree, deviceTree); + foreach (Diagnostic diagnostic in deviceCompilation.GetDiagnostics(context.CancellationToken)) + { + if (diagnostic.Severity != DiagnosticSeverity.Error) + { + continue; + } + + if (diagnostic.Location is { Kind: LocationKind.SourceFile } location + && location.SourceTree != deviceTree) + { + continue; + } + + context.ReportDiagnostic(diagnostic); + } + } + private static bool IsTopLevel(TypeDeclarationSyntax typeDeclaration) => typeDeclaration.Parent is NamespaceDeclarationSyntax || typeDeclaration.Parent is FileScopedNamespaceDeclarationSyntax diff --git a/PerfectNumbers.Core/PerfectNumbers.Core.csproj b/PerfectNumbers.Core/PerfectNumbers.Core.csproj index 20690aa..f4a97b8 100644 --- a/PerfectNumbers.Core/PerfectNumbers.Core.csproj +++ b/PerfectNumbers.Core/PerfectNumbers.Core.csproj @@ -5,8 +5,14 @@ enable enable 12.0 + true + $(IntermediateOutputPath)generated + + + + @@ -28,4 +34,15 @@ + + + <_DeviceDependentGeneratedFiles Include="$(CompilerGeneratedFilesOutputPath)\DeviceDependentGenerator\PerfectNumbers.Core.Generators.DeviceDependentGenerator\**\*.generated.cs" /> + + + +