diff --git a/generator.json b/generator.json
index 8bbae05cda..54df300afb 100644
--- a/generator.json
+++ b/generator.json
@@ -42,6 +42,7 @@
"AddIncludes",
"ClangScraper",
"MarkNativeNames",
+ "ExtractHandles",
"ExtractNestedTyping",
"TransformHandles",
"TransformFunctions",
@@ -59,8 +60,7 @@
"InputTestRoot": "tests/SDL"
},
"TransformHandles": {
- "AssumeMissingTypesOpaque": true,
- "UseDSL": true
+ "UseDsl": true
},
"TransformFunctions": {
"BoolTypes": {
@@ -228,6 +228,7 @@
"ChangeNativeClass",
"AddApiProfiles",
"MixKhronosData",
+ "ExtractHandles",
"ExtractNestedTyping",
"TransformHandles",
"InterceptNativeFunctions",
@@ -351,8 +352,7 @@
"BenefitOfTheDoubtArrayTransformation": true
},
"TransformHandles": {
- "AssumeMissingTypesOpaque": true,
- "UseDSL": true
+ "UseDsl": true
},
"StripAttributes": {
"Remove": [
@@ -370,6 +370,7 @@
"AddIncludes",
"ClangScraper",
"MarkNativeNames",
+ "ExtractHandles",
"ExtractNestedTyping",
"TransformHandles",
"MixKhronosData",
@@ -423,8 +424,7 @@
}
},
"TransformHandles": {
- "AssumeMissingTypesOpaque": true,
- "UseDSL": true
+ "UseDsl": true
},
"PrettifyNames": {
"GlobalPrefixHints": ["PFN_vk","vk"],
diff --git a/sources/SilkTouch/SilkTouch/Mods/Common/ModLoader.cs b/sources/SilkTouch/SilkTouch/Mods/Common/ModLoader.cs
index 8556bd7539..1f454cb49b 100644
--- a/sources/SilkTouch/SilkTouch/Mods/Common/ModLoader.cs
+++ b/sources/SilkTouch/SilkTouch/Mods/Common/ModLoader.cs
@@ -25,6 +25,7 @@ public class ModLoader
nameof(BakeSourceSets) => typeof(BakeSourceSets),
nameof(AddApiProfiles) => typeof(AddApiProfiles),
nameof(MixKhronosData) => typeof(MixKhronosData),
+ nameof(ExtractHandles) => typeof(ExtractHandles),
nameof(TransformHandles) => typeof(TransformHandles),
nameof(TransformEnums) => typeof(TransformEnums),
nameof(ExtractNestedTyping) => typeof(ExtractNestedTyping),
diff --git a/sources/SilkTouch/SilkTouch/Mods/ExtractHandles.cs b/sources/SilkTouch/SilkTouch/Mods/ExtractHandles.cs
new file mode 100644
index 0000000000..d1018b9caf
--- /dev/null
+++ b/sources/SilkTouch/SilkTouch/Mods/ExtractHandles.cs
@@ -0,0 +1,324 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.Extensions.Logging;
+using Silk.NET.SilkTouch.Naming;
+using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
+
+namespace Silk.NET.SilkTouch.Mods;
+
+///
+/// Adds empty handle structs by searching for missing types referenced through pointers.
+/// If all references to the missing type are through a pointer,
+/// that missing type is then added as an empty struct.
+///
+/// See for applying further transformations.
+///
+public class ExtractHandles(ILogger logger) : Mod
+{
+ ///
+ public override async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default)
+ {
+ await base.ExecuteAsync(ctx, ct);
+
+ var project = ctx.SourceProject;
+ if (project == null)
+ {
+ return;
+ }
+
+ var compilation = await project.GetCompilationAsync(ct);
+ if (compilation == null)
+ {
+ throw new InvalidOperationException("Failed to get compilation");
+ }
+
+ // Find missing handle types
+ var handleDiscoverer = new MissingHandleTypeDiscoverer(logger, compilation, ct);
+ var missingHandleTypes = handleDiscoverer.GetMissingHandleTypes();
+
+ // Generate syntax nodes containing empty structs to represent the missing handle types
+ var structGenerator = new EmptyStructGenerator();
+ var syntaxNodes = structGenerator.GenerateSyntaxNodes(missingHandleTypes);
+
+ // Add syntax nodes to the project as new documents
+ foreach (var (fullyQualifiedName, node) in syntaxNodes)
+ {
+ var relativePath = $"Handles/{PathForFullyQualified(fullyQualifiedName)}";
+ project = project
+ .AddDocument(
+ Path.GetFileName(relativePath),
+ node.NormalizeWhitespace(),
+ filePath: project.FullPath(relativePath)
+ )
+ .Project;
+ }
+
+ ctx.SourceProject = project;
+ }
+
+ private class MissingHandleTypeDiscoverer(
+ ILogger logger,
+ Compilation compilation,
+ CancellationToken ct
+ ) : SymbolVisitor
+ {
+ private readonly HashSet _nonHandleTypes =
+ new(SymbolEqualityComparer.Default);
+ private readonly Dictionary _missingTypes =
+ new(SymbolEqualityComparer.Default);
+
+ private string? _currentNamespace = null;
+ private int _pointerTypeDepth = 0;
+
+ ///
+ /// Gets all missing handle types that are found and the namespace that they should be created in.
+ ///
+ public Dictionary GetMissingHandleTypes()
+ {
+ // We need to find and generate all missing handle types
+ // Handle types are types that are only referenced through a pointer
+ // We do this by parsing through the list of type errors
+ var typeErrors = compilation
+ .GetDiagnostics(ct)
+ .Where(d => d.Id == "CS0246") // Type errors
+ .ToList();
+
+ // Find symbols that contain ITypeErrorSymbols
+ // These symbols are not necessarily ITypeErrorSymbols
+ var symbolsFound = new HashSet(SymbolEqualityComparer.Default);
+ foreach (var typeError in typeErrors)
+ {
+ var syntaxTree = typeError.Location.SourceTree;
+ if (syntaxTree == null)
+ {
+ continue;
+ }
+
+ var semanticModel = compilation.GetSemanticModel(syntaxTree);
+
+ // Get the syntax node the type error corresponds to
+ var currentSyntax = syntaxTree.GetRoot().FindNode(typeError.Location.SourceSpan);
+
+ // Search upwards to find a syntax node that we can call GetDeclaredSymbol on
+ // This is because calling GetDeclaredSymbol on the starting node will just return null
+ var isSuccess = false;
+ while (currentSyntax != null && currentSyntax is not TypeDeclarationSyntax)
+ {
+ switch (currentSyntax)
+ {
+ case VariableDeclarationSyntax variableDeclarationSyntax:
+ {
+ foreach (var declaratorSyntax in variableDeclarationSyntax.Variables)
+ {
+ var symbol = semanticModel.GetDeclaredSymbol(declaratorSyntax, ct);
+ if (symbol != null)
+ {
+ symbolsFound.Add(symbol);
+ isSuccess = true;
+
+ // All of the declarators will have the same type, so getting the first symbol is enough
+ break;
+ }
+ }
+
+ break;
+ }
+ case MemberDeclarationSyntax memberDeclarationSyntax:
+ {
+ var symbol = semanticModel.GetDeclaredSymbol(
+ memberDeclarationSyntax,
+ ct
+ );
+ if (symbol != null)
+ {
+ symbolsFound.Add(symbol);
+ isSuccess = true;
+ }
+
+ break;
+ }
+ // Skip syntaxes that will never contain handle types
+ case BaseTypeSyntax:
+ case AttributeSyntax:
+ {
+ isSuccess = true;
+ break;
+ }
+ }
+
+ currentSyntax = currentSyntax.Parent;
+ }
+
+ if (!isSuccess)
+ {
+ // This is to warn of unhandled cases
+ logger.LogWarning(
+ "Failed to find corresponding symbol for type error. There may be an unhandled case in the code"
+ );
+ }
+ }
+
+ // These symbols contain at least one IErrorTypeSymbol, we need to search downwards for them
+ foreach (var symbol in symbolsFound)
+ {
+ Visit(symbol);
+ }
+
+ return new Dictionary(
+ _missingTypes.Where(kvp => !_nonHandleTypes.Contains(kvp.Key)),
+ SymbolEqualityComparer.Default
+ );
+ }
+
+ public override void VisitMethod(IMethodSymbol symbol)
+ {
+ base.VisitMethod(symbol);
+
+ _currentNamespace = symbol.NamespaceFromSymbol();
+ foreach (var parameterSymbol in symbol.Parameters)
+ {
+ Visit(parameterSymbol);
+ }
+ _currentNamespace = null;
+ }
+
+ public override void VisitParameter(IParameterSymbol symbol)
+ {
+ base.VisitParameter(symbol);
+
+ _currentNamespace = symbol.NamespaceFromSymbol();
+ Visit(symbol.Type);
+ _currentNamespace = null;
+ }
+
+ public override void VisitProperty(IPropertySymbol symbol)
+ {
+ base.VisitProperty(symbol);
+
+ _currentNamespace = symbol.NamespaceFromSymbol();
+ Visit(symbol.Type);
+ _currentNamespace = null;
+ }
+
+ public override void VisitField(IFieldSymbol symbol)
+ {
+ base.VisitField(symbol);
+
+ _currentNamespace = symbol.NamespaceFromSymbol();
+ Visit(symbol.Type);
+ _currentNamespace = null;
+ }
+
+ public override void VisitLocal(ILocalSymbol symbol)
+ {
+ base.VisitLocal(symbol);
+
+ _currentNamespace = symbol.NamespaceFromSymbol();
+ Visit(symbol.Type);
+ _currentNamespace = null;
+ }
+
+ public override void VisitPointerType(IPointerTypeSymbol symbol)
+ {
+ base.VisitPointerType(symbol);
+
+ _pointerTypeDepth++;
+ Visit(symbol.PointedAtType);
+ _pointerTypeDepth--;
+ }
+
+ public override void VisitNamedType(INamedTypeSymbol symbol)
+ {
+ base.VisitNamedType(symbol);
+
+ if (symbol is IErrorTypeSymbol errorTypeSymbol)
+ {
+ if (_currentNamespace == null)
+ {
+ throw new InvalidOperationException(
+ $"{nameof(_currentNamespace)} should not be null"
+ );
+ }
+
+ if (_pointerTypeDepth == 0)
+ {
+ _nonHandleTypes.Add(errorTypeSymbol);
+ }
+
+ if (_missingTypes.TryGetValue(errorTypeSymbol, out var sharedNamespace))
+ {
+ _missingTypes[errorTypeSymbol] = NameUtils
+ .FindCommonPrefix([sharedNamespace, _currentNamespace], true, false, true)
+ .Trim('.');
+ }
+ else
+ {
+ _missingTypes[errorTypeSymbol] = _currentNamespace;
+ }
+ }
+ }
+ }
+
+ private class EmptyStructGenerator
+ {
+ ///
+ /// Generates a syntax node for each specified type.
+ ///
+ /// Map from error type symbol to the namespace the type should be created in.
+ /// Map from the fully qualified name of the generated type to the syntax node containing code for that type.
+ public Dictionary GenerateSyntaxNodes(
+ Dictionary typesToGenerate
+ ) =>
+ GenerateSyntaxNodes(
+ typesToGenerate
+ .Select(kvp => new KeyValuePair(kvp.Key.Name, kvp.Value))
+ .ToDictionary()
+ );
+
+ ///
+ /// Generates a syntax node for each specified type.
+ ///
+ /// Map from type name to the namespace the type should be created in.
+ /// Map from the fully qualified name of the generated type to the syntax node containing code for that type.
+ public Dictionary GenerateSyntaxNodes(
+ Dictionary missingHandleTypes
+ )
+ {
+ var results = new Dictionary();
+ foreach (var (name, ns) in missingHandleTypes)
+ {
+ var fullyQualifiedName = string.IsNullOrWhiteSpace(ns) ? name : $"{ns}.{name}";
+ var structDeclarationSyntax = StructDeclaration(name)
+ .WithModifiers(
+ TokenList(
+ Token(SyntaxKind.PublicKeyword),
+ Token(SyntaxKind.UnsafeKeyword),
+ Token(SyntaxKind.PartialKeyword)
+ )
+ );
+
+ results[fullyQualifiedName] = CompilationUnit()
+ .WithMembers(
+ SingletonList(
+ string.IsNullOrWhiteSpace(ns)
+ ? structDeclarationSyntax
+ : FileScopedNamespaceDeclaration(
+ ModUtils.NamespaceIntoIdentifierName(ns)
+ )
+ .WithMembers(
+ SingletonList(
+ structDeclarationSyntax
+ )
+ )
+ )
+ );
+ }
+
+ return results;
+ }
+ }
+}
diff --git a/sources/SilkTouch/SilkTouch/Mods/ExtractNestedTyping.cs b/sources/SilkTouch/SilkTouch/Mods/ExtractNestedTyping.cs
index fd53e3a615..215028fb15 100644
--- a/sources/SilkTouch/SilkTouch/Mods/ExtractNestedTyping.cs
+++ b/sources/SilkTouch/SilkTouch/Mods/ExtractNestedTyping.cs
@@ -322,11 +322,20 @@ mem is not StructDeclarationSyntax struc
continue;
}
- var iden = $"{node.Identifier}_{match.Groups[1].Value}";
+ var iden = $"{node.Identifier}{match.Groups[1].Value}";
_typeRenames[struc.Identifier.ToString()] = iden;
struc =
- VisitStructDeclaration(struc.WithIdentifier(Identifier(iden)))
- as StructDeclarationSyntax
+ VisitStructDeclaration(
+ struc
+ .WithIdentifier(Identifier(iden))
+ .WithAttributeLists(
+ struc.AttributeLists.AddResolvedNameAffix(
+ NameAffixType.Prefix,
+ "NestedStructParent",
+ node.Identifier.ToString()
+ )
+ )
+ ) as StructDeclarationSyntax
?? struc;
ExtractedNestedStructs.Add(struc);
members = members.RemoveAt(i--);
@@ -529,6 +538,11 @@ _fallbackFromOuterFunctionPointer is not null
: default
)
.WithNativeName(currentNativeTypeName)
+ .AddResolvedNameAffix(
+ NameAffixType.Prefix,
+ "FunctionPointerParent",
+ currentNativeTypeName
+ )
.AddNameAffix(
NameAffixType.Suffix,
"FunctionPointerDelegateType",
diff --git a/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs b/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs
index 5e958705c6..04feaa8cd0 100644
--- a/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs
+++ b/sources/SilkTouch/SilkTouch/Mods/TransformHandles.cs
@@ -25,11 +25,6 @@ namespace Silk.NET.SilkTouch.Mods;
/// VkBuffer*, usages of that pointer will be replaced by VkBufferHandle. For a 2-dimensional pointer,
/// VkBuffer**, the resulting replacement is VkBufferHandle*.
///
-///
-/// It is assumed that all handle types in the generated syntax do not require a using directive in order to be
-/// in scope. That is, if a file with the namespace Silk.NET.OpenGL is encountered and it is referencing
-/// Program, Program must be declared in Silk.NET.OpenGL, Silk.NET, or Silk.
-///
[ModConfiguration]
public class TransformHandles(
IOptionsSnapshot config,
@@ -41,16 +36,10 @@ ILogger logger
///
public class Config
{
- ///
- /// Whether it should be assumed that missing types are likely opaque if they are only used as a pointer type
- /// and therefore should be subjected to handle transformations.
- ///
- public bool AssumeMissingTypesOpaque { get; init; }
-
///
/// Whether the DSL (i.e. nullptr) should be usable with handle types.
///
- public bool UseDSL { get; init; }
+ public bool UseDsl { get; init; }
}
///
@@ -58,6 +47,7 @@ public override async Task ExecuteAsync(IModContext ctx, CancellationToken ct =
{
await base.ExecuteAsync(ctx, ct);
+ var cfg = config.Get(ctx.JobKey);
var project = ctx.SourceProject;
if (project == null)
{
@@ -70,45 +60,13 @@ public override async Task ExecuteAsync(IModContext ctx, CancellationToken ct =
throw new InvalidOperationException("Failed to get compilation");
}
- var cfg = config.Get(ctx.JobKey);
- if (cfg.AssumeMissingTypesOpaque)
- {
- // Find missing handle types
- var handleDiscoverer = new MissingHandleTypeDiscoverer(logger, compilation, ct);
- var missingHandleTypes = handleDiscoverer.GetMissingHandleTypes();
-
- // Generate syntax nodes containing empty structs to represent the missing handle types
- var structGenerator = new EmptyStructGenerator();
- var syntaxNodes = structGenerator.GenerateSyntaxNodes(missingHandleTypes);
-
- // Add syntax nodes to the project as new documents
- foreach (var (fullyQualifiedName, node) in syntaxNodes)
- {
- var relativePath = $"Handles/{PathForFullyQualified(fullyQualifiedName)}";
- project = project
- .AddDocument(
- Path.GetFileName(relativePath),
- node.NormalizeWhitespace(),
- filePath: project.FullPath(relativePath)
- )
- .Project;
- }
-
- // Update compilation
- compilation = await project.GetCompilationAsync(ct);
- if (compilation == null)
- {
- throw new InvalidOperationException("Failed to get compilation");
- }
- }
-
// Find handle documents
var handleTypeDiscoverer = new HandleTypeDiscoverer(project, compilation, ct);
var handleTypes = await handleTypeDiscoverer.GetHandleTypesAsync();
// Store handle document IDs for later
// We will use these IDs to know which documents to rewrite and rename
- var handleTypeDocumentIds = new List<(string OriginalName, DocumentId DocumentId)>();
+ var handleTypeDocumentIds = new List();
foreach (var handleTypeSymbol in handleTypes)
{
if (handleTypeSymbol.DeclaringSyntaxReferences.Length > 1)
@@ -124,7 +82,7 @@ public override async Task ExecuteAsync(IModContext ctx, CancellationToken ct =
var documentId = project.GetDocumentId(declaringSyntaxReference.SyntaxTree);
if (documentId != null)
{
- handleTypeDocumentIds.Add((handleTypeSymbol.Name, documentId));
+ handleTypeDocumentIds.Add(documentId);
}
}
@@ -141,8 +99,8 @@ [new PointerDimensionReductionTransformer()],
project = ctx.SourceProject;
// Use document IDs from earlier
- var handleTypeRewriter = new HandleTypeRewriter(cfg.UseDSL);
- foreach (var (originalName, documentId) in handleTypeDocumentIds)
+ var handleTypeRewriter = new HandleTypeRewriter(cfg.UseDsl);
+ foreach (var documentId in handleTypeDocumentIds)
{
var document =
project.GetDocument(documentId)
@@ -165,270 +123,6 @@ [new PointerDimensionReductionTransformer()],
}
ctx.SourceProject = project;
-
- return;
- }
-
- private class MissingHandleTypeDiscoverer(
- ILogger logger,
- Compilation compilation,
- CancellationToken ct
- ) : SymbolVisitor
- {
- private readonly HashSet _nonHandleTypes =
- new(SymbolEqualityComparer.Default);
- private readonly Dictionary _missingTypes =
- new(SymbolEqualityComparer.Default);
-
- private string? _currentNamespace = null;
- private int _pointerTypeDepth = 0;
-
- ///
- /// Gets all missing handle types that are found and the namespace that they should be created in.
- ///
- public Dictionary GetMissingHandleTypes()
- {
- // We need to find and generate all missing handle types
- // Handle types are types that are only referenced through a pointer
- // We do this by parsing through the list of type errors
- var typeErrors = compilation
- .GetDiagnostics(ct)
- .Where(d => d.Id == "CS0246") // Type errors
- .ToList();
-
- // Find symbols that contain ITypeErrorSymbols
- // These symbols are not necessarily ITypeErrorSymbols
- var symbolsFound = new HashSet(SymbolEqualityComparer.Default);
- foreach (var typeError in typeErrors)
- {
- var syntaxTree = typeError.Location.SourceTree;
- if (syntaxTree == null)
- {
- continue;
- }
-
- var semanticModel = compilation.GetSemanticModel(syntaxTree);
-
- // Get the syntax node the type error corresponds to
- var currentSyntax = syntaxTree.GetRoot().FindNode(typeError.Location.SourceSpan);
-
- // Search upwards to find a syntax node that we can call GetDeclaredSymbol on
- // This is because calling GetDeclaredSymbol on the starting node will just return null
- var isSuccess = false;
- while (currentSyntax != null && currentSyntax is not TypeDeclarationSyntax)
- {
- switch (currentSyntax)
- {
- case VariableDeclarationSyntax variableDeclarationSyntax:
- {
- foreach (var declaratorSyntax in variableDeclarationSyntax.Variables)
- {
- var symbol = semanticModel.GetDeclaredSymbol(declaratorSyntax, ct);
- if (symbol != null)
- {
- symbolsFound.Add(symbol);
- isSuccess = true;
-
- // All of the declarators will have the same type, so getting the first symbol is enough
- break;
- }
- }
-
- break;
- }
- case MemberDeclarationSyntax memberDeclarationSyntax:
- {
- var symbol = semanticModel.GetDeclaredSymbol(
- memberDeclarationSyntax,
- ct
- );
- if (symbol != null)
- {
- symbolsFound.Add(symbol);
- isSuccess = true;
- }
-
- break;
- }
- // Skip syntaxes that will never contain handle types
- case BaseTypeSyntax:
- case AttributeSyntax:
- {
- isSuccess = true;
- break;
- }
- }
-
- currentSyntax = currentSyntax.Parent;
- }
-
- if (!isSuccess)
- {
- // This is to warn of unhandled cases
- logger.LogWarning(
- "Failed to find corresponding symbol for type error. There may be an unhandled case in the code"
- );
- }
- }
-
- // These symbols contain at least one IErrorTypeSymbol, we need to search downwards for them
- foreach (var symbol in symbolsFound)
- {
- Visit(symbol);
- }
-
- return new Dictionary(
- _missingTypes.Where(kvp => !_nonHandleTypes.Contains(kvp.Key)),
- SymbolEqualityComparer.Default
- );
- }
-
- public override void VisitMethod(IMethodSymbol symbol)
- {
- base.VisitMethod(symbol);
-
- _currentNamespace = symbol.NamespaceFromSymbol();
- foreach (var parameterSymbol in symbol.Parameters)
- {
- Visit(parameterSymbol);
- }
- _currentNamespace = null;
- }
-
- public override void VisitParameter(IParameterSymbol symbol)
- {
- base.VisitParameter(symbol);
-
- _currentNamespace = symbol.NamespaceFromSymbol();
- Visit(symbol.Type);
- _currentNamespace = null;
- }
-
- public override void VisitProperty(IPropertySymbol symbol)
- {
- base.VisitProperty(symbol);
-
- _currentNamespace = symbol.NamespaceFromSymbol();
- Visit(symbol.Type);
- _currentNamespace = null;
- }
-
- public override void VisitField(IFieldSymbol symbol)
- {
- base.VisitField(symbol);
-
- _currentNamespace = symbol.NamespaceFromSymbol();
- Visit(symbol.Type);
- _currentNamespace = null;
- }
-
- public override void VisitLocal(ILocalSymbol symbol)
- {
- base.VisitLocal(symbol);
-
- _currentNamespace = symbol.NamespaceFromSymbol();
- Visit(symbol.Type);
- _currentNamespace = null;
- }
-
- public override void VisitPointerType(IPointerTypeSymbol symbol)
- {
- base.VisitPointerType(symbol);
-
- _pointerTypeDepth++;
- Visit(symbol.PointedAtType);
- _pointerTypeDepth--;
- }
-
- public override void VisitNamedType(INamedTypeSymbol symbol)
- {
- base.VisitNamedType(symbol);
-
- if (symbol is IErrorTypeSymbol errorTypeSymbol)
- {
- if (_currentNamespace == null)
- {
- throw new InvalidOperationException(
- $"{nameof(_currentNamespace)} should not be null"
- );
- }
-
- if (_pointerTypeDepth == 0)
- {
- _nonHandleTypes.Add(errorTypeSymbol);
- }
-
- if (_missingTypes.TryGetValue(errorTypeSymbol, out var sharedNamespace))
- {
- _missingTypes[errorTypeSymbol] = NameUtils
- .FindCommonPrefix([sharedNamespace, _currentNamespace], true, false, true)
- .Trim('.');
- }
- else
- {
- _missingTypes[errorTypeSymbol] = _currentNamespace;
- }
- }
- }
- }
-
- private class EmptyStructGenerator
- {
- ///
- /// Generates a syntax node for each specified type.
- ///
- /// Map from error type symbol to the namespace the type should be created in.
- /// Map from the fully qualified name of the generated type to the syntax node containing code for that type.
- public Dictionary GenerateSyntaxNodes(
- Dictionary typesToGenerate
- ) =>
- GenerateSyntaxNodes(
- typesToGenerate
- .Select(kvp => new KeyValuePair(kvp.Key.Name, kvp.Value))
- .ToDictionary()
- );
-
- ///
- /// Generates a syntax node for each specified type.
- ///
- /// Map from type name to the namespace the type should be created in.
- /// Map from the fully qualified name of the generated type to the syntax node containing code for that type.
- public Dictionary GenerateSyntaxNodes(
- Dictionary missingHandleTypes
- )
- {
- var results = new Dictionary();
- foreach (var (name, ns) in missingHandleTypes)
- {
- var fullyQualifiedName = string.IsNullOrWhiteSpace(ns) ? name : $"{ns}.{name}";
- var structDeclarationSyntax = StructDeclaration(name)
- .WithModifiers(
- TokenList(
- Token(SyntaxKind.PublicKeyword),
- Token(SyntaxKind.UnsafeKeyword),
- Token(SyntaxKind.PartialKeyword)
- )
- );
-
- results[fullyQualifiedName] = CompilationUnit()
- .WithMembers(
- SingletonList(
- string.IsNullOrWhiteSpace(ns)
- ? structDeclarationSyntax
- : FileScopedNamespaceDeclaration(
- ModUtils.NamespaceIntoIdentifierName(ns)
- )
- .WithMembers(
- SingletonList(
- structDeclarationSyntax
- )
- )
- )
- );
- }
-
- return results;
- }
}
private class HandleTypeDiscoverer(
@@ -533,7 +227,7 @@ public override void VisitNamedType(INamedTypeSymbol symbol)
}
}
- private class HandleTypeRewriter(bool useDSL) : CSharpSyntaxRewriter
+ private class HandleTypeRewriter(bool useDsl) : CSharpSyntaxRewriter
{
public override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node)
{
@@ -547,7 +241,7 @@ public override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node)
.WithMembers(
List(
GetDefaultHandleMembers(structName)
- .Concat(useDSL ? GetDSLHandleMembers(structName) : [])
+ .Concat(useDsl ? GetDslHandleMembers(structName) : [])
)
)
.WithModifiers(
@@ -629,7 +323,7 @@ string structName
Identifier("Equals")
)
.WithModifiers(
- TokenList([Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)])
+ TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword))
)
.WithParameterList(
ParameterList(
@@ -668,7 +362,7 @@ string structName
Identifier("GetHashCode")
)
.WithModifiers(
- TokenList([Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword)])
+ TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.OverrideKeyword))
)
.WithExpressionBody(
ArrowExpressionClause(
@@ -700,7 +394,7 @@ string structName
Token(SyntaxKind.EqualsEqualsToken)
)
.WithModifiers(
- TokenList([Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)])
+ TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword))
)
.WithParameterList(
ParameterList(
@@ -737,7 +431,7 @@ string structName
Token(SyntaxKind.ExclamationEqualsToken)
)
.WithModifiers(
- TokenList([Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)])
+ TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword))
)
.WithParameterList(
ParameterList(
@@ -771,7 +465,7 @@ string structName
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
}
- private static IEnumerable GetDSLHandleMembers(string structName)
+ private static IEnumerable GetDslHandleMembers(string structName)
{
yield return MethodDeclaration(
PredefinedType(Token(SyntaxKind.BoolKeyword)),
@@ -800,7 +494,7 @@ private static IEnumerable GetDSLHandleMembers(string s
Token(SyntaxKind.EqualsEqualsToken)
)
.WithModifiers(
- TokenList([Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)])
+ TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword))
)
.WithParameterList(
ParameterList(
@@ -837,7 +531,7 @@ private static IEnumerable GetDSLHandleMembers(string s
Token(SyntaxKind.ExclamationEqualsToken)
)
.WithModifiers(
- TokenList([Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)])
+ TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword))
)
.WithParameterList(
ParameterList(
@@ -875,7 +569,7 @@ private static IEnumerable GetDSLHandleMembers(string s
IdentifierName(structName)
)
.WithModifiers(
- TokenList([Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword)])
+ TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.StaticKeyword))
)
.WithParameterList(
ParameterList(
diff --git a/sources/SilkTouch/SilkTouch/Naming/NameAffixer.cs b/sources/SilkTouch/SilkTouch/Naming/NameAffixer.cs
index a778a7d2dc..5a160814f2 100644
--- a/sources/SilkTouch/SilkTouch/Naming/NameAffixer.cs
+++ b/sources/SilkTouch/SilkTouch/Naming/NameAffixer.cs
@@ -92,17 +92,87 @@ public static SyntaxList AddNameAffix(
Literal($"\"{affixType}\"", affixType)
)
);
+
var categoryArgument = AttributeArgument(
LiteralExpression(
SyntaxKind.StringLiteralExpression,
Literal($"\"{category}\"", category)
)
);
+
var affixArgument = AttributeArgument(
LiteralExpression(SyntaxKind.StringLiteralExpression, Literal($"\"{affix}\"", affix))
);
+
var argumentList = AttributeArgumentList([typeArgument, categoryArgument, affixArgument]);
+ var attribute = AttributeList([Attribute(IdentifierName("NameAffix"), argumentList)]);
+
+ return addToInner ? [attribute, .. attributeLists] : [.. attributeLists, attribute];
+ }
+
+ ///
+ /// This is similar to
+ /// but allows the name of another symbol to be referenced.
+ ///
+ /// This ensures transformations applied to the referenced symbol's name
+ /// are also applied to this affix.
+ ///
+ ///
+ /// This allows compound names to be handled more cleanly.
+ ///
+ ///
+ /// For example, PerformanceCounterDescriptionARM can be used as a resolved prefix for PerformanceCounterDescriptionARMName.
+ /// If PerformanceCounterDescriptionARM becomes ARMPerformanceCounterDescription,
+ /// then PerformanceCounterDescriptionARMName will also be output as ARMPerformanceCounterDescriptionName.
+ ///
+ public static SyntaxList AddResolvedNameAffix(
+ this IEnumerable attributeLists,
+ NameAffixType type,
+ string category,
+ string resolvedAffix,
+ bool addToInner = false
+ )
+ {
+ var affixType = type switch
+ {
+ NameAffixType.Prefix => "Prefix",
+ NameAffixType.Suffix => "Suffix",
+ _ => throw new ArgumentOutOfRangeException(nameof(type)),
+ };
+
+ var typeArgument = AttributeArgument(
+ LiteralExpression(
+ SyntaxKind.StringLiteralExpression,
+ Literal($"\"{affixType}\"", affixType)
+ )
+ );
+
+ var categoryArgument = AttributeArgument(
+ LiteralExpression(
+ SyntaxKind.StringLiteralExpression,
+ Literal($"\"{category}\"", category)
+ )
+ );
+ // nameof(resolvedAffix)
+ var affixArgument = AttributeArgument(
+ InvocationExpression(
+ IdentifierName(
+ Identifier(
+ TriviaList(),
+ SyntaxKind.NameOfKeyword,
+ "nameof",
+ "nameof",
+ TriviaList()
+ )
+ )
+ )
+ .WithArgumentList(
+ ArgumentList(SingletonSeparatedList(Argument(IdentifierName(resolvedAffix))))
+ )
+ );
+
+ var argumentList = AttributeArgumentList([typeArgument, categoryArgument, affixArgument]);
var attribute = AttributeList([Attribute(IdentifierName("NameAffix"), argumentList)]);
return addToInner ? [attribute, .. attributeLists] : [.. attributeLists, attribute];