2using Microsoft.CodeAnalysis;
6public static class SymbolExtension
8 public static bool IsTarget(
this ISymbol symbol)
10 if (symbol is INamespaceOrTypeSymbol t && t.GetMembers().Any(IsTarget))
12 return symbol.GetAttributes().Any(attr => attr.AttributeClass?.Name ==
"ExportAttribute");
15 public static IEnumerable<INamedTypeSymbol> GetAllTypes(
this INamespaceOrTypeSymbol symbol)
17 if (symbol is INamedTypeSymbol t)
19 foreach (var child
in symbol.GetMembers().OfType<INamespaceOrTypeSymbol>())
20 foreach (var ret
in child.GetAllTypes())
24 public static string GetFullName(
this ISymbol symbol,
string delimiter =
".")
26 var queue =
new Stack<string>();
27 while (symbol is INamespaceOrTypeSymbol or IMethodSymbol)
29 if (!
string.IsNullOrWhiteSpace(symbol.Name))
30 queue.Push(symbol.Name);
31 symbol = symbol.ContainingSymbol;
34 var builder =
new StringBuilder();
35 for (var first =
true; queue.Count > 0; first =
false)
38 builder.Append(delimiter);
39 builder.Append(queue.Pop());
42 return builder.ToString();
45 private static string? ToMangleCode(
this ITypeSymbol type)
47 if (type.IsReferenceType)
50 return type.GetFullName()
switch
52 "System.SByte" =>
"s8",
53 "System.Int16" =>
"s16",
54 "System.Int32" =>
"s32",
55 "System.Int64" =>
"s64",
56 "System.Byte" =>
"u8",
57 "System.UInt16" =>
"u16",
58 "System.UInt32" =>
"u32",
59 "System.UInt64" =>
"u64",
60 "System.Half" =>
"fp16",
61 "System.Single" =>
"fp32",
62 "System.Double" =>
"fp64",
67 public static string ToNativeBridgeType(
this ITypeSymbol type)
69 return type.GetFullName(
"::")
switch
71 "System::SByte" =>
"int8_t",
72 "System::Int16" =>
"int16_t",
73 "System::Int32" =>
"int32_t",
74 "System::Int64" =>
"int64_t",
75 "System::Byte" =>
"uint8_t",
76 "System::UInt16" =>
"uint16_t",
77 "System::UInt32" =>
"uint32_t",
78 "System::UInt64" =>
"uint64_t",
79 "System::Half" =>
"_Float16",
80 "System::Single" =>
"float",
81 "System::Double" =>
"double",
86 public static string ToNativeInterfaceType(
this ITypeSymbol type,
bool ret =
false)
88 var name = type.GetFullName(
"::");
91 "System::SByte" =>
"int8_t",
92 "System::Int16" =>
"int16_t",
93 "System::Int32" =>
"int32_t",
94 "System::Int64" =>
"int64_t",
95 "System::Byte" =>
"uint8_t",
96 "System::UInt16" =>
"uint16_t",
97 "System::UInt32" =>
"uint32_t",
98 "System::UInt64" =>
"uint64_t",
99 "System::Half" =>
"_Float16",
100 "System::Single" =>
"float",
101 "System::Double" =>
"double",
102 _ => ret ? name : $
"{name}&"
106 private static bool IsRootNamespace(ISymbol symbol)
109 return (s = symbol as INamespaceSymbol) !=
null && s.IsGlobalNamespace;
112 public static string GetFullyQualifiedName(
this ISymbol? s)
114 if (s ==
null || IsRootNamespace(s))
119 var
asm = s.ContainingAssembly;
121 var sb =
new StringBuilder(s.MetadataName);
124 s = s.ContainingSymbol;
126 while (!IsRootNamespace(s))
128 if (s is ITypeSymbol && last is ITypeSymbol)
137 sb.Insert(0, s.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat));
139 s = s.ContainingSymbol;
142 return $
"{sb}, {asm}";
145 private static Diagnostic UnsupportedType(ITypeSymbol type)
146 => Diagnostic.Create(
148 $
"'{GetFullName(type)}' is not supported by MLLIF",
149 DiagnosticSeverity.Error, DiagnosticSeverity.Error,
152 public static string? MangleName(
this IMethodSymbol method, SourceProductionContext? spc =
null)
154 var builder =
new StringBuilder();
155 builder.Append(
"__mllif__").Append(method.Name);
157 foreach (var param
in method.Parameters)
159 if (param.Type.ToMangleCode() is not { } code)
161 spc?.ReportDiagnostic(UnsupportedType(param.Type));
165 builder.Append(
'_').Append(code.Replace(
'*',
'p'));
168 return builder.ToString();