diff --git a/sources/ClangSharp.Interop/Extensions/CXCursor.cs b/sources/ClangSharp.Interop/Extensions/CXCursor.cs index 3af7012f..81d426d8 100644 --- a/sources/ClangSharp.Interop/Extensions/CXCursor.cs +++ b/sources/ClangSharp.Interop/Extensions/CXCursor.cs @@ -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); diff --git a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs index f430268d..dc6f1cf6 100644 --- a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs +++ b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs @@ -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); @@ -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); diff --git a/sources/ClangSharp/Cursors/Exprs/FloatingLiteral.cs b/sources/ClangSharp/Cursors/Exprs/FloatingLiteral.cs index 73892014..52324c2d 100644 --- a/sources/ClangSharp/Cursors/Exprs/FloatingLiteral.cs +++ b/sources/ClangSharp/Cursors/Exprs/FloatingLiteral.cs @@ -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; } diff --git a/sources/libClangSharp/ClangSharp.cpp b/sources/libClangSharp/ClangSharp.cpp index 70389fb9..9596c014 100644 --- a/sources/libClangSharp/ClangSharp.cpp +++ b/sources/libClangSharp/ClangSharp.cpp @@ -1367,6 +1367,38 @@ double clangsharp_Cursor_getFloatingLiteralValueAsApproximateDouble(CXCursor C) return 0; } +unsigned clangsharp_Cursor_getFloatingLiteralValueAsDouble(CXCursor C, double* value) { + if (isStmtOrExpr(C.kind)) { + const Stmt* S = getCursorStmt(C); + + if (const FloatingLiteral* FL = dyn_cast(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(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); diff --git a/sources/libClangSharp/ClangSharp.h b/sources/libClangSharp/ClangSharp.h index 4e5384b9..a01ecbcd 100644 --- a/sources/libClangSharp/ClangSharp.h +++ b/sources/libClangSharp/ClangSharp.h @@ -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); diff --git a/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs b/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs index 399abb94..49dcf0f8 100644 --- a/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs +++ b/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs @@ -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().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() {