[clang] [libclang/python] Add missing enum variants (PR #143264)
Jannick Kremer via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 16 06:31:42 PDT 2025
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/143264
>From be61f911f07e5c5a497f942e530bd0f86f19478f Mon Sep 17 00:00:00 2001
From: Jannick Kremer <jannick.kremer at mailbox.org>
Date: Sat, 7 Jun 2025 21:57:17 +0900
Subject: [PATCH 01/11] [libclang/python] Add missing enum variants
Add tests to ensure that all C-enum variants are defined on Python side.
---
.../python/tests/cindex/test_enums.py | 49 ++++++++++++++++++-
1 file changed, 48 insertions(+), 1 deletion(-)
diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py
index 48452fd4f82d0..f7ed2e39037c1 100644
--- a/clang/bindings/python/tests/cindex/test_enums.py
+++ b/clang/bindings/python/tests/cindex/test_enums.py
@@ -1,4 +1,5 @@
import unittest
+from pathlib import Path
from clang.cindex import (
AccessSpecifier,
@@ -13,6 +14,7 @@
TemplateArgumentKind,
TLSKind,
TokenKind,
+ TranslationUnit,
TypeKind,
)
@@ -46,8 +48,53 @@ def test_from_id(self):
def test_duplicate_ids(self):
"""Check that no two kinds have the same id"""
- # for enum in self.enums:
for enum in self.enums:
num_declared_variants = len(enum._member_map_.keys())
num_unique_variants = len(list(enum))
self.assertEqual(num_declared_variants, num_unique_variants)
+
+ def test_all_variants(self):
+ """Check that all libclang enum values are also defined in cindex"""
+ cenum_to_pythonenum = {
+ "CX_CXXAccessSpecifier": AccessSpecifier,
+ "CXAvailabilityKind": AvailabilityKind,
+ "CXBinaryOperatorKind": BinaryOperator,
+ "CXCursorKind": CursorKind,
+ "CXCursor_ExceptionSpecificationKind": ExceptionSpecificationKind,
+ "CXLinkageKind": LinkageKind,
+ "CXRefQualifierKind": RefQualifierKind,
+ "CX_StorageClass": StorageClass,
+ "CXTemplateArgumentKind": TemplateArgumentKind,
+ "CXTLSKind": TLSKind,
+ "CXTokenKind": TokenKind,
+ "CXTypeKind": TypeKind,
+ }
+
+ indexheader = (
+ Path(__file__).parent.parent.parent.parent.parent
+ / "include/clang-c/Index.h"
+ )
+ tu = TranslationUnit.from_source(indexheader, ["-x", "c++"])
+
+ enum_variant_map = {}
+ # For all enums in self.enums, extract all enum variants defined in Index.h
+ for cursor in tu.cursor.walk_preorder():
+ type_class = cenum_to_pythonenum.get(cursor.type.spelling)
+ if (
+ cursor.kind == CursorKind.ENUM_CONSTANT_DECL
+ and type_class in self.enums
+ ):
+ if type_class not in enum_variant_map:
+ enum_variant_map[type_class] = []
+ enum_variant_map[type_class].append(cursor.enum_value)
+
+ for enum in self.enums:
+ with self.subTest(enum):
+ python_kinds = set([kind.value for kind in enum])
+ c_kinds = set(enum_variant_map[enum])
+ missing_python_kinds = c_kinds - python_kinds
+ self.assertEqual(
+ missing_python_kinds,
+ set(),
+ f"Please ensure these variants are defined inside {enum} in cindex.py.",
+ )
>From 78a0cbeb5119e1beb2c2b3f64bde9dc452af588a Mon Sep 17 00:00:00 2001
From: Jannick Kremer <jannick.kremer at mailbox.org>
Date: Sat, 7 Jun 2025 23:29:01 +0900
Subject: [PATCH 02/11] Add new variants
---
clang/bindings/python/clang/cindex.py | 62 ++++++++++++++++++-
.../python/tests/cindex/test_enums.py | 2 +-
2 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 3398823836e62..23a8b6b439ca5 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -708,7 +708,6 @@ def is_unexposed(self):
"""Test if this is an unexposed kind."""
return conf.lib.clang_isUnexposed(self) # type: ignore [no-any-return]
-
###
# Declaration Kinds
@@ -835,7 +834,6 @@ def is_unexposed(self):
# A C++ access specifier decl.
CXX_ACCESS_SPEC_DECL = 39
-
###
# Reference Kinds
@@ -1436,12 +1434,60 @@ def is_unexposed(self):
# OpenMP scope directive.
OMP_SCOPE_DIRECTIVE = 306
+ # OpenMP reverse directive.
+ OMPReverseDirective = 307
+
+ # OpenMP interchange directive.
+ OMPInterchangeDirective = 308
+
+ # OpenMP assume directive.
+ OMPAssumeDirective = 309
+
# OpenMP stripe directive.
OMP_STRIPE_DIRECTIVE = 310
# OpenACC Compute Construct.
OPEN_ACC_COMPUTE_DIRECTIVE = 320
+ # OpenACC Loop Construct.
+ OpenACCLoopConstruct = 321
+
+ # OpenACC Combined Constructs.
+ OpenACCCombinedConstruct = 322
+
+ # OpenACC data Construct.
+ OpenACCDataConstruct = 323
+
+ # OpenACC enter data Construct.
+ OpenACCEnterDataConstruct = 324
+
+ # OpenACC exit data Construct.
+ OpenACCExitDataConstruct = 325
+
+ # OpenACC host_data Construct.
+ OpenACCHostDataConstruct = 326
+
+ # OpenACC wait Construct.
+ OpenACCWaitConstruct = 327
+
+ # OpenACC init Construct.
+ OpenACCInitConstruct = 328
+
+ # OpenACC shutdown Construct.
+ OpenACCShutdownConstruct = 329
+
+ # OpenACC set Construct.
+ OpenACCSetConstruct = 330
+
+ # OpenACC update Construct.
+ OpenACCUpdateConstruct = 331
+
+ # OpenACC atomic Construct.
+ OpenACCAtomicConstruct = 332
+
+ # OpenACC cache Construct.
+ OpenACCCacheConstruct = 333
+
###
# Other Kinds
@@ -1560,6 +1606,7 @@ class ExceptionSpecificationKind(BaseEnumeration):
UNEVALUATED = 6
UNINSTANTIATED = 7
UNPARSED = 8
+ NOTHROW = 9
### Cursors ###
@@ -2492,6 +2539,13 @@ def spelling(self):
FLOAT128 = 30
HALF = 31
FLOAT16 = 32
+ SHORTACCUM = 33
+ ACCUM = 34
+ LONGACCUM = 35
+ USHORTACCUM = 36
+ UACCUM = 37
+ ULONGACCUM = 38
+ BFLOAT16 = 39
IBM128 = 40
COMPLEX = 100
POINTER = 101
@@ -2576,6 +2630,10 @@ def spelling(self):
ATOMIC = 177
BTFTAGATTRIBUTED = 178
+ HLSLRESOURCE = 179
+ HLSLATTRIBUTEDRESOURCE = 180
+ HLSLINLINESPIRV = 181
+
class RefQualifierKind(BaseEnumeration):
"""Describes a specific ref-qualifier of a type."""
diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py
index f7ed2e39037c1..0be1b58b2d744 100644
--- a/clang/bindings/python/tests/cindex/test_enums.py
+++ b/clang/bindings/python/tests/cindex/test_enums.py
@@ -96,5 +96,5 @@ def test_all_variants(self):
self.assertEqual(
missing_python_kinds,
set(),
- f"Please ensure these variants are defined inside {enum} in cindex.py.",
+ f"Please ensure these are defined in {enum} in cindex.py.",
)
>From 1fa6e5073ed29fc3befdeb24d3df2cd67f09ee91 Mon Sep 17 00:00:00 2001
From: Jannick Kremer <jannick.kremer at mailbox.org>
Date: Mon, 15 Sep 2025 23:02:51 +0900
Subject: [PATCH 03/11] Determine enums automatically via BaseEnumeration
subclasses
---
.../python/tests/cindex/test_enums.py | 20 +++++--------------
1 file changed, 5 insertions(+), 15 deletions(-)
diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py
index 0be1b58b2d744..2215bbca04f2a 100644
--- a/clang/bindings/python/tests/cindex/test_enums.py
+++ b/clang/bindings/python/tests/cindex/test_enums.py
@@ -16,25 +16,13 @@
TokenKind,
TranslationUnit,
TypeKind,
+ PrintingPolicyProperty,
+ BaseEnumeration,
)
class TestEnums(unittest.TestCase):
- enums = [
- TokenKind,
- CursorKind,
- TemplateArgumentKind,
- ExceptionSpecificationKind,
- AvailabilityKind,
- AccessSpecifier,
- TypeKind,
- RefQualifierKind,
- LanguageKind,
- LinkageKind,
- TLSKind,
- StorageClass,
- BinaryOperator,
- ]
+ enums = BaseEnumeration.__subclasses__()
def test_from_id(self):
"""Check that kinds can be constructed from valid IDs"""
@@ -61,7 +49,9 @@ def test_all_variants(self):
"CXBinaryOperatorKind": BinaryOperator,
"CXCursorKind": CursorKind,
"CXCursor_ExceptionSpecificationKind": ExceptionSpecificationKind,
+ "CXLanguageKind": LanguageKind,
"CXLinkageKind": LinkageKind,
+ "CXPrintingPolicyProperty": PrintingPolicyProperty,
"CXRefQualifierKind": RefQualifierKind,
"CX_StorageClass": StorageClass,
"CXTemplateArgumentKind": TemplateArgumentKind,
>From fbf906e51e7a41be01c132abbdeba77444fa0b5b Mon Sep 17 00:00:00 2001
From: Jannick Kremer <jannick.kremer at mailbox.org>
Date: Mon, 15 Sep 2025 23:06:30 +0900
Subject: [PATCH 04/11] Fix lexicographic ordering
---
clang/bindings/python/tests/cindex/test_enums.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py
index 2215bbca04f2a..ea53aa8333f36 100644
--- a/clang/bindings/python/tests/cindex/test_enums.py
+++ b/clang/bindings/python/tests/cindex/test_enums.py
@@ -45,6 +45,7 @@ def test_all_variants(self):
"""Check that all libclang enum values are also defined in cindex"""
cenum_to_pythonenum = {
"CX_CXXAccessSpecifier": AccessSpecifier,
+ "CX_StorageClass": StorageClass,
"CXAvailabilityKind": AvailabilityKind,
"CXBinaryOperatorKind": BinaryOperator,
"CXCursorKind": CursorKind,
@@ -53,7 +54,6 @@ def test_all_variants(self):
"CXLinkageKind": LinkageKind,
"CXPrintingPolicyProperty": PrintingPolicyProperty,
"CXRefQualifierKind": RefQualifierKind,
- "CX_StorageClass": StorageClass,
"CXTemplateArgumentKind": TemplateArgumentKind,
"CXTLSKind": TLSKind,
"CXTokenKind": TokenKind,
>From ad6ab772638134cea9391d93ecf0c970c3c2d501 Mon Sep 17 00:00:00 2001
From: Jannick Kremer <jannick.kremer at mailbox.org>
Date: Mon, 15 Sep 2025 23:06:58 +0900
Subject: [PATCH 05/11] Fix comment
---
clang/bindings/python/tests/cindex/test_enums.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py
index ea53aa8333f36..fd9cb418cc621 100644
--- a/clang/bindings/python/tests/cindex/test_enums.py
+++ b/clang/bindings/python/tests/cindex/test_enums.py
@@ -42,7 +42,7 @@ def test_duplicate_ids(self):
self.assertEqual(num_declared_variants, num_unique_variants)
def test_all_variants(self):
- """Check that all libclang enum values are also defined in cindex"""
+ """Check that all libclang enum values are also defined in cindex.py"""
cenum_to_pythonenum = {
"CX_CXXAccessSpecifier": AccessSpecifier,
"CX_StorageClass": StorageClass,
>From fb04f0993f5dd926368ba394622201d4fd9b0138 Mon Sep 17 00:00:00 2001
From: Jannick Kremer <jannick.kremer at mailbox.org>
Date: Mon, 15 Sep 2025 23:10:18 +0900
Subject: [PATCH 06/11] Also test that cindex.py contains no superfluous
variants
---
clang/bindings/python/tests/cindex/test_enums.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py
index fd9cb418cc621..4c23f4fd46353 100644
--- a/clang/bindings/python/tests/cindex/test_enums.py
+++ b/clang/bindings/python/tests/cindex/test_enums.py
@@ -81,10 +81,17 @@ def test_all_variants(self):
for enum in self.enums:
with self.subTest(enum):
python_kinds = set([kind.value for kind in enum])
- c_kinds = set(enum_variant_map[enum])
+ # Defined in Index.h but not in cindex.py
missing_python_kinds = c_kinds - python_kinds
self.assertEqual(
missing_python_kinds,
set(),
f"Please ensure these are defined in {enum} in cindex.py.",
)
+ # Defined in cindex.py but not in Index.h
+ superfluous_python_kinds = python_kinds - c_kinds
+ self.assertEqual(
+ superfluous_python_kinds,
+ set(),
+ f"Please ensure that all {enum} kinds defined in cindex.py have an equivalent in Index.h",
+ )
>From c1fa85ecd99ab19fe4b9f006e28a82fe59c1afaa Mon Sep 17 00:00:00 2001
From: Jannick Kremer <jannick.kremer at mailbox.org>
Date: Mon, 15 Sep 2025 23:13:58 +0900
Subject: [PATCH 07/11] Rename variable
---
clang/bindings/python/tests/cindex/test_enums.py | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py
index 4c23f4fd46353..bdcf3b1a203ed 100644
--- a/clang/bindings/python/tests/cindex/test_enums.py
+++ b/clang/bindings/python/tests/cindex/test_enums.py
@@ -69,14 +69,11 @@ def test_all_variants(self):
enum_variant_map = {}
# For all enums in self.enums, extract all enum variants defined in Index.h
for cursor in tu.cursor.walk_preorder():
- type_class = cenum_to_pythonenum.get(cursor.type.spelling)
- if (
- cursor.kind == CursorKind.ENUM_CONSTANT_DECL
- and type_class in self.enums
- ):
- if type_class not in enum_variant_map:
- enum_variant_map[type_class] = []
- enum_variant_map[type_class].append(cursor.enum_value)
+ python_enum = cenum_to_pythonenum.get(cursor.type.spelling)
+ if cursor.kind == CursorKind.ENUM_CONSTANT_DECL:
+ if python_enum not in enum_variant_map:
+ enum_variant_map[python_enum] = []
+ enum_variant_map[python_enum].append(cursor.enum_value)
for enum in self.enums:
with self.subTest(enum):
>From 0cc05084ee759ef79c6270508207702c08ad21bd Mon Sep 17 00:00:00 2001
From: Jannick Kremer <jannick.kremer at mailbox.org>
Date: Mon, 15 Sep 2025 23:16:16 +0900
Subject: [PATCH 08/11] Report missing enum names instead of values
---
clang/bindings/python/tests/cindex/test_enums.py | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py
index bdcf3b1a203ed..5637b453aa231 100644
--- a/clang/bindings/python/tests/cindex/test_enums.py
+++ b/clang/bindings/python/tests/cindex/test_enums.py
@@ -72,23 +72,31 @@ def test_all_variants(self):
python_enum = cenum_to_pythonenum.get(cursor.type.spelling)
if cursor.kind == CursorKind.ENUM_CONSTANT_DECL:
if python_enum not in enum_variant_map:
- enum_variant_map[python_enum] = []
- enum_variant_map[python_enum].append(cursor.enum_value)
+ enum_variant_map[python_enum] = dict()
+ enum_variant_map[python_enum][cursor.enum_value] = cursor.spelling
for enum in self.enums:
with self.subTest(enum):
python_kinds = set([kind.value for kind in enum])
+ num_to_c_kind = enum_variant_map[enum]
+ c_kinds = set(num_to_c_kind.keys())
# Defined in Index.h but not in cindex.py
missing_python_kinds = c_kinds - python_kinds
+ missing_names = set(
+ [num_to_c_kind[kind] for kind in missing_python_kinds]
+ )
self.assertEqual(
- missing_python_kinds,
+ missing_names,
set(),
f"Please ensure these are defined in {enum} in cindex.py.",
)
# Defined in cindex.py but not in Index.h
superfluous_python_kinds = python_kinds - c_kinds
+ missing_names = set(
+ [enum.from_id(kind) for kind in superfluous_python_kinds]
+ )
self.assertEqual(
- superfluous_python_kinds,
+ missing_names,
set(),
f"Please ensure that all {enum} kinds defined in cindex.py have an equivalent in Index.h",
)
>From 804550a74ed91fdfa082140867e918cf7cdc554f Mon Sep 17 00:00:00 2001
From: Jannick Kremer <jannick.kremer at mailbox.org>
Date: Tue, 16 Sep 2025 22:29:01 +0900
Subject: [PATCH 09/11] Remove AccessSpecifier.NONE
---
clang/bindings/python/clang/cindex.py | 1 -
clang/docs/ReleaseNotes.rst | 1 +
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 23a8b6b439ca5..99ec75d1d5ddc 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2491,7 +2491,6 @@ class AccessSpecifier(BaseEnumeration):
PUBLIC = 1
PROTECTED = 2
PRIVATE = 3
- NONE = 4
### Type Kinds ###
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index dbba8f5db0cef..eb84d990b4268 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -105,6 +105,7 @@ Clang Python Bindings Potentially Breaking Changes
- TypeKind ``ELABORATED`` is not used anymore, per clang AST changes removing
ElaboratedTypes. The value becomes unused, and all the existing users should
expect the former underlying type to be reported instead.
+- Remove ``AccessSpecifier.NONE`` kind. No libclang interfaces ever returned this kind.
What's New in Clang |release|?
==============================
>From 6a39f06e320928a43237947f239255c870dc5af4 Mon Sep 17 00:00:00 2001
From: Jannick Kremer <jannick.kremer at mailbox.org>
Date: Tue, 16 Sep 2025 22:30:17 +0900
Subject: [PATCH 10/11] Add TypeKind aliases from Index.h
---
clang/bindings/python/clang/cindex.py | 2 ++
clang/bindings/python/tests/cindex/test_enums.py | 7 -------
2 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 99ec75d1d5ddc..76269805ffa77 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2546,6 +2546,8 @@ def spelling(self):
ULONGACCUM = 38
BFLOAT16 = 39
IBM128 = 40
+ FIRSTBUILTIN = VOID
+ LASTBUILTIN = IBM128
COMPLEX = 100
POINTER = 101
BLOCKPOINTER = 102
diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py
index 5637b453aa231..98370bf6c0109 100644
--- a/clang/bindings/python/tests/cindex/test_enums.py
+++ b/clang/bindings/python/tests/cindex/test_enums.py
@@ -34,13 +34,6 @@ def test_from_id(self):
with self.assertRaises(ValueError):
enum.from_id(-1)
- def test_duplicate_ids(self):
- """Check that no two kinds have the same id"""
- for enum in self.enums:
- num_declared_variants = len(enum._member_map_.keys())
- num_unique_variants = len(list(enum))
- self.assertEqual(num_declared_variants, num_unique_variants)
-
def test_all_variants(self):
"""Check that all libclang enum values are also defined in cindex.py"""
cenum_to_pythonenum = {
>From 7439bc93f8638e31e318e1696b24f8440bc6f25a Mon Sep 17 00:00:00 2001
From: Jannick Kremer <jannick.kremer at mailbox.org>
Date: Tue, 16 Sep 2025 22:31:04 +0900
Subject: [PATCH 11/11] Add FIXME for C++ parsing of Index.h
---
clang/bindings/python/tests/cindex/test_enums.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py
index 98370bf6c0109..1052ed881840a 100644
--- a/clang/bindings/python/tests/cindex/test_enums.py
+++ b/clang/bindings/python/tests/cindex/test_enums.py
@@ -57,6 +57,9 @@ def test_all_variants(self):
Path(__file__).parent.parent.parent.parent.parent
/ "include/clang-c/Index.h"
)
+ # FIXME: Index.h is a C file, but we read it as a C++ file because we
+ # don't get ENUM_CONSTANT_DECL cursors otherwise, which we need here
+ # See bug report: https://github.com/llvm/llvm-project/issues/159075
tu = TranslationUnit.from_source(indexheader, ["-x", "c++"])
enum_variant_map = {}
More information about the cfe-commits
mailing list