[clang] [libclang/python] Add CompletionChunkKind enum and deprecate old CompletionChunk.Kind (PR #176631)
Jannick Kremer via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 20 04:58:44 PST 2026
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/176631
>From 76e2a19d3a2047b728832f0a2c4e16b8e1b76944 Mon Sep 17 00:00:00 2001
From: Jannick Kremer <jannick.kremer at mailbox.org>
Date: Sun, 18 Jan 2026 16:35:05 +0900
Subject: [PATCH 1/3] Add CompletionChunkKind enum
Add tests to ensure string-comparability with CompletionChunk.Kind
---
clang/bindings/python/clang/cindex.py | 48 +++++++++++++++++++
.../tests/cindex/test_code_completion.py | 13 ++++-
.../python/tests/cindex/test_enums.py | 2 +
3 files changed, 62 insertions(+), 1 deletion(-)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 29c35628cf60c..45a8ddf83bb27 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -3117,6 +3117,54 @@ def isKindInformative(self) -> bool:
def isKindResultType(self) -> bool:
return self.__kindNumber == 15
+### Completion Chunk Kinds ###
+class CompletionChunkKind(BaseEnumeration):
+ """
+ Describes a single piece of text within a code-completion string.
+ """
+
+ def __str__(self) -> str:
+ """
+ Converts enum value to string in the old camelCase format.
+ This is a temporary measure that will be changed in the future release
+ to return string in ALL_CAPS format, like for other enums.
+ """
+
+ warnings.warn(
+ "String representation of 'CompletionChunkKind' will be "
+ "changed in a future release from 'camelCase' to 'ALL_CAPS' to "
+ "match other enums. 'CompletionChunkKind's can be "
+ "compared to one another without conversion to string.",
+ DeprecationWarning,
+ )
+ # Remove underscores
+ components = self.name.split("_")
+ # Upper-camel case each split component
+ components = [component.lower().capitalize() for component in components]
+ return "".join(components)
+
+ OPTIONAL = 0
+ TYPED_TEXT = 1
+ TEXT = 2
+ PLACEHOLDER = 3
+ INFORMATIVE = 4
+ CURRENT_PARAMETER = 5
+ LEFT_PAREN = 6
+ RIGHT_PAREN = 7
+ LEFT_BRACKET = 8
+ RIGHT_BRACKET = 9
+ LEFT_BRACE = 10
+ RIGHT_BRACE = 11
+ LEFT_ANGLE = 12
+ RIGHT_ANGLE = 13
+ COMMA = 14
+ RESULT_TYPE = 15
+ COLON = 16
+ SEMI_COLON = 17
+ EQUAL = 18
+ HORIZONTAL_SPACE = 19
+ VERTICAL_SPACE = 20
+
completionChunkKindMap = {
0: CompletionChunk.Kind("Optional"),
diff --git a/clang/bindings/python/tests/cindex/test_code_completion.py b/clang/bindings/python/tests/cindex/test_code_completion.py
index 4c0ecca85e4f4..e4924e1f8f4c6 100644
--- a/clang/bindings/python/tests/cindex/test_code_completion.py
+++ b/clang/bindings/python/tests/cindex/test_code_completion.py
@@ -1,4 +1,4 @@
-from clang.cindex import AvailabilityKind, CompletionString, TranslationUnit
+from clang.cindex import AvailabilityKind, CompletionChunkKind, completionChunkKindMap, CompletionString, TranslationUnit
import unittest
from pathlib import Path
@@ -174,3 +174,14 @@ def test_compat_str(self):
for id, string in kindStringMap.items():
kind = CompletionString.AvailabilityKindCompat.from_id(id)
self.assertEqual(str(kind), string)
+
+ def test_completion_chunk_kind_compatibility(self):
+ # Check that all new kinds correspond to an old kind
+ for new_kind in CompletionChunkKind:
+ old_kind = completionChunkKindMap[new_kind.value]
+ self.assertEqual(str(old_kind), str(new_kind))
+
+ # Check that all old kinds correspond to a new kind
+ for value, old_kind in completionChunkKindMap.items():
+ new_kind = CompletionChunkKind.from_id(value)
+ self.assertEqual(str(old_kind), str(new_kind))
diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py
index f50bd219cee77..283a54998470c 100644
--- a/clang/bindings/python/tests/cindex/test_enums.py
+++ b/clang/bindings/python/tests/cindex/test_enums.py
@@ -5,6 +5,7 @@
AccessSpecifier,
AvailabilityKind,
BinaryOperator,
+ CompletionChunkKind,
CompletionString,
CursorKind,
ExceptionSpecificationKind,
@@ -45,6 +46,7 @@ def test_all_variants(self):
"CX_StorageClass": StorageClass,
"CXAvailabilityKind": AvailabilityKind,
"CXBinaryOperatorKind": BinaryOperator,
+ "CXCompletionChunkKind": CompletionChunkKind,
"CXCursorKind": CursorKind,
"CXCursor_ExceptionSpecificationKind": ExceptionSpecificationKind,
"CXLanguageKind": LanguageKind,
>From 949eff5f27e55065d06d9d5bb3ae880b7bd87df7 Mon Sep 17 00:00:00 2001
From: Jannick Kremer <jannick.kremer at mailbox.org>
Date: Tue, 20 Jan 2026 21:46:27 +0900
Subject: [PATCH 2/3] Replace CompletionChunk.Kind by CompletionChunkKind
---
clang/bindings/python/clang/cindex.py | 68 ++++---------------
.../tests/cindex/test_code_completion.py | 15 +---
2 files changed, 15 insertions(+), 68 deletions(-)
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 45a8ddf83bb27..86817df234300 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -3053,46 +3053,29 @@ class _CXUnsavedFile(Structure):
class CompletionChunk:
- class Kind:
- def __init__(self, name: str):
- self.name = name
-
- def __str__(self) -> str:
- return self.name
-
- def __repr__(self) -> str:
- return "<ChunkKind: %s>" % self
+ __kind_id: int
def __init__(self, completionString: CObjP, key: int):
self.cs = completionString
self.key = key
- self.__kindNumberCache = -1
+ self.__kind_id = conf.lib.clang_getCompletionChunkKind(
+ self.cs, self.key
+ )
def __repr__(self) -> str:
return "{'" + self.spelling + "', " + str(self.kind) + "}"
@CachedProperty
def spelling(self) -> str:
- if self.__kindNumber in SPELLING_CACHE:
- return SPELLING_CACHE[self.__kindNumber]
+ if self.__kind_id in SPELLING_CACHE:
+ return SPELLING_CACHE[self.__kind_id]
return _CXString.from_result(
conf.lib.clang_getCompletionChunkText(self.cs, self.key)
)
- # We do not use @CachedProperty here, as the manual implementation is
- # apparently still significantly faster. Please profile carefully if you
- # would like to add CachedProperty back.
- @property
- def __kindNumber(self) -> int:
- if self.__kindNumberCache == -1:
- self.__kindNumberCache = conf.lib.clang_getCompletionChunkKind(
- self.cs, self.key
- )
- return self.__kindNumberCache
-
@CachedProperty
- def kind(self) -> Kind:
- return completionChunkKindMap[self.__kindNumber]
+ def kind(self) -> CompletionChunkKind:
+ return CompletionChunkKind.from_id(self.__kind_id)
@CachedProperty
def string(self) -> CompletionString | None:
@@ -3103,19 +3086,19 @@ def string(self) -> CompletionString | None:
return CompletionString(res)
def isKindOptional(self) -> bool:
- return self.__kindNumber == 0
+ return self.__kind_id == 0
def isKindTypedText(self) -> bool:
- return self.__kindNumber == 1
+ return self.__kind_id == 1
def isKindPlaceHolder(self) -> bool:
- return self.__kindNumber == 3
+ return self.__kind_id == 3
def isKindInformative(self) -> bool:
- return self.__kindNumber == 4
+ return self.__kind_id == 4
def isKindResultType(self) -> bool:
- return self.__kindNumber == 15
+ return self.__kind_id == 15
### Completion Chunk Kinds ###
class CompletionChunkKind(BaseEnumeration):
@@ -3166,31 +3149,6 @@ def __str__(self) -> str:
VERTICAL_SPACE = 20
-completionChunkKindMap = {
- 0: CompletionChunk.Kind("Optional"),
- 1: CompletionChunk.Kind("TypedText"),
- 2: CompletionChunk.Kind("Text"),
- 3: CompletionChunk.Kind("Placeholder"),
- 4: CompletionChunk.Kind("Informative"),
- 5: CompletionChunk.Kind("CurrentParameter"),
- 6: CompletionChunk.Kind("LeftParen"),
- 7: CompletionChunk.Kind("RightParen"),
- 8: CompletionChunk.Kind("LeftBracket"),
- 9: CompletionChunk.Kind("RightBracket"),
- 10: CompletionChunk.Kind("LeftBrace"),
- 11: CompletionChunk.Kind("RightBrace"),
- 12: CompletionChunk.Kind("LeftAngle"),
- 13: CompletionChunk.Kind("RightAngle"),
- 14: CompletionChunk.Kind("Comma"),
- 15: CompletionChunk.Kind("ResultType"),
- 16: CompletionChunk.Kind("Colon"),
- 17: CompletionChunk.Kind("SemiColon"),
- 18: CompletionChunk.Kind("Equal"),
- 19: CompletionChunk.Kind("HorizontalSpace"),
- 20: CompletionChunk.Kind("VerticalSpace"),
-}
-
-
class CompletionString(ClangObject):
# AvailabilityKindCompat is an exact copy of AvailabilityKind, except for __str__.
# This is a temporary measure to keep the string representation the same
diff --git a/clang/bindings/python/tests/cindex/test_code_completion.py b/clang/bindings/python/tests/cindex/test_code_completion.py
index e4924e1f8f4c6..a8a0a51a449d7 100644
--- a/clang/bindings/python/tests/cindex/test_code_completion.py
+++ b/clang/bindings/python/tests/cindex/test_code_completion.py
@@ -1,4 +1,4 @@
-from clang.cindex import AvailabilityKind, CompletionChunkKind, completionChunkKindMap, CompletionString, TranslationUnit
+from clang.cindex import AvailabilityKind, CompletionString, TranslationUnit
import unittest
from pathlib import Path
@@ -137,7 +137,7 @@ class Q : public P {
]
self.check_completion_results(cr, expected)
- def test_availability_kind_compat_(self):
+ def test_availability_kind_compat(self):
numKinds = len(CompletionString.AvailabilityKindCompat)
# Compare with regular kind
@@ -174,14 +174,3 @@ def test_compat_str(self):
for id, string in kindStringMap.items():
kind = CompletionString.AvailabilityKindCompat.from_id(id)
self.assertEqual(str(kind), string)
-
- def test_completion_chunk_kind_compatibility(self):
- # Check that all new kinds correspond to an old kind
- for new_kind in CompletionChunkKind:
- old_kind = completionChunkKindMap[new_kind.value]
- self.assertEqual(str(old_kind), str(new_kind))
-
- # Check that all old kinds correspond to a new kind
- for value, old_kind in completionChunkKindMap.items():
- new_kind = CompletionChunkKind.from_id(value)
- self.assertEqual(str(old_kind), str(new_kind))
>From de6ddd277a6b371f2d2342872cca37690dd1f41d Mon Sep 17 00:00:00 2001
From: Jannick Kremer <jannick.kremer at mailbox.org>
Date: Tue, 20 Jan 2026 21:58:22 +0900
Subject: [PATCH 3/3] Add release note
---
clang/docs/ReleaseNotes.rst | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b75715e873c50..db414dca5a15d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -65,6 +65,13 @@ Clang Python Bindings Potentially Breaking Changes
to compare with the return values of ``CompletionString.availability``.
- Remove ``availabilityKinds``. In this release, uses of ``availabilityKinds``
need to be replaced by ``CompletionString.AvailabilityKind``.
+- ``CompletionChunk.kind`` now returns instances of ``CompletionChunkKind``.
+
+ Instances of ``CompletionChunkKind`` have the same ``__str__`` representation
+ as the previous ``CompletionChunk.Kind``s for compatibility.
+ These representations will be changed in a future release to match other enums.
+- Remove ``completionChunkKindMap``. In this release, uses of ``completionChunkKindMap``
+ need to be replaced by ``CompletionChunkKind``.
What's New in Clang |release|?
==============================
More information about the cfe-commits
mailing list