You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
3.7 KiB
118 lines
3.7 KiB
using System.Linq; |
|
using System.Text; |
|
using Microsoft.CodeAnalysis; |
|
using Microsoft.CodeAnalysis.CSharp; |
|
|
|
namespace gaemstone.SourceGen.Utility; |
|
|
|
public static class SymbolExtensions |
|
{ |
|
public static bool IsNullable(this ITypeSymbol type) => type.IsValueType |
|
? (type.OriginalDefinition?.SpecialType == SpecialType.System_Nullable_T) |
|
: (type.NullableAnnotation == NullableAnnotation.Annotated); |
|
|
|
public static bool IsPrimitiveType(this ITypeSymbol symbol) |
|
=> symbol.SpecialType switch { |
|
SpecialType.System_Boolean or |
|
SpecialType.System_SByte or |
|
SpecialType.System_Int16 or |
|
SpecialType.System_Int32 or |
|
SpecialType.System_Int64 or |
|
SpecialType.System_Byte or |
|
SpecialType.System_UInt16 or |
|
SpecialType.System_UInt32 or |
|
SpecialType.System_UInt64 or |
|
SpecialType.System_Single or |
|
SpecialType.System_Double or |
|
SpecialType.System_Char or |
|
SpecialType.System_String or |
|
SpecialType.System_Object => true, |
|
_ => false, |
|
}; |
|
|
|
public static string GetFullName( |
|
this ISymbol symbol, FullNameStyle style = FullNameStyle.Full) |
|
{ |
|
var builder = new StringBuilder(); |
|
AppendFullName(symbol, builder, style); |
|
return builder.ToString(); |
|
} |
|
|
|
public static void AppendFullName( |
|
this ISymbol symbol, StringBuilder builder, |
|
FullNameStyle style = FullNameStyle.Full) |
|
{ |
|
var withGeneric = (style != FullNameStyle.NoGeneric); |
|
var withMetadata = (style == FullNameStyle.Metadata); |
|
|
|
if ((symbol.Kind != SymbolKind.TypeParameter) |
|
&& (symbol.ContainingSymbol is ISymbol parent) |
|
&& (parent is not INamespaceSymbol { IsGlobalNamespace: true })) |
|
{ |
|
AppendFullName(parent, builder, style); |
|
builder.Append((withMetadata && (parent is ITypeSymbol)) ? '+' : '.'); |
|
} |
|
|
|
if ((symbol is INamedTypeSymbol { IsGenericType: true } typeSymbol) |
|
&& !(withGeneric && withMetadata)) |
|
{ |
|
var length = symbol.MetadataName.IndexOf('`'); |
|
builder.Append(symbol.MetadataName, 0, length); |
|
|
|
if (withGeneric) { |
|
builder.Append('<'); |
|
foreach (var arg in typeSymbol.TypeArguments) { |
|
AppendFullName(arg, builder, style); |
|
builder.Append(','); |
|
} |
|
builder.Length--; // Remove the last ',' character. |
|
builder.Append('>'); |
|
} |
|
} |
|
else builder.Append(symbol.MetadataName); |
|
} |
|
|
|
public static string? GetNamespace(this ISymbol symbol) |
|
=> symbol.ContainingNamespace?.GetFullName(); |
|
|
|
public static bool HasAttribute(this ISymbol symbol, string name, |
|
FullNameStyle matchStyle = FullNameStyle.Metadata) |
|
=> symbol.GetAttributes().Any(attr => |
|
attr.AttributeClass!.GetFullName(matchStyle) == name); |
|
|
|
public static AttributeData? FindAttribute(this ISymbol symbol, string name, |
|
FullNameStyle matchStyle = FullNameStyle.Metadata) |
|
=> symbol.GetAttributes().FirstOrDefault(attr => |
|
attr.AttributeClass!.GetFullName(matchStyle) == name); |
|
|
|
public static string ToStringLiteral(this string? input) |
|
=> (input != null) ? SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, |
|
SyntaxFactory.Literal(input)).ToFullString() : "null"; |
|
} |
|
|
|
public enum FullNameStyle |
|
{ |
|
Full, // Namespace.Foo.Bar<Baz<Quux>> |
|
Metadata, // Namespace.Foo+Bar`1 |
|
NoGeneric, // Namespace.Foo.Bar |
|
} |
|
|
|
public struct StringifyOptions |
|
{ |
|
public static readonly StringifyOptions Default = new(); |
|
public static readonly StringifyOptions StripGeneric = new(){ Generic = GenericDisplayMode.None }; |
|
public static readonly StringifyOptions MetadataGeneric = new(){ Generic = GenericDisplayMode.Metadata }; |
|
|
|
public bool Namespace { get; set; } = true; |
|
// TODO: public bool FriendlyNames { get; set; } = true; |
|
public GenericDisplayMode Generic { get; set; } = GenericDisplayMode.Full; |
|
|
|
public StringifyOptions() { } |
|
|
|
public enum GenericDisplayMode |
|
{ |
|
None, // Foo |
|
Metadata, // Foo`1 |
|
Full, // Foo<Bar<Baz>> |
|
} |
|
}
|
|
|