[clang] [libclang/python] Add non ref and unqualified getters for types (PR #175534)
Martin Rodriguez Reboredo via cfe-commits
cfe-commits at lists.llvm.org
Sat Jul 18 15:17:11 PDT 2026
https://github.com/YakoYakoYokuYoku updated https://github.com/llvm/llvm-project/pull/175534
>From dec451f9668003b4841e2c4d3ba69b2f9b47adcd Mon Sep 17 00:00:00 2001
From: Martin Rodriguez Reboredo <yakoyoku at gmail.com>
Date: Mon, 12 Jan 2026 01:04:05 -0300
Subject: [PATCH 1/2] [libclang] Query atomic unqualified in cindex
This is purpoted to be exposed in Python.
Signed-off-by: Martin Rodriguez Reboredo <yakoyoku at gmail.com>
---
clang/docs/ReleaseNotes.md | 2 ++
clang/include/clang-c/Index.h | 17 ++++++++++++++++-
clang/tools/libclang/CXType.cpp | 4 ++++
3 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index a39bc2dfc5b6d..64113829ac8e6 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -393,6 +393,8 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
### libclang
+- Implemented `clang_getAtomicUnqualifiedType` for unsugaring `_Atomic` qualified types. (#GH175534)
+
### Code Completion
### Static Analyzer
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 8427236e0b444..59055b6cd6ab6 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -3390,7 +3390,9 @@ CINDEX_LINKAGE CXType clang_getPointeeType(CXType T);
* Retrieve the unqualified variant of the given type, removing as
* little sugar as possible.
*
- * For example, given the following series of typedefs:
+ * This routine looks through various kinds of sugar to find the
+ * least-desugared type that is unqualified. For example, given the
+ * following series of typedefs:
*
* \code
* typedef int Integer;
@@ -3420,9 +3422,22 @@ CINDEX_LINKAGE CXType clang_getPointeeType(CXType T);
*
* A type that resulted from a call to \c clang_getUnqualifiedType
* will return \c false for all of the above calls.
+ *
+ * Note: In C, the _Atomic qualifier is special (see C23 6.2.5p32 for
+ * details), and it is not stripped by this function. Use
+ * clang_getAtomicUnqualifiedType() to strip qualifiers including
+ * _Atomic.
*/
CINDEX_LINKAGE CXType clang_getUnqualifiedType(CXType CT);
+/**
+ * Remove all qualifiers including _Atomic.
+ *
+ * Like \c clang_getUnqualifiedType(), the type may still be
+ * qualified if it is a sugared array type.
+ */
+CINDEX_LINKAGE CXType clang_getAtomicUnqualifiedType(CXType CT);
+
/**
* For reference types (e.g., "const int&"), returns the type that the
* reference refers to (e.g "const int").
diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp
index 0063939dec423..e3cb5ef3c0f37 100644
--- a/clang/tools/libclang/CXType.cpp
+++ b/clang/tools/libclang/CXType.cpp
@@ -518,6 +518,10 @@ CXType clang_getUnqualifiedType(CXType CT) {
return MakeCXType(GetQualType(CT).getUnqualifiedType(), GetTU(CT));
}
+CXType clang_getAtomicUnqualifiedType(CXType CT) {
+ return MakeCXType(GetQualType(CT).getAtomicUnqualifiedType(), GetTU(CT));
+}
+
CXType clang_getNonReferenceType(CXType CT) {
return MakeCXType(GetQualType(CT).getNonReferenceType(), GetTU(CT));
}
>From 78a907fe6adb8cf66af74a8d431e3a17bb48aad9 Mon Sep 17 00:00:00 2001
From: Martin Rodriguez Reboredo <yakoyoku at gmail.com>
Date: Mon, 12 Jan 2026 01:04:05 -0300
Subject: [PATCH 2/2] [libclang/python] Add non ref and unqualified getters for
types
These methods were missing in the bindings API.
Signed-off-by: Martin Rodriguez Reboredo <yakoyoku at gmail.com>
---
clang/bindings/python/clang/cindex.py | 34 +++++++++++++
.../bindings/python/tests/cindex/test_type.py | 51 +++++++++++++++++++
clang/docs/ReleaseNotes.md | 2 +
3 files changed, 87 insertions(+)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 24b737139dba8..9fc1350121f09 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2812,6 +2812,37 @@ def get_canonical(self) -> Type:
"""
return Type.from_result(conf.lib.clang_getCanonicalType(self), self)
+ def get_non_reference(self) -> Type:
+ """
+ Return the type stripped of references from a Type.
+
+ If a type is either an l-value or an r-value reference then those
+ are going to be removed. It returns the type unchanged otherwise.
+ """
+ return Type.from_result(conf.lib.clang_getNonReferenceType(self), self)
+
+ def get_unqualified(self) -> Type:
+ """
+ Return the type without any qualifiers from a Type.
+
+ A type can be qualified with const, volatile, restrict or a
+ combination of these. This method removes the qualifier of a type. In
+ the absence of any of these, the type is returned unchanged.
+
+ Arrays and the _Atomic qualifier are not stripped by this function.
+ See ``get_atomic_unqualified()`` for atomics.
+ """
+ return Type.from_result(conf.lib.clang_getUnqualifiedType(self), self)
+
+ def get_atomic_unqualified(self) -> Type:
+ """
+ Remove all qualifiers including _Atomic.
+
+ Like ``get_unqualified_type()``, the type may still be qualified if it
+ is a sugared array type.
+ """
+ return Type.from_result(conf.lib.clang_getAtomicUnqualifiedType(self), self)
+
def get_fully_qualified_name(
self, policy: PrintingPolicy, with_global_ns_prefix: bool = False
) -> str:
@@ -4339,6 +4370,7 @@ def set_property(self, property, value):
("clang_getArgType", [Type, c_uint], Type),
("clang_getArrayElementType", [Type], Type),
("clang_getArraySize", [Type], c_longlong),
+ ("clang_getAtomicUnqualifiedType", [Type], Type),
("clang_getFieldDeclBitWidth", [Cursor], c_int),
("clang_getCanonicalCursor", [Cursor], Cursor),
("clang_getCanonicalType", [Type], Type),
@@ -4417,6 +4449,7 @@ def set_property(self, property, value):
),
("clang_getLocation", [TranslationUnit, File, c_uint, c_uint], SourceLocation),
("clang_getLocationForOffset", [TranslationUnit, File, c_uint], SourceLocation),
+ ("clang_getNonReferenceType", [Type], Type),
("clang_getNullCursor", None, Cursor),
("clang_getNumArgTypes", [Type], c_uint),
("clang_getNumCompletionChunks", [c_void_p], c_int),
@@ -4446,6 +4479,7 @@ def set_property(self, property, value):
("clang_getTypeKindSpelling", [c_uint], _CXString),
("clang_getTypePrettyPrinted", [Type, PrintingPolicy], _CXString),
("clang_getTypeSpelling", [Type], _CXString),
+ ("clang_getUnqualifiedType", [Type], Type),
("clang_hashCursor", [Cursor], c_uint),
("clang_isAttribute", [CursorKind], c_uint),
("clang_getFullyQualifiedName", [Type, PrintingPolicy, c_uint], _CXString),
diff --git a/clang/bindings/python/tests/cindex/test_type.py b/clang/bindings/python/tests/cindex/test_type.py
index 562ac74e98b6e..b2a8b97182fd5 100644
--- a/clang/bindings/python/tests/cindex/test_type.py
+++ b/clang/bindings/python/tests/cindex/test_type.py
@@ -530,6 +530,57 @@ def test_pretty(self):
pp.set_property(PrintingPolicyProperty.SuppressTagKeyword, False)
self.assertEqual(f.type.get_canonical().pretty_printed(pp), "struct X")
+ def test_non_reference(self):
+ source = """
+ int &reference;
+ """
+ tu = get_tu(source, lang="cpp")
+ reference = get_cursor(tu, "reference")
+ self.assertEqual(
+ reference.type.get_non_reference().get_ref_qualifier(),
+ RefQualifierKind.NONE,
+ )
+
+ def test_unqualified(self):
+ source = """
+ bool b;
+ const long c;
+ volatile long v;
+ const volatile int cv;
+ _Atomic int a;
+ void f(int *__restrict l, const int *__restrict r, long s);
+ const bool &ref;
+ """
+ tu = get_tu(source, lang="cpp")
+ b = get_cursor(tu, "b")
+ c = get_cursor(tu, "c")
+ v = get_cursor(tu, "v")
+ cv = get_cursor(tu, "cv")
+ a = get_cursor(tu, "a")
+ l = get_cursor(tu, "l")
+ r = get_cursor(tu, "r")
+ ref = get_cursor(tu, "ref")
+ self.assertEqual(b.type.get_unqualified().spelling, "bool")
+ self.assertEqual(c.type.get_unqualified().spelling, "long")
+ self.assertEqual(v.type.get_unqualified().spelling, "long")
+ self.assertEqual(cv.type.get_unqualified().spelling, "int")
+ self.assertEqual(a.type.get_unqualified().spelling, "_Atomic(int)")
+ self.assertEqual(l.type.get_unqualified().spelling, "int *")
+ self.assertEqual(r.type.get_unqualified().spelling, "const int *")
+ self.assertEqual(ref.type.get_unqualified().spelling, "const bool &")
+ self.assertEqual(
+ ref.type.get_non_reference().get_unqualified().spelling, "bool"
+ )
+
+ def test_atomic_unqualified(self):
+ source = """
+ _Atomic int a;
+ """
+ tu = get_tu(source, lang="c")
+ a = get_cursor(tu, "a")
+ self.assertEqual(a.type.get_unqualified().spelling, "_Atomic(int)")
+ self.assertEqual(a.type.get_atomic_unqualified().spelling, "int")
+
def test_fully_qualified_name(self):
source = """
namespace home {
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 64113829ac8e6..92f7beef27c8a 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -427,6 +427,8 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the
### Python Binding Changes
+- Exposed `clang_getNonReferenceType`, `clang_getUnqualifiedType` and `clang_getAtomicUnqualifiedType` via `Type.get_non_reference()`, `Type.get_unqualified()` and `Type.get_atomic_unqualified()` respectively. (#GH175534)
+
### OpenMP Support
### SYCL Support
More information about the cfe-commits
mailing list