Skip to content

Conversation

@DeinAlptraum
Copy link
Contributor

@DeinAlptraum DeinAlptraum commented Mar 21, 2025

Make Cursor hashable
Add Cursor.has_attr()
Add Cursor.specialized_template

This covers the Cursor interface changes added by #120590

Make Cursor hashable Add Cursor.has_attr() Add Cursor.specialized_template
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:as-a-library libclang and C++ API labels Mar 21, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 21, 2025

@llvm/pr-subscribers-clang

Author: Jannick Kremer (DeinAlptraum)

Changes

Make Cursor hashable
Add Cursor.has_attr()
Add Cursor.specialized_template


Full diff: https://github.com/llvm/llvm-project/pull/132377.diff

3 Files Affected:

  • (modified) clang/bindings/python/clang/cindex.py (+17)
  • (modified) clang/bindings/python/tests/cindex/test_cursor.py (+40)
  • (modified) clang/docs/ReleaseNotes.rst (+6)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 879a0a3c5c58c..090ee899ad60e 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -1561,6 +1561,9 @@ def __eq__(self, other): def __ne__(self, other): return not self.__eq__(other) + def __hash__(self) -> int: + return self.hash + def is_definition(self): """ Returns true if the declaration pointed at by the cursor is also a @@ -2035,6 +2038,13 @@ def lexical_parent(self): return self._lexical_parent + @property + def specialized_template(self) -> Cursor | None: + """Return the primary template that this cursor is a specialization of, if any.""" + return Cursor.from_cursor_result( + conf.lib.clang_getSpecializedCursorTemplate(self), self + ) + @property def translation_unit(self): """Returns the TranslationUnit to which this Cursor belongs.""" @@ -2178,6 +2188,12 @@ def get_bitfield_width(self): """ return conf.lib.clang_getFieldDeclBitWidth(self) # type: ignore [no-any-return] + def has_attrs(self) -> bool: + """ + Determine whether the given cursor has any attributes. + """ + return bool(conf.lib.clang_Cursor_hasAttrs(self)) + @staticmethod def from_result(res, arg): assert isinstance(res, Cursor) @@ -3932,6 +3948,7 @@ def set_property(self, property, value): ("clang_getCursorType", [Cursor], Type), ("clang_getCursorUSR", [Cursor], _CXString), ("clang_Cursor_getMangling", [Cursor], _CXString), + ("clang_Cursor_hasAttrs", [Cursor], c_uint), # ("clang_getCXTUResourceUsage", # [TranslationUnit], # CXTUResourceUsage), diff --git a/clang/bindings/python/tests/cindex/test_cursor.py b/clang/bindings/python/tests/cindex/test_cursor.py index c6aa65ce3c29f..9947f551cc2f8 100644 --- a/clang/bindings/python/tests/cindex/test_cursor.py +++ b/clang/bindings/python/tests/cindex/test_cursor.py @@ -4,6 +4,7 @@ AvailabilityKind, BinaryOperator, Config, + Cursor, CursorKind, PrintingPolicy, PrintingPolicyProperty, @@ -995,3 +996,42 @@ def test_pretty_print(self): pp.set_property(PrintingPolicyProperty.Bool, False) self.assertEqual(pp.get_property(PrintingPolicyProperty.Bool), False) self.assertEqual(f.pretty_printed(pp), "void f(_Bool x) {\n}\n") + + def test_has_attrs(self): + tu = get_tu( + """ +struct A; +struct A final {}; + +struct B; +struct B {}; +""", + lang="cpp", + ) + A = get_cursor(tu, "A") + B = get_cursor(tu, "B") + self.assertTrue(A.get_definition().has_attrs()) + self.assertFalse(B.get_definition().has_attrs()) + + def test_hash(self): + def accumulate_cursors(cursor: Cursor, all_cursors: list[Cursor]): + all_cursors.append(cursor) + for child in cursor.get_children(): + all_cursors = accumulate_cursors(child, all_cursors) + return all_cursors + + tu = get_tu(kInput) + all_cursors = accumulate_cursors(tu.cursor, []) + cursor_hashes = set() + for cursor in all_cursors: + self.assertNotIn(hash(cursor), cursor_hashes) + cursor_hashes.add(hash(cursor)) + + def test_specialized_template(self): + tu = get_tu(kTemplateArgTest, lang="cpp") + foos = get_cursors(tu, "foo") + prime_foo = foos[1].specialized_template + + self.assertNotEqual(foos[0], foos[1]) + self.assertEqual(foos[0], prime_foo) + self.assertIsNone(tu.cursor.specialized_template) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index a25808e36bd51..ab68be3702840 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -442,6 +442,12 @@ Sanitizers Python Binding Changes ---------------------- +- Made ``Cursor`` hashable. +- Added ``Cursor.has_attrs``, a binding for ``clang_Cursor_hasAttrs``, to check + whether a cursor has any attributes. +- Added ``Cursor.specialized_template``, a binding for + ``clang_getSpecializedCursorTemplate``, to retrieve the primary template that + the cursor is a specialization of. - Added ``Type.get_methods``, a binding for ``clang_visitCXXMethods``, which allows visiting the methods of a class. 
@github-actions
Copy link

github-actions bot commented Mar 22, 2025

✅ With the latest revision this PR passed the Python code formatter.

@DeinAlptraum DeinAlptraum requested a review from Endilll March 22, 2025 11:01
@DeinAlptraum DeinAlptraum merged commit 20fc2d5 into llvm:main Mar 24, 2025
14 checks passed
@DeinAlptraum DeinAlptraum deleted the 120590-cursorinterface branch March 27, 2025 12:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:as-a-library libclang and C++ API clang Clang issues not falling into any other category

4 participants