Skip to content

Commit

Permalink
Replace syntax factory with template for BOOL special members
Browse files Browse the repository at this point in the history
  • Loading branch information
AArnott committed Jun 15, 2022
1 parent b968c38 commit d66e7cc
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 108 deletions.
91 changes: 1 addition & 90 deletions src/Microsoft.Windows.CsWin32/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3763,11 +3763,6 @@ private ClassDeclarationSyntax DeclareCocreatableClass(TypeDefinition typeDef)
private StructDeclarationSyntax DeclareTypeDefStruct(TypeDefinition typeDef, TypeDefinitionHandle typeDefHandle)
{
IdentifierNameSyntax name = IdentifierName(this.Reader.GetString(typeDef.Name));
if (name.Identifier.ValueText == "BOOL")
{
return this.DeclareTypeDefBOOLStruct(typeDef);
}

bool isHandle = name.Identifier.ValueText == "HGDIOBJ";
foreach (CustomAttributeHandle attHandle in typeDef.GetCustomAttributes())
{
Expand Down Expand Up @@ -3870,6 +3865,7 @@ private StructDeclarationSyntax DeclareTypeDefStruct(TypeDefinition typeDef, Typ
break;
case "HRESULT":
case "NTSTATUS":
case "BOOL":
case "BOOLEAN":
members = members.AddRange(this.ExtractMembersFromTemplate(name.Identifier.ValueText));
break;
Expand Down Expand Up @@ -4146,91 +4142,6 @@ private MethodDeclarationSyntax CreateAsSpanMethodOverValueAndLength(TypeSyntax
.WithLeadingTrivia(StrAsSpanComment);
}

private StructDeclarationSyntax DeclareTypeDefBOOLStruct(TypeDefinition typeDef)
{
IdentifierNameSyntax name = IdentifierName("BOOL");

FieldDefinition fieldDef = this.Reader.GetFieldDefinition(typeDef.GetFields().Single());
CustomAttributeHandleCollection fieldAttributes = fieldDef.GetCustomAttributes();
IdentifierNameSyntax fieldName = IdentifierName("value");
VariableDeclaratorSyntax fieldDeclarator = VariableDeclarator(fieldName.Identifier);
(TypeSyntax FieldType, SyntaxList<MemberDeclarationSyntax> AdditionalMembers, AttributeSyntax? MarshalAs) fieldInfo =
this.ReinterpretFieldType(fieldDef, fieldDef.DecodeSignature(SignatureHandleProvider.Instance, null).ToTypeSyntax(this.fieldTypeSettings, fieldAttributes).Type, fieldAttributes, this.DefaultContext);
SyntaxList<MemberDeclarationSyntax> members = List<MemberDeclarationSyntax>();

FieldDeclarationSyntax fieldSyntax = FieldDeclaration(
VariableDeclaration(fieldInfo.FieldType).AddVariables(fieldDeclarator))
.AddModifiers(TokenWithSpace(SyntaxKind.PrivateKeyword), TokenWithSpace(SyntaxKind.ReadOnlyKeyword));
members = members.Add(fieldSyntax);
MemberAccessExpressionSyntax fieldAccessExpression = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName("value"));

// Add property accessor
members = members.Add(PropertyDeclaration(PredefinedType(TokenWithSpace(SyntaxKind.IntKeyword)), "Value")
.WithExpressionBody(ArrowExpressionClause(fieldAccessExpression)).WithSemicolonToken(SemicolonWithLineFeed)
.AddModifiers(TokenWithSpace(this.Visibility)));

// unsafe BOOL(bool value) => this.value = *(sbyte*)&value;
IdentifierNameSyntax valueParameter = IdentifierName("value");
ExpressionSyntax boolToSByte = PrefixUnaryExpression(
SyntaxKind.PointerIndirectionExpression,
CastExpression(
PointerType(PredefinedType(TokenWithNoSpace(SyntaxKind.SByteKeyword))),
PrefixUnaryExpression(SyntaxKind.AddressOfExpression, valueParameter)));
members = members.Add(ConstructorDeclaration(name.Identifier)
.AddModifiers(TokenWithSpace(this.Visibility), TokenWithSpace(SyntaxKind.UnsafeKeyword))
.AddParameterListParameters(Parameter(valueParameter.Identifier).WithType(PredefinedType(TokenWithSpace(SyntaxKind.BoolKeyword))))
.WithExpressionBody(ArrowExpressionClause(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, fieldAccessExpression, boolToSByte).WithOperatorToken(TokenWithSpaces(SyntaxKind.EqualsToken))))
.WithSemicolonToken(SemicolonWithLineFeed));

// BOOL(int value) => this.value = value;
members = members.Add(ConstructorDeclaration(name.Identifier)
.AddModifiers(TokenWithSpace(this.Visibility))
.AddParameterListParameters(Parameter(valueParameter.Identifier).WithType(PredefinedType(TokenWithSpace(SyntaxKind.IntKeyword))))
.WithExpressionBody(ArrowExpressionClause(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, fieldAccessExpression, valueParameter).WithOperatorToken(TokenWithSpaces(SyntaxKind.EqualsToken))))
.WithSemicolonToken(SemicolonWithLineFeed));

// public unsafe static implicit operator bool(BOOL value)
// {
// sbyte v = checked((sbyte)value.value);
// return *(bool*)&v;
// }
IdentifierNameSyntax localVarName = IdentifierName("v");
ExpressionSyntax sbyteToBool = PrefixUnaryExpression(
SyntaxKind.PointerIndirectionExpression,
CastExpression(
PointerType(PredefinedType(TokenWithNoSpace(SyntaxKind.BoolKeyword))),
PrefixUnaryExpression(SyntaxKind.AddressOfExpression, localVarName)));
BlockSyntax? implicitBOOLtoBoolBody = Block().AddStatements(
LocalDeclarationStatement(VariableDeclaration(PredefinedType(Token(SyntaxKind.SByteKeyword)))).AddDeclarationVariables(
VariableDeclarator(localVarName.Identifier).WithInitializer(EqualsValueClause(CheckedExpression(SyntaxKind.CheckedExpression, CastExpression(PredefinedType(Token(SyntaxKind.SByteKeyword)), MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, valueParameter, fieldName)))))),
ReturnStatement(sbyteToBool));
members = members.Add(ConversionOperatorDeclaration(Token(SyntaxKind.ImplicitKeyword), PredefinedType(Token(SyntaxKind.BoolKeyword)))
.AddParameterListParameters(Parameter(valueParameter.Identifier).WithType(name.WithTrailingTrivia(TriviaList(Space))))
.WithBody(implicitBOOLtoBoolBody)
.AddModifiers(TokenWithSpace(SyntaxKind.PublicKeyword), TokenWithSpace(SyntaxKind.StaticKeyword), TokenWithSpace(SyntaxKind.UnsafeKeyword))); // operators MUST be public

