Skip to content

Commit 4dc0513

Browse files
authored
[libclang/python] Sync python kinds with Index.h enums (#143264)
Add tests to ensure that all C-enum variants are defined on Python side, and that the Python bindings do not contain variants not defined on the C side
1 parent 868aa5f commit 4dc0513

File tree

3 files changed

+134
-24
lines changed

3 files changed

+134
-24
lines changed

clang/bindings/python/clang/cindex.py

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,6 @@ def is_unexposed(self):
708708
"""Test if this is an unexposed kind."""
709709
return conf.lib.clang_isUnexposed(self) # type: ignore [no-any-return]
710710

711-
712711
###
713712
# Declaration Kinds
714713

@@ -835,7 +834,6 @@ def is_unexposed(self):
835834
# A C++ access specifier decl.
836835
CXX_ACCESS_SPEC_DECL = 39
837836

838-
839837
###
840838
# Reference Kinds
841839

@@ -1436,12 +1434,60 @@ def is_unexposed(self):
14361434
# OpenMP scope directive.
14371435
OMP_SCOPE_DIRECTIVE = 306
14381436

1437+
# OpenMP reverse directive.
1438+
OMPReverseDirective = 307
1439+
1440+
# OpenMP interchange directive.
1441+
OMPInterchangeDirective = 308
1442+
1443+
# OpenMP assume directive.
1444+
OMPAssumeDirective = 309
1445+
14391446
# OpenMP stripe directive.
14401447
OMP_STRIPE_DIRECTIVE = 310
14411448

14421449
# OpenACC Compute Construct.
14431450
OPEN_ACC_COMPUTE_DIRECTIVE = 320
14441451

1452+
# OpenACC Loop Construct.
1453+
OpenACCLoopConstruct = 321
1454+
1455+
# OpenACC Combined Constructs.
1456+
OpenACCCombinedConstruct = 322
1457+
1458+
# OpenACC data Construct.
1459+
OpenACCDataConstruct = 323
1460+
1461+
# OpenACC enter data Construct.
1462+
OpenACCEnterDataConstruct = 324
1463+
1464+
# OpenACC exit data Construct.
1465+
OpenACCExitDataConstruct = 325
1466+
1467+
# OpenACC host_data Construct.
1468+
OpenACCHostDataConstruct = 326
1469+
1470+
# OpenACC wait Construct.
1471+
OpenACCWaitConstruct = 327
1472+
1473+
# OpenACC init Construct.
1474+
OpenACCInitConstruct = 328
1475+
1476+
# OpenACC shutdown Construct.
1477+
OpenACCShutdownConstruct = 329
1478+
1479+
# OpenACC set Construct.
1480+
OpenACCSetConstruct = 330
1481+
1482+
# OpenACC update Construct.
1483+
OpenACCUpdateConstruct = 331
1484+
1485+
# OpenACC atomic Construct.
1486+
OpenACCAtomicConstruct = 332
1487+
1488+
# OpenACC cache Construct.
1489+
OpenACCCacheConstruct = 333
1490+
14451491
###
14461492
# Other Kinds
14471493

@@ -1560,6 +1606,7 @@ class ExceptionSpecificationKind(BaseEnumeration):
15601606
UNEVALUATED = 6
15611607
UNINSTANTIATED = 7
15621608
UNPARSED = 8
1609+
NOTHROW = 9
15631610

15641611
### Cursors ###
15651612

@@ -2444,7 +2491,6 @@ class AccessSpecifier(BaseEnumeration):
24442491
PUBLIC = 1
24452492
PROTECTED = 2
24462493
PRIVATE = 3
2447-
NONE = 4
24482494

24492495
### Type Kinds ###
24502496

@@ -2492,7 +2538,16 @@ def spelling(self):
24922538
FLOAT128 = 30
24932539
HALF = 31
24942540
FLOAT16 = 32
2541+
SHORTACCUM = 33
2542+
ACCUM = 34
2543+
LONGACCUM = 35
2544+
USHORTACCUM = 36
2545+
UACCUM = 37
2546+
ULONGACCUM = 38
2547+
BFLOAT16 = 39
24952548
IBM128 = 40
2549+
FIRSTBUILTIN = VOID
2550+
LASTBUILTIN = IBM128
24962551
COMPLEX = 100
24972552
POINTER = 101
24982553
BLOCKPOINTER = 102
@@ -2576,6 +2631,10 @@ def spelling(self):
25762631
ATOMIC = 177
25772632
BTFTAGATTRIBUTED = 178
25782633

2634+
HLSLRESOURCE = 179
2635+
HLSLATTRIBUTEDRESOURCE = 180
2636+
HLSLINLINESPIRV = 181
2637+
25792638
class RefQualifierKind(BaseEnumeration):
25802639
"""Describes a specific ref-qualifier of a type."""
25812640

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import unittest
2+
from pathlib import Path
23

34
from clang.cindex import (
45
AccessSpecifier,
@@ -13,26 +14,15 @@
1314
TemplateArgumentKind,
1415
TLSKind,
1516
TokenKind,
17+
TranslationUnit,
1618
TypeKind,
19+
PrintingPolicyProperty,
20+
BaseEnumeration,
1721
)
1822

1923

2024
class TestEnums(unittest.TestCase):
21-
enums = [
22-
TokenKind,
23-
CursorKind,
24-
TemplateArgumentKind,
25-
ExceptionSpecificationKind,
26-
AvailabilityKind,
27-
AccessSpecifier,
28-
TypeKind,
29-
RefQualifierKind,
30-
LanguageKind,
31-
LinkageKind,
32-
TLSKind,
33-
StorageClass,
34-
BinaryOperator,
35-
]
25+
enums = BaseEnumeration.__subclasses__()
3626

3727
def test_from_id(self):
3828
"""Check that kinds can be constructed from valid IDs"""
@@ -44,10 +34,70 @@ def test_from_id(self):
4434
with self.assertRaises(ValueError):
4535
enum.from_id(-1)
4636

47-
def test_duplicate_ids(self):
48-
"""Check that no two kinds have the same id"""
49-
# for enum in self.enums:
37+
def test_all_variants(self):
38+
"""Check that all libclang enum values are also defined in cindex.py"""
39+
cenum_to_pythonenum = {
40+
"CX_CXXAccessSpecifier": AccessSpecifier,
41+
"CX_StorageClass": StorageClass,
42+
"CXAvailabilityKind": AvailabilityKind,
43+
"CXBinaryOperatorKind": BinaryOperator,
44+
"CXCursorKind": CursorKind,
45+
"CXCursor_ExceptionSpecificationKind": ExceptionSpecificationKind,
46+
"CXLanguageKind": LanguageKind,
47+
"CXLinkageKind": LinkageKind,
48+
"CXPrintingPolicyProperty": PrintingPolicyProperty,
49+
"CXRefQualifierKind": RefQualifierKind,
50+
"CXTemplateArgumentKind": TemplateArgumentKind,
51+
"CXTLSKind": TLSKind,
52+
"CXTokenKind": TokenKind,
53+
"CXTypeKind": TypeKind,
54+
}
55+
56+
indexheader = (
57+
Path(__file__).parent.parent.parent.parent.parent
58+
/ "include/clang-c/Index.h"
59+
)
60+
# FIXME: Index.h is a C file, but we read it as a C++ file because we
61+
# don't get ENUM_CONSTANT_DECL cursors otherwise, which we need here
62+
# See bug report: https://github.com/llvm/llvm-project/issues/159075
63+
tu = TranslationUnit.from_source(indexheader, ["-x", "c++"])
64+
65+
enum_variant_map = {}
66+
# For all enums in self.enums, extract all enum variants defined in Index.h
67+
for cursor in tu.cursor.walk_preorder():
68+
if cursor.kind == CursorKind.ENUM_CONSTANT_DECL:
69+
python_enum = cenum_to_pythonenum.get(cursor.type.spelling)
70+
if python_enum not in enum_variant_map:
71+
enum_variant_map[python_enum] = dict()
72+
enum_variant_map[python_enum][cursor.enum_value] = cursor.spelling
73+
5074
for enum in self.enums:
51-
num_declared_variants = len(enum._member_map_.keys())
52-
num_unique_variants = len(list(enum))
53-
self.assertEqual(num_declared_variants, num_unique_variants)
75+
with self.subTest(enum):
76+
# This ensures only the custom assert message below is printed
77+
self.longMessage = False
78+
79+
python_kinds = set([kind.value for kind in enum])
80+
num_to_c_kind = enum_variant_map[enum]
81+
c_kinds = set(num_to_c_kind.keys())
82+
# Defined in Index.h but not in cindex.py
83+
missing_python_kinds = c_kinds - python_kinds
84+
missing_names = set(
85+
[num_to_c_kind[kind] for kind in missing_python_kinds]
86+
)
87+
self.assertEqual(
88+
missing_names,
89+
set(),
90+
f"{missing_names} variants are missing. "
91+
f"Please ensure these are defined in {enum} in cindex.py.",
92+
)
93+
# Defined in cindex.py but not in Index.h
94+
superfluous_python_kinds = python_kinds - c_kinds
95+
missing_names = set(
96+
[enum.from_id(kind) for kind in superfluous_python_kinds]
97+
)
98+
self.assertEqual(
99+
missing_names,
100+
set(),
101+
f"{missing_names} variants only exist in the Python bindings. "
102+
f"Please ensure that all {enum} kinds defined in cindex.py have an equivalent in Index.h",
103+
)

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ Clang Python Bindings Potentially Breaking Changes
125125
- TypeKind ``ELABORATED`` is not used anymore, per clang AST changes removing
126126
ElaboratedTypes. The value becomes unused, and all the existing users should
127127
expect the former underlying type to be reported instead.
128+
- Remove ``AccessSpecifier.NONE`` kind. No libclang interfaces ever returned this kind.
128129

129130
What's New in Clang |release|?
130131
==============================

0 commit comments

Comments
 (0)