Skip to content

Commit

Permalink
Merge pull request #13 from ufcpp/roslyn_3_9_0
Browse files Browse the repository at this point in the history
Roslyn 3 9 0
  • Loading branch information
ufcpp authored Oct 3, 2021
2 parents 9bcfc86 + 0314645 commit 28f4a00
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 174 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
Expand Down
8 changes: 8 additions & 0 deletions src/StringLiteralGenerator/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"profiles": {
"StringLiteralGenerator": {
"commandName": "DebugRoslynComponent",
"targetProject": "..\\..\\samples\\StringLiteralSample\\StringLiteralSample.csproj"
}
}
}
3 changes: 2 additions & 1 deletion src/StringLiteralGenerator/StringLiteralGenerator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>
<IsRoslynComponent>true</IsRoslynComponent>
<IncludeBuildOutput>false</IncludeBuildOutput>

<PackageId>StringLiteralGenerator</PackageId>
Expand All @@ -18,7 +19,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.8.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.9.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2" PrivateAssets="all" />
</ItemGroup>

Expand Down
26 changes: 26 additions & 0 deletions src/StringLiteralGenerator/TypeInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Microsoft.CodeAnalysis;

namespace StringLiteralGenerator;

public partial class Utf8StringLiteralGenerator
{
private record struct TypeInfo(string? Namespace, string Name)
{
public TypeInfo(INamedTypeSymbol t)
: this(GetNamespace(t), t.Name)
{ }

private static string? GetNamespace(INamedTypeSymbol t)
{
var x = t.ContainingNamespace;
return string.IsNullOrEmpty(x.Name) ? null : x.ToDisplayString();
}
}

private record struct MethodInfo(string Name, Accessibility Accessibility, string Text)
{
public MethodInfo(IMethodSymbol m, string text)
: this(m.Name, m.DeclaredAccessibility, text)
{ }
}
}
84 changes: 84 additions & 0 deletions src/StringLiteralGenerator/Utf8StringLiteralGenerator.Emitter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using Microsoft.CodeAnalysis;
using System;
using System.Collections.Generic;
using System.Text;

namespace StringLiteralGenerator;

public partial class Utf8StringLiteralGenerator : ISourceGenerator
{
private static string GetFilename(TypeInfo type, StringBuilder buffer)
{
buffer.Clear();

if (type.Namespace is { } ns)
{
buffer.Append(ns.Replace('.', '_'));
buffer.Append('_');
}
buffer.Append(type.Name);
buffer.Append("_utf8literal.cs");

return buffer.ToString();
}

private static string Generate(TypeInfo type, IEnumerable<MethodInfo> methods, StringBuilder buffer)
{
var (ns, name) = type;

buffer.Clear();
buffer.AppendLine("// <auto-generated />");

if (ns is not null)
{
buffer.Append(@"namespace ");
buffer.Append(ns);
buffer.Append(@"
{
");
}
buffer.Append(@"partial class ");
buffer.Append(name);
buffer.Append(@"
{
");
foreach (var (methodName, accessibility, value) in methods)
{
buffer.Append(" ");
buffer.Append(AccessibilityText(accessibility));
buffer.Append(" static partial System.ReadOnlySpan<byte> ");
buffer.Append(methodName);
buffer.Append("() => new byte[] {");

foreach (var b in Encoding.UTF8.GetBytes(value))
{
buffer.Append(b);
buffer.Append(", ");
}

buffer.Append(@"};
");
}

buffer.Append(@"}
");
if (ns is not null)
{
buffer.Append(@"}
");
}

return buffer.ToString();
}

private static string AccessibilityText(Accessibility accessibility) => accessibility switch
{
Accessibility.Public => "public",
Accessibility.Protected => "protected",
Accessibility.Private => "private",
Accessibility.Internal => "internal",
Accessibility.ProtectedOrInternal => "protected internal",
Accessibility.ProtectedAndInternal => "private protected",
_ => throw new InvalidOperationException(),
};
}
26 changes: 26 additions & 0 deletions src/StringLiteralGenerator/Utf8StringLiteralGenerator.Init.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using System.Text;

namespace StringLiteralGenerator;

public partial class Utf8StringLiteralGenerator : ISourceGenerator
{
private const string attributeText = @"// <auto-generated />
using System;
namespace StringLiteral
{
[System.Diagnostics.Conditional(""COMPILE_TIME_ONLY"")]
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
sealed class Utf8Attribute : Attribute
{
public Utf8Attribute(string s) { }
}
}
";

private static void AddAttribute(GeneratorPostInitializationContext context)
{
context.AddSource("Utf8Attribute", SourceText.From(attributeText, Encoding.UTF8));
}
}
43 changes: 43 additions & 0 deletions src/StringLiteralGenerator/Utf8StringLiteralGenerator.Parser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace StringLiteralGenerator;

public partial class Utf8StringLiteralGenerator : ISourceGenerator
{
private const string attributeName = "StringLiteral.Utf8Attribute";

private static bool IsStaticPartial(MemberDeclarationSyntax m)
{
bool isStatic = false;
bool isPartial = false;
foreach (var mod in m.Modifiers)
{
isStatic |= mod.Text == "static";
isPartial |= mod.Text == "partial";
}
return isStatic && isPartial;
}

static bool ReturnsString(IMethodSymbol methodSymbol)
{
return methodSymbol.ReturnType is INamedTypeSymbol s
&& s.ToDisplayString() == "System.ReadOnlySpan<byte>";
}

static string? GetUtf8Attribute(IMethodSymbol methodSymbol)
{
foreach (var a in methodSymbol.GetAttributes())
{
if (a.AttributeClass?.ToDisplayString() == attributeName)
{
var args = a.ConstructorArguments;
if (args.Length != 1) continue;

if (args[0].Value is string value) return value;
}
}

return null;
}
}
Loading

0 comments on commit 28f4a00

Please sign in to comment.