Skip to content

[libclang/python] Add typing annotations for the Type class #140378

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 18, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 61 additions & 66 deletions clang/bindings/python/clang/cindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
cast as Tcast,
Generic,
Iterator,
Literal,
Optional,
Sequence,
Type as TType,
Expand Down Expand Up @@ -1982,7 +1983,7 @@ def type(self) -> Type:
Retrieve the Type (if any) of the entity pointed at by the cursor.
"""
if not hasattr(self, "_type"):
self._type = Type.from_result(conf.lib.clang_getCursorType(self), (self,))
self._type = Type.from_result(conf.lib.clang_getCursorType(self), self)

return self._type

Expand All @@ -2009,7 +2010,7 @@ def result_type(self) -> Type:
"""Retrieve the Type of the result for this Cursor."""
if not hasattr(self, "_result_type"):
self._result_type = Type.from_result(
conf.lib.clang_getCursorResultType(self), (self,)
conf.lib.clang_getCursorResultType(self), self
)

return self._result_type
Expand Down Expand Up @@ -2040,7 +2041,7 @@ def underlying_typedef_type(self) -> Type:
if not hasattr(self, "_underlying_type"):
assert self.kind.is_declaration()
self._underlying_type = Type.from_result(
conf.lib.clang_getTypedefDeclUnderlyingType(self), (self,)
conf.lib.clang_getTypedefDeclUnderlyingType(self), self
)

return self._underlying_type
Expand All @@ -2056,7 +2057,7 @@ def enum_type(self) -> Type:
if not hasattr(self, "_enum_type"):
assert self.kind == CursorKind.ENUM_DECL
self._enum_type = Type.from_result(
conf.lib.clang_getEnumDeclIntegerType(self), (self,)
conf.lib.clang_getEnumDeclIntegerType(self), self
)

return self._enum_type
Expand Down Expand Up @@ -2197,7 +2198,7 @@ def get_template_argument_kind(self, num: int) -> TemplateArgumentKind:
def get_template_argument_type(self, num: int) -> Type:
"""Returns the CXType for the indicated template argument."""
return Type.from_result(
conf.lib.clang_Cursor_getTemplateArgumentType(self, num), (self, num)
conf.lib.clang_Cursor_getTemplateArgumentType(self, num), self
)

@cursor_null_guard
Expand Down Expand Up @@ -2597,8 +2598,10 @@ 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)

Expand Down Expand Up @@ -2635,7 +2638,7 @@ def __getitem__(self, key: int) -> Type:
)

result = Type.from_result(
conf.lib.clang_getArgType(self.parent, key), (self.parent, key)
conf.lib.clang_getArgType(self.parent, key), self.parent
)
if result.kind == TypeKind.INVALID:
raise IndexError("Argument could not be retrieved.")
Expand All @@ -2646,63 +2649,56 @@ def __getitem__(self, key: int) -> Type:
return ArgumentsIterator(self)

@property
def element_type(self):
def element_type(self) -> Type:
"""Retrieve the Type of elements within this Type.

If accessed on a type that is not an array, complex, or vector type, an
exception will be raised.
"""
result = Type.from_result(conf.lib.clang_getElementType(self), (self,))
result = Type.from_result(conf.lib.clang_getElementType(self), self)
if result.kind == TypeKind.INVALID:
raise Exception("Element type not available on this type.")

return result

@property
def element_count(self):
def element_count(self) -> int:
"""Retrieve the number of elements in this type.

Returns an int.

If the Type is not an array or vector, this raises.
"""
result = conf.lib.clang_getNumElements(self)
result: int = conf.lib.clang_getNumElements(self)
if result < 0:
raise Exception("Type does not have elements.")

return result

@property
def translation_unit(self):
def translation_unit(self) -> TranslationUnit:
"""The TranslationUnit to which this Type is associated."""
# If this triggers an AttributeError, the instance was not properly
# instantiated.
return self._tu

@staticmethod
def from_result(res, args):
def from_result(res: Type, arg: Cursor | Type) -> Type:
assert isinstance(res, Type)

tu = None
for arg in args:
if hasattr(arg, "translation_unit"):
tu = arg.translation_unit
break

assert tu is not None
res._tu = tu
assert arg.translation_unit is not None
res._tu = arg.translation_unit

return res

def get_num_template_arguments(self):
def get_num_template_arguments(self) -> int:
return conf.lib.clang_Type_getNumTemplateArguments(self) # type: ignore [no-any-return]

def get_template_argument_type(self, num):
def get_template_argument_type(self, num: int) -> Type:
return Type.from_result(
conf.lib.clang_Type_getTemplateArgumentAsType(self, num), (self, num)
conf.lib.clang_Type_getTemplateArgumentAsType(self, num), self
)

def get_canonical(self):
def get_canonical(self) -> Type:
"""
Return the canonical type for a Type.