// public static implicit operator BOOL(bool value) => new BOOL(value);
members = members.Add(ConversionOperatorDeclaration(Token(SyntaxKind.ImplicitKeyword), name)
.AddParameterListParameters(Parameter(valueParameter.Identifier).WithType(PredefinedType(TokenWithSpace(SyntaxKind.BoolKeyword))))
.WithExpressionBody(ArrowExpressionClause(ObjectCreationExpression(name).AddArgumentListArguments(Argument(valueParameter))))
.AddModifiers(TokenWithSpace(SyntaxKind.PublicKeyword), TokenWithSpace(SyntaxKind.StaticKeyword)) // operators MUST be public
.WithSemicolonToken(SemicolonWithLineFeed));

// public static explicit operator BOOL(int value) => new BOOL(value);
members = members.Add(ConversionOperatorDeclaration(Token(SyntaxKind.ExplicitKeyword), name)
.AddParameterListParameters(Parameter(valueParameter.Identifier).WithType(PredefinedType(TokenWithSpace(SyntaxKind.IntKeyword))))
.WithExpressionBody(ArrowExpressionClause(ObjectCreationExpression(name).AddArgumentListArguments(Argument(valueParameter))))
.AddModifiers(TokenWithSpace(SyntaxKind.PublicKeyword), TokenWithSpace(SyntaxKind.StaticKeyword)) // operators MUST be public
.WithSemicolonToken(SemicolonWithLineFeed));

StructDeclarationSyntax result = StructDeclaration(name.Identifier)
.WithMembers(members)
.WithModifiers(TokenList(TokenWithSpace(this.Visibility), TokenWithSpace(SyntaxKind.ReadOnlyKeyword), TokenWithSpace(SyntaxKind.PartialKeyword)));

result = this.AddApiDocumentation(name.Identifier.ValueText, result);
return result;
}

