diff --git a/generator.json b/generator.json
index 1d08ab7d61..6c68161c18 100644
--- a/generator.json
+++ b/generator.json
@@ -68,6 +68,11 @@
"SDL_bool": null
}
},
+ "TransformProperties": {
+ "BoolTypes": {
+ "SDL_bool": null
+ }
+ },
"IdentifySharedPrefixes": {
"GlobalPrefixHints": ["SDL"]
},
@@ -224,6 +229,11 @@
"GLboolean": null
}
},
+ "TransformProperties": {
+ "BoolTypes": {
+ "GLboolean": null
+ }
+ },
"StripAttributes": {
"Remove": [
"NativeTypeName",
@@ -361,6 +371,12 @@
},
"BenefitOfTheDoubtArrayTransformation": true
},
+ "TransformProperties": {
+ "BoolTypes": {
+ "ALboolean": null,
+ "ALCboolean": null
+ }
+ },
"TransformHandles": {
"UseDsl": true
},
@@ -434,6 +450,11 @@
"VkBool32": null
}
},
+ "TransformProperties": {
+ "BoolTypes": {
+ "VkBool32": null
+ }
+ },
"TransformHandles": {
"UseDsl": true
},
diff --git a/sources/SilkTouch/SilkTouch/Mods/TransformFunctions.cs b/sources/SilkTouch/SilkTouch/Mods/TransformFunctions.cs
index 1d97c3a230..e106d5ad98 100644
--- a/sources/SilkTouch/SilkTouch/Mods/TransformFunctions.cs
+++ b/sources/SilkTouch/SilkTouch/Mods/TransformFunctions.cs
@@ -1,11 +1,8 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
+// 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.Syntax;
-using Silk.NET.SilkTouch.Clang;
using Silk.NET.SilkTouch.Mods.Transformation;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
@@ -30,9 +27,9 @@ public class Configuration
public required bool IntReturnsMaybeBool { get; init; }
///
- /// Types to treat as boolean and their boolean schemes if different to default.
+ /// Types to treat as boolean and their boolean schemes if different from the default.
///
- public Dictionary? BoolTypes { get; init; }
+ public Dictionary BoolTypes { get; init; } = [];
}
///
diff --git a/sources/SilkTouch/SilkTouch/Mods/TransformProperties.cs b/sources/SilkTouch/SilkTouch/Mods/TransformProperties.cs
index 4ce2a40291..ac49ebb763 100644
--- a/sources/SilkTouch/SilkTouch/Mods/TransformProperties.cs
+++ b/sources/SilkTouch/SilkTouch/Mods/TransformProperties.cs
@@ -1,29 +1,50 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
-using System.Threading;
-using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.Extensions.Options;
+using Silk.NET.SilkTouch.Mods.Transformation;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace Silk.NET.SilkTouch.Mods;
///
-/// Applies transformations to property signatures.
+/// Applies transformations to fields and properties.
///
///
-/// Today, this only includes transforming properties like static ReadOnlySpan<byte> Thing => "thing"u8;
-/// to be static Utf8String Thing => "thing"u8;.
+/// Despite the name of the name, fields are also handled here because
+/// they often need to be transformed alongside properties.
+///
+/// This currently does the following transformations:
+/// 1. Transform string constant properties like
+/// static ReadOnlySpan<byte> Thing => "thing"u8; to be
+/// static Utf8String Thing => "thing"u8;.
+/// 2. Transform fields and properties that are recognised
+/// to be akin to booleans to use the MaybeBool type.
+/// This functionality is based on .
///
-public class TransformProperties : IMod
+[ModConfiguration]
+public class TransformProperties(IOptionsSnapshot cfg) : IMod
{
+ ///
+ /// Configuration for the .
+ ///
+ public class Configuration
+ {
+ ///
+ /// Types to treat as boolean and their boolean schemes if different from the default.
+ ///
+ public Dictionary BoolTypes { get; init; } = [];
+ }
+
///
public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default)
{
- var rw = new Rewriter();
+ var config = cfg.Get(ctx.JobKey);
+
+ var rw = new Rewriter(config);
var proj = ctx.SourceProject;
foreach (var docId in ctx.SourceProject?.DocumentIds ?? [])
{
@@ -38,17 +59,75 @@ public async Task ExecuteAsync(IModContext ctx, CancellationToken ct = default)
ctx.SourceProject = proj;
}
- private class Rewriter : CSharpSyntaxRewriter
+ private class Rewriter(Configuration config) : CSharpSyntaxRewriter
{
+ public override SyntaxNode? VisitFieldDeclaration(FieldDeclarationSyntax node)
+ {
+ // Transform bool-like fields to use MaybeBool
+ var nativeType =
+ node.AttributeLists.GetNativeTypeName() ?? node.Declaration.Type.ToString();
+ if (
+ config.BoolTypes.TryGetValue(nativeType, out var scheme)
+ || (nativeType == "bool" && node.Declaration.Type.ToString().Trim() != "bool") // stdbool.h, hopefully...
+ )
+ {
+ var newType = string.IsNullOrWhiteSpace(scheme)
+ ? GenericName(
+ Identifier("MaybeBool"),
+ TypeArgumentList(SingletonSeparatedList(node.Declaration.Type))
+ )
+ : GenericName(
+ Identifier("MaybeBool"),
+ TypeArgumentList(
+ SeparatedList(
+ // ReSharper disable once RedundantCast <-- false positive
+ (IEnumerable)
+ [node.Declaration.Type, IdentifierName(scheme)]
+ )
+ )
+ );
+
+ node = node.WithDeclaration(node.Declaration.WithType(newType));
+ }
+
+ return base.VisitFieldDeclaration(node);
+ }
+
public override SyntaxNode? VisitPropertyDeclaration(PropertyDeclarationSyntax node)
{
+ // Transform bool-like properties to use MaybeBool
+ var nativeType = node.AttributeLists.GetNativeTypeName() ?? node.Type.ToString();
+ if (
+ config.BoolTypes.TryGetValue(nativeType, out var scheme)
+ || (nativeType == "bool" && node.Type.ToString().Trim() != "bool") // stdbool.h, hopefully...
+ )
+ {
+ var newType = string.IsNullOrWhiteSpace(scheme)
+ ? GenericName(
+ Identifier("MaybeBool"),
+ TypeArgumentList(SingletonSeparatedList(node.Type))
+ )
+ : GenericName(
+ Identifier("MaybeBool"),
+ TypeArgumentList(
+ SeparatedList(
+ // ReSharper disable once RedundantCast <-- false positive
+ (IEnumerable)[node.Type, IdentifierName(scheme)]
+ )
+ )
+ );
+
+ node = node.WithType(newType);
+ }
+
+ // Transform ReadOnlySpan string constants to use Utf8String
if (
node.Modifiers.Any(SyntaxKind.StaticKeyword)
&& node.Type
is GenericNameSyntax
{
TypeArgumentList.Arguments: [PredefinedTypeSyntax pt],
- Identifier.Text: "ReadOnlySpan"
+ Identifier.Text: "ReadOnlySpan",
}
&& (
pt.Keyword.IsKind(SyntaxKind.ByteKeyword)
diff --git a/sources/SilkTouch/SilkTouch/Mods/Transformation/BoolTransformer.cs b/sources/SilkTouch/SilkTouch/Mods/Transformation/BoolTransformer.cs
index 8519678e15..f80eabf678 100644
--- a/sources/SilkTouch/SilkTouch/Mods/Transformation/BoolTransformer.cs
+++ b/sources/SilkTouch/SilkTouch/Mods/Transformation/BoolTransformer.cs
@@ -1,9 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Extensions.Options;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
@@ -30,7 +27,7 @@ Action next
var retNative = current.GetNativeReturnTypeName() ?? current.ReturnType.ToString();
if (
(current.ReturnType.IsInteger() && cfg.IntReturnsMaybeBool)
- || (cfg.BoolTypes?.TryGetValue(retNative, out retBoolScheme) ?? false)
+ || cfg.BoolTypes.TryGetValue(retNative, out retBoolScheme)
|| (retNative == "bool" && current.ReturnType.ToString().Trim() != "bool") // stdbool.h, hopefully...
)
{
@@ -63,7 +60,7 @@ Action next
paramNative is not null
&& param.Type is not null
&& (
- (cfg.BoolTypes?.TryGetValue(paramNative, out paramBoolScheme) ?? false)
+ cfg.BoolTypes.TryGetValue(paramNative, out paramBoolScheme)
|| (paramNative == "bool" && param.Type.ToString().Trim() != "bool") // stdbool.h, hopefully...
)
)