Expand All @@ -2712,9 +2708,11 @@ def get_canonical(self):
example, if 'T' is a typedef for 'int', the canonical type for
'T' would be 'int'.
"""
return Type.from_result(conf.lib.clang_getCanonicalType(self), (self,))
return Type.from_result(conf.lib.clang_getCanonicalType(self), self)

def get_fully_qualified_name(self, policy, with_global_ns_prefix=False):
def get_fully_qualified_name(
self, policy: PrintingPolicy, with_global_ns_prefix: bool = False
) -> str:
"""
Get the fully qualified name for a type.

Expand All @@ -2727,118 +2725,118 @@ def get_fully_qualified_name(self, policy, with_global_ns_prefix=False):
conf.lib.clang_getFullyQualifiedName(self, policy, with_global_ns_prefix)
)

def is_const_qualified(self):
def is_const_qualified(self) -> bool:
"""Determine whether a Type has the "const" qualifier set.

This does not look through typedefs that may have added "const"
at a different level.
"""
return conf.lib.clang_isConstQualifiedType(self) # type: ignore [no-any-return]

def is_volatile_qualified(self):
def is_volatile_qualified(self) -> bool:
"""Determine whether a Type has the "volatile" qualifier set.

This does not look through typedefs that may have added "volatile"
at a different level.
"""
return conf.lib.clang_isVolatileQualifiedType(self) # type: ignore [no-any-return]

def is_restrict_qualified(self):
def is_restrict_qualified(self) -> bool:
"""Determine whether a Type has the "restrict" qualifier set.

This does not look through typedefs that may have added "restrict" at
a different level.
"""
return conf.lib.clang_isRestrictQualifiedType(self) # type: ignore [no-any-return]

def is_function_variadic(self):
def is_function_variadic(self) -> bool:
"""Determine whether this function Type is a variadic function type."""
assert self.kind == TypeKind.FUNCTIONPROTO

return conf.lib.clang_isFunctionTypeVariadic(self) # type: ignore [no-any-return]

def get_address_space(self):
def get_address_space(self) -> int:
return conf.lib.clang_getAddressSpace(self) # type: ignore [no-any-return]

def get_typedef_name(self):
def get_typedef_name(self) -> str:
return _CXString.from_result(conf.lib.clang_getTypedefName(self))

def is_pod(self):
def is_pod(self) -> bool:
"""Determine whether this Type represents plain old data (POD)."""
return conf.lib.clang_isPODType(self) # type: ignore [no-any-return]

def get_pointee(self):
def get_pointee(self) -> Type:
"""
For pointer types, returns the type of the pointee.
"""
return Type.from_result(conf.lib.clang_getPointeeType(self), (self,))
return Type.from_result(conf.lib.clang_getPointeeType(self), self)

def get_declaration(self):
def get_declaration(self) -> Cursor:
"""
Return the cursor for the declaration of the given type.
"""
return Cursor.from_non_null_cursor_result(
conf.lib.clang_getTypeDeclaration(self), self
)

def get_result(self):
def get_result(self) -> Type:
"""
Retrieve the result type associated with a function type.
"""
return Type.from_result(conf.lib.clang_getResultType(self), (self,))
return Type.from_result(conf.lib.clang_getResultType(self), self)

def get_array_element_type(self):
def get_array_element_type(self) -> Type:
"""
Retrieve the type of the elements of the array type.
"""
return Type.from_result(conf.lib.clang_getArrayElementType(self), (self,))
return Type.from_result(conf.lib.clang_getArrayElementType(self), self)

