Use compilation units

Use filescoped namespaces where supported
This commit is contained in:
2024-04-11 11:59:00 +02:00
parent 5d63d73f93
commit 9d7ce59e14
3 changed files with 65 additions and 46 deletions
@@ -1,14 +1,9 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Sybil;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace System.Extensions;
#nullable enable
@@ -32,8 +27,11 @@ public class DependencyPropertyGenerator : IIncrementalGenerator
{
context.RegisterPostInitializationOutput(context =>
{
var attributeNamespaceBuilder = SyntaxBuilder.CreateNamespace(AttributeNamespace)
.WithUsing("System.ComponentModel")
var compilationUnitBuilder =
SyntaxBuilder.CreateCompilationUnit()
.WithUsing("System.ComponentModel")
.WithNamespace(
SyntaxBuilder.CreateNamespace(AttributeNamespace)
.WithClass(SyntaxBuilder.CreateClass(AttributeName)
.WithModifier(Public)
.WithConstructor(SyntaxBuilder.CreateConstructor(AttributeName)
@@ -46,9 +44,9 @@ public class DependencyPropertyGenerator : IIncrementalGenerator
.WithProperty(SyntaxBuilder.CreateProperty("object", InitialValue)
.WithModifier(Public)
.WithAccessor(SyntaxBuilder.CreateGetter())
.WithAccessor(SyntaxBuilder.CreateSetter())));
var attributeSyntax = attributeNamespaceBuilder.Build();
var source = attributeSyntax.ToFullString();
.WithAccessor(SyntaxBuilder.CreateSetter()))));
var compilationUnitSyntax = compilationUnitBuilder.Build();
var source = compilationUnitSyntax.ToFullString();
context.AddSource($"{AttributeName}.g", source);
});
@@ -74,13 +72,20 @@ public class DependencyPropertyGenerator : IIncrementalGenerator
return default;
}
private static void Execute(Compilation _, ImmutableArray<ClassDeclarationSyntax?> classes, SourceProductionContext sourceProductionContext)
private static void Execute(Compilation compilation, ImmutableArray<ClassDeclarationSyntax?> classes, SourceProductionContext sourceProductionContext)
{
if (classes.IsDefaultOrEmpty)
{
return;
}
var maybeLanguageVersion = (compilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions)?.LanguageVersion;
if (!maybeLanguageVersion.HasValue)
{
return;
}
var languageVersion = maybeLanguageVersion.Value;
var distinctClasses = classes.Distinct();
foreach (var c in distinctClasses.OfType<ClassDeclarationSyntax>())
{
@@ -100,13 +105,17 @@ public class DependencyPropertyGenerator : IIncrementalGenerator
var generatedClassBuilder = SyntaxBuilder.CreateClass(className)
.WithModifiers(string.Join(" ", c.Modifiers.Select(m => m.ToFullString())));
var generatedNamespaceBuilder = SyntaxBuilder.CreateNamespace(originalNamespaceSyntax.Name.ToFullString())
.WithClass(generatedClassBuilder);
var generatedCompilationUnit = SyntaxBuilder.CreateCompilationUnit()
.WithNamespace(
(languageVersion >= LanguageVersion.CSharp10 ?
SyntaxBuilder.CreateFileScopedNamespace(originalNamespaceSyntax.Name.ToFullString()) :
SyntaxBuilder.CreateNamespace(originalNamespaceSyntax.Name.ToFullString()))
.WithClass(generatedClassBuilder));
if (originalNamespaceSyntax.Usings.OfType<UsingDirectiveSyntax>().Any(u => u.Name?.ToString() == DependencyPropertyNamespace) is false &&
(originalNamespaceSyntax.Parent as CompilationUnitSyntax)?.Usings.Any(u => u.Name?.ToString() == DependencyPropertyNamespace) is false)
{
generatedNamespaceBuilder.WithUsing(DependencyPropertyNamespace);
generatedCompilationUnit.WithUsing(DependencyPropertyNamespace);
}
foreach (var field in c.DescendantNodes().OfType<FieldDeclarationSyntax>())
@@ -144,20 +153,20 @@ public class DependencyPropertyGenerator : IIncrementalGenerator
.WithField(dependencyPropertyFieldBuilder);
}
var generatedNamespace = generatedNamespaceBuilder.Build();
var generatedSyntax = generatedCompilationUnit.Build();
if (originalNamespaceSyntax.Usings.Count != 0)
{
generatedNamespace = generatedNamespace.AddUsings([.. originalNamespaceSyntax.Usings]);
generatedSyntax = generatedSyntax.AddUsings([.. originalNamespaceSyntax.Usings]);
}
else
{
if (originalNamespaceSyntax.Parent is CompilationUnitSyntax compilationUnit)
{
generatedNamespace = generatedNamespace.AddUsings([.. compilationUnit.Usings]);
generatedSyntax = generatedSyntax.AddUsings([.. compilationUnit.Usings]);
}
}
var fileSource = generatedNamespace.ToFullString();
var fileSource = generatedSyntax.ToFullString();
sourceProductionContext.AddSource($"{className}.g", fileSource);
}
}
@@ -3,6 +3,8 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
using Sybil;
using System.Linq;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp;
using System.Diagnostics;
namespace System.Extensions;
#nullable enable
@@ -22,8 +24,9 @@ public class NotifyPropertyChangedGenerator : IIncrementalGenerator
{
context.RegisterPostInitializationOutput(context =>
{
var attributeNamespaceBuilder = SyntaxBuilder.CreateNamespace(AttributeNamespace)
.WithUsing("System.ComponentModel")
var compilationUnitBuilder = SyntaxBuilder.CreateCompilationUnit()
.WithNamespace(
SyntaxBuilder.CreateNamespace(AttributeNamespace)
.WithClass(SyntaxBuilder.CreateClass(AttributeName)
.WithModifier(Public)
.WithConstructor(SyntaxBuilder.CreateConstructor(AttributeName)
@@ -32,9 +35,9 @@ public class NotifyPropertyChangedGenerator : IIncrementalGenerator
.WithArgument(AttributeTargets.Field)
.WithArgument("Inherited", false)
.WithArgument("AllowMultiple", false))
.WithBaseClass(nameof(Attribute)));
var attributeSyntax = attributeNamespaceBuilder.Build();
var source = attributeSyntax.ToFullString();
.WithBaseClass(nameof(Attribute))));
var compilationUnitSyntax = compilationUnitBuilder.Build();
var source = compilationUnitSyntax.ToFullString();
context.AddSource($"{AttributeName}.g", source);
});
@@ -60,13 +63,20 @@ public class NotifyPropertyChangedGenerator : IIncrementalGenerator
return default;
}
private static void Execute(Compilation _, ImmutableArray<ClassDeclarationSyntax?> classes, SourceProductionContext sourceProductionContext)
private static void Execute(Compilation compilation, ImmutableArray<ClassDeclarationSyntax?> classes, SourceProductionContext sourceProductionContext)
{
if (classes.IsDefaultOrEmpty)
{
return;
}
var maybeLanguageVersion = (compilation.SyntaxTrees.FirstOrDefault()?.Options as CSharpParseOptions)?.LanguageVersion;
if (!maybeLanguageVersion.HasValue)
{
return;
}
var languageVersion = maybeLanguageVersion.Value;
var distinctClasses = classes.Distinct();
foreach (var c in distinctClasses.OfType<ClassDeclarationSyntax>())
{
@@ -98,25 +108,12 @@ public class NotifyPropertyChangedGenerator : IIncrementalGenerator
var generatedClassBuilder = SyntaxBuilder.CreateClass(className)
.WithModifiers(string.Join(" ", c.Modifiers.Select(m => m.ToFullString())));
var generatedNamespaceBuilder = SyntaxBuilder.CreateNamespace(originalNamespaceSyntax.Name.ToFullString())
.WithClass(generatedClassBuilder);
if (originalNamespaceSyntax.Usings.Count != 0)
{
foreach (var u in originalNamespaceSyntax.Usings.OfType<UsingDirectiveSyntax>())
{
generatedNamespaceBuilder.WithUsing(u.Name?.ToString());
}
}
else
{
if (originalNamespaceSyntax.Parent is CompilationUnitSyntax compilationUnit)
{
foreach(var u in compilationUnit.Usings.OfType<UsingDirectiveSyntax>())
{
generatedNamespaceBuilder.WithUsing(u.Name?.ToString());
}
}
}
var compilationUnitBuilder = SyntaxBuilder.CreateCompilationUnit()
.WithNamespace(
(languageVersion >= LanguageVersion.CSharp10 ?
SyntaxBuilder.CreateFileScopedNamespace(originalNamespaceSyntax.Name.ToFullString()) :
SyntaxBuilder.CreateNamespace(originalNamespaceSyntax.Name.ToFullString()))
.WithClass(generatedClassBuilder));
foreach (var field in c.DescendantNodes().OfType<FieldDeclarationSyntax>())
{
@@ -141,7 +138,20 @@ public class NotifyPropertyChangedGenerator : IIncrementalGenerator
generatedClassBuilder.WithProperty(propertyBuilder);
}
var fileSource = generatedNamespaceBuilder.Build().ToFullString();
var generatedSyntax = compilationUnitBuilder.Build();
if (originalNamespaceSyntax.Usings.Count != 0)
{
generatedSyntax = generatedSyntax.AddUsings([.. originalNamespaceSyntax.Usings]);
}
else
{
if (originalNamespaceSyntax.Parent is CompilationUnitSyntax compilationUnit)
{
generatedSyntax = generatedSyntax.AddUsings([.. compilationUnit.Usings]);
}
}
var fileSource = generatedSyntax.ToFullString();
sourceProductionContext.AddSource($"{className}.g", fileSource);
}
}
@@ -7,7 +7,7 @@
<Authors>Alexandru Macocian</Authors>
<Description>Source generator library.</Description>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<Version>0.2.0</Version>
<Version>0.3.0</Version>
<LangVersion>latest</LangVersion>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
@@ -20,7 +20,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" PrivateAssets="all" />
<PackageReference Include="Sybil" Version="0.5.0" PrivateAssets="all" />
<PackageReference Include="Sybil" Version="0.6.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>