Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sources/ClangSharp.Interop/Extensions/CXCursor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,8 @@ public readonly CXCursor DefaultArg

public readonly long IntegerLiteralValue => clangsharp.Cursor_getIntegerLiteralValue(this);

public readonly ulong UnsignedIntegerLiteralValue => clangsharp.Cursor_getUnsignedIntegerLiteralValue(this);

public readonly bool IsAllEnumCasesCovered => clangsharp.Cursor_getIsAllEnumCasesCovered(this) != 0;

public readonly bool IsAlwaysNull => clangsharp.Cursor_getIsAlwaysNull(this) != 0;
Expand Down
4 changes: 4 additions & 0 deletions sources/ClangSharp.Interop/clangsharp/clangsharp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,10 @@ public static partial class @clangsharp
[return: NativeTypeName("int64_t")]
public static extern long Cursor_getIntegerLiteralValue(CXCursor C);

[DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getUnsignedIntegerLiteralValue", ExactSpelling = true)]
[return: NativeTypeName("uint64_t")]
public static extern ulong Cursor_getUnsignedIntegerLiteralValue(CXCursor C);

[DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getIsAllEnumCasesCovered", ExactSpelling = true)]
[return: NativeTypeName("unsigned int")]
public static extern uint Cursor_getIsAllEnumCasesCovered(CXCursor C);
Expand Down
2 changes: 2 additions & 0 deletions sources/ClangSharp/Cursors/Exprs/IntegerLiteral.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,7 @@ internal IntegerLiteral(CXCursor handle) : base(handle, CXCursor_IntegerLiteral,

public long Value => Handle.IntegerLiteralValue;

public ulong UnsignedValue => Handle.UnsignedIntegerLiteralValue;

public string ValueString => _valueString.Value;
}
12 changes: 12 additions & 0 deletions sources/libClangSharp/ClangSharp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,18 @@ int64_t clangsharp_Cursor_getIntegerLiteralValue(CXCursor C) {
return 0;
}

uint64_t clangsharp_Cursor_getUnsignedIntegerLiteralValue(CXCursor C) {
if (isStmtOrExpr(C.kind)) {
const Stmt* S = getCursorStmt(C);

if (const IntegerLiteral* IL = dyn_cast<IntegerLiteral>(S)) {
return IL->getValue().getZExtValue();
}
}

return 0;
}

unsigned clangsharp_Cursor_getIsAllEnumCasesCovered(CXCursor C) {
if (isStmtOrExpr(C.kind)) {
const Stmt* S = getCursorStmt(C);
Expand Down
2 changes: 2 additions & 0 deletions sources/libClangSharp/ClangSharp.h
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,8 @@ CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getInstantiatedFromMember(CXCursor

CLANGSHARP_LINKAGE int64_t clangsharp_Cursor_getIntegerLiteralValue(CXCursor C);

CLANGSHARP_LINKAGE uint64_t clangsharp_Cursor_getUnsignedIntegerLiteralValue(CXCursor C);

CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getIsAllEnumCasesCovered(CXCursor C);

CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getIsAlwaysNull(CXCursor C);
Expand Down
59 changes: 59 additions & 0 deletions tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,63 @@ struct B {
Assert.That(structB, Is.Not.Null, "struct B not found");
Assert.That(structB.IsPOD, Is.False, "struct B should be not POD");
}

[Test]
public void UnsignedValue()
{
ObjectiveCTest.AssertNeedNewClangSharp();

var inputContents = $$"""
enum E {
A = 1,
B = 4294967295U,
C = 4294967296U,
D = 18446744073709551615ULL,
E = -1,
F = -4294967295,
G = -4294967296,
H = -18446744073709551615LL,
};
""";

using var translationUnit = CreateTranslationUnit(inputContents);

var decls = translationUnit.TranslationUnitDecl.Decls.OfType<EnumDecl>().ToList();

var enumE = decls.SingleOrDefault(d => d.Name == "E")!;
Assert.That(enumE, Is.Not.Null, "enum E not found");

var checkField = (string fieldName, long expectedValue, ulong expectedUnsignedValue, bool negative) => {
var field = enumE.Enumerators.SingleOrDefault(e => e.Name == fieldName)!;
Assert.That(field, Is.Not.Null, $"enum E::{fieldName} not found");
var initExpr = field.InitExpr;
Assert.That(initExpr, Is.Not.Null, $"enum E::{fieldName} InitExpr is null");

var isNegativeExpression = false;
var castExpr = (ImplicitCastExpr)initExpr!;
var subExpr = castExpr.SubExpr;
if (subExpr is UnaryOperator unaryOperator)
{
Assert.That(unaryOperator.Opcode, Is.EqualTo(CXUnaryOperatorKind.CXUnaryOperator_Minus), $"enum E::{fieldName} InitExpr is not a minus UnaryOperator");
subExpr = unaryOperator.SubExpr;
isNegativeExpression = true;
}
var literalExpr = subExpr as IntegerLiteral;
Assert.That(literalExpr, Is.Not.Null, $"enum E::{fieldName} InitExpr is not IntegerLiteral {castExpr.SubExpr!.GetType().Name}");
Assert.That(literalExpr!.Value, Is.EqualTo(expectedValue), $"enum E::{fieldName} value mismatch");
Assert.That(literalExpr!.UnsignedValue, Is.EqualTo(expectedUnsignedValue), $"enum E::{fieldName} unsigned value mismatch");
Assert.That(negative, Is.EqualTo(isNegativeExpression), $"enum E::{fieldName} negative mismatch");
};

Assert.Multiple(() => {
checkField("A", 1, 1, false);
checkField("B", -1, 4294967295UL, false);
checkField("C", 4294967296, 4294967296UL, false);
checkField("D", -1, 18446744073709551615UL, false);
checkField("E", 1, 1, true);
checkField("F", 4294967295, 4294967295, true);
checkField("G", 4294967296, 4294967296, true);
checkField("H", -1, 18446744073709551615UL, true);
});
}
}