[clang] [libclang/python] Add type annotations to the TranslationUnit class (PR #180876)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 10 19:05:22 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Jannick Kremer (DeinAlptraum)
<details>
<summary>Changes</summary>
This adds type annotations to the `TranslationUnit` class, enough to pass a strict typecheck. This resolves 19 strict typing errors as the next step towards https://github.com/llvm/llvm-project/issues/76664
---
Full diff: https://github.com/llvm/llvm-project/pull/180876.diff
1 Files Affected:
- (modified) clang/bindings/python/clang/cindex.py (+65-29)
``````````diff
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index f4d7f4fe68966..50b4301a21be5 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -103,9 +103,16 @@
if TYPE_CHECKING:
from ctypes import _Pointer
+ from io import TextIOWrapper
from typing_extensions import Protocol, TypeAlias
StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
+ # The type that is compatible with os.fspath:
+ # str, bytes, or os.PathLikes that return either of these two
+ StrBytesPath: TypeAlias = TUnion[str, bytes, os.PathLike[str], os.PathLike[bytes]]
+ InMemoryFile: TypeAlias = (
+ "tuple[StrBytesPath, TUnion[str, bytes, TextIOWrapper]]"
+ )
LibFunc: TypeAlias = TUnion[
"tuple[str, Optional[list[Any]]]",
"tuple[str, Optional[list[Any]], Any]",
@@ -3463,7 +3470,9 @@ class TranslationUnit(ClangObject):
PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION = 128
@staticmethod
- def process_unsaved_files(unsaved_files) -> Array[_CXUnsavedFile] | None:
+ def process_unsaved_files(
+ unsaved_files: list[InMemoryFile],
+ ) -> Array[_CXUnsavedFile] | None:
unsaved_array = None
if len(unsaved_files):
unsaved_array = (_CXUnsavedFile * len(unsaved_files))()
@@ -3478,8 +3487,13 @@ def process_unsaved_files(unsaved_files) -> Array[_CXUnsavedFile] | None:
@classmethod
def from_source(
- cls, filename, args=None, unsaved_files=None, options=0, index=None
- ):
+ cls,
+ filename: StrBytesPath | None,
+ args: list[TUnion[str, bytes]] | None = None,
+ unsaved_files: list[InMemoryFile] | None = None,
+ options: int = 0,
+ index: Index | None = None,
+ ) -> TranslationUnit:
"""Create a TranslationUnit by parsing source.
This is capable of processing source code both from files on the
@@ -3490,11 +3504,12 @@ def from_source(
etc. e.g. ["-Wall", "-I/path/to/include"].
In-memory file content can be provided via unsaved_files. This is a
- list of 2-tuples. The first element is the filename (str or
+ list of 2-tuples. The first element is the filename (str, bytes or
PathLike). The second element defines the content. Content can be
- provided as str source code or as file objects (anything with a read()
- method). If a file object is being used, content will be read until EOF
- and the read cursor will not be reset to its original position.
+ provided as str or bytes source code, or as file objects (anything with
+ a read() method). If a file object is being used, content will be read
+ until EOF and the read cursor will not be reset to its original
+ position.
options is a bitwise or of TranslationUnit.PARSE_XXX flags which will
control parsing behavior.
@@ -3550,7 +3565,9 @@ def from_source(
return cls(ptr, index=index)
@classmethod
- def from_ast_file(cls, filename, index=None):
+ def from_ast_file(
+ cls, filename: StrPath, index: Index | None = None
+ ) -> TranslationUnit:
"""Create a TranslationUnit instance from a saved AST file.
A previously-saved AST file (provided with -emit-ast or
@@ -3573,7 +3590,7 @@ def from_ast_file(cls, filename, index=None):
return cls(ptr=ptr, index=index)
- def __init__(self, ptr, index):
+ def __init__(self, ptr: CObjP, index: Index) -> None:
"""Create a TranslationUnit instance.
TranslationUnits should be created using one of the from_* @classmethod
@@ -3583,20 +3600,20 @@ def __init__(self, ptr, index):
self.index = index
ClangObject.__init__(self, ptr)
- def __del__(self):
+ def __del__(self) -> None:
conf.lib.clang_disposeTranslationUnit(self)
@property
- def cursor(self):
+ def cursor(self) -> Cursor | None:
"""Retrieve the cursor that represents the given translation unit."""
return Cursor.from_result(conf.lib.clang_getTranslationUnitCursor(self), self)
@property
- def spelling(self):
+ def spelling(self) -> str:
"""Get the original translation unit source file name."""
return _CXString.from_result(conf.lib.clang_getTranslationUnitSpelling(self))
- def get_includes(self):
+ def get_includes(self) -> Iterator[FileInclusion]:
"""
Return an iterable sequence of FileInclusion objects that describe the
sequence of inclusions in a translation unit. The first object in
@@ -3605,25 +3622,32 @@ def get_includes(self):
headers.
"""
- def visitor(fobj, lptr, depth, includes):
+ def visitor(
+ fobj: CObjP,
+ lptr: _Pointer[SourceLocation],
+ depth: int,
+ includes: list[FileInclusion],
+ ) -> None:
if depth > 0:
loc = lptr.contents
includes.append(FileInclusion(loc.file, File(fobj), loc, depth))
# Automatically adapt CIndex/ctype pointers to python objects
- includes = []
+ includes: list[FileInclusion] = []
conf.lib.clang_getInclusions(
self, translation_unit_includes_callback(visitor), includes
)
return iter(includes)
- def get_file(self, filename):
+ def get_file(self, filename: StrBytesPath) -> File:
"""Obtain a File from this translation unit."""
return File.from_name(self, filename)
- def get_location(self, filename, position):
+ def get_location(
+ self, filename: StrBytesPath, position: int | tuple[int, int]
+ ) -> SourceLocation:
"""Obtain a SourceLocation for a file in this translation unit.
The position can be specified by passing:
@@ -3639,7 +3663,11 @@ def get_location(self, filename, position):
return SourceLocation.from_position(self, f, position[0], position[1])
- def get_extent(self, filename, locations):
+ def get_extent(
+ self,
+ filename: StrBytesPath,
+ locations: Sequence[SourceLocation] | Sequence[int] | Sequence[Sequence[int]],
+ ) -> SourceRange:
"""Obtain a SourceRange from this translation unit.
The bounds of the SourceRange must ultimately be defined by a start and
@@ -3703,7 +3731,9 @@ def __getitem__(self, key: int) -> Diagnostic:
return DiagIterator(self)
- def reparse(self, unsaved_files=None, options=0):
+ def reparse(
+ self, unsaved_files: list[InMemoryFile] | None = None, options: int = 0
+ ) -> None:
"""
Reparse an already parsed translation unit.
@@ -3725,7 +3755,7 @@ def reparse(self, unsaved_files=None, options=0):
msg = "Error reparsing translation unit. Error code: " + str(result)
raise TranslationUnitLoadError(msg)
- def save(self, filename):
+ def save(self, filename: StrBytesPath) -> None:
"""Saves the TranslationUnit to a file.
This is equivalent to passing -emit-ast to the clang frontend. The
@@ -3753,14 +3783,14 @@ def save(self, filename):
def codeComplete(
self,
- path,
- line,
- column,
- unsaved_files=None,
- include_macros=False,
- include_code_patterns=False,
- include_brief_comments=False,
- ):
+ path: StrBytesPath,
+ line: int,
+ column: int,
+ unsaved_files: list[InMemoryFile] | None = None,
+ include_macros: bool = False,
+ include_code_patterns: bool = False,
+ include_brief_comments: bool = False,
+ ) -> CodeCompletionResults | None:
"""
Code complete in this translation unit.
@@ -3797,7 +3827,11 @@ def codeComplete(
return CodeCompletionResults(ptr)
return None
- def get_tokens(self, locations=None, extent=None):
+ def get_tokens(
+ self,
+ locations: tuple[SourceLocation, SourceLocation] | None = None,
+ extent: SourceRange | None = None,
+ ) -> Iterator[Token]:
"""Obtain tokens in this translation unit.
This is a generator for Token instances. The caller specifies a range
@@ -3809,6 +3843,8 @@ def get_tokens(self, locations=None, extent=None):
raise TypeError("get_tokens() requires at least one argument")
if locations is not None:
extent = SourceRange(start=locations[0], end=locations[1])
+ if extent is None:
+ raise TypeError("get_tokens() requires at least one argument")
return TokenGroup.get_tokens(self, extent)
``````````
</details>
https://github.com/llvm/llvm-project/pull/180876
More information about the cfe-commits
mailing list