-
Notifications
You must be signed in to change notification settings - Fork 11.5k
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
#101784 part 1: introduce ctyped in an independent manner #101941
base: main
Are you sure you want to change the base?
Conversation
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write If you have received no comments on your PR for a week, you can request a review If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
You can test this locally with the following command:darker --check --diff -r 98e4413a38f286147b863a6ead9625228ab0ec7d...cbe82fc24aa94c919aaa1a01ae72e11ddcd71f19 clang/bindings/python/clang/binder.py clang/bindings/python/clang/ctyped.py clang/bindings/python/tests/ctyped/__init__.py clang/bindings/python/tests/ctyped/test_stub_conversion.py View the diff from darker here.--- clang/binder.py 2024-08-06 14:17:29.000000 +0000
+++ clang/binder.py 2024-08-08 15:03:52.918837 +0000
@@ -8,58 +8,79 @@
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Type, Union
from typing_extensions import Annotated
from .ctyped import *
-from .ctyped import (ANNO_PARAMETER, ANNO_RESULT, ANNO_RESULT_CONVERTER,
- generate_metadata)
+from .ctyped import (
+ ANNO_PARAMETER,
+ ANNO_RESULT,
+ ANNO_RESULT_CONVERTER,
+ generate_metadata,
+)
if TYPE_CHECKING:
from ctypes import CDLL
from types import EllipsisType
- from .cindex import (CCRStructure, CodeCompletionResults,
- CompilationDatabase, CompileCommands, Cursor,
- CursorKind, Diagnostic, File, FileInclusion, Index,
- Rewriter, SourceLocation, SourceRange, StrPath,
- TemplateArgumentKind, Token, TranslationUnit)
+ from .cindex import (
+ CCRStructure,
+ CodeCompletionResults,
+ CompilationDatabase,
+ CompileCommands,
+ Cursor,
+ CursorKind,
+ Diagnostic,
+ File,
+ FileInclusion,
+ Index,
+ Rewriter,
+ SourceLocation,
+ SourceRange,
+ StrPath,
+ TemplateArgumentKind,
+ Token,
+ TranslationUnit,
+ )
from .cindex import Type as ASTType
from .cindex import _CXString, _CXUnsavedFile
else:
EllipsisType = type(Ellipsis)
# delayed imports, a list of import name and their alias
# if alias is same as name, use `...`
CINDEX_DELAYED_IMPORTS: List[Tuple[str, Union[str, EllipsisType]]] = [
- ('CCRStructure', ...),
- ('CodeCompletionResults', ...),
- ('CompilationDatabase', ...),
- ('CompileCommands', ...),
- ('Cursor', ...),
- ('CursorKind', ...),
- ('Diagnostic', ...),
- ('File', ...),
- ('FileInclusion', ...),
- ('Index', ...),
- ('Rewriter', ...),
- ('SourceLocation', ...),
- ('SourceRange', ...),
- ('TemplateArgumentKind', ...),
- ('Token', ...),
- ('TranslationUnit', ...),
- ('Type', 'ASTType'),
- ('_CXString', ...),
- ('_CXUnsavedFile', ...),
- ('c_interop_string', ...),
+ ("CCRStructure", ...),
+ ("CodeCompletionResults", ...),
+ ("CompilationDatabase", ...),
+ ("CompileCommands", ...),
+ ("Cursor", ...),
+ ("CursorKind", ...),
+ ("Diagnostic", ...),
+ ("File", ...),
+ ("FileInclusion", ...),
+ ("Index", ...),
+ ("Rewriter", ...),
+ ("SourceLocation", ...),
+ ("SourceRange", ...),
+ ("TemplateArgumentKind", ...),
+ ("Token", ...),
+ ("TranslationUnit", ...),
+ ("Type", "ASTType"),
+ ("_CXString", ...),
+ ("_CXUnsavedFile", ...),
+ ("c_interop_string", ...),
]
+
def load_cindex_types() -> None:
cindex_imports: Dict[str, Any] = {}
from . import cindex
+
for name, alias in CINDEX_DELAYED_IMPORTS:
- if isinstance(alias, EllipsisType): alias = name
+ if isinstance(alias, EllipsisType):
+ alias = name
cindex_imports[alias] = getattr(cindex, name)
globals().update(cindex_imports)
# ctypes doesn't implicitly convert c_void_p to the appropriate wrapper
@@ -69,79 +90,111 @@
CObjectP = CPointer[c_void_p]
c_object_p: Type[CObjectP] = convert_annotation(CObjectP)
# Register callback types
-TranslationUnitIncludesCallback = Annotated[CFuncPointer, None, c_object_p, CPointer['SourceLocation'], c_uint, py_object]
-CursorVisitCallback = Annotated[CFuncPointer, c_int, 'Cursor', 'Cursor', py_object]
-FieldsVisitCallback = Annotated[CFuncPointer, c_int, 'Cursor', py_object]
+TranslationUnitIncludesCallback = Annotated[
+ CFuncPointer, None, c_object_p, CPointer["SourceLocation"], c_uint, py_object
+]
+CursorVisitCallback = Annotated[CFuncPointer, c_int, "Cursor", "Cursor", py_object]
+FieldsVisitCallback = Annotated[CFuncPointer, c_int, "Cursor", py_object]
# TODO: these lines should replace the definition in cindex.py
-#translation_unit_includes_callback: Type[CFuncPointer] = convert_annotation(TranslationUnitIncludesCallback, globals())
-#cursor_visit_callback: Type[CFuncPointer] = convert_annotation(CursorVisitCallback, globals())
-#fields_visit_callback: Type[CFuncPointer] = convert_annotation(FieldsVisitCallback, globals())
+# translation_unit_includes_callback: Type[CFuncPointer] = convert_annotation(TranslationUnitIncludesCallback, globals())
+# cursor_visit_callback: Type[CFuncPointer] = convert_annotation(CursorVisitCallback, globals())
+# fields_visit_callback: Type[CFuncPointer] = convert_annotation(FieldsVisitCallback, globals())
# Misc object param/result types
# A type may only have param type or result type, this is normal.
-ASTTypeResult = Annotated['ASTType', ANNO_RESULT, 'ASTType', 'ASTType.from_result']
-
-CInteropStringParam = Annotated[Union[str, bytes, None], ANNO_PARAMETER, 'c_interop_string']
-CInteropStringResult = Annotated[Optional[str], ANNO_RESULT, 'c_interop_string', 'c_interop_string.to_python_string']
-
-CXStringResult = Annotated[str, ANNO_RESULT, '_CXString', '_CXString.from_result']
-
-CompilationDatabaseParam = Annotated['CompilationDatabase', ANNO_PARAMETER, c_object_p]
-CompilationDatabaseResult = Annotated['CompilationDatabase', ANNO_RESULT, c_object_p, 'CompilationDatabase.from_result']
-
-CompileCommandsResult = Annotated['CompileCommands', ANNO_RESULT, c_object_p, 'CompileCommands.from_result']
-
-CursorResult = Annotated['Cursor', ANNO_RESULT, 'Cursor', 'Cursor.from_cursor_result']
-CursorNullableResult = Annotated[Optional['Cursor'], ANNO_RESULT, 'Cursor', 'Cursor.from_result']
-
-DiagnosticParam = Annotated['Diagnostic', ANNO_PARAMETER, c_object_p]
-
-FileResult = Annotated['File', ANNO_RESULT, c_object_p, 'File.from_result']
-
-TemplateArgumentKindResult = Annotated['TemplateArgumentKind', ANNO_RESULT_CONVERTER, 'TemplateArgumentKind.from_id']
-
-TranslationUnitParam = Annotated['TranslationUnit', ANNO_PARAMETER, c_object_p]
+ASTTypeResult = Annotated["ASTType", ANNO_RESULT, "ASTType", "ASTType.from_result"]
+
+CInteropStringParam = Annotated[
+ Union[str, bytes, None], ANNO_PARAMETER, "c_interop_string"
+]
+CInteropStringResult = Annotated[
+ Optional[str], ANNO_RESULT, "c_interop_string", "c_interop_string.to_python_string"
+]
+
+CXStringResult = Annotated[str, ANNO_RESULT, "_CXString", "_CXString.from_result"]
+
+CompilationDatabaseParam = Annotated["CompilationDatabase", ANNO_PARAMETER, c_object_p]
+CompilationDatabaseResult = Annotated[
+ "CompilationDatabase", ANNO_RESULT, c_object_p, "CompilationDatabase.from_result"
+]
+
+CompileCommandsResult = Annotated[
+ "CompileCommands", ANNO_RESULT, c_object_p, "CompileCommands.from_result"
+]
+
+CursorResult = Annotated["Cursor", ANNO_RESULT, "Cursor", "Cursor.from_cursor_result"]
+CursorNullableResult = Annotated[
+ Optional["Cursor"], ANNO_RESULT, "Cursor", "Cursor.from_result"
+]
+
+DiagnosticParam = Annotated["Diagnostic", ANNO_PARAMETER, c_object_p]
+
+FileResult = Annotated["File", ANNO_RESULT, c_object_p, "File.from_result"]
+
+TemplateArgumentKindResult = Annotated[
+ "TemplateArgumentKind", ANNO_RESULT_CONVERTER, "TemplateArgumentKind.from_id"
+]
+
+TranslationUnitParam = Annotated["TranslationUnit", ANNO_PARAMETER, c_object_p]
# Functions strictly alphabetical order.
# NOTE:
# - These functions are stubs, they are not implemented, and is replaced by C functions at runtime.
# - If Config.compatibility_check is set to `False`, then a function is allowed to be missing.
# - If a function is missing in C library, it will not be replaced, thus causing NotImplementedError when called.
# - Missing functions are given a `_missing_` attribute, you can check it with `hasattr(conf.lib.xxx, '_missing_')`.
# - These stub functions are generated with a script from old data and manually corrected, so parameter names are missing.
class LibclangExports:
- def clang_annotateTokens(self, p1: TranslationUnit, p2: CPointerParam[Token], p3: CUlongParam, p4: CPointerParam[Cursor]) -> CLongResult:
- raise NotImplementedError
-
- def clang_CompilationDatabase_dispose(self, p1: CompilationDatabaseParam) -> CLongResult:
- raise NotImplementedError
-
- def clang_CompilationDatabase_fromDirectory(self, p1: CInteropStringParam, p2: CPointerParam[c_ulong]) -> CompilationDatabaseResult:
- raise NotImplementedError
-
- def clang_CompilationDatabase_getAllCompileCommands(self, p1: CompilationDatabaseParam) -> CompileCommandsResult:
- raise NotImplementedError
-
- def clang_CompilationDatabase_getCompileCommands(self, p1: CompilationDatabaseParam, p2: CInteropStringParam) -> CompileCommandsResult:
+ def clang_annotateTokens(
+ self,
+ p1: TranslationUnit,
+ p2: CPointerParam[Token],
+ p3: CUlongParam,
+ p4: CPointerParam[Cursor],
+ ) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_CompilationDatabase_dispose(
+ self, p1: CompilationDatabaseParam
+ ) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_CompilationDatabase_fromDirectory(
+ self, p1: CInteropStringParam, p2: CPointerParam[c_ulong]
+ ) -> CompilationDatabaseResult:
+ raise NotImplementedError
+
+ def clang_CompilationDatabase_getAllCompileCommands(
+ self, p1: CompilationDatabaseParam
+ ) -> CompileCommandsResult:
+ raise NotImplementedError
+
+ def clang_CompilationDatabase_getCompileCommands(
+ self, p1: CompilationDatabaseParam, p2: CInteropStringParam
+ ) -> CompileCommandsResult:
raise NotImplementedError
def clang_CompileCommands_dispose(self, p1: CObjectP) -> CLongResult:
raise NotImplementedError
- def clang_CompileCommands_getCommand(self, p1: CObjectP, p2: CUlongParam) -> CObjectP:
+ def clang_CompileCommands_getCommand(
+ self, p1: CObjectP, p2: CUlongParam
+ ) -> CObjectP:
raise NotImplementedError
def clang_CompileCommands_getSize(self, p1: CObjectP) -> CUlongResult:
raise NotImplementedError
- def clang_CompileCommand_getArg(self, p1: CObjectP, p2: CUlongParam) -> CXStringResult:
+ def clang_CompileCommand_getArg(
+ self, p1: CObjectP, p2: CUlongParam
+ ) -> CXStringResult:
raise NotImplementedError
def clang_CompileCommand_getDirectory(self, p1: CObjectP) -> CXStringResult:
raise NotImplementedError
@@ -149,41 +202,60 @@
raise NotImplementedError
def clang_CompileCommand_getNumArgs(self, p1: CObjectP) -> CUlongResult:
raise NotImplementedError
- def clang_codeCompleteAt(self, p1: TranslationUnit, p2: CInteropStringParam, p3: CLongParam, p4: CLongParam, p5: CPointerParam[_CXUnsavedFile], p6: CLongParam, p7: CLongParam) -> CPointer[CCRStructure]:
- raise NotImplementedError
-
- def clang_codeCompleteGetDiagnostic(self, p1: CodeCompletionResults, p2: CLongParam) -> Diagnostic:
- raise NotImplementedError
-
- def clang_codeCompleteGetNumDiagnostics(self, p1: CodeCompletionResults) -> CLongResult:
+ def clang_codeCompleteAt(
+ self,
+ p1: TranslationUnit,
+ p2: CInteropStringParam,
+ p3: CLongParam,
+ p4: CLongParam,
+ p5: CPointerParam[_CXUnsavedFile],
+ p6: CLongParam,
+ p7: CLongParam,
+ ) -> CPointer[CCRStructure]:
+ raise NotImplementedError
+
+ def clang_codeCompleteGetDiagnostic(
+ self, p1: CodeCompletionResults, p2: CLongParam
+ ) -> Diagnostic:
+ raise NotImplementedError
+
+ def clang_codeCompleteGetNumDiagnostics(
+ self, p1: CodeCompletionResults
+ ) -> CLongResult:
raise NotImplementedError
def clang_createIndex(self, p1: CLongParam, p2: CLongParam) -> CObjectP:
raise NotImplementedError
- def clang_createTranslationUnit(self, p1: Index, p2: CInteropStringParam) -> CObjectP:
+ def clang_createTranslationUnit(
+ self, p1: Index, p2: CInteropStringParam
+ ) -> CObjectP:
raise NotImplementedError
def clang_CXRewriter_create(self, p1: TranslationUnit) -> CObjectP:
raise NotImplementedError
def clang_CXRewriter_dispose(self, p1: Rewriter) -> CLongResult:
raise NotImplementedError
- def clang_CXRewriter_insertTextBefore(self, p1: Rewriter, p2: SourceLocation, p3: CInteropStringParam) -> CLongResult:
+ def clang_CXRewriter_insertTextBefore(
+ self, p1: Rewriter, p2: SourceLocation, p3: CInteropStringParam
+ ) -> CLongResult:
raise NotImplementedError
def clang_CXRewriter_overwriteChangedFiles(self, p1: Rewriter) -> CLongResult:
raise NotImplementedError
def clang_CXRewriter_removeText(self, p1: Rewriter, p2: SourceRange) -> CLongResult:
raise NotImplementedError
- def clang_CXRewriter_replaceText(self, p1: Rewriter, p2: SourceRange, p3: CInteropStringParam) -> CLongResult:
+ def clang_CXRewriter_replaceText(
+ self, p1: Rewriter, p2: SourceRange, p3: CInteropStringParam
+ ) -> CLongResult:
raise NotImplementedError
def clang_CXRewriter_writeMainFileToStdOut(self, p1: Rewriter) -> CLongResult:
raise NotImplementedError
@@ -242,11 +314,13 @@
raise NotImplementedError
def clang_defaultSaveOptions(self, p1: TranslationUnit) -> CUlongResult:
raise NotImplementedError
- def clang_disposeCodeCompleteResults(self, p1: CodeCompletionResults) -> CLongResult:
+ def clang_disposeCodeCompleteResults(
+ self, p1: CodeCompletionResults
+ ) -> CLongResult:
raise NotImplementedError
def clang_disposeDiagnostic(self, p1: Diagnostic) -> CLongResult:
raise NotImplementedError
@@ -254,11 +328,13 @@
raise NotImplementedError
def clang_disposeString(self, p1: _CXString) -> CLongResult:
raise NotImplementedError
- def clang_disposeTokens(self, p1: TranslationUnit, p2: CPointer[Token], p3: CUintParam) -> CLongResult:
+ def clang_disposeTokens(
+ self, p1: TranslationUnit, p2: CPointer[Token], p3: CUintParam
+ ) -> CLongResult:
raise NotImplementedError
def clang_disposeTranslationUnit(self, p1: TranslationUnit) -> CLongResult:
raise NotImplementedError
@@ -305,17 +381,21 @@
raise NotImplementedError
def clang_getCompletionBriefComment(self, p1: CObjectP) -> CXStringResult:
raise NotImplementedError
- def clang_getCompletionChunkCompletionString(self, p1: CObjectP, p2: CLongParam) -> CObjectP:
+ def clang_getCompletionChunkCompletionString(
+ self, p1: CObjectP, p2: CLongParam
+ ) -> CObjectP:
raise NotImplementedError
def clang_getCompletionChunkKind(self, p1: CObjectP, p2: CLongParam) -> CLongResult:
raise NotImplementedError
- def clang_getCompletionChunkText(self, p1: CObjectP, p2: CLongParam) -> CXStringResult:
+ def clang_getCompletionChunkText(
+ self, p1: CObjectP, p2: CLongParam
+ ) -> CXStringResult:
raise NotImplementedError
def clang_getCompletionPriority(self, p1: CObjectP) -> CLongResult:
raise NotImplementedError
@@ -350,11 +430,13 @@
raise NotImplementedError
def clang_getCursorReferenced(self, p1: Cursor) -> CursorNullableResult:
raise NotImplementedError
- def clang_getCursorReferenceNameRange(self, p1: Cursor, p2: CUlongParam, p3: CUlongParam) -> SourceRange:
+ def clang_getCursorReferenceNameRange(
+ self, p1: Cursor, p2: CUlongParam, p3: CUlongParam
+ ) -> SourceRange:
raise NotImplementedError
def clang_getCursorResultType(self, p1: Cursor) -> ASTTypeResult:
raise NotImplementedError
@@ -380,20 +462,24 @@
raise NotImplementedError
def clang_getDeclObjCTypeEncoding(self, p1: Cursor) -> CXStringResult:
raise NotImplementedError
- def clang_getDiagnostic(self, p1: TranslationUnitParam, p2: CUlongParam) -> CObjectP:
+ def clang_getDiagnostic(
+ self, p1: TranslationUnitParam, p2: CUlongParam
+ ) -> CObjectP:
raise NotImplementedError
def clang_getDiagnosticCategory(self, p1: Diagnostic) -> CUlongResult:
raise NotImplementedError
def clang_getDiagnosticCategoryText(self, p1: Diagnostic) -> CXStringResult:
raise NotImplementedError
- def clang_getDiagnosticFixIt(self, p1: Diagnostic, p2: CUlongParam, p3: CPointerParam[SourceRange]) -> CXStringResult:
+ def clang_getDiagnosticFixIt(
+ self, p1: Diagnostic, p2: CUlongParam, p3: CPointerParam[SourceRange]
+ ) -> CXStringResult:
raise NotImplementedError
def clang_getDiagnosticInSet(self, p1: CObjectP, p2: CUlongParam) -> CObjectP:
raise NotImplementedError
@@ -404,11 +490,13 @@
raise NotImplementedError
def clang_getDiagnosticNumRanges(self, p1: Diagnostic) -> CUlongResult:
raise NotImplementedError
- def clang_getDiagnosticOption(self, p1: Diagnostic, p2: CPointerParam[_CXString]) -> CXStringResult:
+ def clang_getDiagnosticOption(
+ self, p1: Diagnostic, p2: CPointerParam[_CXString]
+ ) -> CXStringResult:
raise NotImplementedError
def clang_getDiagnosticRange(self, p1: Diagnostic, p2: CUlongParam) -> SourceRange:
raise NotImplementedError
@@ -446,20 +534,36 @@
raise NotImplementedError
def clang_getIncludedFile(self, p1: Cursor) -> FileResult:
raise NotImplementedError
- def clang_getInclusions(self, p1: TranslationUnit, p2: TranslationUnitIncludesCallback, p3: CPyObject[List[FileInclusion]]) -> CLongResult:
- raise NotImplementedError
-
- def clang_getInstantiationLocation(self, p1: SourceLocation, p2: CPointerParam[CObjectP], p3: CPointerParam[c_ulong], p4: CPointerParam[c_ulong], p5: CPointerParam[c_ulong]) -> CLongResult:
- raise NotImplementedError
-
- def clang_getLocation(self, p1: TranslationUnit, p2: File, p3: CUlongParam, p4: CUlongParam) -> SourceLocation:
- raise NotImplementedError
-
- def clang_getLocationForOffset(self, p1: TranslationUnit, p2: File, p3: CUlongParam) -> SourceLocation:
+ def clang_getInclusions(
+ self,
+ p1: TranslationUnit,
+ p2: TranslationUnitIncludesCallback,
+ p3: CPyObject[List[FileInclusion]],
+ ) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_getInstantiationLocation(
+ self,
+ p1: SourceLocation,
+ p2: CPointerParam[CObjectP],
+ p3: CPointerParam[c_ulong],
+ p4: CPointerParam[c_ulong],
+ p5: CPointerParam[c_ulong],
+ ) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_getLocation(
+ self, p1: TranslationUnit, p2: File, p3: CUlongParam, p4: CUlongParam
+ ) -> SourceLocation:
+ raise NotImplementedError
+
+ def clang_getLocationForOffset(
+ self, p1: TranslationUnit, p2: File, p3: CUlongParam
+ ) -> SourceLocation:
raise NotImplementedError
def clang_getNullCursor(self) -> Cursor:
raise NotImplementedError
@@ -515,11 +619,13 @@
raise NotImplementedError
def clang_getTokenSpelling(self, p1: TranslationUnit, p2: Token) -> CXStringResult:
raise NotImplementedError
- def clang_getTranslationUnitCursor(self, p1: TranslationUnit) -> CursorNullableResult:
+ def clang_getTranslationUnitCursor(
+ self, p1: TranslationUnit
+ ) -> CursorNullableResult:
raise NotImplementedError
def clang_getTranslationUnitSpelling(self, p1: TranslationUnit) -> CXStringResult:
raise NotImplementedError
@@ -593,44 +699,79 @@
raise NotImplementedError
def clang_isVolatileQualifiedType(self, p1: ASTType) -> bool:
raise NotImplementedError
- def clang_parseTranslationUnit(self, p1: Index, p2: CInteropStringParam, p3: CPointerParam[c_char_p], p4: CLongParam, p5: CPointerParam[_CXUnsavedFile], p6: CLongParam, p7: CLongParam) -> CObjectP:
- raise NotImplementedError
-
- def clang_reparseTranslationUnit(self, p1: TranslationUnit, p2: CLongParam, p3: CPointerParam[_CXUnsavedFile], p4: CLongParam) -> CLongResult:
- raise NotImplementedError
-
- def clang_saveTranslationUnit(self, p1: TranslationUnit, p2: CInteropStringParam, p3: CUlongParam) -> CLongResult:
- raise NotImplementedError
-
- def clang_tokenize(self, p1: TranslationUnit, p2: SourceRange, p3: CPointerParam[CPointer[Token]], p4: CPointerParam[c_ulong]) -> CLongResult:
- raise NotImplementedError
-
- def clang_visitChildren(self, p1: Cursor, p2: CursorVisitCallback, p3: CPyObject[List[Cursor]]) -> CUlongResult:
+ def clang_parseTranslationUnit(
+ self,
+ p1: Index,
+ p2: CInteropStringParam,
+ p3: CPointerParam[c_char_p],
+ p4: CLongParam,
+ p5: CPointerParam[_CXUnsavedFile],
+ p6: CLongParam,
+ p7: CLongParam,
+ ) -> CObjectP:
+ raise NotImplementedError
+
+ def clang_reparseTranslationUnit(
+ self,
+ p1: TranslationUnit,
+ p2: CLongParam,
+ p3: CPointerParam[_CXUnsavedFile],
+ p4: CLongParam,
+ ) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_saveTranslationUnit(
+ self, p1: TranslationUnit, p2: CInteropStringParam, p3: CUlongParam
+ ) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_tokenize(
+ self,
+ p1: TranslationUnit,
+ p2: SourceRange,
+ p3: CPointerParam[CPointer[Token]],
+ p4: CPointerParam[c_ulong],
+ ) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_visitChildren(
+ self, p1: Cursor, p2: CursorVisitCallback, p3: CPyObject[List[Cursor]]
+ ) -> CUlongResult:
raise NotImplementedError
def clang_Cursor_getNumArguments(self, p1: Cursor) -> CLongResult:
raise NotImplementedError
- def clang_Cursor_getArgument(self, p1: Cursor, p2: CUlongParam) -> CursorNullableResult:
+ def clang_Cursor_getArgument(
+ self, p1: Cursor, p2: CUlongParam
+ ) -> CursorNullableResult:
raise NotImplementedError
def clang_Cursor_getNumTemplateArguments(self, p1: Cursor) -> CLongResult:
raise NotImplementedError
- def clang_Cursor_getTemplateArgumentKind(self, p1: Cursor, p2: CUlongParam) -> TemplateArgumentKindResult:
- raise NotImplementedError
-
- def clang_Cursor_getTemplateArgumentType(self, p1: Cursor, p2: CUlongParam) -> ASTTypeResult:
- raise NotImplementedError
-
- def clang_Cursor_getTemplateArgumentValue(self, p1: Cursor, p2: CUlongParam) -> CLonglongResult:
- raise NotImplementedError
-
- def clang_Cursor_getTemplateArgumentUnsignedValue(self, p1: Cursor, p2: CUlongParam) -> CUlonglongResult:
+ def clang_Cursor_getTemplateArgumentKind(
+ self, p1: Cursor, p2: CUlongParam
+ ) -> TemplateArgumentKindResult:
+ raise NotImplementedError
+
+ def clang_Cursor_getTemplateArgumentType(
+ self, p1: Cursor, p2: CUlongParam
+ ) -> ASTTypeResult:
+ raise NotImplementedError
+
+ def clang_Cursor_getTemplateArgumentValue(
+ self, p1: Cursor, p2: CUlongParam
+ ) -> CLonglongResult:
+ raise NotImplementedError
+
+ def clang_Cursor_getTemplateArgumentUnsignedValue(
+ self, p1: Cursor, p2: CUlongParam
+ ) -> CUlonglongResult:
raise NotImplementedError
def clang_Cursor_isAnonymous(self, p1: Cursor) -> bool:
raise NotImplementedError
@@ -659,14 +800,18 @@
raise NotImplementedError
def clang_Type_getNumTemplateArguments(self, p1: ASTType) -> CLongResult:
raise NotImplementedError
- def clang_Type_getTemplateArgumentAsType(self, p1: ASTType, p2: CUlongParam) -> ASTTypeResult:
- raise NotImplementedError
-
- def clang_Type_getOffsetOf(self, p1: ASTType, p2: CInteropStringParam) -> CLonglongResult:
+ def clang_Type_getTemplateArgumentAsType(
+ self, p1: ASTType, p2: CUlongParam
+ ) -> ASTTypeResult:
+ raise NotImplementedError
+
+ def clang_Type_getOffsetOf(
+ self, p1: ASTType, p2: CInteropStringParam
+ ) -> CLonglongResult:
raise NotImplementedError
def clang_Type_getSizeOf(self, p1: ASTType) -> CLonglongResult:
raise NotImplementedError
@@ -674,11 +819,13 @@
raise NotImplementedError
def clang_Type_getNamedType(self, p1: ASTType) -> ASTTypeResult:
raise NotImplementedError
- def clang_Type_visitFields(self, p1: ASTType, p2: FieldsVisitCallback, p3: CPyObject[List[Cursor]]) -> CUlongResult:
+ def clang_Type_visitFields(
+ self, p1: ASTType, p2: FieldsVisitCallback, p3: CPyObject[List[Cursor]]
+ ) -> CUlongResult:
raise NotImplementedError
class LibclangError(Exception):
m: str
@@ -761,13 +908,15 @@
self._lib = exports
return self._lib
@staticmethod
def cfunc_metadata() -> Dict[str, Dict[str, Any]]:
- ''' Generate ctypes metadata for debugging purpose. '''
+ """Generate ctypes metadata for debugging purpose."""
load_cindex_types()
- return {name: info for name, info in generate_metadata(LibclangExports, globals())}
+ return {
+ name: info for name, info in generate_metadata(LibclangExports, globals())
+ }
def get_filename(self) -> str:
if Config.library_file:
return Config.library_file
@@ -799,6 +948,6 @@
raise LibclangError(msg)
return library
def function_exists(self, name: str) -> bool:
- return not hasattr(getattr(self.lib, name), '_missing_')
+ return not hasattr(getattr(self.lib, name), "_missing_")
--- clang/ctyped.py 2024-08-06 14:17:29.000000 +0000
+++ clang/ctyped.py 2024-08-08 15:03:53.067877 +0000
@@ -1,25 +1,60 @@
# pyright: reportPrivateUsage=false
import sys
-from ctypes import (CFUNCTYPE, POINTER, c_bool, c_byte, c_char, c_char_p,
- c_double, c_float, c_int, c_long, c_longdouble, c_longlong,
- c_short, c_size_t, c_ssize_t, c_ubyte, c_uint, c_ulong,
- c_ulonglong, c_ushort, c_void_p, c_wchar, c_wchar_p,
- py_object)
+from ctypes import (
+ CFUNCTYPE,
+ POINTER,
+ c_bool,
+ c_byte,
+ c_char,
+ c_char_p,
+ c_double,
+ c_float,
+ c_int,
+ c_long,
+ c_longdouble,
+ c_longlong,
+ c_short,
+ c_size_t,
+ c_ssize_t,
+ c_ubyte,
+ c_uint,
+ c_ulong,
+ c_ulonglong,
+ c_ushort,
+ c_void_p,
+ c_wchar,
+ c_wchar_p,
+ py_object,
+)
from inspect import Parameter, signature
-from typing import (TYPE_CHECKING, Any, Callable, Dict, ForwardRef, Generator, Generic,
- List, Optional, Tuple, Type, TypeVar, Union, cast)
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ Callable,
+ Dict,
+ ForwardRef,
+ Generator,
+ Generic,
+ List,
+ Optional,
+ Tuple,
+ Type,
+ TypeVar,
+ Union,
+ cast,
+)
from typing_extensions import Annotated, ParamSpec, TypeAlias
-_T = TypeVar('_T')
+_T = TypeVar("_T")
if TYPE_CHECKING:
from ctypes import _CArgObject, _CData
-AnyCData = TypeVar('AnyCData', bound='_CData')
+AnyCData = TypeVar("AnyCData", bound="_CData")
if TYPE_CHECKING:
from ctypes import Array as _Array
from ctypes import _FuncPointer as _FuncPointer
@@ -31,29 +66,41 @@
# "In addition, if a function argument is explicitly declared to be a
# pointer type (such as POINTER(c_int)) in argtypes, an object of the
# pointed type (c_int in this case) can be passed to the function. ctypes
# will apply the required byref() conversion in this case automatically."
# also, current ctype typeshed thinks byref returns _CArgObject
- _PointerCompatible: TypeAlias = Union[_CArgObject, _Pointer[AnyCData], None, _Array[AnyCData], AnyCData]
+ _PointerCompatible: TypeAlias = Union[
+ _CArgObject, _Pointer[AnyCData], None, _Array[AnyCData], AnyCData
+ ]
_PyObject: TypeAlias = Union[py_object[_T], _T]
else:
# at runtime we don't really import those symbols
- class _Array(Generic[AnyCData]): ...
- class _Pointer(Generic[AnyCData]): ...
- class _PointerCompatible(Generic[AnyCData]): ...
- class _FuncPointer: ...
- class _PyObject(Generic[AnyCData]): ...
+ class _Array(Generic[AnyCData]):
+ ...
+
+ class _Pointer(Generic[AnyCData]):
+ ...
+
+ class _PointerCompatible(Generic[AnyCData]):
+ ...
+
+ class _FuncPointer:
+ ...
+
+ class _PyObject(Generic[AnyCData]):
+ ...
if sys.platform == "win32":
from ctypes import WINFUNCTYPE
else:
+
def WINFUNCTYPE(
- restype: Type['_CData'] | None,
- *argtypes: Type['_CData'],
+ restype: Type["_CData"] | None,
+ *argtypes: Type["_CData"],
use_errno: bool = False,
- use_last_error: bool = False
+ use_last_error: bool = False,
) -> Type[_FuncPointer]:
raise NotImplementedError
# ANNO_CONVETIBLE can be used to declare that a class have a `from_param`
@@ -63,12 +110,12 @@
# `CClass` as parameter type in stub function declaration and you will get what
# you want.
ANNO_BASIC = object()
ANNO_PARAMETER = ANNO_BASIC
-ANNO_RESULT = object() # ANNO_RESULT_ERRCHECK
-ANNO_RESULT_CONVERTER = object() # deprecated by ctypes
+ANNO_RESULT = object() # ANNO_RESULT_ERRCHECK
+ANNO_RESULT_CONVERTER = object() # deprecated by ctypes
ANNO_ARRAY = object()
ANNO_POINTER = object()
ANNO_CFUNC = object()
ANNO_WINFUNC = object()
ANNO_PYOBJ = object()
@@ -115,13 +162,21 @@
CSizeTParam = Annotated[Union[c_size_t, int], ANNO_BASIC, c_size_t]
CSsizeTParam = Annotated[Union[c_ssize_t, int], ANNO_BASIC, c_ssize_t]
CFloatParam = Annotated[Union[c_float, float], ANNO_BASIC, c_float]
CDoubleParam = Annotated[Union[c_double, float], ANNO_BASIC, c_double]
CLongDoubleParam = Annotated[Union[c_longdouble, float], ANNO_BASIC, c_longdouble]
-CCharPParam = Annotated[Union[_Array[c_wchar], c_char_p, bytes, None], ANNO_BASIC, c_char_p]
-CWcharPParam = Annotated[Union[_Array[c_wchar], c_wchar_p, str, None], ANNO_BASIC, c_wchar_p]
-CVoidPParam = Annotated[Union['_CArgObject', _Pointer[Any], _Array[Any], c_void_p, int, None], ANNO_BASIC, c_void_p]
+CCharPParam = Annotated[
+ Union[_Array[c_wchar], c_char_p, bytes, None], ANNO_BASIC, c_char_p
+]
+CWcharPParam = Annotated[
+ Union[_Array[c_wchar], c_wchar_p, str, None], ANNO_BASIC, c_wchar_p
+]
+CVoidPParam = Annotated[
+ Union["_CArgObject", _Pointer[Any], _Array[Any], c_void_p, int, None],
+ ANNO_BASIC,
+ c_void_p,
+]
# export Pointer, PointerCompatible, Array and FuncPointer annotation
CArray = Annotated[_Array[AnyCData], ANNO_ARRAY]
CPointer = Annotated[_Pointer[AnyCData], ANNO_POINTER]
@@ -132,210 +187,253 @@
# using decorators to declare errcheck and converter is convenient
# but you will need to use ANNO_RESULT instead if you need delayed evaluation
-_Params = ParamSpec('_Params')
-_OrigRet = TypeVar('_OrigRet')
-_NewRet = TypeVar('_NewRet')
-
-def with_errcheck(checker: Callable[[_OrigRet, Callable[..., _OrigRet], Tuple[Any, ...]], _NewRet]) -> Callable[[Callable[_Params, _OrigRet]], Callable[_Params, _NewRet]]:
- ''' Decorates a stub function with an error checker. '''
+_Params = ParamSpec("_Params")
+_OrigRet = TypeVar("_OrigRet")
+_NewRet = TypeVar("_NewRet")
+
+
+def with_errcheck(
+ checker: Callable[[_OrigRet, Callable[..., _OrigRet], Tuple[Any, ...]], _NewRet]
+) -> Callable[[Callable[_Params, _OrigRet]], Callable[_Params, _NewRet]]:
+ """Decorates a stub function with an error checker."""
+
def decorator(wrapped: Callable[_Params, _OrigRet]) -> Callable[_Params, _NewRet]:
def wrapper(*args: _Params.args, **kwargs: _Params.kwargs) -> _NewRet:
raise NotImplementedError
# attach original declaration and error checker to wrapper
- setattr(wrapper, '_decl_errcheck_', (wrapped, checker))
+ setattr(wrapper, "_decl_errcheck_", (wrapped, checker))
return wrapper
return decorator
+
# NOTE: Actually, converter is a deprecated form of `restype`.
# According to ctypes documentation:
# "It is possible to assign a callable Python object that is not a ctypes
# type, in this case the function is assumed to return a C int, and the
# callable will be called with this integer, allowing further processing
# or error checking. Using this is deprecated, for more flexible post
# processing or error checking use a ctypes data type as restype and
# assign a callable to the errcheck attribute."
-def with_converter(converter: Callable[[int], _NewRet]) -> Callable[[Callable[_Params, CIntResult]], Callable[_Params, _NewRet]]:
- ''' Decorates a stub function with a converter, its return type MUST be `r_int`. '''
+
+def with_converter(
+ converter: Callable[[int], _NewRet]
+) -> Callable[[Callable[_Params, CIntResult]], Callable[_Params, _NewRet]]:
+ """Decorates a stub function with a converter, its return type MUST be `r_int`."""
+
def decorator(wrapped: Callable[_Params, CIntResult]) -> Callable[_Params, _NewRet]:
def wrapper(*args: _Params.args, **kwargs: _Params.kwargs) -> _NewRet:
raise NotImplementedError
# attach original declaration and converter to wrapper
- setattr(wrapper, '_decl_converter_', (wrapped, converter))
+ setattr(wrapper, "_decl_converter_", (wrapped, converter))
return wrapper
return decorator
-def convert_annotation(typ: Any, global_ns: Optional[Dict[str, Any]] = None) -> Type[Any]:
- ''' Convert an annotation to effective runtime type. '''
+def convert_annotation(
+ typ: Any, global_ns: Optional[Dict[str, Any]] = None
+) -> Type[Any]:
+ """Convert an annotation to effective runtime type."""
if global_ns is None:
global_ns = globals()
if isinstance(typ, ForwardRef):
typ = typ.__forward_arg__
if isinstance(typ, str):
- try: typ = eval(typ, global_ns)
+ try:
+ typ = eval(typ, global_ns)
except Exception as exc:
- raise ValueError('Evaluation of delayed annotation failed!') from exc
-
- if not hasattr(typ, '__metadata__'):
+ raise ValueError("Evaluation of delayed annotation failed!") from exc
+
+ if not hasattr(typ, "__metadata__"):
return cast(Type[Any], typ)
# type is Annotated
ident, *detail = typ.__metadata__
if ident is ANNO_BASIC:
- ctyp, = detail
+ (ctyp,) = detail
return convert_annotation(ctyp, global_ns=global_ns)
elif ident is ANNO_RESULT:
ctyp, _ = detail
return convert_annotation(ctyp, global_ns=global_ns)
elif ident is ANNO_RESULT_CONVERTER:
return c_int
elif ident is ANNO_ARRAY:
- try: count, = detail
+ try:
+ (count,) = detail
except ValueError:
- raise ValueError('CArray needs to be annotated with its size')
- ctyp, = typ.__args__[0].__args__
+ raise ValueError("CArray needs to be annotated with its size")
+ (ctyp,) = typ.__args__[0].__args__
return cast(Type[Any], convert_annotation(ctyp, global_ns=global_ns) * count)
elif ident is ANNO_POINTER:
assert not detail
- ctyp, = typ.__args__[0].__args__
- return POINTER(convert_annotation(ctyp, global_ns=global_ns)) # pyright: ignore
+ (ctyp,) = typ.__args__[0].__args__
+ return POINTER(convert_annotation(ctyp, global_ns=global_ns)) # pyright: ignore
elif ident is ANNO_CFUNC:
if not detail:
- raise ValueError('CFuncPointer needs to be annotated with its signature')
+ raise ValueError("CFuncPointer needs to be annotated with its signature")
return CFUNCTYPE(*(convert_annotation(t, global_ns=global_ns) for t in detail))
elif ident is ANNO_WINFUNC:
if not detail:
- raise ValueError('WinFuncPointer needs to be annotated with its signature')
- return WINFUNCTYPE(*(convert_annotation(t, global_ns=global_ns) for t in detail))
+ raise ValueError("WinFuncPointer needs to be annotated with its signature")
+ return WINFUNCTYPE(
+ *(convert_annotation(t, global_ns=global_ns) for t in detail)
+ )
elif ident is ANNO_PYOBJ:
assert not detail
return py_object
else:
- raise ValueError(f'Unexpected annotated type {typ}')
-
-
-def get_resconv_info(typ: Any, global_ns: Optional[Dict[str, Any]] = None) -> Optional[Tuple[Any, Any]]:
+ raise ValueError(f"Unexpected annotated type {typ}")
+
+
+def get_resconv_info(
+ typ: Any, global_ns: Optional[Dict[str, Any]] = None
+) -> Optional[Tuple[Any, Any]]:
if global_ns is None:
global_ns = globals()
if isinstance(typ, str):
- try: typ = eval(typ, global_ns)
+ try:
+ typ = eval(typ, global_ns)
except Exception as exc:
- raise ValueError('Evaluation of delayed annotation failed!') from exc
-
- if not hasattr(typ, '__metadata__'):
+ raise ValueError("Evaluation of delayed annotation failed!") from exc
+
+ if not hasattr(typ, "__metadata__"):
return None
# type is Annotated
ident, *detail = typ.__metadata__
if ident not in (ANNO_RESULT, ANNO_RESULT_CONVERTER):
return None
if ident is ANNO_RESULT:
_, conv = detail
else:
- conv, = detail
+ (conv,) = detail
if isinstance(conv, str):
conv = eval(conv, global_ns)
if ident is ANNO_RESULT:
return (conv, None)
else:
return (None, conv)
-def convert_func_decl(decl: Callable[..., Any], global_ns: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
- ''' Converts a stub function to ctypes metadata. '''
+def convert_func_decl(
+ decl: Callable[..., Any], global_ns: Optional[Dict[str, Any]] = None
+) -> Dict[str, Any]:
+ """Converts a stub function to ctypes metadata."""
if global_ns is None:
global_ns = globals()
result: Dict[str, Any] = {}
errcheck = None
converter = None
while True:
- if hasattr(decl, '_decl_errcheck_'):
+ if hasattr(decl, "_decl_errcheck_"):
if errcheck is not None or converter is not None:
- raise ValueError('duplicate return conversion specifications, burst your legs')
- decl, errcheck = getattr(decl, '_decl_errcheck_')
+ raise ValueError(
+ "duplicate return conversion specifications, burst your legs"
+ )
+ decl, errcheck = getattr(decl, "_decl_errcheck_")
continue
- if hasattr(decl, '_decl_converter_'):
+ if hasattr(decl, "_decl_converter_"):
if errcheck is not None or converter is not None:
- raise ValueError('duplicate return conversion specifications, burst your legs')
- decl, converter = getattr(decl, '_decl_converter_')
+ raise ValueError(
+ "duplicate return conversion specifications, burst your legs"
+ )
+ decl, converter = getattr(decl, "_decl_converter_")
continue
break
sig = signature(decl)
- param_annos = [p.annotation for p in sig.parameters.values() if p.name != 'self']
+ param_annos = [p.annotation for p in sig.parameters.values() if p.name != "self"]
if all(anno is not Parameter.empty for anno in param_annos):
- result['argtypes'] = [convert_annotation(anno, global_ns=global_ns) for anno in param_annos] or None
+ result["argtypes"] = [
+ convert_annotation(anno, global_ns=global_ns) for anno in param_annos
+ ] or None
if sig.return_annotation is not Parameter.empty:
resconv = get_resconv_info(sig.return_annotation, global_ns=global_ns)
if resconv is not None:
if errcheck is not None or converter is not None:
- ValueError('duplicate return conversion specifications, burst your legs')
+ ValueError(
+ "duplicate return conversion specifications, burst your legs"
+ )
errcheck, converter = resconv
- result['restype'] = convert_annotation(sig.return_annotation, global_ns=global_ns)
-
- if errcheck is not None: result['errcheck'] = errcheck
- if converter is not None: result['restype'] = converter
+ result["restype"] = convert_annotation(
+ sig.return_annotation, global_ns=global_ns
+ )
+
+ if errcheck is not None:
+ result["errcheck"] = errcheck
+ if converter is not None:
+ result["restype"] = converter
return result
if TYPE_CHECKING:
from ctypes import CDLL, WinDLL
-_LibDecl = TypeVar('_LibDecl')
-
-def generate_metadata(decl_cls: Type[_LibDecl], global_ns: Optional[Dict[str, Any]] = None) -> Generator[Tuple[str, Dict[str, Any]], None, None]:
- ''' Generate ctypes metadata for a stub class. '''
+_LibDecl = TypeVar("_LibDecl")
+
+
+def generate_metadata(
+ decl_cls: Type[_LibDecl], global_ns: Optional[Dict[str, Any]] = None
+) -> Generator[Tuple[str, Dict[str, Any]], None, None]:
+ """Generate ctypes metadata for a stub class."""
if global_ns is None:
global_ns = globals()
for name in dir(decl_cls):
- if name.startswith('_'): continue
+ if name.startswith("_"):
+ continue
value = getattr(decl_cls, name)
- if not callable(value): continue
+ if not callable(value):
+ continue
yield name, convert_func_decl(value, global_ns=global_ns)
-def load_annotated_library(loader: 'Union[CDLL, WinDLL]', decl_cls: Type[_LibDecl], global_ns: Optional[Dict[str, Any]] = None) -> Tuple[_LibDecl, List[str]]:
- ''' Load a library and set signature metadata according to python type hints.
- `decl_cls` is a class which should only contain method declarations.
- Note: you should only name `self` as `self`, the converter depends on this.
- '''
+
+def load_annotated_library(
+ loader: "Union[CDLL, WinDLL]",
+ decl_cls: Type[_LibDecl],
+ global_ns: Optional[Dict[str, Any]] = None,
+) -> Tuple[_LibDecl, List[str]]:
+ """Load a library and set signature metadata according to python type hints.
+ `decl_cls` is a class which should only contain method declarations.
+ Note: you should only name `self` as `self`, the converter depends on this.
+ """
if global_ns is None:
global_ns = globals()
result = decl_cls()
missing: List[str] = []
for name, info in generate_metadata(decl_cls, global_ns=global_ns):
- try: func = getattr(loader, name)
+ try:
+ func = getattr(loader, name)
except AttributeError:
stub = getattr(result, name)
stub._missing_ = True
missing.append(name)
continue
@@ -347,87 +445,82 @@
return result, missing
__all__ = [
- 'ANNO_PARAMETER',
- 'AnyCData',
-
- 'c_bool',
- 'c_char',
- 'c_wchar',
- 'c_byte',
- 'c_ubyte',
- 'c_short',
- 'c_ushort',
- 'c_int',
- 'c_uint',
- 'c_long',
- 'c_ulong',
- 'c_longlong',
- 'c_ulonglong',
- 'c_size_t',
- 'c_ssize_t',
- 'c_float',
- 'c_double',
- 'c_longdouble',
- 'c_char_p',
- 'c_wchar_p',
- 'c_void_p',
- 'py_object',
-
- 'CBoolParam',
- 'CCharParam',
- 'CWcharParam',
- 'CByteParam',
- 'CUbyteParam',
- 'CShortParam',
- 'CUshortParam',
- 'CIntParam',
- 'CUintParam',
- 'CLongParam',
- 'CUlongParam',
- 'CLonglongParam',
- 'CUlonglongParam',
- 'CSizeTParam',
- 'CSsizeTParam',
- 'CFloatParam',
- 'CDoubleParam',
- 'CLongDoubleParam',
- 'CCharPParam',
- 'CWcharPParam',
- 'CVoidPParam',
-
- 'CBoolResult',
- 'CCharResult',
- 'CWcharResult',
- 'CByteResult',
- 'CUbyteResult',
- 'CShortResult',
- 'CUshortResult',
- 'CIntResult',
- 'CUintResult',
- 'CLongResult',
- 'CUlongResult',
- 'CLonglongResult',
- 'CUlonglongResult',
- 'CSizeTResult',
- 'CSsizeTResult',
- 'CFloatResult',
- 'CDoubleResult',
- 'CLongdoubleResult',
- 'CCharPResult',
- 'CWcharPResult',
- 'CVoidPResult',
-
- 'CArray',
- 'CPointer',
- 'CPointerParam',
- 'CFuncPointer',
- 'WinFuncPointer',
- 'CPyObject',
-
- 'convert_annotation',
- 'with_errcheck',
- 'with_converter',
- 'load_annotated_library',
+ "ANNO_PARAMETER",
+ "AnyCData",
+ "c_bool",
+ "c_char",
+ "c_wchar",
+ "c_byte",
+ "c_ubyte",
+ "c_short",
+ "c_ushort",
+ "c_int",
+ "c_uint",
+ "c_long",
+ "c_ulong",
+ "c_longlong",
+ "c_ulonglong",
+ "c_size_t",
+ "c_ssize_t",
+ "c_float",
+ "c_double",
+ "c_longdouble",
+ "c_char_p",
+ "c_wchar_p",
+ "c_void_p",
+ "py_object",
+ "CBoolParam",
+ "CCharParam",
+ "CWcharParam",
+ "CByteParam",
+ "CUbyteParam",
+ "CShortParam",
+ "CUshortParam",
+ "CIntParam",
+ "CUintParam",
+ "CLongParam",
+ "CUlongParam",
+ "CLonglongParam",
+ "CUlonglongParam",
+ "CSizeTParam",
+ "CSsizeTParam",
+ "CFloatParam",
+ "CDoubleParam",
+ "CLongDoubleParam",
+ "CCharPParam",
+ "CWcharPParam",
+ "CVoidPParam",
+ "CBoolResult",
+ "CCharResult",
+ "CWcharResult",
+ "CByteResult",
+ "CUbyteResult",
+ "CShortResult",
+ "CUshortResult",
+ "CIntResult",
+ "CUintResult",
+ "CLongResult",
+ "CUlongResult",
+ "CLonglongResult",
+ "CUlonglongResult",
+ "CSizeTResult",
+ "CSsizeTResult",
+ "CFloatResult",
+ "CDoubleResult",
+ "CLongdoubleResult",
+ "CCharPResult",
+ "CWcharPResult",
+ "CVoidPResult",
+ "CArray",
+ "CPointer",
+ "CPointerParam",
+ "CFuncPointer",
+ "WinFuncPointer",
+ "CPyObject",
+ "convert_annotation",
+ "with_errcheck",
+ "with_converter",
+ "load_annotated_library",
]
--- tests/ctyped/test_stub_conversion.py 2024-08-06 14:17:29.000000 +0000
+++ tests/ctyped/test_stub_conversion.py 2024-08-08 15:03:53.238072 +0000
@@ -6,13 +6,19 @@
from dictdiffer import diff as dictdiff
from clang.binder import Config as BinderConfig
from clang.binder import c_object_p
from clang.cindex import *
-from clang.cindex import (CCRStructure, Rewriter, _CXString, c_interop_string,
- cursor_visit_callback, fields_visit_callback,
- translation_unit_includes_callback)
+from clang.cindex import (
+ CCRStructure,
+ Rewriter,
+ _CXString,
+ c_interop_string,
+ cursor_visit_callback,
+ fields_visit_callback,
+ translation_unit_includes_callback,
+)
# Functions strictly alphabetical order.
# This is previous version of ctypes metadata, we check equality to this so
# that we can ensure `ctyped` doesn't break anything in its conversion.
@@ -302,56 +308,82 @@
]
# Sadly, ctypes provides no API to check if type is pointer or array.
# Here we use regex to check type name.
-arr_regex = re.compile(r'(?P<typ>[A-Za-z0-9_]+)_Array_(?P<count>[0-9]+)')
-ptr_regex = re.compile(r'LP_(?P<typ>[A-Za-z0-9_]+)')
+arr_regex = re.compile(r"(?P<typ>[A-Za-z0-9_]+)_Array_(?P<count>[0-9]+)")
+ptr_regex = re.compile(r"LP_(?P<typ>[A-Za-z0-9_]+)")
+
def is_ptr_type(typ: Any):
- return typ in (c_void_p, c_char_p, c_wchar_p) or ptr_regex.fullmatch(typ.__name__) is not None
+ return (
+ typ in (c_void_p, c_char_p, c_wchar_p)
+ or ptr_regex.fullmatch(typ.__name__) is not None
+ )
+
def is_arr_type(typ: Any):
return arr_regex.fullmatch(typ.__name__) is not None
+
# If we change a c_void_p parameter to a more exact pointer types, it
# should still be working.
def is_void_specialization(old_type: Any, new_type: Any):
return old_type == c_void_p and is_ptr_type(new_type)
def old_data_to_dict(data: List[Any]):
result: Dict[str, Any] = {}
- result['argtypes'], *data = data
- if not result['argtypes']: result['argtypes'] = None
- if data: result['restype'], *data = data
- else: result['restype'] = c_int
- if data: result['errcheck'], *data = data
+ result["argtypes"], *data = data
+ if not result["argtypes"]:
+ result["argtypes"] = None
+ if data:
+ result["restype"], *data = data
+ else:
+ result["restype"] = c_int
+ if data:
+ result["errcheck"], *data = data
return result
def is_incompatible_diff(diff: Any):
kind, path, detail = diff
- if kind == 'add': return True
+ if kind == "add":
+ return True
old_type, new_type = detail
- if is_void_specialization(old_type, new_type): return False
+ if is_void_specialization(old_type, new_type):
+ return False
return True
class TestStubConversion(unittest.TestCase):
def test_equality(self):
"""Ensure that ctyped does not break anything."""
- old_function_dict: Dict[str, Dict[str, Any]] = {name: old_data_to_dict(val) for name, *val in FUNCTION_LIST}
+ old_function_dict: Dict[str, Dict[str, Any]] = {
+ name: old_data_to_dict(val) for name, *val in FUNCTION_LIST
+ }
new_function_dict = BinderConfig.cfunc_metadata()
missing_functions = set(old_function_dict.keys())
stable_functions: Set[str] = set()
for new_func in new_function_dict:
if new_func in missing_functions:
missing_functions.remove(new_func)
stable_functions.add(new_func)
- type_diff = [list(dictdiff(old_function_dict[name], new_function_dict[name])) for name in stable_functions]
- type_break = [diffset for diffset in type_diff if diffset and any(is_incompatible_diff(diff) for diff in diffset)]
-
- self.assertTrue(not missing_functions, f'Functions {missing_functions} are missing after stub conversion!')
- self.assertTrue(not type_break, f'Type break happens after stub conversion: {type_break}!')
+ type_diff = [
+ list(dictdiff(old_function_dict[name], new_function_dict[name]))
+ for name in stable_functions
+ ]
+ type_break = [
+ diffset
+ for diffset in type_diff
+ if diffset and any(is_incompatible_diff(diff) for diff in diffset)
+ ]
+
+ self.assertTrue(
+ not missing_functions,
+ f"Functions {missing_functions} are missing after stub conversion!",
+ )
+ self.assertTrue(
+ not type_break, f"Type break happens after stub conversion: {type_break}!"
+ )
|
@llvm/pr-subscribers-clang Author: None (TsXor) ChangesThis is part 1 as described in #101784. Note: compared to #101784, I added a check that prevents Patch is 63.81 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/101941.diff 4 Files Affected:
diff --git a/clang/bindings/python/clang/binder.py b/clang/bindings/python/clang/binder.py
new file mode 100644
index 0000000000000..8cc661a097cb2
--- /dev/null
+++ b/clang/bindings/python/clang/binder.py
@@ -0,0 +1,804 @@
+# pyright: reportPrivateUsage=false
+
+# Enable delayed evaluation of function annotations.
+from __future__ import annotations
+
+import os
+from ctypes import cdll
+from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Type, Union
+
+from typing_extensions import Annotated
+
+from .ctyped import *
+from .ctyped import (ANNO_PARAMETER, ANNO_RESULT, ANNO_RESULT_CONVERTER,
+ generate_metadata)
+
+if TYPE_CHECKING:
+ from ctypes import CDLL
+ from types import EllipsisType
+
+ from .cindex import (CCRStructure, CodeCompletionResults,
+ CompilationDatabase, CompileCommands, Cursor,
+ CursorKind, Diagnostic, File, FileInclusion, Index,
+ Rewriter, SourceLocation, SourceRange, StrPath,
+ TemplateArgumentKind, Token, TranslationUnit)
+ from .cindex import Type as ASTType
+ from .cindex import _CXString, _CXUnsavedFile
+else:
+ EllipsisType = type(Ellipsis)
+
+
+# delayed imports, a list of import name and their alias
+# if alias is same as name, use `...`
+CINDEX_DELAYED_IMPORTS: List[Tuple[str, Union[str, EllipsisType]]] = [
+ ('CCRStructure', ...),
+ ('CodeCompletionResults', ...),
+ ('CompilationDatabase', ...),
+ ('CompileCommands', ...),
+ ('Cursor', ...),
+ ('CursorKind', ...),
+ ('Diagnostic', ...),
+ ('File', ...),
+ ('FileInclusion', ...),
+ ('Index', ...),
+ ('Rewriter', ...),
+ ('SourceLocation', ...),
+ ('SourceRange', ...),
+ ('TemplateArgumentKind', ...),
+ ('Token', ...),
+ ('TranslationUnit', ...),
+ ('Type', 'ASTType'),
+ ('_CXString', ...),
+ ('_CXUnsavedFile', ...),
+ ('c_interop_string', ...),
+]
+
+def load_cindex_types() -> None:
+ cindex_imports: Dict[str, Any] = {}
+ from . import cindex
+ for name, alias in CINDEX_DELAYED_IMPORTS:
+ if isinstance(alias, EllipsisType): alias = name
+ cindex_imports[alias] = getattr(cindex, name)
+ globals().update(cindex_imports)
+
+
+# ctypes doesn't implicitly convert c_void_p to the appropriate wrapper
+# 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**.
+CObjectP = CPointer[c_void_p]
+c_object_p: Type[CObjectP] = convert_annotation(CObjectP)
+
+
+# Register callback types
+TranslationUnitIncludesCallback = Annotated[CFuncPointer, None, c_object_p, CPointer['SourceLocation'], c_uint, py_object]
+CursorVisitCallback = Annotated[CFuncPointer, c_int, 'Cursor', 'Cursor', py_object]
+FieldsVisitCallback = Annotated[CFuncPointer, c_int, 'Cursor', py_object]
+
+# TODO: these lines should replace the definition in cindex.py
+#translation_unit_includes_callback: Type[CFuncPointer] = convert_annotation(TranslationUnitIncludesCallback, globals())
+#cursor_visit_callback: Type[CFuncPointer] = convert_annotation(CursorVisitCallback, globals())
+#fields_visit_callback: Type[CFuncPointer] = convert_annotation(FieldsVisitCallback, globals())
+
+
+# Misc object param/result types
+# A type may only have param type or result type, this is normal.
+ASTTypeResult = Annotated['ASTType', ANNO_RESULT, 'ASTType', 'ASTType.from_result']
+
+CInteropStringParam = Annotated[Union[str, bytes, None], ANNO_PARAMETER, 'c_interop_string']
+CInteropStringResult = Annotated[Optional[str], ANNO_RESULT, 'c_interop_string', 'c_interop_string.to_python_string']
+
+CXStringResult = Annotated[str, ANNO_RESULT, '_CXString', '_CXString.from_result']
+
+CompilationDatabaseParam = Annotated['CompilationDatabase', ANNO_PARAMETER, c_object_p]
+CompilationDatabaseResult = Annotated['CompilationDatabase', ANNO_RESULT, c_object_p, 'CompilationDatabase.from_result']
+
+CompileCommandsResult = Annotated['CompileCommands', ANNO_RESULT, c_object_p, 'CompileCommands.from_result']
+
+CursorResult = Annotated['Cursor', ANNO_RESULT, 'Cursor', 'Cursor.from_cursor_result']
+CursorNullableResult = Annotated[Optional['Cursor'], ANNO_RESULT, 'Cursor', 'Cursor.from_result']
+
+DiagnosticParam = Annotated['Diagnostic', ANNO_PARAMETER, c_object_p]
+
+FileResult = Annotated['File', ANNO_RESULT, c_object_p, 'File.from_result']
+
+TemplateArgumentKindResult = Annotated['TemplateArgumentKind', ANNO_RESULT_CONVERTER, 'TemplateArgumentKind.from_id']
+
+TranslationUnitParam = Annotated['TranslationUnit', ANNO_PARAMETER, c_object_p]
+
+
+# Functions strictly alphabetical order.
+# NOTE:
+# - These functions are stubs, they are not implemented, and is replaced by C functions at runtime.
+# - If Config.compatibility_check is set to `False`, then a function is allowed to be missing.
+# - If a function is missing in C library, it will not be replaced, thus causing NotImplementedError when called.
+# - Missing functions are given a `_missing_` attribute, you can check it with `hasattr(conf.lib.xxx, '_missing_')`.
+# - These stub functions are generated with a script from old data and manually corrected, so parameter names are missing.
+class LibclangExports:
+ def clang_annotateTokens(self, p1: TranslationUnit, p2: CPointerParam[Token], p3: CUlongParam, p4: CPointerParam[Cursor]) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_CompilationDatabase_dispose(self, p1: CompilationDatabaseParam) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_CompilationDatabase_fromDirectory(self, p1: CInteropStringParam, p2: CPointerParam[c_ulong]) -> CompilationDatabaseResult:
+ raise NotImplementedError
+
+ def clang_CompilationDatabase_getAllCompileCommands(self, p1: CompilationDatabaseParam) -> CompileCommandsResult:
+ raise NotImplementedError
+
+ def clang_CompilationDatabase_getCompileCommands(self, p1: CompilationDatabaseParam, p2: CInteropStringParam) -> CompileCommandsResult:
+ raise NotImplementedError
+
+ def clang_CompileCommands_dispose(self, p1: CObjectP) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_CompileCommands_getCommand(self, p1: CObjectP, p2: CUlongParam) -> CObjectP:
+ raise NotImplementedError
+
+ def clang_CompileCommands_getSize(self, p1: CObjectP) -> CUlongResult:
+ raise NotImplementedError
+
+ def clang_CompileCommand_getArg(self, p1: CObjectP, p2: CUlongParam) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_CompileCommand_getDirectory(self, p1: CObjectP) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_CompileCommand_getFilename(self, p1: CObjectP) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_CompileCommand_getNumArgs(self, p1: CObjectP) -> CUlongResult:
+ raise NotImplementedError
+
+ def clang_codeCompleteAt(self, p1: TranslationUnit, p2: CInteropStringParam, p3: CLongParam, p4: CLongParam, p5: CPointerParam[_CXUnsavedFile], p6: CLongParam, p7: CLongParam) -> CPointer[CCRStructure]:
+ raise NotImplementedError
+
+ def clang_codeCompleteGetDiagnostic(self, p1: CodeCompletionResults, p2: CLongParam) -> Diagnostic:
+ raise NotImplementedError
+
+ def clang_codeCompleteGetNumDiagnostics(self, p1: CodeCompletionResults) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_createIndex(self, p1: CLongParam, p2: CLongParam) -> CObjectP:
+ raise NotImplementedError
+
+ def clang_createTranslationUnit(self, p1: Index, p2: CInteropStringParam) -> CObjectP:
+ raise NotImplementedError
+
+ def clang_CXRewriter_create(self, p1: TranslationUnit) -> CObjectP:
+ raise NotImplementedError
+
+ def clang_CXRewriter_dispose(self, p1: Rewriter) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_CXRewriter_insertTextBefore(self, p1: Rewriter, p2: SourceLocation, p3: CInteropStringParam) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_CXRewriter_overwriteChangedFiles(self, p1: Rewriter) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_CXRewriter_removeText(self, p1: Rewriter, p2: SourceRange) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_CXRewriter_replaceText(self, p1: Rewriter, p2: SourceRange, p3: CInteropStringParam) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_CXRewriter_writeMainFileToStdOut(self, p1: Rewriter) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_CXXConstructor_isConvertingConstructor(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_CXXConstructor_isCopyConstructor(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_CXXConstructor_isDefaultConstructor(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_CXXConstructor_isMoveConstructor(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_CXXField_isMutable(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_CXXMethod_isConst(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_CXXMethod_isDefaulted(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_CXXMethod_isDeleted(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_CXXMethod_isCopyAssignmentOperator(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_CXXMethod_isMoveAssignmentOperator(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_CXXMethod_isExplicit(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_CXXMethod_isPureVirtual(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_CXXMethod_isStatic(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_CXXMethod_isVirtual(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_CXXRecord_isAbstract(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_Cursor_getStorageClass(self, p1: Cursor) -> CIntResult:
+ raise NotImplementedError
+
+ def clang_EnumDecl_isScoped(self, p1: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_defaultDiagnosticDisplayOptions(self) -> CUlongResult:
+ raise NotImplementedError
+
+ def clang_defaultSaveOptions(self, p1: TranslationUnit) -> CUlongResult:
+ raise NotImplementedError
+
+ def clang_disposeCodeCompleteResults(self, p1: CodeCompletionResults) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_disposeDiagnostic(self, p1: Diagnostic) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_disposeIndex(self, p1: Index) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_disposeString(self, p1: _CXString) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_disposeTokens(self, p1: TranslationUnit, p2: CPointer[Token], p3: CUintParam) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_disposeTranslationUnit(self, p1: TranslationUnit) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_equalCursors(self, p1: Cursor, p2: Cursor) -> bool:
+ raise NotImplementedError
+
+ def clang_equalLocations(self, p1: SourceLocation, p2: SourceLocation) -> bool:
+ raise NotImplementedError
+
+ def clang_equalRanges(self, p1: SourceRange, p2: SourceRange) -> bool:
+ raise NotImplementedError
+
+ def clang_equalTypes(self, p1: ASTType, p2: ASTType) -> bool:
+ raise NotImplementedError
+
+ def clang_formatDiagnostic(self, p1: Diagnostic, p2: CUlongParam) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_getAddressSpace(self, p1: ASTType) -> CIntResult:
+ raise NotImplementedError
+
+ def clang_getArgType(self, p1: ASTType, p2: CUlongParam) -> ASTTypeResult:
+ raise NotImplementedError
+
+ def clang_getArrayElementType(self, p1: ASTType) -> ASTTypeResult:
+ raise NotImplementedError
+
+ def clang_getArraySize(self, p1: ASTType) -> CLonglongResult:
+ raise NotImplementedError
+
+ def clang_getFieldDeclBitWidth(self, p1: Cursor) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_getCanonicalCursor(self, p1: Cursor) -> CursorResult:
+ raise NotImplementedError
+
+ def clang_getCanonicalType(self, p1: ASTType) -> ASTTypeResult:
+ raise NotImplementedError
+
+ def clang_getChildDiagnostics(self, p1: Diagnostic) -> CObjectP:
+ raise NotImplementedError
+
+ def clang_getCompletionAvailability(self, p1: CObjectP) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_getCompletionBriefComment(self, p1: CObjectP) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_getCompletionChunkCompletionString(self, p1: CObjectP, p2: CLongParam) -> CObjectP:
+ raise NotImplementedError
+
+ def clang_getCompletionChunkKind(self, p1: CObjectP, p2: CLongParam) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_getCompletionChunkText(self, p1: CObjectP, p2: CLongParam) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_getCompletionPriority(self, p1: CObjectP) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_getCString(self, p1: _CXString) -> CInteropStringResult:
+ raise NotImplementedError
+
+ def clang_getCursor(self, p1: TranslationUnit, p2: SourceLocation) -> Cursor:
+ raise NotImplementedError
+
+ def clang_getCursorAvailability(self, p1: Cursor) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_getCursorDefinition(self, p1: Cursor) -> CursorNullableResult:
+ raise NotImplementedError
+
+ def clang_getCursorDisplayName(self, p1: Cursor) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_getCursorExceptionSpecificationType(self, p1: Cursor) -> CIntResult:
+ raise NotImplementedError
+
+ def clang_getCursorExtent(self, p1: Cursor) -> SourceRange:
+ raise NotImplementedError
+
+ def clang_getCursorLexicalParent(self, p1: Cursor) -> CursorResult:
+ raise NotImplementedError
+
+ def clang_getCursorLinkage(self, p1: Cursor) -> CIntResult:
+ raise NotImplementedError
+
+ def clang_getCursorLocation(self, p1: Cursor) -> SourceLocation:
+ raise NotImplementedError
+
+ def clang_getCursorReferenced(self, p1: Cursor) -> CursorNullableResult:
+ raise NotImplementedError
+
+ def clang_getCursorReferenceNameRange(self, p1: Cursor, p2: CUlongParam, p3: CUlongParam) -> SourceRange:
+ raise NotImplementedError
+
+ def clang_getCursorResultType(self, p1: Cursor) -> ASTTypeResult:
+ raise NotImplementedError
+
+ def clang_getCursorSemanticParent(self, p1: Cursor) -> CursorResult:
+ raise NotImplementedError
+
+ def clang_getCursorSpelling(self, p1: Cursor) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_getCursorTLSKind(self, p1: Cursor) -> CIntResult:
+ raise NotImplementedError
+
+ def clang_getCursorType(self, p1: Cursor) -> ASTTypeResult:
+ raise NotImplementedError
+
+ def clang_getCursorUSR(self, p1: Cursor) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_Cursor_getMangling(self, p1: Cursor) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_getCXXAccessSpecifier(self, p1: Cursor) -> CUlongResult:
+ raise NotImplementedError
+
+ def clang_getDeclObjCTypeEncoding(self, p1: Cursor) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_getDiagnostic(self, p1: TranslationUnitParam, p2: CUlongParam) -> CObjectP:
+ raise NotImplementedError
+
+ def clang_getDiagnosticCategory(self, p1: Diagnostic) -> CUlongResult:
+ raise NotImplementedError
+
+ def clang_getDiagnosticCategoryText(self, p1: Diagnostic) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_getDiagnosticFixIt(self, p1: Diagnostic, p2: CUlongParam, p3: CPointerParam[SourceRange]) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_getDiagnosticInSet(self, p1: CObjectP, p2: CUlongParam) -> CObjectP:
+ raise NotImplementedError
+
+ def clang_getDiagnosticLocation(self, p1: Diagnostic) -> SourceLocation:
+ raise NotImplementedError
+
+ def clang_getDiagnosticNumFixIts(self, p1: Diagnostic) -> CUlongResult:
+ raise NotImplementedError
+
+ def clang_getDiagnosticNumRanges(self, p1: Diagnostic) -> CUlongResult:
+ raise NotImplementedError
+
+ def clang_getDiagnosticOption(self, p1: Diagnostic, p2: CPointerParam[_CXString]) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_getDiagnosticRange(self, p1: Diagnostic, p2: CUlongParam) -> SourceRange:
+ raise NotImplementedError
+
+ def clang_getDiagnosticSeverity(self, p1: Diagnostic) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_getDiagnosticSpelling(self, p1: Diagnostic) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_getElementType(self, p1: ASTType) -> ASTTypeResult:
+ raise NotImplementedError
+
+ def clang_getEnumConstantDeclUnsignedValue(self, p1: Cursor) -> CUlonglongResult:
+ raise NotImplementedError
+
+ def clang_getEnumConstantDeclValue(self, p1: Cursor) -> CLonglongResult:
+ raise NotImplementedError
+
+ def clang_getEnumDeclIntegerType(self, p1: Cursor) -> ASTTypeResult:
+ raise NotImplementedError
+
+ def clang_getExceptionSpecificationType(self, p1: ASTType) -> CIntResult:
+ raise NotImplementedError
+
+ def clang_getFile(self, p1: TranslationUnit, p2: CInteropStringParam) -> CObjectP:
+ raise NotImplementedError
+
+ def clang_getFileName(self, p1: File) -> CXStringResult:
+ raise NotImplementedError
+
+ def clang_getFileTime(self, p1: File) -> CUlongResult:
+ raise NotImplementedError
+
+ def clang_getIBOutletCollectionType(self, p1: Cursor) -> ASTTypeResult:
+ raise NotImplementedError
+
+ def clang_getIncludedFile(self, p1: Cursor) -> FileResult:
+ raise NotImplementedError
+
+ def clang_getInclusions(self, p1: TranslationUnit, p2: TranslationUnitIncludesCallback, p3: CPyObject[List[FileInclusion]]) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_getInstantiationLocation(self, p1: SourceLocation, p2: CPointerParam[CObjectP], p3: CPointerParam[c_ulong], p4: CPointerParam[c_ulong], p5: CPointerParam[c_ulong]) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_getLocation(self, p1: TranslationUnit, p2: File, p3: CUlongParam, p4: CUlongParam) -> SourceLocation:
+ raise NotImplementedError
+
+ def clang_getLocationForOffset(self, p1: TranslationUnit, p2: File, p3: CUlongParam) -> SourceLocation:
+ raise NotImplementedError
+
+ def clang_getNullCursor(self) -> Cursor:
+ raise NotImplementedError
+
+ def clang_getNumArgTypes(self, p1: ASTType) -> CUlongResult:
+ raise NotImplementedError
+
+ def clang_getNumCompletionChunks(self, p1: CObjectP) -> CLongResult:
+ raise NotImplementedError
+
+ def clang_getNumDiagnostics(self, p1: TranslationUnitParam) -> CUlongResult:
+ raise NotImplementedError
+
+ def clang_getNumDiagnosticsInSet(self, p1: CObjectP) -> CUlongResult:
+ raise NotImplementedError
+
+ def clang_getNumElements(self, p1: ASTType) -> CLonglongResult:
+ raise NotImplementedError
+
+ def clang_getNumOverloadedDecls(self, p1: Cursor) -> CUlongResult:
+ raise NotImplementedError
+
+ def clang_getOverloadedDecl(self, p1: Cursor, p2: CUlongParam) -> CursorResult:
+ raise NotImplementedError
+
+ def clang_getPointeeType(self, p1: ASTType) -> ASTTypeResult:
+ raise NotImplementedError
+
+ def clang_getRange(self, p1: SourceLocation, p2: SourceLocation) -> SourceRange:
+ raise NotImplementedError
+
+ def clang_getRangeEnd(self, p1: SourceRange) -> SourceLocation:
+ raise NotImplementedError
+
+ def clang_getRangeStart(self, p1: SourceRange) -> SourceLocation:
+ raise NotImplementedError
+
+ d...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for splitting that large PR into something smaller. That said, 1.6k lines of changes is no small change either.
This PR needs more high-level explanation of what you try to achieve and how. At the moment I'm not sold we want to go in this direction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see value in annotating exported C functions themselves (binder.py
), because they are wrapped by cindex.py
. From maintenance perspective I'd rather leave # type: ignore
at the call sites of those functions, than accept a whole new pile of stubs. Users of cindex.py
won't notice either way, because I don't think they need to interact with C functions directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I think is just contradictory: I don't see value in leaving # type: ignore
at the call sites of those functions everywhere. If you are satisfied with this, why don't we just make a cindex.pyi
stub independent from cindex.py
? Users of cindex.py
won't notice either way.
I chose this metadata reflection way like pydantic
just because it is beneficial to this binding. Having typed C functions can let us make less errors and easier to review.
The ultimate goal of introducing inline typing is to benefit both the project developers and users. I'm not being sarcastic. If we are really satisfied with current situation, we should really consider using separated pyi
stubs instead of ignoring every call. Simply run stubgen
on #101784 and do some little fixes, a stub is done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact there are even some C functions used implicitly here: they are not declared in functionList
, and relies on default restype
as c_int
to work. (Including clang_getCursorTLSKind
, which causes segfault here, but I'm not sure if absense of signature is the cause.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding the segfault: this was a purely local problem for me, the function runs just fine for me now, and has always run fine in tests in the CI.
I only left that comment to indicate that I couldn't test that specific part.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the information, but I want to point out the bug #101548 fixed is actually avoidable by annotating exported C functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file seems to implement a whole abstraction layer for annotations. I'd like to understand what the benefits are, because I see a non-trivial amount of complexity here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I collected a document at https://gist.github.com/TsXor/97f73ec170c223b1ba21fb78742c2489 .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The complexity here is because conversion rules in ctypes
is just complex itself. You have 2 ways to do 1 thing there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with what Endill said: this is a rather big change and I'm not sure I see it adding enough value to justify this.
It also adds quite some complexity on top of the otherwise relatively light-weight Python bindings. I generally like seeing changes towards better typing annotations, but this is not something we need to push through no-matter-what and e.g. the type: ignore
s, while not exactly pretty, are "good enough" for our case.
Another reason I'm hesitant to support this, is that the bindings currently depend only on the Python standard library, and adding e.g. ctyped
would break this. Adding outside dependencies is not strictly a problem, but again any change to this would imo need a good justification that I don't see at the moment.
Edit: sorry, I got confused during review, thought the relative .ctyped
import was an outside module import. Dismiss the "outside dependencies" comment
3e12ffd
to
cbe82fc
Compare
I've been staring at Status quo
class SourceLocation(Structure):
_fields_ = [("ptr_data", c_void_p * 2), ("int_data", c_uint)]
Recent developments
Proposed direction
# bad
def get_template_argument_kind(self, num: int) -> TemplateArgumentKind:
return conf.lib.clang_Cursor_getTemplateArgumentKind(self, num) # type: ignore [no-any-return]
# good
def get_template_argument_kind(self, num: int) -> TemplateArgumentKind:
return TemplateArgumentKind.from_id(conf.lib.clang_Cursor_getTemplateArgumentKind(self, num))
# bad
def start(self) -> SourceLocation:
return conf.lib.clang_getRangeStart(self) # type: ignore [no-any-return]
# good
def start(self) -> SourceLocation:
return SourceLocation(conf.lib.clang_getRangeStart(self))
I hope this long write-up help us to get on the same page, and find a way forward. |
I still think we can still do something to stop #101548 from happening again. Here is a script that can locate all import ast, sys
from typing import List, Optional, Set
from clang import cindex
if sys.version_info < (3, 9):
from astunparse import unparse
ast.unparse = unparse
del unparse
class CCallVisitor(ast.NodeVisitor):
lib_node: str
attr_set: Set[str]
error_nodes: List[ast.expr]
def __init__(self, lib_node: str, attr_set: Set[str]):
self.lib_node = lib_node
self.attr_set = attr_set
self.error_nodes = []
def check_target_call(self, node: ast.expr) -> Optional[str]:
node_text = ast.unparse(node).strip()
if not node_text.startswith(self.lib_node):
return None
return node_text
def visit_Call(self, node: ast.Call) -> None:
func = node.func
node_text = self.check_target_call(func)
if node_text is not None:
if not (isinstance(func, ast.Attribute) and func.attr in self.attr_set):
self.error_nodes.append(node)
with open(cindex.__file__, 'rt') as modfp:
modtxt = modfp.read()
modast = ast.parse(modtxt, mode='exec')
func_checker = CCallVisitor(
'conf.lib',
{fn[0] for fn in cindex.functionList},
)
func_checker.visit(modast)
for node in func_checker.error_nodes:
print(f'lineno={node.lineno}, col_offset={node.col_offset}, {ast.unparse(node)}') |
I think this can be prevented by additional testing. Feel free to submit your suggestion as an additional test. |
@Endilll thanks a lot for the summary! Turning this into documentation also sounds like a good idea. 15. & 16. fully agree it would be nicer to go without using this 17. this does not work out of the box, at least not without further changes. E.g. the exact example you gave there results in an error for me. Regarding lib function calls for functions not declared in |
If you mean |
That one worked fine for me (need the args passed as well, but that's it), I meant the Good point about the restype for |
I don't quite get what 17 meant. As far as I know about ctypes, |
Yes, I'd like us to stop relying on that for the same reason I don't like
Yes, 17 is about type errors when a structural type is returned. Good point about |
This is part 1 as described in #101784.
I moved
LibclangExports
,LibclangError
and modifiedConfig
class to a new file:binder.py
. It can now be used bycindex.py
with a simplefrom .binder import Config
.This PR doesn't modify any existing files, so it is safe to merge. However, @DeinAlptraum will need to manually delete
functionList
,Config
class andLibclangError
and addfrom .binder import Config
to utilize its typing benefits.Note: compared to #101784, I added a check that prevents
ctyped
from importingWINFUNCTYPE
when not on windows, which should fix failing linux tests.