diff --git a/sources/ClangSharp.Interop/Extensions/CXCursor.cs b/sources/ClangSharp.Interop/Extensions/CXCursor.cs index 9f4b518d..fac983dd 100644 --- a/sources/ClangSharp.Interop/Extensions/CXCursor.cs +++ b/sources/ClangSharp.Interop/Extensions/CXCursor.cs @@ -1358,6 +1358,8 @@ public readonly ReadOnlySpan OverriddenCursors public readonly CXPrintingPolicy PrintingPolicy => (kind != default) ? (CXPrintingPolicy)clang.getCursorPrintingPolicy(this) : default; + public readonly CXString QualifiedName => clangsharp.Cursor_getQualifiedName(this); + public readonly CXString RawCommentText => clang.Cursor_getRawCommentText(this); public readonly CXType ReceiverType => !IsExpression ? default : clang.Cursor_getReceiverType(this); diff --git a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs index 79d0d406..6c61f400 100644 --- a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs +++ b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs @@ -812,6 +812,9 @@ public static unsafe partial class @clangsharp [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getProtocol", ExactSpelling = true)] public static extern CXCursor Cursor_getProtocol(CXCursor C, [NativeTypeName("unsigned int")] uint i); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getQualifiedName", ExactSpelling = true)] + public static extern CXString Cursor_getQualifiedName(CXCursor C); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getRedeclContext", ExactSpelling = true)] public static extern CXCursor Cursor_getRedeclContext(CXCursor C); diff --git a/sources/ClangSharp/Cursors/Decls/NamedDecl.cs b/sources/ClangSharp/Cursors/Decls/NamedDecl.cs index dc78fe78..da478d6f 100644 --- a/sources/ClangSharp/Cursors/Decls/NamedDecl.cs +++ b/sources/ClangSharp/Cursors/Decls/NamedDecl.cs @@ -26,6 +26,8 @@ private protected NamedDecl(CXCursor handle, CXCursorKind expectedCursorKind, CX public string Name => Spelling; + public string QualifiedName => Handle.QualifiedName.ToString(); + public NamedDecl UnderlyingDecl => _underlyingDecl.Value; public CXVisibilityKind Visibility => Handle.Visibility; diff --git a/sources/libClangSharp/ClangSharp.cpp b/sources/libClangSharp/ClangSharp.cpp index 9f67c3dc..9771bc84 100644 --- a/sources/libClangSharp/ClangSharp.cpp +++ b/sources/libClangSharp/ClangSharp.cpp @@ -3975,6 +3975,18 @@ CXCursor clangsharp_Cursor_getProtocol(CXCursor C, unsigned i) { return clang_getNullCursor(); } +CXString clangsharp_Cursor_getQualifiedName(CXCursor C) { + if (isDeclOrTU(C.kind)) { + const Decl* D = getCursorDecl(C); + + if (const NamedDecl* ND = dyn_cast(D)) { + return createDup(ND->getQualifiedNameAsString()); + } + } + + return createEmpty(); +} + CXCursor clangsharp_Cursor_getRedeclContext(CXCursor C) { if (isDeclOrTU(C.kind)) { const Decl* D = getCursorDecl(C); diff --git a/sources/libClangSharp/ClangSharp.h b/sources/libClangSharp/ClangSharp.h index 9b945876..51feab3d 100644 --- a/sources/libClangSharp/ClangSharp.h +++ b/sources/libClangSharp/ClangSharp.h @@ -695,6 +695,8 @@ CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getPropertyAttributes(CXCursor C); CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getProtocol(CXCursor C, unsigned i); +CLANGSHARP_LINKAGE CXString clangsharp_Cursor_getQualifiedName(CXCursor C); + CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getRedeclContext(CXCursor C); CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getReferenced(CXCursor C); diff --git a/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs b/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs index b3f6a0bb..a32618fb 100644 --- a/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs +++ b/tests/ClangSharp.UnitTests/CursorTests/DeclTest.cs @@ -126,6 +126,39 @@ struct B { Assert.That(structB.IsPOD, Is.False, "struct B should be not POD"); } + + [Test] + public void QualifiedNameTest() + { + AssertNeedNewClangSharp(); + + var inputContents = """ +class C { + void M(); + int F; +}; + +struct S { + void M(); + int F; +}; +"""; + + using var translationUnit = CreateTranslationUnit(inputContents); + + var records = translationUnit.TranslationUnitDecl.Decls.OfType().ToArray(); + var classDecl = records.Single(v => v.Name == "C"); + var structDecl = records.Single(v => v.Name == "S"); + var classM = classDecl.Decls.OfType().Single(); + var structM = structDecl.Decls.OfType().Single(); + + Assert.That(classDecl.QualifiedName, Is.EqualTo("C"), "Class"); + Assert.That(classM.QualifiedName, Is.EqualTo("C::M"), "Class Method"); + + Assert.That(structDecl.QualifiedName, Is.EqualTo("S"), "Struct"); + Assert.That(structM.QualifiedName, Is.EqualTo("S::M"), "Struct Method"); + } + [Test] public void UnsignedValue() {