Skip to content
Closed
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
26 changes: 26 additions & 0 deletions sources/ClangSharp.Interop/Extensions/CXCursor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,32 @@ public readonly CXCursor DefaultArg

public readonly double FloatingLiteralValueAsApproximateDouble => clangsharp.Cursor_getFloatingLiteralValueAsApproximateDouble(this);

public readonly double? FloatingLiteralValueAsDouble
{
get
{
double value = default;
if (clangsharp.Cursor_getFloatingLiteralValueAsDouble(this, &value) != 0)
{
return value;
}
return null;
}
}

public readonly float? FloatingLiteralValueAsFloat
{
get
{
float value = default;
if (clangsharp.Cursor_getFloatingLiteralValueAsFloat(this, &value) != 0)
{
return value;
}
return null;
}
}

public readonly int FieldDeclBitWidth => clang.getFieldDeclBitWidth(this);

public readonly int FieldIndex => clangsharp.Cursor_getFieldIndex(this);
Expand Down
10 changes: 9 additions & 1 deletion sources/ClangSharp.Interop/clangsharp/clangsharp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace ClangSharp.Interop;

public static partial class @clangsharp
public static unsafe partial class @clangsharp
{
[DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getArgument", ExactSpelling = true)]
public static extern CXCursor Cursor_getArgument(CXCursor C, [NativeTypeName("unsigned int")] uint i);
Expand Down Expand Up @@ -240,6 +240,14 @@ public static partial class @clangsharp
[DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getFloatingLiteralValueAsApproximateDouble", ExactSpelling = true)]
public static extern double Cursor_getFloatingLiteralValueAsApproximateDouble(CXCursor C);

[DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getFloatingLiteralValueAsDouble", ExactSpelling = true)]
[return: NativeTypeName("unsigned int")]
public static extern uint Cursor_getFloatingLiteralValueAsDouble(CXCursor C, double* value);

[DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getFloatingLiteralValueAsFloat", ExactSpelling = true)]
[return: NativeTypeName("unsigned int")]
public static extern uint Cursor_getFloatingLiteralValueAsFloat(CXCursor C, float* value);

[DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getFoundDecl", ExactSpelling = true)]
public static extern CXCursor Cursor_getFoundDecl(CXCursor C);

Expand Down
4 changes: 4 additions & 0 deletions sources/ClangSharp/Cursors/Exprs/FloatingLiteral.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,9 @@ internal FloatingLiteral(CXCursor handle) : base(handle, CXCursor_FloatingLitera

public double ValueAsApproximateDouble => Handle.FloatingLiteralValueAsApproximateDouble;

public double? ValueAsDouble => Handle.FloatingLiteralValueAsDouble;

public float? ValueAsFloat => Handle.FloatingLiteralValueAsFloat;

public string ValueString => _valueString.Value;
}
32 changes: 32 additions & 0 deletions sources/libClangSharp/ClangSharp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1367,6 +1367,38 @@ double clangsharp_Cursor_getFloatingLiteralValueAsApproximateDouble(CXCursor C)
return 0;
}

unsigned clangsharp_Cursor_getFloatingLiteralValueAsDouble(CXCursor C, double* value) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand the need for these APIs?

ValueAsApproximateDouble only loses data in the case that we have some "more precise" type than double, such as x87DoubleExtended or IEEEquad (which aren't portable to C# right now anyways).

So what it looks like you want is just some unsigned clangsharp_Cursor_isFloatingLiteralRepresentableBy(CXCursor C, CX_FloatingSemantics semantics).

Such an API then allows this to be more generally supported in managed land instead, as you can simply check "is the floating-literal regardless of semantics losslessly representable by this other semantic". You can then take and cast ValueAsApproximateDouble to the target format in that case for the two types that are being supported here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I'll try ValueAsApproximateDouble and see if that works.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ValueAsApproximateDouble works fine, so this is not needed, thanks!

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

if (const FloatingLiteral* FL = dyn_cast<FloatingLiteral>(S)) {
llvm::APFloat fl = FL->getValue();
if (fl.isRepresentableBy(fl.getSemantics(), fl.IEEEdouble())) {
*value = FL->getValue ().convertToDouble();
return 1;
}
}
}

return 0;
}

unsigned clangsharp_Cursor_getFloatingLiteralValueAsFloat(CXCursor C, float* value) {
if (isStmtOrExpr(C.kind)) {
const Stmt* S = getCursorStmt(C);

if (const FloatingLiteral* FL = dyn_cast<FloatingLiteral>(S)) {
llvm::APFloat fl = FL->getValue();
if (fl.isRepresentableBy(fl.getSemantics(), fl.IEEEsingle())) {
*value = FL->getValue ().convertToFloat();
return 1;
}
}
}

return 0;
}

CXCursor clangsharp_Cursor_getFoundDecl(CXCursor C) {
if (isStmtOrExpr(C.kind)) {
const Stmt* S = getCursorStmt(C);
Expand Down
4 changes: 4 additions & 0 deletions sources/libClangSharp/ClangSharp.h
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,10 @@ CLANGSHARP_LINKAGE CX_FloatingSemantics clangsharp_Cursor_getFloatingLiteralSema

CLANGSHARP_LINKAGE double clangsharp_Cursor_getFloatingLiteralValueAsApproximateDouble(CXCursor C);

CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getFloatingLiteralValueAsDouble(CXCursor C, double* value);

CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getFloatingLiteralValueAsFloat(CXCursor C, float* value);

CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getFoundDecl(CXCursor C);

CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getField(CXCursor C, unsigned i);
Expand Down
41 changes: 41 additions & 0 deletions tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,47 @@ class tuple;
Assert.That(packElements[1].AsType.AsString, Is.EqualTo("long"));
}

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

var inputContents = $$"""
const float F1 = 3.14f;
const double D1 = 2.718281828;
const long double Q1 = 1.61803398874989484820458683436563811772030917980576286213544862270526046281890244L;
""";

using var translationUnit = CreateTranslationUnit(inputContents);

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

var checkConstant = (string constantName, float? expectedFloat, double? expectedDouble, double expectedApproximateDouble) => {
var constant = decls.SingleOrDefault(e => e.Name == constantName)!;
var expr = constant.Init!;
if (expr is ImplicitCastExpr castExpr)
{
expr = castExpr.SubExpr;
}
if (expr is FloatingLiteral floatingLiteral)
{
Assert.That(floatingLiteral.ValueAsFloat, Is.EqualTo(expectedFloat).Within(0.0001), $"Constant {constantName} float value mismatch");
Assert.That(floatingLiteral.ValueAsDouble, Is.EqualTo(expectedDouble).Within(0.0001), $"Constant {constantName} double value mismatch");
Assert.That(floatingLiteral.ValueAsApproximateDouble, Is.EqualTo(expectedApproximateDouble).Within(0.0001), $"Constant {constantName} double value mismatch");
}
else
{
Assert.Fail($"Constant {constantName} InitExpr is not FloatingLiteral, but {expr.GetType().Name}");
}
};

Assert.Multiple(() => {
checkConstant("F1", 3.14f, 3.14, 3.14);
checkConstant("D1", null, 2.718281828, 2.718281828);
checkConstant("Q1", null, 1.61803398874989484820458683436563811772030917980576, 1.61803398874989484820458683436563811772030917980576);
});
}

[Test]
public void IsPodTest()
{
Expand Down