private EnumDeclarationSyntax DeclareEnum(TypeDefinition typeDef)
{
bool flagsEnum = false;
Expand Down
11 changes: 11 additions & 0 deletions src/Microsoft.Windows.CsWin32/templates/BOOL.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
partial struct BOOL
{
internal unsafe BOOL(bool value) => this.Value = *(sbyte*)&value;
public static unsafe implicit operator bool(BOOL value)
{
sbyte v = checked((sbyte)value.Value);
return *(bool*)&v;
}

public static implicit operator BOOL(bool value) => new BOOL(value);
}
69 changes: 51 additions & 18 deletions test/Microsoft.Windows.CsWin32.Tests/GeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1576,20 +1576,31 @@ namespace Windows.Win32
namespace Foundation
{
[DebuggerDisplay(""{Value}"")]
internal readonly partial struct BOOL
: IEquatable<BOOL>
{
private readonly int value;
internal readonly int Value;
internal BOOL(int value) => this.Value = value;
public static implicit operator int(BOOL value) => value.Value;
public static explicit operator BOOL(int value) => new BOOL(value);
public static bool operator ==(BOOL left, BOOL right) => left.Value == right.Value;
public static bool operator !=(BOOL left, BOOL right) => !(left == right);
public bool Equals(BOOL other) => this.Value == other.Value;
internal int Value => this.value;
internal unsafe BOOL(bool value) => this.value = *(sbyte*)&value;
internal BOOL(int value) => this.value = value;
public override bool Equals(object obj) => obj is BOOL other && this.Equals(other);
public override int GetHashCode() => this.Value.GetHashCode();
internal unsafe BOOL(bool value) => this.Value = *(sbyte*)&value;
public static unsafe implicit operator bool(BOOL value)
{
sbyte v = checked((sbyte)value.value);
sbyte v = checked((sbyte)value.Value);
return *(bool*)&v;
}
public static implicit operator BOOL(bool value) => new BOOL(value);
public static explicit operator BOOL(int value) => new BOOL(value);
}
}
}
Expand Down Expand Up @@ -1837,20 +1848,31 @@ namespace Windows.Win32
namespace Foundation
{
[DebuggerDisplay(""{Value}"")]
internal readonly partial struct BOOL
: IEquatable<BOOL>
{
private readonly int value;
internal readonly int Value;
internal BOOL(int value) => this.Value = value;
public static implicit operator int(BOOL value) => value.Value;
public static explicit operator BOOL(int value) => new BOOL(value);
public static bool operator ==(BOOL left, BOOL right) => left.Value == right.Value;
public static bool operator !=(BOOL left, BOOL right) => !(left == right);
public bool Equals(BOOL other) => this.Value == other.Value;
public override bool Equals(object obj) => obj is BOOL other && this.Equals(other);
internal int Value => this.value;
internal unsafe BOOL(bool value) => this.value = *(sbyte*)&value;
internal BOOL(int value) => this.value = value;
public override int GetHashCode() => this.Value.GetHashCode();
internal unsafe BOOL(bool value) => this.Value = *(sbyte*)&value;
public static unsafe implicit operator bool(BOOL value)
{
sbyte v = checked((sbyte)value.value);
sbyte v = checked((sbyte)value.Value);
return *(bool*)&v;
}
public static implicit operator BOOL(bool value) => new BOOL(value);
public static explicit operator BOOL(int value) => new BOOL(value);
}
}
}
Expand Down Expand Up @@ -2149,20 +2171,31 @@ namespace Windows.Win32
namespace Foundation
{
[DebuggerDisplay(""{Value}"")]
internal readonly partial struct BOOL
: IEquatable<BOOL>
{
private readonly int value;
internal readonly int Value;
internal BOOL(int value) => this.Value = value;
public static implicit operator int(BOOL value) => value.Value;
public static explicit operator BOOL(int value) => new BOOL(value);
public static bool operator ==(BOOL left, BOOL right) => left.Value == right.Value;
public static bool operator !=(BOOL left, BOOL right) => !(left == right);
internal int Value => this.value;
internal unsafe BOOL(bool value) => this.value = *(sbyte*)&value;
internal BOOL(int value) => this.value = value;
public bool Equals(BOOL other) => this.Value == other.Value;
public override bool Equals(object obj) => obj is BOOL other && this.Equals(other);
public override int GetHashCode() => this.Value.GetHashCode();
internal unsafe BOOL(bool value) => this.Value = *(sbyte*)&value;
public static unsafe implicit operator bool(BOOL value)
{
sbyte v = checked((sbyte)value.value);
sbyte v = checked((sbyte)value.Value);
return *(bool*)&v;
}
public static implicit operator BOOL(bool value) => new BOOL(value);
public static explicit operator BOOL(int value) => new BOOL(value);
}
}
}
Expand Down

0 comments on commit d66e7cc

Please sign in to comment.