修复了大量存在的问题,增加了假鸭子类型等等机制

This commit is contained in:
2026-06-25 14:49:46 +08:00
parent 19f2787db0
commit d88d11b646
827 changed files with 32617 additions and 18316 deletions

View File

@@ -10,36 +10,36 @@ from lib.core.SymbolData import (
FuncSymbolData, DefineSymbolData, AnonymousTypeData
)
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.SymbolUtils import AnnotationContainsTType, CheckAnnotationHasCInline, IsTModule
from lib.includes import t
from lib.core.SymbolUtils import AnnotationContainsTType, CheckAnnotationHasCInline
class ASTSymbolExtractor:
"""从 Python 源文件的 AST 中提取所有符号信息"""
def __init__(self, symbol_table: SymbolTable):
self._symtab = symbol_table
def __init__(self, symbol_table: SymbolTable) -> None:
self._symtab: SymbolTable = symbol_table
def extract(self, file_path: str) -> ModuleSymbols:
"""提取文件中的所有符号信息"""
with open(file_path, 'r', encoding='utf-8') as f:
code = f.read()
tree = ast.parse(code)
code: str = f.read()
tree: ast.Module = ast.parse(code)
result = ModuleSymbols(file_path=file_path)
result: ModuleSymbols = ModuleSymbols(file_path=file_path)
# 第一步:收集所有类的成员和匿名类型
class_members = {}
class_members: dict[str, dict[str, CTypeInfo]] = {}
for node in tree.body:
if isinstance(node, ast.ClassDef):
members = {}
members: dict[str, CTypeInfo] = {}
self._collect_members(node, members, result.anonymous_types)
class_members[node.name] = members
# 第二步:从每个顶层节点提取符号信息
for node in tree.body:
if isinstance(node, ast.ClassDef):
members_info = class_members.get(node.name, {})
members_info: dict[str, CTypeInfo] = class_members.get(node.name, {})
result.classes.append(self._extract_class(node, members_info))
elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
self._extract_ann_assign(node, result)
@@ -52,46 +52,59 @@ class ASTSymbolExtractor:
# 成员收集(递归处理嵌套匿名类)
# ------------------------------------------------------------------
def _collect_members(self, class_node, members, anonymous_types, prefix=''):
def _collect_members(self, class_node: ast.ClassDef, members: dict[str, CTypeInfo], anonymous_types: dict[str, AnonymousTypeData], prefix: str = '') -> None:
"""递归收集类成员,包括嵌套匿名类型"""
for item in class_node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
member_name = item.target.id
full_name = f'{prefix}{member_name}' if prefix else member_name
member_type = CTypeInfo.FromNode(item.annotation, self._symtab)
member_name: str = item.target.id
full_name: str = f'{prefix}{member_name}' if prefix else member_name
member_type: CTypeInfo | None = CTypeInfo.FromNode(item.annotation, self._symtab)
if member_type is None:
member_type = CTypeInfo()
member_type.BaseType = t.CInt()
is_ptr = member_type.IsPtr
is_ptr: bool = member_type.IsPtr
if isinstance(item.annotation, ast.BinOp):
annotation_str = ast.dump(item.annotation)
annotation_str: str = ast.dump(item.annotation)
if 'CPtr' in annotation_str:
is_ptr = True
members[full_name] = member_type.Copy()
elif isinstance(item, ast.ClassDef):
is_anonymous = any(
is_anonymous: bool = any(
any(AnnotationContainsTType(base, 'Anonymous') for base in item.bases)
) if item.bases else False
if is_anonymous:
is_union = any(
is_union: bool = any(
any(AnnotationContainsTType(base, 'CUnion') for base in item.bases)
)
# 也检查装饰器形式 @t.CUnion
if not is_union and hasattr(item, 'decorator_list') and item.decorator_list:
for deco in item.decorator_list:
if isinstance(deco, ast.Attribute) and hasattr(deco.value, 'id') and IsTModule(deco.value.id, self._symtab) and deco.attr == 'CUnion':
is_union = True
break
elif isinstance(deco, ast.Name):
cls2: type | None = getattr(t, deco.id, None)
if cls2 is None and hasattr(self._symtab, '_t_type_symbols'):
cls2 = self._symtab._t_type_symbols.get(deco.id)
if cls2 is not None and isinstance(cls2, type) and issubclass(cls2, t.CUnion):
is_union = True
break
nested_name = f'{prefix}{item.name}' if prefix else item.name
nested_name: str = f'{prefix}{item.name}' if prefix else item.name
members[nested_name] = CTypeInfo()
members[nested_name].BaseType = f'union {item.name}' if is_union else f'struct {item.name}'
members[nested_name].PtrCount = 0
members[nested_name].ArrayDims = []
new_prefix = f'{prefix}{item.name}.' if prefix else f'{item.name}.'
new_prefix: str = f'{prefix}{item.name}.' if prefix else f'{item.name}.'
self._collect_members(item, members, anonymous_types, new_prefix)
anonymous_members = {}
anonymous_members: dict[str, CTypeInfo] = {}
for full_name, member_info in members.items():
if full_name.startswith(f"{nested_name}."):
member_name = full_name[len(nested_name) + 1:]
member_name: str = full_name[len(nested_name) + 1:]
anonymous_members[member_name] = member_info
if item.name not in anonymous_types:
@@ -106,28 +119,47 @@ class ASTSymbolExtractor:
# 类符号提取
# ------------------------------------------------------------------
def _extract_class(self, node, members_info) -> ClassSymbolData:
def _extract_class(self, node: ast.ClassDef, members_info: dict[str, CTypeInfo]) -> ClassSymbolData:
"""从 ClassDef 节点提取类符号数据"""
type_kind = 'struct'
is_cpython_object = False
is_packed = False
type_kind: str = 'struct'
is_cpython_object: bool = False
is_packed: bool = False
# 检查装饰器
if hasattr(node, 'decorator_list') and node.decorator_list:
for decorator in node.decorator_list:
if isinstance(decorator, ast.Attribute):
if (hasattr(decorator.value, 'id') and
decorator.value.id == 't' and
decorator.attr == 'Object'):
is_cpython_object = True
break
IsTModule(decorator.value.id, self._symtab)):
if decorator.attr == 'Object':
is_cpython_object = True
elif decorator.attr == 'CUnion':
type_kind = 'union'
elif decorator.attr in ('CEnum', 'REnum'):
type_kind = 'enum'
elif decorator.attr == 'CStruct':
type_kind = 'struct'
elif isinstance(decorator, ast.Name):
# from t import CStruct / CUnion / CEnum / REnum
cls: type | None = getattr(t, decorator.id, None)
if cls is None and hasattr(self._symtab, '_t_type_symbols'):
cls = self._symtab._t_type_symbols.get(decorator.id)
if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType):
if issubclass(cls, t.CUnion):
type_kind = 'union'
elif issubclass(cls, (t.CEnum, t.REnum)):
type_kind = 'enum'
elif issubclass(cls, t.CStruct):
type_kind = 'struct'
elif decorator.id == 'Object':
is_cpython_object = True
elif isinstance(decorator, ast.Call):
if isinstance(decorator.func, ast.Attribute):
if hasattr(decorator.func.value, 'id') and decorator.func.value.id == 'c' and decorator.func.attr == 'Attribute':
for arg in decorator.args:
if isinstance(arg, ast.Attribute):
if isinstance(arg.value, ast.Attribute):
if hasattr(arg.value.value, 'id') and arg.value.value.id == 't' and arg.value.attr == 'attr' and arg.attr == 'packed':
if hasattr(arg.value.value, 'id') and IsTModule(arg.value.value.id, self._symtab) and arg.value.attr == 'attr' and arg.attr == 'packed':
is_packed = True
# 检查基类
@@ -149,19 +181,19 @@ class ASTSymbolExtractor:
type_kind = 'exception'
break
elif isinstance(base, ast.Name):
base_entry = self._symtab.get(base.id)
base_entry: CTypeInfo | None = self._symtab.get(base.id)
if base_entry and base_entry.IsExceptionClass:
type_kind = 'exception'
break
# 提取枚举成员
enum_members = []
enum_members: list[tuple[str, int, int]] = []
if type_kind == 'enum':
next_enum_value = 0
next_enum_value: int = 0
for item in node.body:
if isinstance(item, ast.Assign):
if len(item.targets) == 1 and isinstance(item.targets[0], ast.Name):
member_name = item.targets[0].id
member_name: str = item.targets[0].id
if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
next_enum_value = item.value.value + 1
else:
@@ -169,7 +201,7 @@ class ASTSymbolExtractor:
enum_members.append((member_name, next_enum_value - 1, item.lineno))
elif isinstance(item, ast.AnnAssign):
if isinstance(item.target, ast.Name):
member_name = item.target.id
member_name: str = item.target.id
if item.value:
if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
next_enum_value = item.value.value + 1
@@ -193,12 +225,12 @@ class ASTSymbolExtractor:
# AnnAssign 提取typedef / define
# ------------------------------------------------------------------
def _extract_ann_assign(self, node, result: ModuleSymbols):
def _extract_ann_assign(self, node: ast.AnnAssign, result: ModuleSymbols) -> None:
"""从 AnnAssign 节点提取 typedef 或 define 数据"""
var_name = node.target.id
has_cdefine = AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False
has_postdef = AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False
has_ctypedef = AnnotationContainsTType(node.annotation, 'CTypedef') if node.annotation else False
var_name: str = node.target.id
has_cdefine: bool = AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False
has_postdef: bool = AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False
has_ctypedef: bool = AnnotationContainsTType(node.annotation, 'CTypedef') if node.annotation else False
if has_cdefine:
result.defines.append(DefineSymbolData(
@@ -221,11 +253,11 @@ class ASTSymbolExtractor:
# 函数提取
# ------------------------------------------------------------------
def _extract_function(self, node) -> FuncSymbolData:
def _extract_function(self, node: ast.FunctionDef) -> FuncSymbolData:
"""从 FunctionDef 节点提取函数符号数据"""
params = [(arg.arg, arg.annotation) for arg in node.args.args]
is_variadic = node.args.vararg is not None
is_inline = CheckAnnotationHasCInline(node.returns)
params: list[tuple[str, ast.AST | None]] = [(arg.arg, arg.annotation) for arg in node.args.args]
is_variadic: bool = node.args.vararg is not None
is_inline: bool = CheckAnnotationHasCInline(node.returns)
return FuncSymbolData(
name=node.name,