[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
@@ -67,89 +67,690 @@ import clang.enumerations import os -import sys - -if sys.version_info[0] == 3: -# Python 3 strings are unicode, translate them to/from utf8 for C-interop. -class c_interop_string(c_char_p): -def __init__(self, p=None): -if p is None: -p = "" -if isinstance(p, str): -p = p.encode("utf8") -super(c_char_p, self).__init__(p) - -def __str__(self): -return self.value - -@property -def value(self): -if super(c_char_p, self).value is None: -return None -return super(c_char_p, self).value.decode("utf8") - -@classmethod -def from_param(cls, param): -if isinstance(param, str): -return cls(param) -if isinstance(param, bytes): -return cls(param) -if param is None: -# Support passing null to C functions expecting char arrays -return None -raise TypeError( -"Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__) -) +from enum import Enum + +from typing import ( +Any, +Callable, +cast as Tcast, +Generic, +Iterable, +Iterator, +Optional, +Sequence, +Type as TType, +TypeVar, +TYPE_CHECKING, +Union as TUnion, +) +from typing_extensions import Protocol, TypeAlias + +if TYPE_CHECKING: +from ctypes import _Pointer, _FuncPointer, _CArgObject +from io import TextIOWrapper + +StrPath: TypeAlias = TUnion[str, os.PathLike[str]] +InMemoryFile: TypeAlias = ( +"tuple[TUnion[str, os.PathLike[Any]], TUnion[str, TextIOWrapper]]" +) +LibFunc: TypeAlias = TUnion[ +"tuple[str, Optional[list[Any]]]", +"tuple[str, Optional[list[Any]], Any]", +"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]", +] +CObjP: TypeAlias = _Pointer[Any] -@staticmethod -def to_python_string(x, *args): -return x.value +TSeq = TypeVar("TSeq", covariant=True) -def b(x): -if isinstance(x, bytes): -return x -return x.encode("utf8") +class NoSliceSequence(Protocol[TSeq]): +def __len__(self) -> int: +... -elif sys.version_info[0] == 2: -# Python 2 strings are utf8 byte strings, no translation is needed for -# C-interop. -c_interop_string = c_char_p +def __getitem__(self, key: int) -> TSeq: +... -def _to_python_string(x, *args): -return x -c_interop_string.to_python_string = staticmethod(_to_python_string) +class ClangLib(Protocol): DeinAlptraum wrote: This protocol was the only working way I found to pass the type check with the CDLL, due to the library functions being added dynamically, but it is rather ugly and adds a thousand lines of bloat. If anyone has a better idea, I'm happy to hear it. https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
@@ -67,89 +67,690 @@ import clang.enumerations import os -import sys - -if sys.version_info[0] == 3: -# Python 3 strings are unicode, translate them to/from utf8 for C-interop. -class c_interop_string(c_char_p): -def __init__(self, p=None): -if p is None: -p = "" -if isinstance(p, str): -p = p.encode("utf8") -super(c_char_p, self).__init__(p) - -def __str__(self): -return self.value - -@property -def value(self): -if super(c_char_p, self).value is None: -return None -return super(c_char_p, self).value.decode("utf8") - -@classmethod -def from_param(cls, param): -if isinstance(param, str): -return cls(param) -if isinstance(param, bytes): -return cls(param) -if param is None: -# Support passing null to C functions expecting char arrays -return None -raise TypeError( -"Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__) -) +from enum import Enum + +from typing import ( +Any, DeinAlptraum wrote: I used Any (mostly) to label ununused arguments. More specific annotations would have been possible in some cases, but I did not find this worth the effort. https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
@@ -642,51 +1259,29 @@ def register(value, name): ### Cursor Kinds ### -class BaseEnumeration(object): -""" -Common base class for named enumerations held in sync with Index.h values. +TEnum = TypeVar("TEnum", bound="BaseEnumeration") -Subclasses must define their own _kinds and _name_map members, as: -_kinds = [] -_name_map = None -These values hold the per-subclass instances and value-to-name mappings, -respectively. +class BaseEnumeration(Enum): +""" +Common base class for named enumerations held in sync with Index.h values. """ -def __init__(self, value): -if value >= len(self.__class__._kinds): -self.__class__._kinds += [None] * (value - len(self.__class__._kinds) + 1) -if self.__class__._kinds[value] is not None: -raise ValueError( -"{0} value {1} already loaded".format(str(self.__class__), value) -) -self.value = value -self.__class__._kinds[value] = self -self.__class__._name_map = None +value: int -def from_param(self): +def from_param(self) -> int: return self.value -@property -def name(self): -"""Get the enumeration name of this cursor kind.""" -if self._name_map is None: -self._name_map = {} -for key, value in self.__class__.__dict__.items(): -if isinstance(value, self.__class__): -self._name_map[value] = key -return self._name_map[self] - @classmethod -def from_id(cls, id): -if id >= len(cls._kinds) or cls._kinds[id] is None: -raise ValueError("Unknown template argument kind %d" % id) -return cls._kinds[id] +def from_id(cls: type[TEnum], id: int) -> TEnum: +try: +return cls(id) +except ValueError: +raise ValueError("Unknown %s %d" % (cls.__class__, id)) DeinAlptraum wrote: This also resolves behavior that I would consider a bug: for negative IDs, if you pass e.g. -1, this would return the last element of `_kinds` (due to Python list syntax) instea dof raising the appropriate value error. https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
@@ -642,51 +1259,29 @@ def register(value, name): ### Cursor Kinds ### -class BaseEnumeration(object): -""" -Common base class for named enumerations held in sync with Index.h values. +TEnum = TypeVar("TEnum", bound="BaseEnumeration") -Subclasses must define their own _kinds and _name_map members, as: -_kinds = [] -_name_map = None -These values hold the per-subclass instances and value-to-name mappings, -respectively. +class BaseEnumeration(Enum): DeinAlptraum wrote: Since I've collected the shared functionality of all enums into this class, including e.g. `__repr__` definitions, some of them may differ slightly in output. E.g. the representation of a `TemplateArgumentKind.INTEGRAL` is exactly `TemplateArgumentKind.INTEGRAL`, compared to `'clang.cindex.TemplateArgumentKind'>.INTEGRAL`, which is consistent with the representation of most other enums. https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
@@ -3968,7 +4500,7 @@ def function_exists(self, name): return True -def register_enumerations(): +def register_enumerations() -> None: DeinAlptraum wrote: This implementation dynamically adds the TokenKind variants, which means it also suffers from the same problems as the previoius "manual" implementation of enums: if you write e.g. `TokenKind.PUNCTUATION` in a program and typecheck it, it will throw an error since it doesn't recognize `PUNCTUATION` as a member of `TokenKind`. I'm not sure why this one enum is outsourced to a different file and implemented via this dynamic registering approach. I'd be in favor of removing that and handling it just like the other enums. https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
@@ -232,13 +840,16 @@ class _CXString(Structure): _fields_ = [("spelling", c_char_p), ("free", c_int)] -def __del__(self): +def __del__(self) -> None: conf.lib.clang_disposeString(self) @staticmethod -def from_result(res, fn=None, args=None): +def from_result(res: _CXString, fn: Any = None, args: Any = None) -> str: assert isinstance(res, _CXString) -return conf.lib.clang_getCString(res) +pystr = conf.lib.clang_getCString(res) +if pystr is None: +return "" +return pystr DeinAlptraum wrote: `conf.lib.clang_getCString` may sometimes (though seemingly rarely) return `None` instead of a Python `str`. This is used in a lot of places throughout this file, and while parts of it seem to be aware of this (e.g. doc string saying that this may return `None`) other places are not (e.g. calling `len` on the return value, which will crash if it is `None`). Many parts of the interface also directly return the result of this function, and having to check for `None` in all of these places seems potentially impractical, so I went for returning empty strings instead of `None` instead. But due to the inconsistent usage throughout this file, I'm not sure how far this corresponds more or less to the original intention. https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
@@ -67,89 +67,690 @@ import clang.enumerations import os -import sys - -if sys.version_info[0] == 3: -# Python 3 strings are unicode, translate them to/from utf8 for C-interop. -class c_interop_string(c_char_p): -def __init__(self, p=None): -if p is None: -p = "" -if isinstance(p, str): -p = p.encode("utf8") -super(c_char_p, self).__init__(p) - -def __str__(self): -return self.value - -@property -def value(self): -if super(c_char_p, self).value is None: -return None -return super(c_char_p, self).value.decode("utf8") - -@classmethod -def from_param(cls, param): -if isinstance(param, str): -return cls(param) -if isinstance(param, bytes): -return cls(param) -if param is None: -# Support passing null to C functions expecting char arrays -return None -raise TypeError( -"Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__) -) +from enum import Enum + +from typing import ( +Any, +Callable, +cast as Tcast, +Generic, +Iterable, +Iterator, +Optional, +Sequence, +Type as TType, +TypeVar, +TYPE_CHECKING, +Union as TUnion, +) +from typing_extensions import Protocol, TypeAlias + +if TYPE_CHECKING: +from ctypes import _Pointer, _FuncPointer, _CArgObject +from io import TextIOWrapper + +StrPath: TypeAlias = TUnion[str, os.PathLike[str]] +InMemoryFile: TypeAlias = ( +"tuple[TUnion[str, os.PathLike[Any]], TUnion[str, TextIOWrapper]]" +) +LibFunc: TypeAlias = TUnion[ +"tuple[str, Optional[list[Any]]]", +"tuple[str, Optional[list[Any]], Any]", +"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]", +] +CObjP: TypeAlias = _Pointer[Any] -@staticmethod -def to_python_string(x, *args): -return x.value +TSeq = TypeVar("TSeq", covariant=True) -def b(x): -if isinstance(x, bytes): -return x -return x.encode("utf8") +class NoSliceSequence(Protocol[TSeq]): +def __len__(self) -> int: +... -elif sys.version_info[0] == 2: -# Python 2 strings are utf8 byte strings, no translation is needed for -# C-interop. -c_interop_string = c_char_p +def __getitem__(self, key: int) -> TSeq: +... -def _to_python_string(x, *args): -return x -c_interop_string.to_python_string = staticmethod(_to_python_string) +class ClangLib(Protocol): +def clang_annotateTokens( +self, tu: TranslationUnit, token: _CArgObject, num: int, cursor: _CArgObject +) -> None: +... -def b(x): -return x +def clang_CompilationDatabase_dispose(self, cdb: CompilationDatabase) -> None: +... + +def clang_CompilationDatabase_fromDirectory( +self, buildDir: str, errorCode: _CArgObject +) -> CompilationDatabase: +... + +def clang_CompilationDatabase_getAllCompileCommands( +self, cdb: CompilationDatabase +) -> CompileCommands: +... + +def clang_CompilationDatabase_getCompileCommands( +self, cdb: CompilationDatabase, filename: str +) -> CompileCommands: +... + +def clang_CompileCommands_dispose(self, ccmds: CObjP) -> None: +... + +def clang_CompileCommands_getCommand(self, ccmds: CObjP, key: int) -> CObjP: +... + +def clang_CompileCommands_getSize(self, ccmds: CObjP) -> c_uint: +... + +def clang_CompileCommand_getArg(self, cmd: CObjP, key: int) -> str: +... + +def clang_CompileCommand_getDirectory(self, cmd: CObjP) -> str: +... + +def clang_CompileCommand_getFilename(self, cmd: CObjP) -> str: +... + +def clang_CompileCommand_getNumArgs(self, cmd: CObjP) -> int: DeinAlptraum wrote: According to the definitions in `functionList`, all library functions return C types for number (`c_int, c_uint, c_longlong, c_ulonglong`). However, checking the types of the return values tells me that in all cases where I looked, these actually returned Python `int`s. According to the `ctypes` docs, you need explicit conversion i.e. calling `c_uint(https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
@@ -67,89 +67,690 @@ import clang.enumerations import os -import sys - -if sys.version_info[0] == 3: -# Python 3 strings are unicode, translate them to/from utf8 for C-interop. -class c_interop_string(c_char_p): -def __init__(self, p=None): -if p is None: -p = "" -if isinstance(p, str): -p = p.encode("utf8") -super(c_char_p, self).__init__(p) - -def __str__(self): -return self.value - -@property -def value(self): -if super(c_char_p, self).value is None: -return None -return super(c_char_p, self).value.decode("utf8") - -@classmethod -def from_param(cls, param): -if isinstance(param, str): -return cls(param) -if isinstance(param, bytes): -return cls(param) -if param is None: -# Support passing null to C functions expecting char arrays -return None -raise TypeError( -"Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__) -) +from enum import Enum + +from typing import ( +Any, +Callable, +cast as Tcast, +Generic, +Iterable, +Iterator, +Optional, +Sequence, +Type as TType, +TypeVar, +TYPE_CHECKING, +Union as TUnion, +) +from typing_extensions import Protocol, TypeAlias + +if TYPE_CHECKING: +from ctypes import _Pointer, _FuncPointer, _CArgObject +from io import TextIOWrapper + +StrPath: TypeAlias = TUnion[str, os.PathLike[str]] +InMemoryFile: TypeAlias = ( +"tuple[TUnion[str, os.PathLike[Any]], TUnion[str, TextIOWrapper]]" +) +LibFunc: TypeAlias = TUnion[ +"tuple[str, Optional[list[Any]]]", +"tuple[str, Optional[list[Any]], Any]", +"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]", +] +CObjP: TypeAlias = _Pointer[Any] -@staticmethod -def to_python_string(x, *args): -return x.value +TSeq = TypeVar("TSeq", covariant=True) -def b(x): -if isinstance(x, bytes): -return x -return x.encode("utf8") +class NoSliceSequence(Protocol[TSeq]): +def __len__(self) -> int: +... -elif sys.version_info[0] == 2: -# Python 2 strings are utf8 byte strings, no translation is needed for -# C-interop. -c_interop_string = c_char_p +def __getitem__(self, key: int) -> TSeq: +... -def _to_python_string(x, *args): -return x -c_interop_string.to_python_string = staticmethod(_to_python_string) +class ClangLib(Protocol): +def clang_annotateTokens( +self, tu: TranslationUnit, token: _CArgObject, num: int, cursor: _CArgObject +) -> None: +... -def b(x): -return x +def clang_CompilationDatabase_dispose(self, cdb: CompilationDatabase) -> None: +... + +def clang_CompilationDatabase_fromDirectory( +self, buildDir: str, errorCode: _CArgObject +) -> CompilationDatabase: +... + +def clang_CompilationDatabase_getAllCompileCommands( +self, cdb: CompilationDatabase +) -> CompileCommands: +... + +def clang_CompilationDatabase_getCompileCommands( +self, cdb: CompilationDatabase, filename: str +) -> CompileCommands: +... + +def clang_CompileCommands_dispose(self, ccmds: CObjP) -> None: +... + +def clang_CompileCommands_getCommand(self, ccmds: CObjP, key: int) -> CObjP: +... + +def clang_CompileCommands_getSize(self, ccmds: CObjP) -> c_uint: +... + +def clang_CompileCommand_getArg(self, cmd: CObjP, key: int) -> str: +... + +def clang_CompileCommand_getDirectory(self, cmd: CObjP) -> str: +... + +def clang_CompileCommand_getFilename(self, cmd: CObjP) -> str: +... + +def clang_CompileCommand_getNumArgs(self, cmd: CObjP) -> int: +... + +def clang_codeCompleteAt( +self, +tu: TranslationUnit, +filename: str, +line: int, +column: int, +unsaved_files: TUnion[int, Array[_CXUnsavedFile]], +num_unsaved_files: int, +options: int, +) -> _Pointer[CCRStructure]: +... + +def clang_codeCompleteGetDiagnostic( +self, ccrs: CodeCompletionResults, key: int +) -> Diagnostic: +... + +def clang_codeCompleteGetNumDiagnostics(self, ccrs: CodeCompletionResults) -> c_int: +... + +def clang_createIndex(self, excludeDecls: int, displayDiagnostics: int) -> CObjP: +... + +def clang_createTranslationUnit(self, index: Index, filename: str) -> CObjP: +... + +def clang_CXXConstructor_isConvertingConstructor(self, cursor: Cursor) -> bool: +... + +def clang_CXXConstructor_isCopyConstructor(self, cursor: Cursor) -> bool: +
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
@@ -2341,30 +2830,32 @@ class Type(Structure): _fields_ = [("_kind_id", c_int), ("data", c_void_p * 2)] +_tu: TranslationUnit + @property -def kind(self): +def kind(self) -> TypeKind: """Return the kind of this type.""" return TypeKind.from_id(self._kind_id) -def argument_types(self): +def argument_types(self) -> NoSliceSequence[Type]: """Retrieve a container for the non-variadic arguments for this type. The returned object is iterable and indexable. Each item in the container is a Type instance. """ -class ArgumentsIterator(collections_abc.Sequence): -def __init__(self, parent): +class ArgumentsIterator: DeinAlptraum wrote: Removed the inheritance here, since ArgumentsIterator doesn't actually implement everything needed by the protocol anyway (which is precisely why I had to add the `NoSliceSequence` protocol) https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
@@ -67,89 +67,690 @@ import clang.enumerations import os -import sys - -if sys.version_info[0] == 3: -# Python 3 strings are unicode, translate them to/from utf8 for C-interop. -class c_interop_string(c_char_p): -def __init__(self, p=None): -if p is None: -p = "" -if isinstance(p, str): -p = p.encode("utf8") -super(c_char_p, self).__init__(p) - -def __str__(self): -return self.value - -@property -def value(self): -if super(c_char_p, self).value is None: -return None -return super(c_char_p, self).value.decode("utf8") - -@classmethod -def from_param(cls, param): -if isinstance(param, str): -return cls(param) -if isinstance(param, bytes): -return cls(param) -if param is None: -# Support passing null to C functions expecting char arrays -return None -raise TypeError( -"Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__) -) +from enum import Enum + +from typing import ( +Any, +Callable, +cast as Tcast, +Generic, +Iterable, +Iterator, +Optional, +Sequence, +Type as TType, +TypeVar, +TYPE_CHECKING, +Union as TUnion, +) +from typing_extensions import Protocol, TypeAlias + +if TYPE_CHECKING: +from ctypes import _Pointer, _FuncPointer, _CArgObject +from io import TextIOWrapper + +StrPath: TypeAlias = TUnion[str, os.PathLike[str]] +InMemoryFile: TypeAlias = ( +"tuple[TUnion[str, os.PathLike[Any]], TUnion[str, TextIOWrapper]]" +) +LibFunc: TypeAlias = TUnion[ +"tuple[str, Optional[list[Any]]]", +"tuple[str, Optional[list[Any]], Any]", +"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]", +] +CObjP: TypeAlias = _Pointer[Any] -@staticmethod -def to_python_string(x, *args): -return x.value +TSeq = TypeVar("TSeq", covariant=True) -def b(x): -if isinstance(x, bytes): -return x -return x.encode("utf8") +class NoSliceSequence(Protocol[TSeq]): +def __len__(self) -> int: +... -elif sys.version_info[0] == 2: -# Python 2 strings are utf8 byte strings, no translation is needed for -# C-interop. -c_interop_string = c_char_p +def __getitem__(self, key: int) -> TSeq: +... -def _to_python_string(x, *args): -return x -c_interop_string.to_python_string = staticmethod(_to_python_string) +class ClangLib(Protocol): +def clang_annotateTokens( +self, tu: TranslationUnit, token: _CArgObject, num: int, cursor: _CArgObject +) -> None: +... -def b(x): -return x +def clang_CompilationDatabase_dispose(self, cdb: CompilationDatabase) -> None: +... + +def clang_CompilationDatabase_fromDirectory( +self, buildDir: str, errorCode: _CArgObject +) -> CompilationDatabase: +... + +def clang_CompilationDatabase_getAllCompileCommands( +self, cdb: CompilationDatabase +) -> CompileCommands: +... + +def clang_CompilationDatabase_getCompileCommands( +self, cdb: CompilationDatabase, filename: str +) -> CompileCommands: +... + +def clang_CompileCommands_dispose(self, ccmds: CObjP) -> None: +... + +def clang_CompileCommands_getCommand(self, ccmds: CObjP, key: int) -> CObjP: +... + +def clang_CompileCommands_getSize(self, ccmds: CObjP) -> c_uint: +... + +def clang_CompileCommand_getArg(self, cmd: CObjP, key: int) -> str: +... + +def clang_CompileCommand_getDirectory(self, cmd: CObjP) -> str: +... + +def clang_CompileCommand_getFilename(self, cmd: CObjP) -> str: +... + +def clang_CompileCommand_getNumArgs(self, cmd: CObjP) -> int: +... + +def clang_codeCompleteAt( +self, +tu: TranslationUnit, +filename: str, +line: int, +column: int, +unsaved_files: TUnion[int, Array[_CXUnsavedFile]], +num_unsaved_files: int, +options: int, +) -> _Pointer[CCRStructure]: +... + +def clang_codeCompleteGetDiagnostic( +self, ccrs: CodeCompletionResults, key: int +) -> Diagnostic: +... + +def clang_codeCompleteGetNumDiagnostics(self, ccrs: CodeCompletionResults) -> c_int: +... + +def clang_createIndex(self, excludeDecls: int, displayDiagnostics: int) -> CObjP: +... + +def clang_createTranslationUnit(self, index: Index, filename: str) -> CObjP: +... + +def clang_CXXConstructor_isConvertingConstructor(self, cursor: Cursor) -> bool: +... + +def clang_CXXConstructor_isCopyConstructor(self, cursor: Cursor) -> bool: +
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
@@ -1722,23 +2300,23 @@ def location(self): return self._loc @property -def linkage(self): +def linkage(self) -> LinkageKind: """Return the linkage of this cursor.""" if not hasattr(self, "_linkage"): self._linkage = conf.lib.clang_getCursorLinkage(self) return LinkageKind.from_id(self._linkage) @property -def tls_kind(self): +def tls_kind(self) -> TLSKind: """Return the thread-local storage (TLS) kind of this cursor.""" if not hasattr(self, "_tls_kind"): self._tls_kind = conf.lib.clang_getCursorTLSKind(self) DeinAlptraum wrote: The `conf.lib.clang_getCursorTLSKind()` call leads to segmentation faults on my system (even before I changed anything) so I wasn't able to test this. https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
DeinAlptraum wrote: @AaronBallman could you review this or recommend reviewers? I didn't see any category in `clang/CodeOwners.rst` that seems to cover the bindings. https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
https://github.com/DeinAlptraum converted_to_draft https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
DeinAlptraum wrote: I was just made aware of [some](https://github.com/llvm/llvm-project/pull/77219) [changes](https://github.com/llvm/llvm-project/pull/77228) by @linux4life798 that seem reasonable to merge before this, so I've returned this to draft status for now. Sorry for the confusion. https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
DeinAlptraum wrote: \*Ping* @boomanaiden154 @linux4life798 a review/feedback would be appreciated! https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
@@ -10,26 +10,6 @@ class TestTokenKind(unittest.TestCase): -def test_constructor(self): DeinAlptraum wrote: thNot really: - `test_constructor`: this tests the ability to add enum variants "on the fly", which is not possible with the Python stdlib's `Enum` class - `test_bad_register`: the `Enum` class tests for this on initialization, so if you define a duplicate `Enum` variant, you will get a failure on import already. This makes the test both a) effectively covered by that and b) you couldn't import the module to run such a test anyway in a case where there's a duplicate - `test_unknown_value`: this is covered in `test_from_id` in `test_enums.py` since I added the `TokenKind` class to the test there https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/95608 >From 35bfcfbc69ee812c59350440b7b15c5e23ad1307 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Fri, 14 Jun 2024 22:12:09 +0100 Subject: [PATCH 1/3] [libclang/python] Refactor enum usage Use Python's builtin enum class instead of writing our own. This is preparation for strict typing in PR #78114 --- clang/bindings/python/clang/cindex.py | 1670 - .../python/tests/cindex/test_enums.py | 14 +- 2 files changed, 768 insertions(+), 916 deletions(-) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index b3d51e4d2a668..aacfc333723c4 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -68,6 +68,7 @@ import collections.abc import os +from enum import Enum # Python 3 strings are unicode, translate them to/from utf8 for C-interop. @@ -611,51 +612,25 @@ def register(value, name): ### Cursor Kinds ### -class BaseEnumeration: +class BaseEnumeration(Enum): """ Common base class for named enumerations held in sync with Index.h values. - -Subclasses must define their own _kinds and _name_map members, as: -_kinds = [] -_name_map = None -These values hold the per-subclass instances and value-to-name mappings, -respectively. - """ -def __init__(self, value): -if value >= len(self.__class__._kinds): -self.__class__._kinds += [None] * (value - len(self.__class__._kinds) + 1) -if self.__class__._kinds[value] is not None: -raise ValueError( -"{0} value {1} already loaded".format(str(self.__class__), value) -) -self.value = value -self.__class__._kinds[value] = self -self.__class__._name_map = None def from_param(self): return self.value -@property -def name(self): -"""Get the enumeration name of this cursor kind.""" -if self._name_map is None: -self._name_map = {} -for key, value in self.__class__.__dict__.items(): -if isinstance(value, self.__class__): -self._name_map[value] = key -return self._name_map[self] - @classmethod def from_id(cls, id): -if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None: -raise ValueError("Unknown template argument kind %d" % id) -return cls._kinds[id] +try: +return cls(id) +except ValueError: +raise ValueError("Unknown %s %d" % (cls.__name__, id)) from None def __repr__(self): return "%s.%s" % ( -self.__class__, +self.__class__.__name__, self.name, ) @@ -665,14 +640,10 @@ class CursorKind(BaseEnumeration): A CursorKind describes the kind of entity that a cursor points to. """ -# The required BaseEnumeration declarations. -_kinds = [] -_name_map = None - @staticmethod def get_all_kinds(): """Return all CursorKind enumeration instances.""" -return [x for x in CursorKind._kinds if not x is None] +return list(CursorKind) def is_declaration(self): """Test if this is a declaration kind.""" @@ -710,822 +681,820 @@ def is_unexposed(self): """Test if this is an unexposed kind.""" return conf.lib.clang_isUnexposed(self) -def __repr__(self): -return "CursorKind.%s" % (self.name,) - -### -# Declaration Kinds +### +# Declaration Kinds -# A declaration whose specific kind is not exposed via this interface. -# -# Unexposed declarations have the same operations as any other kind of -# declaration; one can extract their location information, spelling, find their -# definitions, etc. However, the specific kind of the declaration is not -# reported. -CursorKind.UNEXPOSED_DECL = CursorKind(1) +# A declaration whose specific kind is not exposed via this interface. +# +# Unexposed declarations have the same operations as any other kind of +# declaration; one can extract their location information, spelling, find +# their definitions, etc. However, the specific kind of the declaration is +# not reported. +UNEXPOSED_DECL = 1 -# A C or C++ struct. -CursorKind.STRUCT_DECL = CursorKind(2) +# A C or C++ struct. +STRUCT_DECL = 2 -# A C or C++ union. -CursorKind.UNION_DECL = CursorKind(3) +# A C or C++ union. +UNION_DECL = 3 -# A C++ class. -CursorKind.CLASS_DECL = CursorKind(4) +# A C++ class. +CLASS_DECL = 4 -# An enumeration. -CursorKind.ENUM_DECL = CursorKind(5) +# An enumeration. +ENUM_DECL = 5 -# A field (in C) or non-static data member (in C++) in a struct, union, or C++ -# class. -CursorKind.FIELD_DECL = CursorKind(6) +# A field (in C) or non-static data member (in C++) in a struct, union, or +# C++ class.
[clang] [libclang/python] Refactor enum usage (PR #95608)
@@ -10,26 +10,6 @@ class TestTokenKind(unittest.TestCase): -def test_constructor(self): DeinAlptraum wrote: So the existing "custom" enum implementation included a sort of constructor, as we see in this test, that takes a number and name and then adds that as a new variant to the existing enum. No such constructor exists for the builtin `Enum` class, so there isn't really an equivalent for this test under the new implementation. We could test that it is impossible for the user to add their own variants dynamically at runtime by doing something like `TokenKind.NEW_VARIANT = 6`, but that doesn't really seem like our problem, and was also possible under the old implementation Your comment did however raise another question for me: while we've covered that there are no duplicate names with different IDs, we haven't covered that there are no duplicate IDs with different names, and this is indeed possible in the enum class, and not covered by our current tests so I just added one. https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
DeinAlptraum wrote: @Endilll do you think this needs a second review? If not, could you merge this? Since I don't have commit access https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
@@ -386,6 +386,10 @@ def __contains__(self, other): # same file, in between lines if self.start.line < other.line < self.end.line: return True +# between columns in one-liner range +elif self.start.line == other.line == self.end.line: DeinAlptraum wrote: Clarification because I probably expressed myself inaccurately: On C-side, in `SourceLocation.h` we implement `operator==`, `operator<=` both as direct comparisons on the raw encoding (`SourceLocation::getRawEncoding()`). This is not file-sensitive.* On the C/Python _bindings_ side, we already expose `clang_equalLocations`, which looks like this: ``` unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) { return (loc1.ptr_data[0] == loc2.ptr_data[0] && loc1.ptr_data[1] == loc2.ptr_data[1] && loc1.int_data == loc2.int_data); } ``` This _is_ file sensitive. The problem arises because this function is used already to implement `SourceLocation.__eq__` on the Python bindings side. This means that the internal `SourceLocation::operator==` is inconsistent with the bindings' `SourceLocation.__eq__` (the latter is file-sensitive, the former is not). The C-bindings are not affected by this as they do not implement `CXSourceLocation::opreraor==` or `CXSourceLocation::opreraor<=`. *Note that this is not obvious from the code (at least to me) and I'm not familiar with the C side yet, so I tested this manually in Python, by exposing these operators to the Python bindings (pls don't judge me) https://github.com/llvm/llvm-project/pull/101802 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/101802 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/101802 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/101802 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
@@ -386,6 +386,10 @@ def __contains__(self, other): # same file, in between lines if self.start.line < other.line < self.end.line: return True +# between columns in one-liner range +elif self.start.line == other.line == self.end.line: DeinAlptraum wrote: Okay, that was my mistake: when testing this, I created two separate TUs for the two files, and _that_ is apparently where it's sensitive. So no issue on the C-side here after al. Going back to the Python bindings: we are now left with a pre-existing `SourceLocation.__eq__` that _is_ file-sensitive, and in order to have a clean implementation, we would like a `SourceLocation.__le__` / `SourceLOcation.__lt__` that is _not_ file-sensitive, so it can be used for `SourceRange.__contains__`. Exposing something like this would be ugly due to inconsistency. So I guess it would be the easiest to implement such an `operator<=` function just locally inside `SourceRange.__contains__` to simplify the logic there, and not expose any new functionality at all. What do you think? https://github.com/llvm/llvm-project/pull/101802 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/101802 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] #101784 part 2: fix error handling of TranslationUnit.reparse (PR #102410)
https://github.com/DeinAlptraum commented: A couple minor comments, and the code formatting should be fixed (see output of the failing CI run), and then this is good to go! https://github.com/llvm/llvm-project/pull/102410 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] #101784 part 2: fix error handling of TranslationUnit.reparse (PR #102410)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/102410 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] #101784 part 2: fix error handling of TranslationUnit.reparse (PR #102410)
@@ -161,7 +161,34 @@ class TranslationUnitLoadError(Exception): FIXME: Make libclang expose additional error information in this scenario. DeinAlptraum wrote: I would say your change resolves the `FIXME` here. Thanks for expanding this to the `create`/`parse` functions as well! https://github.com/llvm/llvm-project/pull/102410 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] #101784 part 2: fix error handling of TranslationUnit.reparse (PR #102410)
@@ -59,6 +59,9 @@ Clang Python Bindings Potentially Breaking Changes - Calling a property on the `CompletionChunk` or `CompletionString` class statically now leads to an error, instead of returning a `CachedProperty` object that is used internally. Properties are only available on instances. +- `TranslationUnitLoadError` now contains an error code in `error_code` + attribute. Also, `TranslationUnit.reparse` will throw `TranslationUnitLoadError` + when operation fails. DeinAlptraum wrote: Code highlighting should be in double ` (yes the example above that did it incorrectly... will fix) https://github.com/llvm/llvm-project/pull/102410 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] #101784 part 2: fix error handling of TranslationUnit.reparse (PR #102410)
@@ -161,7 +161,34 @@ class TranslationUnitLoadError(Exception): FIXME: Make libclang expose additional error information in this scenario. """ -pass +# A generic error code, no further details are available. +# +# Errors of this kind can get their own specific error codes in future +# libclang versions. +ERROR_FAILURE = 1 + +# libclang crashed while performing the requested operation. +ERROR_CRASHED = 2 + +# The function detected that the arguments violate the function +# contract. +ERROR_INVALID_ARGUMENTS = 3 + +# An AST deserialization error has occurred. +ERROR_AST_READ_ERROR = 4 + +def __init__(self, enumeration: int, message: str): +assert isinstance(enumeration, int) + +if enumeration < 1 or enumeration > 4: +raise Exception( +"Encountered undefined CXError " +"constant: %d. Please file a bug to have this " +"value supported." % enumeration +) + +self.error_code = enumeration +Exception.__init__(self, "Error %d: %s" % (enumeration or 0, message)) DeinAlptraum wrote: What do you need the `or 0` for? https://github.com/llvm/llvm-project/pull/102410 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] #101784 part 2: fix error handling of TranslationUnit.reparse (PR #102410)
@@ -149,8 +149,8 @@ def b(x: str | bytes) -> bytes: # this by marshalling object arguments as void**. c_object_p: TType[_Pointer[Any]] = POINTER(c_void_p) -### Exception Classes ### +### Exception Classes ### DeinAlptraum wrote: Unnecessary whitespace changes https://github.com/llvm/llvm-project/pull/102410 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [NFC][libclang/python] Fix code highlighting in release notes (PR #102807)
https://github.com/DeinAlptraum created https://github.com/llvm/llvm-project/pull/102807 This corrects a release note introduced in #98745 >From 64212e4c8afe2ad75144bf36a1212c4e417dd8c9 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Sun, 11 Aug 2024 11:00:52 +0200 Subject: [PATCH] [NFC][libclang/python] Fix code highlighting in release notes This corrects a release note introduced in #98745 --- clang/docs/ReleaseNotes.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index d002a9c747dd6..6796a619ba97f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -61,9 +61,9 @@ Clang Frontend Potentially Breaking Changes Clang Python Bindings Potentially Breaking Changes -- - Parts of the interface returning string results will now return - the empty string `""` when no result is available, instead of `None`. -- Calling a property on the `CompletionChunk` or `CompletionString` class - statically now leads to an error, instead of returning a `CachedProperty` object + the empty string ``""`` when no result is available, instead of ``None``. +- Calling a property on the ``CompletionChunk`` or ``CompletionString`` class + statically now leads to an error, instead of returning a ``CachedProperty`` object that is used internally. Properties are only available on instances. What's New in Clang |release|? ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [NFC][libclang/python] Fix code highlighting in release notes (PR #102807)
https://github.com/DeinAlptraum closed https://github.com/llvm/llvm-project/pull/102807 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [NFC][libclang/python] Fix code highlighting in release notes (PR #102807)
DeinAlptraum wrote: Unrelated, this change only touched release notes https://github.com/llvm/llvm-project/pull/102807 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Improve error reporting of `TranslationUnit` creating functions (PR #102410)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/102410 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Improve error reporting of `TranslationUnit` creating functions (PR #102410)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/102410 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Improve error reporting of `TranslationUnit` creating functions (PR #102410)
https://github.com/DeinAlptraum approved this pull request. LGTM. Thanks for adding better error handling! @Endilll do you also want to take a look at this before it is merged? Otherwise, this is good to go imo. https://github.com/llvm/llvm-project/pull/102410 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Improve error reporting of `TranslationUnit` creating functions (PR #102410)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/102410 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/101802 >From 572b1be0b204561fdbb049f0c17f065d17198ac0 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Sat, 3 Aug 2024 09:28:02 +0100 Subject: [PATCH 1/3] [libclang/python] Fix bug in SourceRange.__contains__, add tests --- clang/bindings/python/clang/cindex.py | 4 ++ .../python/tests/cindex/test_source_range.py | 56 +++ 2 files changed, 60 insertions(+) create mode 100644 clang/bindings/python/tests/cindex/test_source_range.py diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index c251c46a04adf4..5fd7cc64810732 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -386,6 +386,10 @@ def __contains__(self, other): # same file, in between lines if self.start.line < other.line < self.end.line: return True +# between columns in one-liner range +elif self.start.line == other.line == self.end.line: +if self.start.column <= other.column <= self.end.column: +return True elif self.start.line == other.line: # same file first line if self.start.column <= other.column: diff --git a/clang/bindings/python/tests/cindex/test_source_range.py b/clang/bindings/python/tests/cindex/test_source_range.py new file mode 100644 index 00..9f76848e890207 --- /dev/null +++ b/clang/bindings/python/tests/cindex/test_source_range.py @@ -0,0 +1,56 @@ +import unittest + +from clang.cindex import SourceLocation, SourceRange + +from .util import get_tu + + +def create_location(tu, line, column): +return SourceLocation.from_position(tu, tu.get_file(tu.spelling), line, column) + + +def create_range(tu, line1, column1, line2, column2): +return SourceRange.from_locations( +create_location(tu, line1, column1), create_location(tu, line2, column2) +) + + +class TestSourceRange(unittest.TestCase): +def test_contains(self): +tu = get_tu( +"""a +a +a +a""" +) + +l13 = create_location(tu, 1, 3) +l21 = create_location(tu, 2, 1) +l22 = create_location(tu, 2, 2) +l23 = create_location(tu, 2, 3) +l24 = create_location(tu, 2, 4) +l25 = create_location(tu, 2, 5) +l33 = create_location(tu, 3, 3) +l31 = create_location(tu, 3, 1) +r22_24 = create_range(tu, 2, 2, 2, 4) +r23_23 = create_range(tu, 2, 3, 2, 3) +r24_32 = create_range(tu, 2, 4, 3, 2) +r14_32 = create_range(tu, 1, 4, 3, 2) + +assert l13 not in r22_24 # Line before start +assert l21 not in r22_24 # Column before start +assert l22 in r22_24 # Colum on start +assert l23 in r22_24 # Column in range +assert l24 in r22_24 # Column on end +assert l25 not in r22_24 # Column after end +assert l33 not in r22_24 # Line after end + +assert l23 in r23_23 # In one-column range + +assert l23 not in r24_32 # Outside range in first line +assert l33 not in r24_32 # Outside range in last line +assert l25 in r24_32 # In range in first line +assert l31 in r24_32 # In range in last line + +assert l21 in r14_32 # In range at start of center line +assert l25 in r14_32 # In range at end of center line >From e27cf4b01f61dd6cf7ee8fa86857c566716eabfb Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Wed, 7 Aug 2024 19:54:35 +0200 Subject: [PATCH 2/3] Implement SourceRange.__contains__ via SourceLocation.__le__ --- clang/bindings/python/clang/cindex.py | 25 + clang/docs/ReleaseNotes.rst | 2 ++ 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 5fd7cc64810732..162ed786607550 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -270,6 +270,14 @@ def _get_instantiation(self): self._data = (f, int(l.value), int(c.value), int(o.value)) return self._data +def __le__(self, other): +if self.line < other.line: +return True +if self.line == other.line and self.column <= other.column: +return True +# when self.line > other.line +return False + @staticmethod def from_position(tu, file, line, column): """ @@ -383,22 +391,7 @@ def __contains__(self, other): ): # same file name return False -# same file, in between lines -if self.start.line < other.line < self.end.line: -return True -# between columns in one-liner range -elif self.start.line == other.line == self.end.line: -if self.start.column <= other.column <= self.end.column: -return True
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
@@ -386,6 +386,10 @@ def __contains__(self, other): # same file, in between lines if self.start.line < other.line < self.end.line: return True +# between columns in one-liner range +elif self.start.line == other.line == self.end.line: DeinAlptraum wrote: I've exposed a `clang_lessThanLocations` function on C-side, similar to the `clang_equalLocations` function, and used this to implement the operators on Python side. Hope that resolves this case. https://github.com/llvm/llvm-project/pull/101802 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/101802 >From 572b1be0b204561fdbb049f0c17f065d17198ac0 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Sat, 3 Aug 2024 09:28:02 +0100 Subject: [PATCH 1/3] [libclang/python] Fix bug in SourceRange.__contains__, add tests --- clang/bindings/python/clang/cindex.py | 4 ++ .../python/tests/cindex/test_source_range.py | 56 +++ 2 files changed, 60 insertions(+) create mode 100644 clang/bindings/python/tests/cindex/test_source_range.py diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index c251c46a04adf4..5fd7cc64810732 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -386,6 +386,10 @@ def __contains__(self, other): # same file, in between lines if self.start.line < other.line < self.end.line: return True +# between columns in one-liner range +elif self.start.line == other.line == self.end.line: +if self.start.column <= other.column <= self.end.column: +return True elif self.start.line == other.line: # same file first line if self.start.column <= other.column: diff --git a/clang/bindings/python/tests/cindex/test_source_range.py b/clang/bindings/python/tests/cindex/test_source_range.py new file mode 100644 index 00..9f76848e890207 --- /dev/null +++ b/clang/bindings/python/tests/cindex/test_source_range.py @@ -0,0 +1,56 @@ +import unittest + +from clang.cindex import SourceLocation, SourceRange + +from .util import get_tu + + +def create_location(tu, line, column): +return SourceLocation.from_position(tu, tu.get_file(tu.spelling), line, column) + + +def create_range(tu, line1, column1, line2, column2): +return SourceRange.from_locations( +create_location(tu, line1, column1), create_location(tu, line2, column2) +) + + +class TestSourceRange(unittest.TestCase): +def test_contains(self): +tu = get_tu( +"""a +a +a +a""" +) + +l13 = create_location(tu, 1, 3) +l21 = create_location(tu, 2, 1) +l22 = create_location(tu, 2, 2) +l23 = create_location(tu, 2, 3) +l24 = create_location(tu, 2, 4) +l25 = create_location(tu, 2, 5) +l33 = create_location(tu, 3, 3) +l31 = create_location(tu, 3, 1) +r22_24 = create_range(tu, 2, 2, 2, 4) +r23_23 = create_range(tu, 2, 3, 2, 3) +r24_32 = create_range(tu, 2, 4, 3, 2) +r14_32 = create_range(tu, 1, 4, 3, 2) + +assert l13 not in r22_24 # Line before start +assert l21 not in r22_24 # Column before start +assert l22 in r22_24 # Colum on start +assert l23 in r22_24 # Column in range +assert l24 in r22_24 # Column on end +assert l25 not in r22_24 # Column after end +assert l33 not in r22_24 # Line after end + +assert l23 in r23_23 # In one-column range + +assert l23 not in r24_32 # Outside range in first line +assert l33 not in r24_32 # Outside range in last line +assert l25 in r24_32 # In range in first line +assert l31 in r24_32 # In range in last line + +assert l21 in r14_32 # In range at start of center line +assert l25 in r14_32 # In range at end of center line >From e27cf4b01f61dd6cf7ee8fa86857c566716eabfb Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Wed, 7 Aug 2024 19:54:35 +0200 Subject: [PATCH 2/3] Implement SourceRange.__contains__ via SourceLocation.__le__ --- clang/bindings/python/clang/cindex.py | 25 + clang/docs/ReleaseNotes.rst | 2 ++ 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 5fd7cc64810732..162ed786607550 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -270,6 +270,14 @@ def _get_instantiation(self): self._data = (f, int(l.value), int(c.value), int(o.value)) return self._data +def __le__(self, other): +if self.line < other.line: +return True +if self.line == other.line and self.column <= other.column: +return True +# when self.line > other.line +return False + @staticmethod def from_position(tu, file, line, column): """ @@ -383,22 +391,7 @@ def __contains__(self, other): ): # same file name return False -# same file, in between lines -if self.start.line < other.line < self.end.line: -return True -# between columns in one-liner range -elif self.start.line == other.line == self.end.line: -if self.start.column <= other.column <= self.end.column: -return True
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/101802 >From 572b1be0b204561fdbb049f0c17f065d17198ac0 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Sat, 3 Aug 2024 09:28:02 +0100 Subject: [PATCH 1/4] [libclang/python] Fix bug in SourceRange.__contains__, add tests --- clang/bindings/python/clang/cindex.py | 4 ++ .../python/tests/cindex/test_source_range.py | 56 +++ 2 files changed, 60 insertions(+) create mode 100644 clang/bindings/python/tests/cindex/test_source_range.py diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index c251c46a04adf4..5fd7cc64810732 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -386,6 +386,10 @@ def __contains__(self, other): # same file, in between lines if self.start.line < other.line < self.end.line: return True +# between columns in one-liner range +elif self.start.line == other.line == self.end.line: +if self.start.column <= other.column <= self.end.column: +return True elif self.start.line == other.line: # same file first line if self.start.column <= other.column: diff --git a/clang/bindings/python/tests/cindex/test_source_range.py b/clang/bindings/python/tests/cindex/test_source_range.py new file mode 100644 index 00..9f76848e890207 --- /dev/null +++ b/clang/bindings/python/tests/cindex/test_source_range.py @@ -0,0 +1,56 @@ +import unittest + +from clang.cindex import SourceLocation, SourceRange + +from .util import get_tu + + +def create_location(tu, line, column): +return SourceLocation.from_position(tu, tu.get_file(tu.spelling), line, column) + + +def create_range(tu, line1, column1, line2, column2): +return SourceRange.from_locations( +create_location(tu, line1, column1), create_location(tu, line2, column2) +) + + +class TestSourceRange(unittest.TestCase): +def test_contains(self): +tu = get_tu( +"""a +a +a +a""" +) + +l13 = create_location(tu, 1, 3) +l21 = create_location(tu, 2, 1) +l22 = create_location(tu, 2, 2) +l23 = create_location(tu, 2, 3) +l24 = create_location(tu, 2, 4) +l25 = create_location(tu, 2, 5) +l33 = create_location(tu, 3, 3) +l31 = create_location(tu, 3, 1) +r22_24 = create_range(tu, 2, 2, 2, 4) +r23_23 = create_range(tu, 2, 3, 2, 3) +r24_32 = create_range(tu, 2, 4, 3, 2) +r14_32 = create_range(tu, 1, 4, 3, 2) + +assert l13 not in r22_24 # Line before start +assert l21 not in r22_24 # Column before start +assert l22 in r22_24 # Colum on start +assert l23 in r22_24 # Column in range +assert l24 in r22_24 # Column on end +assert l25 not in r22_24 # Column after end +assert l33 not in r22_24 # Line after end + +assert l23 in r23_23 # In one-column range + +assert l23 not in r24_32 # Outside range in first line +assert l33 not in r24_32 # Outside range in last line +assert l25 in r24_32 # In range in first line +assert l31 in r24_32 # In range in last line + +assert l21 in r14_32 # In range at start of center line +assert l25 in r14_32 # In range at end of center line >From e27cf4b01f61dd6cf7ee8fa86857c566716eabfb Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Wed, 7 Aug 2024 19:54:35 +0200 Subject: [PATCH 2/4] Implement SourceRange.__contains__ via SourceLocation.__le__ --- clang/bindings/python/clang/cindex.py | 25 + clang/docs/ReleaseNotes.rst | 2 ++ 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 5fd7cc64810732..162ed786607550 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -270,6 +270,14 @@ def _get_instantiation(self): self._data = (f, int(l.value), int(c.value), int(o.value)) return self._data +def __le__(self, other): +if self.line < other.line: +return True +if self.line == other.line and self.column <= other.column: +return True +# when self.line > other.line +return False + @staticmethod def from_position(tu, file, line, column): """ @@ -383,22 +391,7 @@ def __contains__(self, other): ): # same file name return False -# same file, in between lines -if self.start.line < other.line < self.end.line: -return True -# between columns in one-liner range -elif self.start.line == other.line == self.end.line: -if self.start.column <= other.column <= self.end.column: -return True
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
@@ -50,6 +50,18 @@ unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) { loc1.int_data == loc2.int_data); } +unsigned clang_lessThanLocations(CXSourceLocation loc1, CXSourceLocation loc2) { + const SourceLocation Loc1 = SourceLocation::getFromRawEncoding(loc1.int_data); + const SourceLocation Loc2 = SourceLocation::getFromRawEncoding(loc2.int_data); + + const SourceManager &SM = + *static_cast(loc1.ptr_data[0]); + if (!SM.isWrittenInSameFile(Loc1, Loc2)) DeinAlptraum wrote: Good point, went with `isBeforeInTranslationUnit` https://github.com/llvm/llvm-project/pull/101802 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/101802 >From 572b1be0b204561fdbb049f0c17f065d17198ac0 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Sat, 3 Aug 2024 09:28:02 +0100 Subject: [PATCH 1/4] [libclang/python] Fix bug in SourceRange.__contains__, add tests --- clang/bindings/python/clang/cindex.py | 4 ++ .../python/tests/cindex/test_source_range.py | 56 +++ 2 files changed, 60 insertions(+) create mode 100644 clang/bindings/python/tests/cindex/test_source_range.py diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index c251c46a04adf4..5fd7cc64810732 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -386,6 +386,10 @@ def __contains__(self, other): # same file, in between lines if self.start.line < other.line < self.end.line: return True +# between columns in one-liner range +elif self.start.line == other.line == self.end.line: +if self.start.column <= other.column <= self.end.column: +return True elif self.start.line == other.line: # same file first line if self.start.column <= other.column: diff --git a/clang/bindings/python/tests/cindex/test_source_range.py b/clang/bindings/python/tests/cindex/test_source_range.py new file mode 100644 index 00..9f76848e890207 --- /dev/null +++ b/clang/bindings/python/tests/cindex/test_source_range.py @@ -0,0 +1,56 @@ +import unittest + +from clang.cindex import SourceLocation, SourceRange + +from .util import get_tu + + +def create_location(tu, line, column): +return SourceLocation.from_position(tu, tu.get_file(tu.spelling), line, column) + + +def create_range(tu, line1, column1, line2, column2): +return SourceRange.from_locations( +create_location(tu, line1, column1), create_location(tu, line2, column2) +) + + +class TestSourceRange(unittest.TestCase): +def test_contains(self): +tu = get_tu( +"""a +a +a +a""" +) + +l13 = create_location(tu, 1, 3) +l21 = create_location(tu, 2, 1) +l22 = create_location(tu, 2, 2) +l23 = create_location(tu, 2, 3) +l24 = create_location(tu, 2, 4) +l25 = create_location(tu, 2, 5) +l33 = create_location(tu, 3, 3) +l31 = create_location(tu, 3, 1) +r22_24 = create_range(tu, 2, 2, 2, 4) +r23_23 = create_range(tu, 2, 3, 2, 3) +r24_32 = create_range(tu, 2, 4, 3, 2) +r14_32 = create_range(tu, 1, 4, 3, 2) + +assert l13 not in r22_24 # Line before start +assert l21 not in r22_24 # Column before start +assert l22 in r22_24 # Colum on start +assert l23 in r22_24 # Column in range +assert l24 in r22_24 # Column on end +assert l25 not in r22_24 # Column after end +assert l33 not in r22_24 # Line after end + +assert l23 in r23_23 # In one-column range + +assert l23 not in r24_32 # Outside range in first line +assert l33 not in r24_32 # Outside range in last line +assert l25 in r24_32 # In range in first line +assert l31 in r24_32 # In range in last line + +assert l21 in r14_32 # In range at start of center line +assert l25 in r14_32 # In range at end of center line >From e27cf4b01f61dd6cf7ee8fa86857c566716eabfb Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Wed, 7 Aug 2024 19:54:35 +0200 Subject: [PATCH 2/4] Implement SourceRange.__contains__ via SourceLocation.__le__ --- clang/bindings/python/clang/cindex.py | 25 + clang/docs/ReleaseNotes.rst | 2 ++ 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 5fd7cc64810732..162ed786607550 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -270,6 +270,14 @@ def _get_instantiation(self): self._data = (f, int(l.value), int(c.value), int(o.value)) return self._data +def __le__(self, other): +if self.line < other.line: +return True +if self.line == other.line and self.column <= other.column: +return True +# when self.line > other.line +return False + @staticmethod def from_position(tu, file, line, column): """ @@ -383,22 +391,7 @@ def __contains__(self, other): ): # same file name return False -# same file, in between lines -if self.start.line < other.line < self.end.line: -return True -# between columns in one-liner range -elif self.start.line == other.line == self.end.line: -if self.start.column <= other.column <= self.end.column: -return True
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/101802 >From 572b1be0b204561fdbb049f0c17f065d17198ac0 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Sat, 3 Aug 2024 09:28:02 +0100 Subject: [PATCH 1/5] [libclang/python] Fix bug in SourceRange.__contains__, add tests --- clang/bindings/python/clang/cindex.py | 4 ++ .../python/tests/cindex/test_source_range.py | 56 +++ 2 files changed, 60 insertions(+) create mode 100644 clang/bindings/python/tests/cindex/test_source_range.py diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index c251c46a04adf4..5fd7cc64810732 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -386,6 +386,10 @@ def __contains__(self, other): # same file, in between lines if self.start.line < other.line < self.end.line: return True +# between columns in one-liner range +elif self.start.line == other.line == self.end.line: +if self.start.column <= other.column <= self.end.column: +return True elif self.start.line == other.line: # same file first line if self.start.column <= other.column: diff --git a/clang/bindings/python/tests/cindex/test_source_range.py b/clang/bindings/python/tests/cindex/test_source_range.py new file mode 100644 index 00..9f76848e890207 --- /dev/null +++ b/clang/bindings/python/tests/cindex/test_source_range.py @@ -0,0 +1,56 @@ +import unittest + +from clang.cindex import SourceLocation, SourceRange + +from .util import get_tu + + +def create_location(tu, line, column): +return SourceLocation.from_position(tu, tu.get_file(tu.spelling), line, column) + + +def create_range(tu, line1, column1, line2, column2): +return SourceRange.from_locations( +create_location(tu, line1, column1), create_location(tu, line2, column2) +) + + +class TestSourceRange(unittest.TestCase): +def test_contains(self): +tu = get_tu( +"""a +a +a +a""" +) + +l13 = create_location(tu, 1, 3) +l21 = create_location(tu, 2, 1) +l22 = create_location(tu, 2, 2) +l23 = create_location(tu, 2, 3) +l24 = create_location(tu, 2, 4) +l25 = create_location(tu, 2, 5) +l33 = create_location(tu, 3, 3) +l31 = create_location(tu, 3, 1) +r22_24 = create_range(tu, 2, 2, 2, 4) +r23_23 = create_range(tu, 2, 3, 2, 3) +r24_32 = create_range(tu, 2, 4, 3, 2) +r14_32 = create_range(tu, 1, 4, 3, 2) + +assert l13 not in r22_24 # Line before start +assert l21 not in r22_24 # Column before start +assert l22 in r22_24 # Colum on start +assert l23 in r22_24 # Column in range +assert l24 in r22_24 # Column on end +assert l25 not in r22_24 # Column after end +assert l33 not in r22_24 # Line after end + +assert l23 in r23_23 # In one-column range + +assert l23 not in r24_32 # Outside range in first line +assert l33 not in r24_32 # Outside range in last line +assert l25 in r24_32 # In range in first line +assert l31 in r24_32 # In range in last line + +assert l21 in r14_32 # In range at start of center line +assert l25 in r14_32 # In range at end of center line >From e27cf4b01f61dd6cf7ee8fa86857c566716eabfb Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Wed, 7 Aug 2024 19:54:35 +0200 Subject: [PATCH 2/5] Implement SourceRange.__contains__ via SourceLocation.__le__ --- clang/bindings/python/clang/cindex.py | 25 + clang/docs/ReleaseNotes.rst | 2 ++ 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 5fd7cc64810732..162ed786607550 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -270,6 +270,14 @@ def _get_instantiation(self): self._data = (f, int(l.value), int(c.value), int(o.value)) return self._data +def __le__(self, other): +if self.line < other.line: +return True +if self.line == other.line and self.column <= other.column: +return True +# when self.line > other.line +return False + @staticmethod def from_position(tu, file, line, column): """ @@ -383,22 +391,7 @@ def __contains__(self, other): ): # same file name return False -# same file, in between lines -if self.start.line < other.line < self.end.line: -return True -# between columns in one-liner range -elif self.start.line == other.line == self.end.line: -if self.start.column <= other.column <= self.end.column: -return True
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
DeinAlptraum wrote: Implemented all your suggestions https://github.com/llvm/llvm-project/pull/101802 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/101802 >From 572b1be0b204561fdbb049f0c17f065d17198ac0 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Sat, 3 Aug 2024 09:28:02 +0100 Subject: [PATCH 1/6] [libclang/python] Fix bug in SourceRange.__contains__, add tests --- clang/bindings/python/clang/cindex.py | 4 ++ .../python/tests/cindex/test_source_range.py | 56 +++ 2 files changed, 60 insertions(+) create mode 100644 clang/bindings/python/tests/cindex/test_source_range.py diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index c251c46a04adf4..5fd7cc64810732 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -386,6 +386,10 @@ def __contains__(self, other): # same file, in between lines if self.start.line < other.line < self.end.line: return True +# between columns in one-liner range +elif self.start.line == other.line == self.end.line: +if self.start.column <= other.column <= self.end.column: +return True elif self.start.line == other.line: # same file first line if self.start.column <= other.column: diff --git a/clang/bindings/python/tests/cindex/test_source_range.py b/clang/bindings/python/tests/cindex/test_source_range.py new file mode 100644 index 00..9f76848e890207 --- /dev/null +++ b/clang/bindings/python/tests/cindex/test_source_range.py @@ -0,0 +1,56 @@ +import unittest + +from clang.cindex import SourceLocation, SourceRange + +from .util import get_tu + + +def create_location(tu, line, column): +return SourceLocation.from_position(tu, tu.get_file(tu.spelling), line, column) + + +def create_range(tu, line1, column1, line2, column2): +return SourceRange.from_locations( +create_location(tu, line1, column1), create_location(tu, line2, column2) +) + + +class TestSourceRange(unittest.TestCase): +def test_contains(self): +tu = get_tu( +"""a +a +a +a""" +) + +l13 = create_location(tu, 1, 3) +l21 = create_location(tu, 2, 1) +l22 = create_location(tu, 2, 2) +l23 = create_location(tu, 2, 3) +l24 = create_location(tu, 2, 4) +l25 = create_location(tu, 2, 5) +l33 = create_location(tu, 3, 3) +l31 = create_location(tu, 3, 1) +r22_24 = create_range(tu, 2, 2, 2, 4) +r23_23 = create_range(tu, 2, 3, 2, 3) +r24_32 = create_range(tu, 2, 4, 3, 2) +r14_32 = create_range(tu, 1, 4, 3, 2) + +assert l13 not in r22_24 # Line before start +assert l21 not in r22_24 # Column before start +assert l22 in r22_24 # Colum on start +assert l23 in r22_24 # Column in range +assert l24 in r22_24 # Column on end +assert l25 not in r22_24 # Column after end +assert l33 not in r22_24 # Line after end + +assert l23 in r23_23 # In one-column range + +assert l23 not in r24_32 # Outside range in first line +assert l33 not in r24_32 # Outside range in last line +assert l25 in r24_32 # In range in first line +assert l31 in r24_32 # In range in last line + +assert l21 in r14_32 # In range at start of center line +assert l25 in r14_32 # In range at end of center line >From e27cf4b01f61dd6cf7ee8fa86857c566716eabfb Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Wed, 7 Aug 2024 19:54:35 +0200 Subject: [PATCH 2/6] Implement SourceRange.__contains__ via SourceLocation.__le__ --- clang/bindings/python/clang/cindex.py | 25 + clang/docs/ReleaseNotes.rst | 2 ++ 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 5fd7cc64810732..162ed786607550 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -270,6 +270,14 @@ def _get_instantiation(self): self._data = (f, int(l.value), int(c.value), int(o.value)) return self._data +def __le__(self, other): +if self.line < other.line: +return True +if self.line == other.line and self.column <= other.column: +return True +# when self.line > other.line +return False + @staticmethod def from_position(tu, file, line, column): """ @@ -383,22 +391,7 @@ def __contains__(self, other): ): # same file name return False -# same file, in between lines -if self.start.line < other.line < self.end.line: -return True -# between columns in one-liner range -elif self.start.line == other.line == self.end.line: -if self.start.column <= other.column <= self.end.column: -return True
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/101802 >From 572b1be0b204561fdbb049f0c17f065d17198ac0 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Sat, 3 Aug 2024 09:28:02 +0100 Subject: [PATCH 1/6] [libclang/python] Fix bug in SourceRange.__contains__, add tests --- clang/bindings/python/clang/cindex.py | 4 ++ .../python/tests/cindex/test_source_range.py | 56 +++ 2 files changed, 60 insertions(+) create mode 100644 clang/bindings/python/tests/cindex/test_source_range.py diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index c251c46a04adf4..5fd7cc64810732 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -386,6 +386,10 @@ def __contains__(self, other): # same file, in between lines if self.start.line < other.line < self.end.line: return True +# between columns in one-liner range +elif self.start.line == other.line == self.end.line: +if self.start.column <= other.column <= self.end.column: +return True elif self.start.line == other.line: # same file first line if self.start.column <= other.column: diff --git a/clang/bindings/python/tests/cindex/test_source_range.py b/clang/bindings/python/tests/cindex/test_source_range.py new file mode 100644 index 00..9f76848e890207 --- /dev/null +++ b/clang/bindings/python/tests/cindex/test_source_range.py @@ -0,0 +1,56 @@ +import unittest + +from clang.cindex import SourceLocation, SourceRange + +from .util import get_tu + + +def create_location(tu, line, column): +return SourceLocation.from_position(tu, tu.get_file(tu.spelling), line, column) + + +def create_range(tu, line1, column1, line2, column2): +return SourceRange.from_locations( +create_location(tu, line1, column1), create_location(tu, line2, column2) +) + + +class TestSourceRange(unittest.TestCase): +def test_contains(self): +tu = get_tu( +"""a +a +a +a""" +) + +l13 = create_location(tu, 1, 3) +l21 = create_location(tu, 2, 1) +l22 = create_location(tu, 2, 2) +l23 = create_location(tu, 2, 3) +l24 = create_location(tu, 2, 4) +l25 = create_location(tu, 2, 5) +l33 = create_location(tu, 3, 3) +l31 = create_location(tu, 3, 1) +r22_24 = create_range(tu, 2, 2, 2, 4) +r23_23 = create_range(tu, 2, 3, 2, 3) +r24_32 = create_range(tu, 2, 4, 3, 2) +r14_32 = create_range(tu, 1, 4, 3, 2) + +assert l13 not in r22_24 # Line before start +assert l21 not in r22_24 # Column before start +assert l22 in r22_24 # Colum on start +assert l23 in r22_24 # Column in range +assert l24 in r22_24 # Column on end +assert l25 not in r22_24 # Column after end +assert l33 not in r22_24 # Line after end + +assert l23 in r23_23 # In one-column range + +assert l23 not in r24_32 # Outside range in first line +assert l33 not in r24_32 # Outside range in last line +assert l25 in r24_32 # In range in first line +assert l31 in r24_32 # In range in last line + +assert l21 in r14_32 # In range at start of center line +assert l25 in r14_32 # In range at end of center line >From e27cf4b01f61dd6cf7ee8fa86857c566716eabfb Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Wed, 7 Aug 2024 19:54:35 +0200 Subject: [PATCH 2/6] Implement SourceRange.__contains__ via SourceLocation.__le__ --- clang/bindings/python/clang/cindex.py | 25 + clang/docs/ReleaseNotes.rst | 2 ++ 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 5fd7cc64810732..162ed786607550 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -270,6 +270,14 @@ def _get_instantiation(self): self._data = (f, int(l.value), int(c.value), int(o.value)) return self._data +def __le__(self, other): +if self.line < other.line: +return True +if self.line == other.line and self.column <= other.column: +return True +# when self.line > other.line +return False + @staticmethod def from_position(tu, file, line, column): """ @@ -383,22 +391,7 @@ def __contains__(self, other): ): # same file name return False -# same file, in between lines -if self.start.line < other.line < self.end.line: -return True -# between columns in one-liner range -elif self.start.line == other.line == self.end.line: -if self.start.column <= other.column <= self.end.column: -return True
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
@@ -74,6 +74,16 @@ CINDEX_LINKAGE CXSourceLocation clang_getNullLocation(void); CINDEX_LINKAGE unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2); +/** + * Determine for two source locations if they refer to the same file + * and one of them comes strictly before the other in the source code. + * + * \returns non-zero if the source locations refer to the same file and the + * first one comes strictly before the second one, zero otherwise. + */ +CINDEX_LINKAGE unsigned clang_lessThanLocations(CXSourceLocation loc1, DeinAlptraum wrote: Sounds sensible; Implemented this and the other suggestions. https://github.com/llvm/llvm-project/pull/101802 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/101802 >From 572b1be0b204561fdbb049f0c17f065d17198ac0 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Sat, 3 Aug 2024 09:28:02 +0100 Subject: [PATCH 1/6] [libclang/python] Fix bug in SourceRange.__contains__, add tests --- clang/bindings/python/clang/cindex.py | 4 ++ .../python/tests/cindex/test_source_range.py | 56 +++ 2 files changed, 60 insertions(+) create mode 100644 clang/bindings/python/tests/cindex/test_source_range.py diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index c251c46a04adf4..5fd7cc64810732 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -386,6 +386,10 @@ def __contains__(self, other): # same file, in between lines if self.start.line < other.line < self.end.line: return True +# between columns in one-liner range +elif self.start.line == other.line == self.end.line: +if self.start.column <= other.column <= self.end.column: +return True elif self.start.line == other.line: # same file first line if self.start.column <= other.column: diff --git a/clang/bindings/python/tests/cindex/test_source_range.py b/clang/bindings/python/tests/cindex/test_source_range.py new file mode 100644 index 00..9f76848e890207 --- /dev/null +++ b/clang/bindings/python/tests/cindex/test_source_range.py @@ -0,0 +1,56 @@ +import unittest + +from clang.cindex import SourceLocation, SourceRange + +from .util import get_tu + + +def create_location(tu, line, column): +return SourceLocation.from_position(tu, tu.get_file(tu.spelling), line, column) + + +def create_range(tu, line1, column1, line2, column2): +return SourceRange.from_locations( +create_location(tu, line1, column1), create_location(tu, line2, column2) +) + + +class TestSourceRange(unittest.TestCase): +def test_contains(self): +tu = get_tu( +"""a +a +a +a""" +) + +l13 = create_location(tu, 1, 3) +l21 = create_location(tu, 2, 1) +l22 = create_location(tu, 2, 2) +l23 = create_location(tu, 2, 3) +l24 = create_location(tu, 2, 4) +l25 = create_location(tu, 2, 5) +l33 = create_location(tu, 3, 3) +l31 = create_location(tu, 3, 1) +r22_24 = create_range(tu, 2, 2, 2, 4) +r23_23 = create_range(tu, 2, 3, 2, 3) +r24_32 = create_range(tu, 2, 4, 3, 2) +r14_32 = create_range(tu, 1, 4, 3, 2) + +assert l13 not in r22_24 # Line before start +assert l21 not in r22_24 # Column before start +assert l22 in r22_24 # Colum on start +assert l23 in r22_24 # Column in range +assert l24 in r22_24 # Column on end +assert l25 not in r22_24 # Column after end +assert l33 not in r22_24 # Line after end + +assert l23 in r23_23 # In one-column range + +assert l23 not in r24_32 # Outside range in first line +assert l33 not in r24_32 # Outside range in last line +assert l25 in r24_32 # In range in first line +assert l31 in r24_32 # In range in last line + +assert l21 in r14_32 # In range at start of center line +assert l25 in r14_32 # In range at end of center line >From e27cf4b01f61dd6cf7ee8fa86857c566716eabfb Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Wed, 7 Aug 2024 19:54:35 +0200 Subject: [PATCH 2/6] Implement SourceRange.__contains__ via SourceLocation.__le__ --- clang/bindings/python/clang/cindex.py | 25 + clang/docs/ReleaseNotes.rst | 2 ++ 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 5fd7cc64810732..162ed786607550 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -270,6 +270,14 @@ def _get_instantiation(self): self._data = (f, int(l.value), int(c.value), int(o.value)) return self._data +def __le__(self, other): +if self.line < other.line: +return True +if self.line == other.line and self.column <= other.column: +return True +# when self.line > other.line +return False + @staticmethod def from_position(tu, file, line, column): """ @@ -383,22 +391,7 @@ def __contains__(self, other): ): # same file name return False -# same file, in between lines -if self.start.line < other.line < self.end.line: -return True -# between columns in one-liner range -elif self.start.line == other.line == self.end.line: -if self.start.column <= other.column <= self.end.column: -return True
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/101802 >From 572b1be0b204561fdbb049f0c17f065d17198ac0 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Sat, 3 Aug 2024 09:28:02 +0100 Subject: [PATCH 1/7] [libclang/python] Fix bug in SourceRange.__contains__, add tests --- clang/bindings/python/clang/cindex.py | 4 ++ .../python/tests/cindex/test_source_range.py | 56 +++ 2 files changed, 60 insertions(+) create mode 100644 clang/bindings/python/tests/cindex/test_source_range.py diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index c251c46a04adf4..5fd7cc64810732 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -386,6 +386,10 @@ def __contains__(self, other): # same file, in between lines if self.start.line < other.line < self.end.line: return True +# between columns in one-liner range +elif self.start.line == other.line == self.end.line: +if self.start.column <= other.column <= self.end.column: +return True elif self.start.line == other.line: # same file first line if self.start.column <= other.column: diff --git a/clang/bindings/python/tests/cindex/test_source_range.py b/clang/bindings/python/tests/cindex/test_source_range.py new file mode 100644 index 00..9f76848e890207 --- /dev/null +++ b/clang/bindings/python/tests/cindex/test_source_range.py @@ -0,0 +1,56 @@ +import unittest + +from clang.cindex import SourceLocation, SourceRange + +from .util import get_tu + + +def create_location(tu, line, column): +return SourceLocation.from_position(tu, tu.get_file(tu.spelling), line, column) + + +def create_range(tu, line1, column1, line2, column2): +return SourceRange.from_locations( +create_location(tu, line1, column1), create_location(tu, line2, column2) +) + + +class TestSourceRange(unittest.TestCase): +def test_contains(self): +tu = get_tu( +"""a +a +a +a""" +) + +l13 = create_location(tu, 1, 3) +l21 = create_location(tu, 2, 1) +l22 = create_location(tu, 2, 2) +l23 = create_location(tu, 2, 3) +l24 = create_location(tu, 2, 4) +l25 = create_location(tu, 2, 5) +l33 = create_location(tu, 3, 3) +l31 = create_location(tu, 3, 1) +r22_24 = create_range(tu, 2, 2, 2, 4) +r23_23 = create_range(tu, 2, 3, 2, 3) +r24_32 = create_range(tu, 2, 4, 3, 2) +r14_32 = create_range(tu, 1, 4, 3, 2) + +assert l13 not in r22_24 # Line before start +assert l21 not in r22_24 # Column before start +assert l22 in r22_24 # Colum on start +assert l23 in r22_24 # Column in range +assert l24 in r22_24 # Column on end +assert l25 not in r22_24 # Column after end +assert l33 not in r22_24 # Line after end + +assert l23 in r23_23 # In one-column range + +assert l23 not in r24_32 # Outside range in first line +assert l33 not in r24_32 # Outside range in last line +assert l25 in r24_32 # In range in first line +assert l31 in r24_32 # In range in last line + +assert l21 in r14_32 # In range at start of center line +assert l25 in r14_32 # In range at end of center line >From e27cf4b01f61dd6cf7ee8fa86857c566716eabfb Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Wed, 7 Aug 2024 19:54:35 +0200 Subject: [PATCH 2/7] Implement SourceRange.__contains__ via SourceLocation.__le__ --- clang/bindings/python/clang/cindex.py | 25 + clang/docs/ReleaseNotes.rst | 2 ++ 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 5fd7cc64810732..162ed786607550 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -270,6 +270,14 @@ def _get_instantiation(self): self._data = (f, int(l.value), int(c.value), int(o.value)) return self._data +def __le__(self, other): +if self.line < other.line: +return True +if self.line == other.line and self.column <= other.column: +return True +# when self.line > other.line +return False + @staticmethod def from_position(tu, file, line, column): """ @@ -383,22 +391,7 @@ def __contains__(self, other): ): # same file name return False -# same file, in between lines -if self.start.line < other.line < self.end.line: -return True -# between columns in one-liner range -elif self.start.line == other.line == self.end.line: -if self.start.column <= other.column <= self.end.column: -return True
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
@@ -65,6 +65,9 @@ Clang Python Bindings Potentially Breaking Changes - Calling a property on the ``CompletionChunk`` or ``CompletionString`` class statically now leads to an error, instead of returning a ``CachedProperty`` object that is used internally. Properties are only available on instances. +- For a single-line ``SourceRange`` and a ``SourceLocation`` in the same line, DeinAlptraum wrote: Thanks for the reviews, and added 👍🏼 https://github.com/llvm/llvm-project/pull/101802 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bug in `SourceRange.__contains__`, add tests (PR #101802)
https://github.com/DeinAlptraum closed https://github.com/llvm/llvm-project/pull/101802 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
@@ -665,867 +1312,858 @@ class CursorKind(BaseEnumeration): A CursorKind describes the kind of entity that a cursor points to. """ -# The required BaseEnumeration declarations. -_kinds = [] -_name_map = None - @staticmethod -def get_all_kinds(): +def get_all_kinds() -> list[CursorKind]: """Return all CursorKind enumeration instances.""" -return [x for x in CursorKind._kinds if not x is None] +return [x for x in CursorKind] -def is_declaration(self): +def is_declaration(self) -> bool: """Test if this is a declaration kind.""" return conf.lib.clang_isDeclaration(self) -def is_reference(self): +def is_reference(self) -> bool: """Test if this is a reference kind.""" return conf.lib.clang_isReference(self) -def is_expression(self): +def is_expression(self) -> bool: """Test if this is an expression kind.""" return conf.lib.clang_isExpression(self) -def is_statement(self): +def is_statement(self) -> bool: """Test if this is a statement kind.""" return conf.lib.clang_isStatement(self) -def is_attribute(self): +def is_attribute(self) -> bool: """Test if this is an attribute kind.""" return conf.lib.clang_isAttribute(self) -def is_invalid(self): +def is_invalid(self) -> bool: """Test if this is an invalid kind.""" return conf.lib.clang_isInvalid(self) -def is_translation_unit(self): +def is_translation_unit(self) -> bool: """Test if this is a translation unit kind.""" return conf.lib.clang_isTranslationUnit(self) -def is_preprocessing(self): +def is_preprocessing(self) -> bool: """Test if this is a preprocessing kind.""" return conf.lib.clang_isPreprocessing(self) -def is_unexposed(self): +def is_unexposed(self) -> bool: """Test if this is an unexposed kind.""" return conf.lib.clang_isUnexposed(self) -def __repr__(self): -return "CursorKind.%s" % (self.name,) +### +# Declaration Kinds +# A declaration whose specific kind is not exposed via this interface. +# +# Unexposed declarations have the same operations as any other kind of +# declaration; one can extract their location information, spelling, find their +# definitions, etc. However, the specific kind of the declaration is not +# reported. +UNEXPOSED_DECL = 1 -### -# Declaration Kinds +# A C or C++ struct. +STRUCT_DECL = 2 -# A declaration whose specific kind is not exposed via this interface. -# -# Unexposed declarations have the same operations as any other kind of -# declaration; one can extract their location information, spelling, find their -# definitions, etc. However, the specific kind of the declaration is not -# reported. -CursorKind.UNEXPOSED_DECL = CursorKind(1) +# A C or C++ union. +UNION_DECL = 3 -# A C or C++ struct. -CursorKind.STRUCT_DECL = CursorKind(2) +# A C++ class. +CLASS_DECL = 4 -# A C or C++ union. -CursorKind.UNION_DECL = CursorKind(3) +# An enumeration. +ENUM_DECL = 5 -# A C++ class. -CursorKind.CLASS_DECL = CursorKind(4) +# A field (in C) or non-static data member (in C++) in a struct, union, or C++ +# class. +FIELD_DECL = 6 -# An enumeration. -CursorKind.ENUM_DECL = CursorKind(5) +# An enumerator constant. +ENUM_CONSTANT_DECL = 7 -# A field (in C) or non-static data member (in C++) in a struct, union, or C++ -# class. -CursorKind.FIELD_DECL = CursorKind(6) +# A function. +FUNCTION_DECL = 8 -# An enumerator constant. -CursorKind.ENUM_CONSTANT_DECL = CursorKind(7) +# A variable. +VAR_DECL = 9 -# A function. -CursorKind.FUNCTION_DECL = CursorKind(8) +# A function or method parameter. +PARM_DECL = 10 -# A variable. -CursorKind.VAR_DECL = CursorKind(9) +# An Objective-C @interface. +OBJC_INTERFACE_DECL = 11 -# A function or method parameter. -CursorKind.PARM_DECL = CursorKind(10) +# An Objective-C @interface for a category. +OBJC_CATEGORY_DECL = 12 -# An Objective-C @interface. -CursorKind.OBJC_INTERFACE_DECL = CursorKind(11) +# An Objective-C @protocol declaration. +OBJC_PROTOCOL_DECL = 13 -# An Objective-C @interface for a category. -CursorKind.OBJC_CATEGORY_DECL = CursorKind(12) +# An Objective-C @property declaration. +OBJC_PROPERTY_DECL = 14 -# An Objective-C @protocol declaration. -CursorKind.OBJC_PROTOCOL_DECL = CursorKind(13) +# An Objective-C instance variable. +OBJC_IVAR_DECL = 15 -# An Objective-C @property declaration. -CursorKind.OBJC_PROPERTY_DECL = CursorKind(14) +# An Objective-C instance method. +OBJC_INSTANCE_METHOD_DECL = 16 -# An Objective-C instance variable. -CursorKind.OBJC_IVAR_DECL = CursorKind(15) +# An Objective-C class method. +OBJC_CLASS_METHOD_DECL = 17 -# An Objectiv
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
@@ -2286,192 +2869,151 @@ class TypeKind(BaseEnumeration): Describes the kind of type. """ -# The unique kind objects, indexed by id. -_kinds = [] -_name_map = None - @property -def spelling(self): +def spelling(self) -> str: """Retrieve the spelling of this TypeKind.""" return conf.lib.clang_getTypeKindSpelling(self.value) -def __repr__(self): -return "TypeKind.%s" % (self.name,) - - -TypeKind.INVALID = TypeKind(0) -TypeKind.UNEXPOSED = TypeKind(1) -TypeKind.VOID = TypeKind(2) -TypeKind.BOOL = TypeKind(3) -TypeKind.CHAR_U = TypeKind(4) -TypeKind.UCHAR = TypeKind(5) -TypeKind.CHAR16 = TypeKind(6) -TypeKind.CHAR32 = TypeKind(7) -TypeKind.USHORT = TypeKind(8) -TypeKind.UINT = TypeKind(9) -TypeKind.ULONG = TypeKind(10) -TypeKind.ULONGLONG = TypeKind(11) -TypeKind.UINT128 = TypeKind(12) -TypeKind.CHAR_S = TypeKind(13) -TypeKind.SCHAR = TypeKind(14) -TypeKind.WCHAR = TypeKind(15) -TypeKind.SHORT = TypeKind(16) -TypeKind.INT = TypeKind(17) -TypeKind.LONG = TypeKind(18) -TypeKind.LONGLONG = TypeKind(19) -TypeKind.INT128 = TypeKind(20) -TypeKind.FLOAT = TypeKind(21) -TypeKind.DOUBLE = TypeKind(22) -TypeKind.LONGDOUBLE = TypeKind(23) -TypeKind.NULLPTR = TypeKind(24) -TypeKind.OVERLOAD = TypeKind(25) -TypeKind.DEPENDENT = TypeKind(26) -TypeKind.OBJCID = TypeKind(27) -TypeKind.OBJCCLASS = TypeKind(28) -TypeKind.OBJCSEL = TypeKind(29) -TypeKind.FLOAT128 = TypeKind(30) -TypeKind.HALF = TypeKind(31) -TypeKind.IBM128 = TypeKind(40) -TypeKind.COMPLEX = TypeKind(100) -TypeKind.POINTER = TypeKind(101) -TypeKind.BLOCKPOINTER = TypeKind(102) -TypeKind.LVALUEREFERENCE = TypeKind(103) -TypeKind.RVALUEREFERENCE = TypeKind(104) -TypeKind.RECORD = TypeKind(105) -TypeKind.ENUM = TypeKind(106) -TypeKind.TYPEDEF = TypeKind(107) -TypeKind.OBJCINTERFACE = TypeKind(108) -TypeKind.OBJCOBJECTPOINTER = TypeKind(109) -TypeKind.FUNCTIONNOPROTO = TypeKind(110) -TypeKind.FUNCTIONPROTO = TypeKind(111) -TypeKind.CONSTANTARRAY = TypeKind(112) -TypeKind.VECTOR = TypeKind(113) -TypeKind.INCOMPLETEARRAY = TypeKind(114) -TypeKind.VARIABLEARRAY = TypeKind(115) -TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116) -TypeKind.MEMBERPOINTER = TypeKind(117) -TypeKind.AUTO = TypeKind(118) -TypeKind.ELABORATED = TypeKind(119) -TypeKind.PIPE = TypeKind(120) -TypeKind.OCLIMAGE1DRO = TypeKind(121) -TypeKind.OCLIMAGE1DARRAYRO = TypeKind(122) -TypeKind.OCLIMAGE1DBUFFERRO = TypeKind(123) -TypeKind.OCLIMAGE2DRO = TypeKind(124) -TypeKind.OCLIMAGE2DARRAYRO = TypeKind(125) -TypeKind.OCLIMAGE2DDEPTHRO = TypeKind(126) -TypeKind.OCLIMAGE2DARRAYDEPTHRO = TypeKind(127) -TypeKind.OCLIMAGE2DMSAARO = TypeKind(128) -TypeKind.OCLIMAGE2DARRAYMSAARO = TypeKind(129) -TypeKind.OCLIMAGE2DMSAADEPTHRO = TypeKind(130) -TypeKind.OCLIMAGE2DARRAYMSAADEPTHRO = TypeKind(131) -TypeKind.OCLIMAGE3DRO = TypeKind(132) -TypeKind.OCLIMAGE1DWO = TypeKind(133) -TypeKind.OCLIMAGE1DARRAYWO = TypeKind(134) -TypeKind.OCLIMAGE1DBUFFERWO = TypeKind(135) -TypeKind.OCLIMAGE2DWO = TypeKind(136) -TypeKind.OCLIMAGE2DARRAYWO = TypeKind(137) -TypeKind.OCLIMAGE2DDEPTHWO = TypeKind(138) -TypeKind.OCLIMAGE2DARRAYDEPTHWO = TypeKind(139) -TypeKind.OCLIMAGE2DMSAAWO = TypeKind(140) -TypeKind.OCLIMAGE2DARRAYMSAAWO = TypeKind(141) -TypeKind.OCLIMAGE2DMSAADEPTHWO = TypeKind(142) -TypeKind.OCLIMAGE2DARRAYMSAADEPTHWO = TypeKind(143) -TypeKind.OCLIMAGE3DWO = TypeKind(144) -TypeKind.OCLIMAGE1DRW = TypeKind(145) -TypeKind.OCLIMAGE1DARRAYRW = TypeKind(146) -TypeKind.OCLIMAGE1DBUFFERRW = TypeKind(147) -TypeKind.OCLIMAGE2DRW = TypeKind(148) -TypeKind.OCLIMAGE2DARRAYRW = TypeKind(149) -TypeKind.OCLIMAGE2DDEPTHRW = TypeKind(150) -TypeKind.OCLIMAGE2DARRAYDEPTHRW = TypeKind(151) -TypeKind.OCLIMAGE2DMSAARW = TypeKind(152) -TypeKind.OCLIMAGE2DARRAYMSAARW = TypeKind(153) -TypeKind.OCLIMAGE2DMSAADEPTHRW = TypeKind(154) -TypeKind.OCLIMAGE2DARRAYMSAADEPTHRW = TypeKind(155) -TypeKind.OCLIMAGE3DRW = TypeKind(156) -TypeKind.OCLSAMPLER = TypeKind(157) -TypeKind.OCLEVENT = TypeKind(158) -TypeKind.OCLQUEUE = TypeKind(159) -TypeKind.OCLRESERVEID = TypeKind(160) - -TypeKind.OBJCOBJECT = TypeKind(161) -TypeKind.OBJCCLASS = TypeKind(162) -TypeKind.ATTRIBUTED = TypeKind(163) - -TypeKind.OCLINTELSUBGROUPAVCMCEPAYLOAD = TypeKind(164) -TypeKind.OCLINTELSUBGROUPAVCIMEPAYLOAD = TypeKind(165) -TypeKind.OCLINTELSUBGROUPAVCREFPAYLOAD = TypeKind(166) -TypeKind.OCLINTELSUBGROUPAVCSICPAYLOAD = TypeKind(167) -TypeKind.OCLINTELSUBGROUPAVCMCERESULT = TypeKind(168) -TypeKind.OCLINTELSUBGROUPAVCIMERESULT = TypeKind(169) -TypeKind.OCLINTELSUBGROUPAVCREFRESULT = TypeKind(170) -TypeKind.OCLINTELSUBGROUPAVCSICRESULT = TypeKind(171) -TypeKind.OCLINTELSUBGROUPAVCIMERESULTSINGLEREFERENCESTREAMOUT = TypeKind(172) -TypeKind.OCLINTELSUBGROUPAVCIMERESULTSDUALREFERENCESTREAMOUT = TypeKind(173) -TypeKind.OCLINTELSUBGROUPAVCIMERESULTSSINGLEREFERENCESTREAMIN = TypeKind(174) -TypeKind.OCLINTELSUBGROUPAVCIMEDUALREFERENCESTREAMIN = TypeKind(175) - -TypeKind.EXTVECTOR = TypeKind(176) -TypeKind.ATOMIC = Type
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
https://github.com/DeinAlptraum ready_for_review https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang-bindings] Add strict typing to clang Python bindings (#76664) (PR #78114)
DeinAlptraum wrote: Since https://github.com/llvm/llvm-project/issues/83962 is now closed and the minimum Python version updated to 3.8, this is now finally ready for review. I've updated this with the changes to the Python bindings of the past couple months. I have no idea idea what the error in the test failure means, so any advice would be appreciated. @AaronBallman could you review this or recommend reviewers? https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Add strict typing to clang Python bindings (#76664) (PR #78114)
DeinAlptraum wrote: Thanks a lot for your feedback! Yup I get that the PR is pretty big and might still need significant changes. > 1. I have maintainability concerns about `ClangLib` protocol [...] I completely agree that this is ugly, but I didn't find a better solution that would enable a strict type check. How do you think we should handle this? 1. Do you know of another solution that would correctly annotate this? It would be nice if we could just reuse the types as described in `functionList` but I don't think this is possible 2. Alternatively, we could `type: ignore` all calls to `ClangLib` attributes. That would require about 180 such annotations I believe. 3. Further, we could go without a strict type-check, only fixing type errors to pass a non-strict typecheck, as well as annotating the user-facing interfaces Regarding the other two points: I tried to change as little as possible here in order to enable type annotations or fix type errors. While there's a lot of places in `cindex.py` that could use refactoring etc. I held off on doing this _unless it was strictly necessary_ for annotations. Both > 2. I see several bugfixes that you highlighted with your comments. I > believe they should be done as a separate PR, because they do something else > than just add typing annotations. and > 3. Changes to enums are massive, and feel somewhat out of place in this > PR as well. were a direct result of my attempt to fix type errors or annotate interfaces correctly. The enum changes were also necessary, since the implementation up to now "dynamically" assigned the enum variants after declaration of the class. That means if you use e.g. `CursorKind.UNEXPOSED_DECL` in a script, this will work fine but fail the type check since it doesn't recognize `UNEXPOSED_DECL` as an attribute of `CursorKind`. This is thus effectively part of annotating the user-facing interfaces. Should I close this PR for now and split this into multiple PRs for the bugfixes and then several smaller, grouped changes? https://github.com/llvm/llvm-project/pull/78114 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bugs in custom enum implementation and add tests (PR #95381)
https://github.com/DeinAlptraum created https://github.com/llvm/llvm-project/pull/95381 Do not allow initialization of enum from negative IDs (e.g. from_id(-1) currently produces the last known variant) Rename duplicate enums: CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE and TypeKind.OBJCCLASS Add tests to cover these cases >From 0a81be569d5a8a4ca0945310804106df70962c64 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Thu, 13 Jun 2024 10:43:52 +0100 Subject: [PATCH] [libclang/python] Fix bugs in custom enum implementation and add tests Do not allow initialization of enum from negative IDs (e.g. from_id(-1) currently produces the last known variant) Rename duplicate enums: CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE and TypeKind.OBJCCLASS Add tests to cover these cases --- clang/bindings/python/clang/cindex.py | 8 +-- .../python/tests/cindex/test_enums.py | 55 +++ 2 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 clang/bindings/python/tests/cindex/test_enums.py diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 302d99dccd77b..b3d51e4d2a668 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -649,7 +649,7 @@ def name(self): @classmethod def from_id(cls, id): -if id >= len(cls._kinds) or cls._kinds[id] is None: +if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None: raise ValueError("Unknown template argument kind %d" % id) return cls._kinds[id] @@ -1336,7 +1336,7 @@ def __repr__(self): CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(271) # OpenMP teams distribute simd directive. -CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(272) +CursorKind.OMP_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE = CursorKind(272) # OpenMP teams distribute parallel for simd directive. CursorKind.OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE = CursorKind(273) @@ -2215,7 +2215,7 @@ def name(self): @staticmethod def from_id(id): -if id >= len(StorageClass._kinds) or not StorageClass._kinds[id]: +if id < 0 or id >= len(StorageClass._kinds) or not StorageClass._kinds[id]: raise ValueError("Unknown storage class %d" % id) return StorageClass._kinds[id] @@ -2395,7 +2395,7 @@ def __repr__(self): TypeKind.OCLRESERVEID = TypeKind(160) TypeKind.OBJCOBJECT = TypeKind(161) -TypeKind.OBJCCLASS = TypeKind(162) +TypeKind.OBJCTYPEPARAM = TypeKind(162) TypeKind.ATTRIBUTED = TypeKind(163) TypeKind.OCLINTELSUBGROUPAVCMCEPAYLOAD = TypeKind(164) diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py new file mode 100644 index 0..425c4a8274a17 --- /dev/null +++ b/clang/bindings/python/tests/cindex/test_enums.py @@ -0,0 +1,55 @@ +import unittest + +from clang.cindex import ( +CursorKind, +TemplateArgumentKind, +ExceptionSpecificationKind, +AvailabilityKind, +AccessSpecifier, +TypeKind, +RefQualifierKind, +LinkageKind, +TLSKind, +StorageClass, +) + + +def get_all_kinds(enum): +"""Return all CursorKind enumeration instances.""" +return [x for x in enum._kinds if not x is None] + + +class TestCursorKind(unittest.TestCase): +enums = [ +CursorKind, +TemplateArgumentKind, +ExceptionSpecificationKind, +AvailabilityKind, +AccessSpecifier, +TypeKind, +RefQualifierKind, +LinkageKind, +TLSKind, +StorageClass, +] + +def test_from_id(self): +"""Check that kinds can be constructed from valid IDs""" +for enum in self.enums: +self.assertEqual(enum.from_id(2), enum._kinds[2]) +with self.assertRaises(ValueError): +enum.from_id(len(enum._kinds)) +with self.assertRaises(ValueError): +enum.from_id(-1) + +def test_unique_kinds(self): +"""Check that no kind name has been used multiple times""" +for enum in self.enums: +seen_names = set() +for id in range(len(enum._kinds)): +try: +kind_name = enum.from_id(id).name +except ValueError: +continue +self.assertNotIn(kind_name, seen_names) +seen_names.add(id) ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bugs in custom enum implementation and add tests (PR #95381)
DeinAlptraum wrote: @Endilll I separated the fixes for the enum bugs from the strict typing PR, and added tests that cover these cases. I checked that the tests fail before the fixes and succeed now. https://github.com/llvm/llvm-project/pull/95381 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bugs in custom enum implementation and add tests (PR #95381)
@@ -2395,7 +2395,7 @@ def __repr__(self): TypeKind.OCLRESERVEID = TypeKind(160) TypeKind.OBJCOBJECT = TypeKind(161) -TypeKind.OBJCCLASS = TypeKind(162) +TypeKind.OBJCTYPEPARAM = TypeKind(162) DeinAlptraum wrote: This was a duplicate with variant 28 (OBJCCLASS). Corrected name taken from https://clang.llvm.org/doxygen/group__CINDEX__TYPES.html https://github.com/llvm/llvm-project/pull/95381 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bugs in custom enum implementation and add tests (PR #95381)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/95381 >From bfc36e30e84c616adb8ff57754a49a5bb66d1dd9 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Thu, 13 Jun 2024 10:43:52 +0100 Subject: [PATCH] [libclang/python] Fix bugs in custom enum implementation and add tests Do not allow initialization of enum from negative IDs (e.g. from_id(-1) currently produces the last known variant) Rename duplicate enums: CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE and TypeKind.OBJCCLASS Add tests to cover these cases --- clang/bindings/python/clang/cindex.py | 8 +-- .../python/tests/cindex/test_enums.py | 50 +++ 2 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 clang/bindings/python/tests/cindex/test_enums.py diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 302d99dccd77b..b3d51e4d2a668 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -649,7 +649,7 @@ def name(self): @classmethod def from_id(cls, id): -if id >= len(cls._kinds) or cls._kinds[id] is None: +if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None: raise ValueError("Unknown template argument kind %d" % id) return cls._kinds[id] @@ -1336,7 +1336,7 @@ def __repr__(self): CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(271) # OpenMP teams distribute simd directive. -CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(272) +CursorKind.OMP_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE = CursorKind(272) # OpenMP teams distribute parallel for simd directive. CursorKind.OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE = CursorKind(273) @@ -2215,7 +2215,7 @@ def name(self): @staticmethod def from_id(id): -if id >= len(StorageClass._kinds) or not StorageClass._kinds[id]: +if id < 0 or id >= len(StorageClass._kinds) or not StorageClass._kinds[id]: raise ValueError("Unknown storage class %d" % id) return StorageClass._kinds[id] @@ -2395,7 +2395,7 @@ def __repr__(self): TypeKind.OCLRESERVEID = TypeKind(160) TypeKind.OBJCOBJECT = TypeKind(161) -TypeKind.OBJCCLASS = TypeKind(162) +TypeKind.OBJCTYPEPARAM = TypeKind(162) TypeKind.ATTRIBUTED = TypeKind(163) TypeKind.OCLINTELSUBGROUPAVCMCEPAYLOAD = TypeKind(164) diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py new file mode 100644 index 0..985d71a4fdcfd --- /dev/null +++ b/clang/bindings/python/tests/cindex/test_enums.py @@ -0,0 +1,50 @@ +import unittest + +from clang.cindex import ( +CursorKind, +TemplateArgumentKind, +ExceptionSpecificationKind, +AvailabilityKind, +AccessSpecifier, +TypeKind, +RefQualifierKind, +LinkageKind, +TLSKind, +StorageClass, +) + + +class TestCursorKind(unittest.TestCase): +enums = [ +CursorKind, +TemplateArgumentKind, +ExceptionSpecificationKind, +AvailabilityKind, +AccessSpecifier, +TypeKind, +RefQualifierKind, +LinkageKind, +TLSKind, +StorageClass, +] + +def test_from_id(self): +"""Check that kinds can be constructed from valid IDs""" +for enum in self.enums: +self.assertEqual(enum.from_id(2), enum._kinds[2]) +with self.assertRaises(ValueError): +enum.from_id(len(enum._kinds)) +with self.assertRaises(ValueError): +enum.from_id(-1) + +def test_unique_kinds(self): +"""Check that no kind name has been used multiple times""" +for enum in self.enums: +seen_names = set() +for id in range(len(enum._kinds)): +try: +kind_name = enum.from_id(id).name +except ValueError: +continue +self.assertNotIn(kind_name, seen_names) +seen_names.add(id) ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bugs in custom enum implementation and add tests (PR #95381)
@@ -1336,7 +1336,7 @@ def __repr__(self): CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(271) # OpenMP teams distribute simd directive. -CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(272) +CursorKind.OMP_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE = CursorKind(272) DeinAlptraum wrote: This was a duplicate with variant 271. new name taken from https://clang.llvm.org/doxygen/Index_8h_source.html, line 2011 https://github.com/llvm/llvm-project/pull/95381 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bugs in custom enum implementation and add tests (PR #95381)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/95381 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bugs in custom enum implementation and add tests (PR #95381)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/95381 >From a3da142b0db6581581ccb135800d77b09476f385 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Thu, 13 Jun 2024 10:43:52 +0100 Subject: [PATCH 1/2] [libclang/python] Fix bugs in custom enum implementation and add tests Do not allow initialization of enum from negative IDs (e.g. from_id(-1) currently produces the last known variant) Rename duplicate enums: CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE and TypeKind.OBJCCLASS Add tests to cover these cases --- clang/bindings/python/clang/cindex.py | 8 +-- .../python/tests/cindex/test_enums.py | 50 +++ 2 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 clang/bindings/python/tests/cindex/test_enums.py diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 302d99dccd77b..b3d51e4d2a668 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -649,7 +649,7 @@ def name(self): @classmethod def from_id(cls, id): -if id >= len(cls._kinds) or cls._kinds[id] is None: +if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None: raise ValueError("Unknown template argument kind %d" % id) return cls._kinds[id] @@ -1336,7 +1336,7 @@ def __repr__(self): CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(271) # OpenMP teams distribute simd directive. -CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(272) +CursorKind.OMP_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE = CursorKind(272) # OpenMP teams distribute parallel for simd directive. CursorKind.OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE = CursorKind(273) @@ -2215,7 +2215,7 @@ def name(self): @staticmethod def from_id(id): -if id >= len(StorageClass._kinds) or not StorageClass._kinds[id]: +if id < 0 or id >= len(StorageClass._kinds) or not StorageClass._kinds[id]: raise ValueError("Unknown storage class %d" % id) return StorageClass._kinds[id] @@ -2395,7 +2395,7 @@ def __repr__(self): TypeKind.OCLRESERVEID = TypeKind(160) TypeKind.OBJCOBJECT = TypeKind(161) -TypeKind.OBJCCLASS = TypeKind(162) +TypeKind.OBJCTYPEPARAM = TypeKind(162) TypeKind.ATTRIBUTED = TypeKind(163) TypeKind.OCLINTELSUBGROUPAVCMCEPAYLOAD = TypeKind(164) diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py new file mode 100644 index 0..985d71a4fdcfd --- /dev/null +++ b/clang/bindings/python/tests/cindex/test_enums.py @@ -0,0 +1,50 @@ +import unittest + +from clang.cindex import ( +CursorKind, +TemplateArgumentKind, +ExceptionSpecificationKind, +AvailabilityKind, +AccessSpecifier, +TypeKind, +RefQualifierKind, +LinkageKind, +TLSKind, +StorageClass, +) + + +class TestCursorKind(unittest.TestCase): +enums = [ +CursorKind, +TemplateArgumentKind, +ExceptionSpecificationKind, +AvailabilityKind, +AccessSpecifier, +TypeKind, +RefQualifierKind, +LinkageKind, +TLSKind, +StorageClass, +] + +def test_from_id(self): +"""Check that kinds can be constructed from valid IDs""" +for enum in self.enums: +self.assertEqual(enum.from_id(2), enum._kinds[2]) +with self.assertRaises(ValueError): +enum.from_id(len(enum._kinds)) +with self.assertRaises(ValueError): +enum.from_id(-1) + +def test_unique_kinds(self): +"""Check that no kind name has been used multiple times""" +for enum in self.enums: +seen_names = set() +for id in range(len(enum._kinds)): +try: +kind_name = enum.from_id(id).name +except ValueError: +continue +self.assertNotIn(kind_name, seen_names) +seen_names.add(id) >From 67f43ab2c26129cc6611ba58e81f6fbe6c490dbd Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Thu, 13 Jun 2024 14:18:03 +0100 Subject: [PATCH 2/2] [libclang/python] Add release notes Also simplify the enum test --- clang/bindings/python/tests/cindex/test_enums.py | 7 ++- clang/docs/ReleaseNotes.rst | 8 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py index 985d71a4fdcfd..6fc0e5ed77e3e 100644 --- a/clang/bindings/python/tests/cindex/test_enums.py +++ b/clang/bindings/python/tests/cindex/test_enums.py @@ -40,11 +40,8 @@ def test_from_id(self): def test_unique_kinds(self): """Check that no kind name has been used multiple times""" for enum in self.enums: -seen_names = set() for id in range(len(enum._kinds)):
[clang] [libclang/python] Fix bugs in custom enum implementation and add tests (PR #95381)
@@ -0,0 +1,50 @@ +import unittest + +from clang.cindex import ( +CursorKind, +TemplateArgumentKind, +ExceptionSpecificationKind, +AvailabilityKind, +AccessSpecifier, +TypeKind, +RefQualifierKind, +LinkageKind, +TLSKind, +StorageClass, +) + + +class TestCursorKind(unittest.TestCase): +enums = [ +CursorKind, +TemplateArgumentKind, +ExceptionSpecificationKind, +AvailabilityKind, +AccessSpecifier, +TypeKind, +RefQualifierKind, +LinkageKind, +TLSKind, +StorageClass, +] + +def test_from_id(self): +"""Check that kinds can be constructed from valid IDs""" +for enum in self.enums: +self.assertEqual(enum.from_id(2), enum._kinds[2]) +with self.assertRaises(ValueError): +enum.from_id(len(enum._kinds)) +with self.assertRaises(ValueError): +enum.from_id(-1) + +def test_unique_kinds(self): +"""Check that no kind name has been used multiple times""" +for enum in self.enums: +seen_names = set() +for id in range(len(enum._kinds)): +try: +kind_name = enum.from_id(id).name +except ValueError: +continue +self.assertNotIn(kind_name, seen_names) +seen_names.add(id) DeinAlptraum wrote: I only just realized that even that is not necessary, calling `enum.from_id(id).name` already fails for duplicate IDs, so no assertions needed. https://github.com/llvm/llvm-project/pull/95381 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bugs in custom enum implementation and add tests (PR #95381)
DeinAlptraum wrote: These were all the bugs I'd found, so I think it is https://github.com/llvm/llvm-project/pull/95381 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix bugs in custom enum implementation and add tests (PR #95381)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/95381 >From a3da142b0db6581581ccb135800d77b09476f385 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Thu, 13 Jun 2024 10:43:52 +0100 Subject: [PATCH 1/2] [libclang/python] Fix bugs in custom enum implementation and add tests Do not allow initialization of enum from negative IDs (e.g. from_id(-1) currently produces the last known variant) Rename duplicate enums: CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE and TypeKind.OBJCCLASS Add tests to cover these cases --- clang/bindings/python/clang/cindex.py | 8 +-- .../python/tests/cindex/test_enums.py | 50 +++ 2 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 clang/bindings/python/tests/cindex/test_enums.py diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index 302d99dccd77b..b3d51e4d2a668 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -649,7 +649,7 @@ def name(self): @classmethod def from_id(cls, id): -if id >= len(cls._kinds) or cls._kinds[id] is None: +if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None: raise ValueError("Unknown template argument kind %d" % id) return cls._kinds[id] @@ -1336,7 +1336,7 @@ def __repr__(self): CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(271) # OpenMP teams distribute simd directive. -CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(272) +CursorKind.OMP_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE = CursorKind(272) # OpenMP teams distribute parallel for simd directive. CursorKind.OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE = CursorKind(273) @@ -2215,7 +2215,7 @@ def name(self): @staticmethod def from_id(id): -if id >= len(StorageClass._kinds) or not StorageClass._kinds[id]: +if id < 0 or id >= len(StorageClass._kinds) or not StorageClass._kinds[id]: raise ValueError("Unknown storage class %d" % id) return StorageClass._kinds[id] @@ -2395,7 +2395,7 @@ def __repr__(self): TypeKind.OCLRESERVEID = TypeKind(160) TypeKind.OBJCOBJECT = TypeKind(161) -TypeKind.OBJCCLASS = TypeKind(162) +TypeKind.OBJCTYPEPARAM = TypeKind(162) TypeKind.ATTRIBUTED = TypeKind(163) TypeKind.OCLINTELSUBGROUPAVCMCEPAYLOAD = TypeKind(164) diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py new file mode 100644 index 0..985d71a4fdcfd --- /dev/null +++ b/clang/bindings/python/tests/cindex/test_enums.py @@ -0,0 +1,50 @@ +import unittest + +from clang.cindex import ( +CursorKind, +TemplateArgumentKind, +ExceptionSpecificationKind, +AvailabilityKind, +AccessSpecifier, +TypeKind, +RefQualifierKind, +LinkageKind, +TLSKind, +StorageClass, +) + + +class TestCursorKind(unittest.TestCase): +enums = [ +CursorKind, +TemplateArgumentKind, +ExceptionSpecificationKind, +AvailabilityKind, +AccessSpecifier, +TypeKind, +RefQualifierKind, +LinkageKind, +TLSKind, +StorageClass, +] + +def test_from_id(self): +"""Check that kinds can be constructed from valid IDs""" +for enum in self.enums: +self.assertEqual(enum.from_id(2), enum._kinds[2]) +with self.assertRaises(ValueError): +enum.from_id(len(enum._kinds)) +with self.assertRaises(ValueError): +enum.from_id(-1) + +def test_unique_kinds(self): +"""Check that no kind name has been used multiple times""" +for enum in self.enums: +seen_names = set() +for id in range(len(enum._kinds)): +try: +kind_name = enum.from_id(id).name +except ValueError: +continue +self.assertNotIn(kind_name, seen_names) +seen_names.add(id) >From 67f43ab2c26129cc6611ba58e81f6fbe6c490dbd Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Thu, 13 Jun 2024 14:18:03 +0100 Subject: [PATCH 2/2] [libclang/python] Add release notes Also simplify the enum test --- clang/bindings/python/tests/cindex/test_enums.py | 7 ++- clang/docs/ReleaseNotes.rst | 8 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/clang/bindings/python/tests/cindex/test_enums.py b/clang/bindings/python/tests/cindex/test_enums.py index 985d71a4fdcfd..6fc0e5ed77e3e 100644 --- a/clang/bindings/python/tests/cindex/test_enums.py +++ b/clang/bindings/python/tests/cindex/test_enums.py @@ -40,11 +40,8 @@ def test_from_id(self): def test_unique_kinds(self): """Check that no kind name has been used multiple times""" for enum in self.enums: -seen_names = set() for id in range(len(enum._kinds)):
[clang] [libclang/python] Fix bugs in custom enum implementation and add tests (PR #95381)
DeinAlptraum wrote: @Endilll I merged the Python 3.8 CI into this PR and the CI run was successful (though it only ran on 3.8 for some reason), so can this be merged? https://github.com/llvm/llvm-project/pull/95381 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
https://github.com/DeinAlptraum created https://github.com/llvm/llvm-project/pull/95608 Use Python's builtin enum class instead of writing our own. This is preparation for passing a strict type check in PR #78114 , fixing 920 out of 1341 strict typing errors >From 35bfcfbc69ee812c59350440b7b15c5e23ad1307 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Fri, 14 Jun 2024 22:12:09 +0100 Subject: [PATCH] [libclang/python] Refactor enum usage Use Python's builtin enum class instead of writing our own. This is preparation for strict typing in PR #78114 --- clang/bindings/python/clang/cindex.py | 1670 - .../python/tests/cindex/test_enums.py | 14 +- 2 files changed, 768 insertions(+), 916 deletions(-) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index b3d51e4d2a668..aacfc333723c4 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -68,6 +68,7 @@ import collections.abc import os +from enum import Enum # Python 3 strings are unicode, translate them to/from utf8 for C-interop. @@ -611,51 +612,25 @@ def register(value, name): ### Cursor Kinds ### -class BaseEnumeration: +class BaseEnumeration(Enum): """ Common base class for named enumerations held in sync with Index.h values. - -Subclasses must define their own _kinds and _name_map members, as: -_kinds = [] -_name_map = None -These values hold the per-subclass instances and value-to-name mappings, -respectively. - """ -def __init__(self, value): -if value >= len(self.__class__._kinds): -self.__class__._kinds += [None] * (value - len(self.__class__._kinds) + 1) -if self.__class__._kinds[value] is not None: -raise ValueError( -"{0} value {1} already loaded".format(str(self.__class__), value) -) -self.value = value -self.__class__._kinds[value] = self -self.__class__._name_map = None def from_param(self): return self.value -@property -def name(self): -"""Get the enumeration name of this cursor kind.""" -if self._name_map is None: -self._name_map = {} -for key, value in self.__class__.__dict__.items(): -if isinstance(value, self.__class__): -self._name_map[value] = key -return self._name_map[self] - @classmethod def from_id(cls, id): -if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None: -raise ValueError("Unknown template argument kind %d" % id) -return cls._kinds[id] +try: +return cls(id) +except ValueError: +raise ValueError("Unknown %s %d" % (cls.__name__, id)) from None def __repr__(self): return "%s.%s" % ( -self.__class__, +self.__class__.__name__, self.name, ) @@ -665,14 +640,10 @@ class CursorKind(BaseEnumeration): A CursorKind describes the kind of entity that a cursor points to. """ -# The required BaseEnumeration declarations. -_kinds = [] -_name_map = None - @staticmethod def get_all_kinds(): """Return all CursorKind enumeration instances.""" -return [x for x in CursorKind._kinds if not x is None] +return list(CursorKind) def is_declaration(self): """Test if this is a declaration kind.""" @@ -710,822 +681,820 @@ def is_unexposed(self): """Test if this is an unexposed kind.""" return conf.lib.clang_isUnexposed(self) -def __repr__(self): -return "CursorKind.%s" % (self.name,) - -### -# Declaration Kinds +### +# Declaration Kinds -# A declaration whose specific kind is not exposed via this interface. -# -# Unexposed declarations have the same operations as any other kind of -# declaration; one can extract their location information, spelling, find their -# definitions, etc. However, the specific kind of the declaration is not -# reported. -CursorKind.UNEXPOSED_DECL = CursorKind(1) +# A declaration whose specific kind is not exposed via this interface. +# +# Unexposed declarations have the same operations as any other kind of +# declaration; one can extract their location information, spelling, find +# their definitions, etc. However, the specific kind of the declaration is +# not reported. +UNEXPOSED_DECL = 1 -# A C or C++ struct. -CursorKind.STRUCT_DECL = CursorKind(2) +# A C or C++ struct. +STRUCT_DECL = 2 -# A C or C++ union. -CursorKind.UNION_DECL = CursorKind(3) +# A C or C++ union. +UNION_DECL = 3 -# A C++ class. -CursorKind.CLASS_DECL = CursorKind(4) +# A C++ class. +CLASS_DECL = 4 -# An enumeration. -CursorKind.ENUM_DECL = CursorKind(5) +# An enumeration. +ENUM_DECL = 5 -# A field (in C) or non-static data member (in C++) in a
[clang] [libclang/python] Refactor enum usage (PR #95608)
@@ -611,51 +612,25 @@ def register(value, name): ### Cursor Kinds ### -class BaseEnumeration: +class BaseEnumeration(Enum): """ Common base class for named enumerations held in sync with Index.h values. - -Subclasses must define their own _kinds and _name_map members, as: -_kinds = [] -_name_map = None -These values hold the per-subclass instances and value-to-name mappings, -respectively. - """ -def __init__(self, value): -if value >= len(self.__class__._kinds): -self.__class__._kinds += [None] * (value - len(self.__class__._kinds) + 1) -if self.__class__._kinds[value] is not None: -raise ValueError( -"{0} value {1} already loaded".format(str(self.__class__), value) -) -self.value = value -self.__class__._kinds[value] = self -self.__class__._name_map = None def from_param(self): return self.value -@property -def name(self): -"""Get the enumeration name of this cursor kind.""" -if self._name_map is None: -self._name_map = {} -for key, value in self.__class__.__dict__.items(): -if isinstance(value, self.__class__): -self._name_map[value] = key -return self._name_map[self] DeinAlptraum wrote: The `Enum` class already provides a `name` attribute that follows the exact same format as we had before https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
https://github.com/DeinAlptraum commented: There is also `TokenKind`: this one does not currently inherit from `BaseEnumeration` and is defined somewhat differently, having all its variants and their IDs as a dictionary in `enumerations.py`. This seems quite arbitrary to me, is there any reason it is done this way? Otherwise I would also move this to `cindex.py` as another subclass of `BaseEnumeration` https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
@@ -31,17 +31,9 @@ class TestCursorKind(unittest.TestCase): def test_from_id(self): """Check that kinds can be constructed from valid IDs""" for enum in self.enums: -self.assertEqual(enum.from_id(2), enum._kinds[2]) +self.assertEqual(enum.from_id(2), enum(2)) +max_value = max([variant.value for variant in enum]) with self.assertRaises(ValueError): -enum.from_id(len(enum._kinds)) +enum.from_id(max_value + 1) with self.assertRaises(ValueError): enum.from_id(-1) - -def test_unique_kinds(self): -"""Check that no kind name has been used multiple times""" -for enum in self.enums: -for id in range(len(enum._kinds)): -try: -enum.from_id(id).name -except ValueError: -pass DeinAlptraum wrote: This test is effectively pointless now, since the enum class errors out as soon as the module is loaded in case there are duplicate enum variants https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
@@ -611,51 +612,25 @@ def register(value, name): ### Cursor Kinds ### -class BaseEnumeration: +class BaseEnumeration(Enum): """ Common base class for named enumerations held in sync with Index.h values. - -Subclasses must define their own _kinds and _name_map members, as: -_kinds = [] -_name_map = None -These values hold the per-subclass instances and value-to-name mappings, -respectively. - """ -def __init__(self, value): -if value >= len(self.__class__._kinds): -self.__class__._kinds += [None] * (value - len(self.__class__._kinds) + 1) -if self.__class__._kinds[value] is not None: -raise ValueError( -"{0} value {1} already loaded".format(str(self.__class__), value) -) -self.value = value -self.__class__._kinds[value] = self -self.__class__._name_map = None def from_param(self): return self.value -@property -def name(self): -"""Get the enumeration name of this cursor kind.""" -if self._name_map is None: -self._name_map = {} -for key, value in self.__class__.__dict__.items(): -if isinstance(value, self.__class__): -self._name_map[value] = key -return self._name_map[self] - @classmethod def from_id(cls, id): -if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None: -raise ValueError("Unknown template argument kind %d" % id) -return cls._kinds[id] +try: +return cls(id) +except ValueError: +raise ValueError("Unknown %s %d" % (cls.__name__, id)) from None DeinAlptraum wrote: In hindsight, should the change of error message go into a separate PR? The one we had before, `Unknown template argument kind`, doesn't make much sense since this is the base class of not just `TemplateArgumentKind`. If we don't consider changing error messages as a breaking change, then we could also remove the try-except part entirely since `Enum` already throws a meanginful error, looking like this: `ValueError: 703 is not a valid CursorKind` https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
@@ -611,51 +612,25 @@ def register(value, name): ### Cursor Kinds ### -class BaseEnumeration: +class BaseEnumeration(Enum): """ Common base class for named enumerations held in sync with Index.h values. - -Subclasses must define their own _kinds and _name_map members, as: -_kinds = [] -_name_map = None -These values hold the per-subclass instances and value-to-name mappings, -respectively. - """ -def __init__(self, value): -if value >= len(self.__class__._kinds): -self.__class__._kinds += [None] * (value - len(self.__class__._kinds) + 1) -if self.__class__._kinds[value] is not None: -raise ValueError( -"{0} value {1} already loaded".format(str(self.__class__), value) -) -self.value = value -self.__class__._kinds[value] = self -self.__class__._name_map = None def from_param(self): return self.value -@property -def name(self): -"""Get the enumeration name of this cursor kind.""" -if self._name_map is None: -self._name_map = {} -for key, value in self.__class__.__dict__.items(): -if isinstance(value, self.__class__): -self._name_map[value] = key -return self._name_map[self] - @classmethod def from_id(cls, id): -if id < 0 or id >= len(cls._kinds) or cls._kinds[id] is None: -raise ValueError("Unknown template argument kind %d" % id) -return cls._kinds[id] +try: +return cls(id) +except ValueError: +raise ValueError("Unknown %s %d" % (cls.__name__, id)) from None def __repr__(self): return "%s.%s" % ( -self.__class__, +self.__class__.__name__, DeinAlptraum wrote: This `__repr__` was effectively unused before as each subclass defined its own. This change is necessary so that all subclasses still return exactly the same representation as they did before https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
DeinAlptraum wrote: @Endilll can I ask you for a review again? As a next step towards the python-bindings strict typing PR, this one captures all the enum refactoring changes necessary towards that goal. Don't be scared by the LoC changed: 90% of that is just indentation changes :) https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Refactor enum usage (PR #95608)
https://github.com/DeinAlptraum edited https://github.com/llvm/llvm-project/pull/95608 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/98745 >From c64b124ccc22cd9f92b0a55f60ec92d7101d0048 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Sat, 13 Jul 2024 14:12:34 +0100 Subject: [PATCH 1/2] [libclang/python] Fix some type errors, add type annotations --- clang/bindings/python/clang/cindex.py | 195 +++--- .../tests/cindex/test_code_completion.py | 22 +- .../python/tests/cindex/test_comment.py | 4 +- 3 files changed, 130 insertions(+), 91 deletions(-) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index be024da5e005c..6c70588c28ffa 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -43,7 +43,7 @@ Most object information is exposed using properties, when the underlying API call is efficient. """ -from __future__ import absolute_import, division, print_function +from __future__ import annotations # TODO # @@ -64,48 +64,81 @@ from ctypes import * -import collections.abc import os +import sys from enum import Enum +from typing import ( +Any, +Callable, +Generic, +Optional, +Type as TType, +TypeVar, +TYPE_CHECKING, +Union as TUnion, +) + +if TYPE_CHECKING: +from ctypes import _Pointer +from typing_extensions import Protocol, TypeAlias + +StrPath: TypeAlias = TUnion[str, os.PathLike[str]] +LibFunc: TypeAlias = TUnion[ +"tuple[str, Optional[list[Any]]]", +"tuple[str, Optional[list[Any]], Any]", +"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]", +] +CObjP: TypeAlias = _Pointer[Any] + +TSeq = TypeVar("TSeq", covariant=True) + +class NoSliceSequence(Protocol[TSeq]): +def __len__(self) -> int: +... + +def __getitem__(self, key: int) -> TSeq: +... + # Python 3 strings are unicode, translate them to/from utf8 for C-interop. class c_interop_string(c_char_p): -def __init__(self, p=None): +def __init__(self, p: str | bytes | None = None): if p is None: p = "" if isinstance(p, str): p = p.encode("utf8") super(c_char_p, self).__init__(p) -def __str__(self): -return self.value +def __str__(self) -> str: +return self.value or "" @property -def value(self): -if super(c_char_p, self).value is None: +def value(self) -> str | None: # type: ignore [override] +val = super(c_char_p, self).value +if val is None: return None -return super(c_char_p, self).value.decode("utf8") +return val.decode("utf8") @classmethod -def from_param(cls, param): +def from_param(cls, param: str | bytes | None) -> c_interop_string: if isinstance(param, str): return cls(param) if isinstance(param, bytes): return cls(param) if param is None: # Support passing null to C functions expecting char arrays -return None +return cls(param) raise TypeError( "Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__) ) @staticmethod -def to_python_string(x, *args): +def to_python_string(x: c_interop_string, *args: Any) -> str | None: return x.value -def b(x): +def b(x: str | bytes) -> bytes: if isinstance(x, bytes): return x return x.encode("utf8") @@ -115,9 +148,7 @@ def b(x): # object. This is a problem, because it means that from_parameter will see an # integer and pass the wrong value on platforms where int != void*. Work around # this by marshalling object arguments as void**. -c_object_p = POINTER(c_void_p) - -callbacks = {} +c_object_p: TType[CObjP] = POINTER(c_void_p) ### Exception Classes ### @@ -169,8 +200,11 @@ def __init__(self, enumeration, message): ### Structures and Utility Classes ### +TInstance = TypeVar("TInstance") +TResult = TypeVar("TResult") + -class CachedProperty: +class CachedProperty(Generic[TInstance, TResult]): """Decorator that lazy-loads the value of a property. The first time the property is accessed, the original property function is @@ -178,16 +212,20 @@ class CachedProperty: property, replacing the original method. """ -def __init__(self, wrapped): +def __init__(self, wrapped: Callable[[TInstance], TResult]): self.wrapped = wrapped try: self.__doc__ = wrapped.__doc__ except: pass -def __get__(self, instance, instance_type=None): +def __get__(self, instance: TInstance, instance_type: Any = None) -> TResult: if instance is None: -return self +property_name = self.wrapped.__name__ +class_name = instance_type.__name__ +raise TypeError( +f"'{property_name}' is not a stat
[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)
DeinAlptraum wrote: Since the release branching is done, I've rebased on main to fix the release notes https://github.com/llvm/llvm-project/pull/98745 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Export all enums (PR #100941)
https://github.com/DeinAlptraum created https://github.com/llvm/llvm-project/pull/100941 This resolves #48212 and also adds the remaining unexposed Enums >From c4007832c8ed7cdb56aceebcf61b24ecb75f2aa4 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Sun, 28 Jul 2024 18:30:35 +0100 Subject: [PATCH] [libclang/python] Export all enums --- clang/bindings/python/clang/cindex.py | 5 + 1 file changed, 5 insertions(+) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index be024da5e005c..d9009a8666338 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -4077,6 +4077,7 @@ def function_exists(self, name): conf = Config() __all__ = [ +"AccessSpecifier", "AvailabilityKind", "BinaryOperator", "Config", @@ -4087,12 +4088,16 @@ def function_exists(self, name): "CursorKind", "Cursor", "Diagnostic", +"ExceptionSpecificationKind", "File", "FixIt", "Index", "LinkageKind", +"RefQualifierKind", "SourceLocation", "SourceRange", +"StorageClass", +"TemplateArgumentKind", "TLSKind", "TokenKind", "Token", ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Export all enums (PR #100941)
DeinAlptraum wrote: @Endilll can I ask you for a review again? https://github.com/llvm/llvm-project/pull/100941 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Export all enums (PR #100941)
DeinAlptraum wrote: Could you also merge please? (or are you waiting for something else?) https://github.com/llvm/llvm-project/pull/100941 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Export all enums (PR #100941)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/100941 >From 4b1322b8add0a1189f0f1cbf5583841f3a591f0c Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Sun, 28 Jul 2024 18:30:35 +0100 Subject: [PATCH] [libclang/python] Export all enums --- clang/bindings/python/clang/cindex.py | 5 + 1 file changed, 5 insertions(+) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index be024da5e005c..d9009a8666338 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -4077,6 +4077,7 @@ def function_exists(self, name): conf = Config() __all__ = [ +"AccessSpecifier", "AvailabilityKind", "BinaryOperator", "Config", @@ -4087,12 +4088,16 @@ def function_exists(self, name): "CursorKind", "Cursor", "Diagnostic", +"ExceptionSpecificationKind", "File", "FixIt", "Index", "LinkageKind", +"RefQualifierKind", "SourceLocation", "SourceRange", +"StorageClass", +"TemplateArgumentKind", "TLSKind", "TokenKind", "Token", ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [libclang/python] Fix some type errors, add type annotations (PR #98745)
https://github.com/DeinAlptraum updated https://github.com/llvm/llvm-project/pull/98745 >From 00631fc559197d2bc6bfa9e8ccdae47f33926a37 Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Sat, 13 Jul 2024 14:12:34 +0100 Subject: [PATCH 1/2] [libclang/python] Fix some type errors, add type annotations --- clang/bindings/python/clang/cindex.py | 195 +++--- .../tests/cindex/test_code_completion.py | 22 +- .../python/tests/cindex/test_comment.py | 4 +- 3 files changed, 130 insertions(+), 91 deletions(-) diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index be024da5e005c..6c70588c28ffa 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -43,7 +43,7 @@ Most object information is exposed using properties, when the underlying API call is efficient. """ -from __future__ import absolute_import, division, print_function +from __future__ import annotations # TODO # @@ -64,48 +64,81 @@ from ctypes import * -import collections.abc import os +import sys from enum import Enum +from typing import ( +Any, +Callable, +Generic, +Optional, +Type as TType, +TypeVar, +TYPE_CHECKING, +Union as TUnion, +) + +if TYPE_CHECKING: +from ctypes import _Pointer +from typing_extensions import Protocol, TypeAlias + +StrPath: TypeAlias = TUnion[str, os.PathLike[str]] +LibFunc: TypeAlias = TUnion[ +"tuple[str, Optional[list[Any]]]", +"tuple[str, Optional[list[Any]], Any]", +"tuple[str, Optional[list[Any]], Any, Callable[..., Any]]", +] +CObjP: TypeAlias = _Pointer[Any] + +TSeq = TypeVar("TSeq", covariant=True) + +class NoSliceSequence(Protocol[TSeq]): +def __len__(self) -> int: +... + +def __getitem__(self, key: int) -> TSeq: +... + # Python 3 strings are unicode, translate them to/from utf8 for C-interop. class c_interop_string(c_char_p): -def __init__(self, p=None): +def __init__(self, p: str | bytes | None = None): if p is None: p = "" if isinstance(p, str): p = p.encode("utf8") super(c_char_p, self).__init__(p) -def __str__(self): -return self.value +def __str__(self) -> str: +return self.value or "" @property -def value(self): -if super(c_char_p, self).value is None: +def value(self) -> str | None: # type: ignore [override] +val = super(c_char_p, self).value +if val is None: return None -return super(c_char_p, self).value.decode("utf8") +return val.decode("utf8") @classmethod -def from_param(cls, param): +def from_param(cls, param: str | bytes | None) -> c_interop_string: if isinstance(param, str): return cls(param) if isinstance(param, bytes): return cls(param) if param is None: # Support passing null to C functions expecting char arrays -return None +return cls(param) raise TypeError( "Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__) ) @staticmethod -def to_python_string(x, *args): +def to_python_string(x: c_interop_string, *args: Any) -> str | None: return x.value -def b(x): +def b(x: str | bytes) -> bytes: if isinstance(x, bytes): return x return x.encode("utf8") @@ -115,9 +148,7 @@ def b(x): # object. This is a problem, because it means that from_parameter will see an # integer and pass the wrong value on platforms where int != void*. Work around # this by marshalling object arguments as void**. -c_object_p = POINTER(c_void_p) - -callbacks = {} +c_object_p: TType[CObjP] = POINTER(c_void_p) ### Exception Classes ### @@ -169,8 +200,11 @@ def __init__(self, enumeration, message): ### Structures and Utility Classes ### +TInstance = TypeVar("TInstance") +TResult = TypeVar("TResult") + -class CachedProperty: +class CachedProperty(Generic[TInstance, TResult]): """Decorator that lazy-loads the value of a property. The first time the property is accessed, the original property function is @@ -178,16 +212,20 @@ class CachedProperty: property, replacing the original method. """ -def __init__(self, wrapped): +def __init__(self, wrapped: Callable[[TInstance], TResult]): self.wrapped = wrapped try: self.__doc__ = wrapped.__doc__ except: pass -def __get__(self, instance, instance_type=None): +def __get__(self, instance: TInstance, instance_type: Any = None) -> TResult: if instance is None: -return self +property_name = self.wrapped.__name__ +class_name = instance_type.__name__ +raise TypeError( +f"'{property_name}' is not a stat
[clang] [libclang/python] Export all enums (PR #100941)
DeinAlptraum wrote: This may be my fault, I don't remember if I pulled main before branching for this PR, especially seeing how my last PR also had unrelated test failures https://github.com/llvm/llvm-project/pull/100941 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang][Sema] Remove duplicate check in if-condition (PR #101070)
https://github.com/DeinAlptraum created https://github.com/llvm/llvm-project/pull/101070 Resolves #101041 >From 521082f25bc42104fd436a412b2de2edb60b7b0e Mon Sep 17 00:00:00 2001 From: Jannick Kremer Date: Mon, 29 Jul 2024 20:24:15 +0100 Subject: [PATCH] [Clang][Sema] Remove duplicate check in if-condition --- clang/lib/Sema/SemaOpenMP.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 9c80b3eec914c..1d378e6b830ae 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -23087,8 +23087,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPDoacrossClause( if (DSAStack->getCurrentDirective() == OMPD_ordered && DepType != OMPC_DOACROSS_source && DepType != OMPC_DOACROSS_sink && DepType != OMPC_DOACROSS_sink_omp_cur_iteration && - DepType != OMPC_DOACROSS_source_omp_cur_iteration && - DepType != OMPC_DOACROSS_source) { + DepType != OMPC_DOACROSS_source_omp_cur_iteration) { Diag(DepLoc, diag::err_omp_unexpected_clause_value) << "'source' or 'sink'" << getOpenMPClauseName(OMPC_doacross); return nullptr; ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits