Source Generation
This is v1 of the new source generator.
This commit is contained in:
parent
db04b3b356
commit
84af952300
94
.gitignore
vendored
Normal file
94
.gitignore
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
# ---> JetBrains
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
.idea/**/.idea/**
|
||||
.idea/**/.idea/
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
16
ServerDatabase.SourceGenerator.sln
Normal file
16
ServerDatabase.SourceGenerator.sln
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerDatabase.SourceGenerator", "ServerDatabase.SourceGenerator\ServerDatabase.SourceGenerator.csproj", "{2F4102DB-3F1D-463F-AC27-EA56616DA96D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2F4102DB-3F1D-463F-AC27-EA56616DA96D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2F4102DB-3F1D-463F-AC27-EA56616DA96D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2F4102DB-3F1D-463F-AC27-EA56616DA96D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2F4102DB-3F1D-463F-AC27-EA56616DA96D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -0,0 +1,31 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<LangVersion>latestmajor</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<IncludeBuildOutput>true</IncludeBuildOutput>
|
||||
<Version>1.0.0</Version>
|
||||
<Title>Server Database Source Generator</Title>
|
||||
<Authors>JacobTech</Authors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CustomActionsAfterPack" AfterTargets="Pack">
|
||||
<Message Text="Actions AfterPack: $(PackageId).$(PackageVersion).nupkg" Importance="high" />
|
||||
<Exec Command="nuget push -Source https://nuget.jacobtech.com/v3/index.json bin/Release/$(PackageId).$(PackageVersion).nupkg" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
12
ServerDatabase.SourceGenerator/TableRowAttribute.cs
Normal file
12
ServerDatabase.SourceGenerator/TableRowAttribute.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace ServerDatabase.SourceGenerator;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
|
||||
public sealed class TableRowAttribute : Attribute
|
||||
{
|
||||
public TableRowAttribute(Type type)
|
||||
{
|
||||
this.Type = type;
|
||||
}
|
||||
|
||||
public Type Type { get; private set; }
|
||||
}
|
109
ServerDatabase.SourceGenerator/TableRowGenerator.cs
Normal file
109
ServerDatabase.SourceGenerator/TableRowGenerator.cs
Normal file
@ -0,0 +1,109 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using TypeInfo = Microsoft.CodeAnalysis.TypeInfo;
|
||||
|
||||
namespace ServerDatabase.SourceGenerator;
|
||||
|
||||
[Generator]
|
||||
public class TableRowGenerator : ISourceGenerator
|
||||
{
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
#if DEBUG
|
||||
if (!Debugger.IsAttached) Debugger.Launch();
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
INamedTypeSymbol? attributeSymbol = context.Compilation.GetTypeByMetadataName(typeof(TableRowAttribute).FullName);
|
||||
|
||||
IEnumerable<SyntaxTree> classWithAttributes = context.Compilation.SyntaxTrees.Where(st => st.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>()
|
||||
.Any(p => p.DescendantNodes().OfType<AttributeSyntax>().Any()));
|
||||
|
||||
foreach (SyntaxTree? tree in classWithAttributes)
|
||||
{
|
||||
if (tree is null) continue;
|
||||
SemanticModel semanticModel = context.Compilation.GetSemanticModel(tree);
|
||||
foreach (ClassDeclarationSyntax? declaredClass in tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().Where(cd => cd.DescendantNodes().OfType<AttributeSyntax>().Any()))
|
||||
{
|
||||
if (declaredClass is null) continue;
|
||||
List<SyntaxToken>? nodes = declaredClass
|
||||
.DescendantNodes()
|
||||
.OfType<AttributeSyntax>()
|
||||
.FirstOrDefault(a => a.DescendantTokens().Any(dt => dt.IsKind(SyntaxKind.IdentifierToken) && dt.Parent is not null && semanticModel.GetTypeInfo(dt.Parent).Type is not null && semanticModel.GetTypeInfo(dt.Parent).Type.Name == attributeSymbol.Name))
|
||||
?.DescendantTokens()
|
||||
?.Where(dt => dt.IsKind(SyntaxKind.IdentifierToken))
|
||||
?.ToList();
|
||||
|
||||
if(nodes == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TypeInfo relatedClass = semanticModel.GetTypeInfo(nodes.Last().Parent);
|
||||
|
||||
StringBuilder generatedClass = this.GenerateClass(tree.GetRoot().DescendantNodes().OfType<FileScopedNamespaceDeclarationSyntax>().First().Name.ToString(), declaredClass);
|
||||
|
||||
foreach(IPropertySymbol? classProperty in relatedClass.Type.GetMembers().OfType<IPropertySymbol>())
|
||||
{
|
||||
this.GenerateProperty(classProperty, ref generatedClass);
|
||||
}
|
||||
|
||||
this.CloseClass(generatedClass);
|
||||
|
||||
context.AddSource($"{declaredClass.Identifier}_{relatedClass.Type.Name}.g.cs", SourceText.From(generatedClass.ToString(), Encoding.UTF8));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
context.AddSource("teste.g.cs", SourceText.From(@$"using System;
|
||||
namespace ServerDatabase.SourceGenerator.Generated
|
||||
{{
|
||||
public class bobe
|
||||
{{
|
||||
public string e = @""{e}"";
|
||||
}}
|
||||
}}", Encoding.UTF8));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private void GenerateProperty(IPropertySymbol prop, ref StringBuilder builder)
|
||||
{
|
||||
string bad = prop.Type.ToString();
|
||||
bad = bad.Replace("ServerDatabase.TableColumn<", "");
|
||||
bad = bad.Remove(bad.LastIndexOf('>'));
|
||||
builder.AppendLine($" public {bad} {prop.Name} {{ get; set; }}");
|
||||
}
|
||||
|
||||
private StringBuilder GenerateClass(string n, ClassDeclarationSyntax og)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append(@$"using System;
|
||||
|
||||
namespace {n}
|
||||
{{
|
||||
public partial class " + og.Identifier);
|
||||
|
||||
sb.Append(@"
|
||||
{
|
||||
");
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
private void CloseClass(StringBuilder generatedClass)
|
||||
{
|
||||
generatedClass.Append(
|
||||
@" }
|
||||
}");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user