def get_array_size(self):
def get_array_size(self) -> int:
"""
Retrieve the size of the constant array.
"""
return conf.lib.clang_getArraySize(self) # type: ignore [no-any-return]

def get_class_type(self):
def get_class_type(self) -> Type:
"""
Retrieve the class type of the member pointer type.
"""
return Type.from_result(conf.lib.clang_Type_getClassType(self), (self,))
return Type.from_result(conf.lib.clang_Type_getClassType(self), self)

def get_named_type(self):
def get_named_type(self) -> Type:
"""
Retrieve the type named by the qualified-id.
"""
return Type.from_result(conf.lib.clang_Type_getNamedType(self), (self,))
return Type.from_result(conf.lib.clang_Type_getNamedType(self), self)

def get_align(self):
def get_align(self) -> int:
"""
Retrieve the alignment of the record.
"""
return conf.lib.clang_Type_getAlignOf(self) # type: ignore [no-any-return]

def get_size(self):
def get_size(self) -> int:
"""
Retrieve the size of the record.
"""
return conf.lib.clang_Type_getSizeOf(self) # type: ignore [no-any-return]

def get_offset(self, fieldname):
def get_offset(self, fieldname: str) -> int:
"""
Retrieve the offset of a field in the record.
"""
return conf.lib.clang_Type_getOffsetOf(self, fieldname) # type: ignore [no-any-return]

def get_ref_qualifier(self):
def get_ref_qualifier(self) -> RefQualifierKind:
"""
Retrieve the ref-qualifier of the type.
"""
return RefQualifierKind.from_id(conf.lib.clang_Type_getCXXRefQualifier(self))

def get_fields(self):
def get_fields(self) -> Iterator[Cursor]:
"""Return an iterator for accessing the fields of this type."""

def visitor(field, children):
def visitor(field: Cursor, _: Any) -> Literal[1]:
assert not field.is_null()

# Create reference to TU so it isn't GC'd before Cursor.
Expand All @@ -2850,10 +2848,10 @@ def visitor(field, children):
conf.lib.clang_Type_visitFields(self, fields_visit_callback(visitor), fields)
return iter(fields)

def get_bases(self):
def get_bases(self) -> Iterator[Cursor]:
"""Return an iterator for accessing the base classes of this type."""

def visitor(base, children):
def visitor(base: Cursor, _: Any) -> Literal[1]:
assert not base.is_null()

# Create reference to TU so it isn't GC'd before Cursor.
Expand All @@ -2865,10 +2863,10 @@ def visitor(base, children):
conf.lib.clang_visitCXXBaseClasses(self, fields_visit_callback(visitor), bases)
return iter(bases)

def get_methods(self):
def get_methods(self) -> Iterator[Cursor]:
"""Return an iterator for accessing the methods of this type."""

def visitor(method, children):
def visitor(method: Cursor, _: Any) -> Literal[1]:
assert not method.is_null()

# Create reference to TU so it isn't GC'd before Cursor.
Expand All @@ -2880,7 +2878,7 @@ def visitor(method, children):
conf.lib.clang_visitCXXMethods(self, fields_visit_callback(visitor), methods)
return iter(methods)

def get_exception_specification_kind(self):
def get_exception_specification_kind(self) -> ExceptionSpecificationKind:
"""
Return the kind of the exception specification; a value from
the ExceptionSpecificationKind enumeration.
Expand All @@ -2890,21 +2888,18 @@ def get_exception_specification_kind(self):
)

@property
def spelling(self):
def spelling(self) -> str:
"""Retrieve the spelling of this Type."""
return _CXString.from_result(conf.lib.clang_getTypeSpelling(self))

def pretty_printed(self, policy):
def pretty_printed(self, policy: PrintingPolicy) -> str:
"""Pretty-prints this Type with the given PrintingPolicy"""
return _CXString.from_result(conf.lib.clang_getTypePrettyPrinted(self, policy))

def __eq__(self, other):
if not isinstance(other, Type):
return False

return conf.lib.clang_equalTypes(self, other) # type: ignore [no-any-return]
def __eq__(self, other: object) -> bool:
return isinstance(other, Type) and conf.lib.clang_equalTypes(self, other)

def __ne__(self, other):
def __ne__(self, other: object) -> bool:
return not self.__eq__(other)


Expand Down
Loading