Author: Jannick Kremer
Date: 2026-01-17T23:37:51+09:00
New Revision: dc3a902abed72c58577950cc5c909d7670e4caa8

URL: 
https://github.com/llvm/llvm-project/commit/dc3a902abed72c58577950cc5c909d7670e4caa8
DIFF: 
https://github.com/llvm/llvm-project/commit/dc3a902abed72c58577950cc5c909d7670e4caa8.diff

LOG: Use existing AvailabilityKind enum for code completion availability 
(#160296)

This adresses point 4 from #156680. This is a necessary step before
`CompletionChunk.Kind` can be removed.

The `ChunkCompletion.Kind` implements `__str__` and `__repr__`
differently from our other enum classes. I have adapted the `__repr__`
of `CompletionString` to stringify the availability of the chunk
differently so that it still looks the same as before.

Also introduce a temporary `AvailabilityKindCompat` to ensure that
`__str__` returns the same format, while also leaving a deprecation
warning that this will be removed in a future release.

---------

Co-authored-by: Vlad Serebrennikov <[email protected]>

Added: 
    

Modified: 
    clang/bindings/python/clang/cindex.py
    clang/bindings/python/tests/cindex/test_code_completion.py
    clang/bindings/python/tests/cindex/test_enums.py
    clang/docs/ReleaseNotes.rst

Removed: 
    


################################################################################
diff  --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 2b6ab00c88219..29c35628cf60c 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -84,6 +84,7 @@
 import os
 import sys
 from enum import Enum
+import warnings
 
 from typing import (
     Any,
@@ -3143,15 +3144,51 @@ def isKindResultType(self) -> bool:
 
 
 class CompletionString(ClangObject):
-    class Availability:
-        def __init__(self, name):
-            self.name = name
+    # AvailabilityKindCompat is an exact copy of AvailabilityKind, except for 
__str__.
+    # This is a temporary measure to keep the string representation the same
+    # until we change CompletionString.availability to return AvailabilityKind,
+    # like Cursor.availability does.
+    # Note that deriving from AvailabilityKind directly is not possible.
+    class AvailabilityKindCompat(BaseEnumeration):
+        """
+        Describes the availability of an entity.
+        It is deprecated in favor of AvailabilityKind.
+        """
 
-        def __str__(self):
-            return self.name
+        # Ensure AvailabilityKindCompat is comparable with AvailabilityKind
+        def __eq__(self, other: object) -> bool:
+            if isinstance(
+                other, (AvailabilityKind, 
CompletionString.AvailabilityKindCompat)
+            ):
+                return self.value == other.value
+            else:
+                return NotImplemented
 
-        def __repr__(self):
-            return "<Availability: %s>" % self
+        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 'CompletionString.availability' will 
be "
+                "changed in a future release from 'camelCase' to 'ALL_CAPS' to 
"
+                "match other enums. 'CompletionString.availability' can be "
+                "compared to 'AvailabilityKind' directly, "
+                "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)
+
+        AVAILABLE = 0
+        DEPRECATED = 1
+        NOT_AVAILABLE = 2
+        NOT_ACCESSIBLE = 3
 
     def __len__(self) -> int:
         return self.num_chunks
@@ -3177,9 +3214,9 @@ def priority(self) -> int:
         return conf.lib.clang_getCompletionPriority(self.obj)  # type: ignore 
[no-any-return]
 
     @property
-    def availability(self) -> CompletionChunk.Kind:
+    def availability(self) -> AvailabilityKindCompat:
         res = conf.lib.clang_getCompletionAvailability(self.obj)
-        return availabilityKinds[res]
+        return CompletionString.AvailabilityKindCompat.from_id(res)
 
     @property
     def briefComment(self) -> str:
@@ -3197,14 +3234,6 @@ def __repr__(self) -> str:
         )
 
 
-availabilityKinds = {
-    0: CompletionChunk.Kind("Available"),
-    1: CompletionChunk.Kind("Deprecated"),
-    2: CompletionChunk.Kind("NotAvailable"),
-    3: CompletionChunk.Kind("NotAccessible"),
-}
-
-
 class CodeCompletionResult(Structure):
     _fields_ = [("cursorKind", c_int), ("completionString", c_object_p)]
 

diff  --git a/clang/bindings/python/tests/cindex/test_code_completion.py 
b/clang/bindings/python/tests/cindex/test_code_completion.py
index 32b75eb1ae029..4c0ecca85e4f4 100644
--- a/clang/bindings/python/tests/cindex/test_code_completion.py
+++ b/clang/bindings/python/tests/cindex/test_code_completion.py
@@ -1,5 +1,4 @@
-from clang.cindex import TranslationUnit
-
+from clang.cindex import AvailabilityKind, CompletionString, TranslationUnit
 
 import unittest
 from pathlib import Path
@@ -137,3 +136,41 @@ class Q : public P {
             "{'void', ResultType} | {'~P', TypedText} | {'(', LeftParen} | 
{')', RightParen} || Priority: 79 || Availability: Available || Brief comment: 
",
         ]
         self.check_completion_results(cr, expected)
+
+    def test_availability_kind_compat_(self):
+        numKinds = len(CompletionString.AvailabilityKindCompat)
+
+        # Compare with regular kind
+        for compatKind in CompletionString.AvailabilityKindCompat:
+            commonKind = AvailabilityKind.from_id(compatKind.value)
+            nextKindId = (compatKind.value + 1) % numKinds
+            commonKindUnequal = AvailabilityKind.from_id(nextKindId)
+            self.assertEqual(commonKind, compatKind)
+            self.assertEqual(compatKind, commonKind)
+            self.assertNotEqual(commonKindUnequal, compatKind)
+            self.assertNotEqual(compatKind, commonKindUnequal)
+
+        # Compare two compat kinds
+        for compatKind in CompletionString.AvailabilityKindCompat:
+            compatKind2 = CompletionString.AvailabilityKindCompat.from_id(
+                compatKind.value
+            )
+            nextKindId = (compatKind.value + 1) % numKinds
+            compatKind2Unequal = 
CompletionString.AvailabilityKindCompat.from_id(
+                nextKindId
+            )
+            self.assertEqual(compatKind, compatKind2)
+            self.assertEqual(compatKind2, compatKind)
+            self.assertNotEqual(compatKind2Unequal, compatKind)
+            self.assertNotEqual(compatKind, compatKind2Unequal)
+
+    def test_compat_str(self):
+        kindStringMap = {
+            0: "Available",
+            1: "Deprecated",
+            2: "NotAvailable",
+            3: "NotAccessible",
+        }
+        for id, string in kindStringMap.items():
+            kind = CompletionString.AvailabilityKindCompat.from_id(id)
+            self.assertEqual(str(kind), string)

diff  --git a/clang/bindings/python/tests/cindex/test_enums.py 
b/clang/bindings/python/tests/cindex/test_enums.py
index 0d3453e602edf..f50bd219cee77 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,
+    CompletionString,
     CursorKind,
     ExceptionSpecificationKind,
     LanguageKind,
@@ -22,7 +23,10 @@
 
 
 class TestEnums(unittest.TestCase):
+    # Test all enum classes, except for AvailabilityKindCompat since it is
+    # just a copy of AvailabilityKind and has no corresponding C-class
     enums = BaseEnumeration.__subclasses__()
+    enums.remove(CompletionString.AvailabilityKindCompat)
 
     def test_from_id(self):
         """Check that kinds can be constructed from valid IDs"""

diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4d886c3d55e7c..b75715e873c50 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -54,6 +54,17 @@ Clang Frontend Potentially Breaking Changes
 
 Clang Python Bindings Potentially Breaking Changes
 --------------------------------------------------
+- Remove ``CompletionString.Availability``. No libclang interfaces returned 
instances of it.
+- ``CompletionString.availability`` now returns instances of 
``CompletionString.AvailabilityKindCompat``.
+
+  Instances of ``AvailabilityKindCompat`` have the same ``__str__`` 
representation
+  as the previous ``CompletionChunk.Kind``s and are equality-comparable with
+  the existing ``AvailabilityKind`` enum. It will be replaced by 
``AvailabilityKind``
+  in a future release. When this happens, the return type of 
``CompletionString.availability``
+  will change to ``AvailabilityKind``, so it is recommended to use 
``AvailabilityKind``
+  to compare with the return values of ``CompletionString.availability``.
+- Remove ``availabilityKinds``. In this release, uses of ``availabilityKinds``
+  need to be replaced by ``CompletionString.AvailabilityKind``.
 
 What's New in Clang |release|?
 ==============================


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to