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

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

@@ -3,9 +3,16 @@ from __future__ import annotations
import ast
import sys
import os
import importlib
import types
from typing import Any
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.SymbolUtils import IsTModule
from lib.includes import t
from lib.includes.t import CType, CEnum
from lib.constants.config import mode as _config_mode
from lib.core.VLogger import get_logger as _vlog
class AnnotationLoaderMixin:
@@ -14,7 +21,7 @@ class AnnotationLoaderMixin:
提供注解模块/文件的加载与符号表注册能力。
"""
def _LoadAnnotationModule(self, ModuleName: str, library_name: str = None, parse_method: str = 'auto'):
def _LoadAnnotationModule(self, ModuleName: str, library_name: str | None = None, parse_method: str = 'auto') -> int:
"""加载注解模块并将 CType 子类注册为 typedef
支持两种模式:
@@ -29,25 +36,20 @@ class AnnotationLoaderMixin:
- 'file': 强制使用 AST 模式(文件路径)
- 'module': 强制使用 importlib 模式(模块名)
"""
import importlib
import sys
import os
CurrentDir = os.path.dirname(os.path.abspath(__file__))
ProjectRoot = os.path.dirname(os.path.dirname(os.path.dirname(CurrentDir)))
CurrentDir: str = os.path.dirname(os.path.abspath(__file__))
ProjectRoot: str = os.path.dirname(os.path.dirname(os.path.dirname(CurrentDir)))
if ProjectRoot not in sys.path:
sys.path.insert(0, ProjectRoot)
def register_to_symboltable(module, lib_name: str = None, source_file: str = None):
def register_to_symboltable(module: types.ModuleType, lib_name: str | None = None, source_file: str | None = None) -> int:
"""将模块中的 CType 子类和 CEnum 类注册到符号表"""
from lib.includes.t import CType, CEnum
count = 0
count: int = 0
for AttrName in dir(module):
attr = getattr(module, AttrName)
attr: type = getattr(module, AttrName)
# 优先检查是否是 CEnum 子类(枚举)
if isinstance(attr, type) and issubclass(attr, CEnum) and attr is not CEnum:
# 注册枚举类型
EnumNode = CTypeInfo()
EnumNode: CTypeInfo = CTypeInfo()
EnumNode.Name = AttrName
EnumNode.BaseType = t.CEnum()
EnumNode.IsEnum = True
@@ -57,8 +59,8 @@ class AnnotationLoaderMixin:
EnumNode.file = source_file
self.SymbolTable.insert(AttrName, EnumNode)
if lib_name:
FullName = f'{lib_name}.{AttrName}'
full_EnumNode = CTypeInfo()
FullName: str = f'{lib_name}.{AttrName}'
full_EnumNode: CTypeInfo = CTypeInfo()
full_EnumNode.Name = FullName
full_EnumNode.IsEnum = True
full_EnumNode.set('enum_class', attr)
@@ -69,9 +71,9 @@ class AnnotationLoaderMixin:
# 枚举成员也需要注册
for MemberName in dir(attr):
if not MemberName.startswith('_'):
member = getattr(attr, MemberName, None)
member: int = getattr(attr, MemberName, None)
if isinstance(member, int):
MemberNode = CTypeInfo()
MemberNode: CTypeInfo = CTypeInfo()
MemberNode.Name = MemberName
MemberNode.BaseType = t.CEnum(AttrName)
MemberNode.value = member
@@ -90,23 +92,23 @@ class AnnotationLoaderMixin:
# 继承 CType 的类是类型别名typedef不是结构体
# 使用手动指定的库名称作为前缀
if lib_name:
FullName = f'{lib_name}.{AttrName}'
FullName: str = f'{lib_name}.{AttrName}'
else:
FullName = AttrName
# 同时注册带前缀和不带前缀的名称(都是 typedef 别名)
TypedefNode = CTypeInfo()
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = AttrName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = attr().CName
TypedefNode.OriginalType = attr.__name__
TypedefNode.set('source', 'annotation_module')
TypedefNode.library_name = lib_name
TypedefNode.file = source_file
self.SymbolTable.insert(AttrName, TypedefNode)
if lib_name and FullName != AttrName:
FullTypedef_node = CTypeInfo()
FullTypedef_node: CTypeInfo = CTypeInfo()
FullTypedef_node.Name = FullName
FullTypedef_node.IsTypedef = True
FullTypedef_node.OriginalType = attr().CName
FullTypedef_node.OriginalType = attr.__name__
FullTypedef_node.set('source', 'annotation_module')
FullTypedef_node.library_name = lib_name
FullTypedef_node.file = source_file
@@ -114,29 +116,29 @@ class AnnotationLoaderMixin:
count += 1
# 检查是否是下划线前缀的 CType 子类(如 _CTypedef -> CTypedef
elif AttrName.startswith('_') and len(AttrName) > 1:
PublicName = AttrName[1:]
PublicAttr = getattr(module, PublicName, None)
PublicName: str = AttrName[1:]
PublicAttr: type | None = getattr(module, PublicName, None)
if PublicAttr is not None and not isinstance(attr, type):
continue
if isinstance(attr, type) and issubclass(attr, CType) and attr is not CType:
if not self.SymbolTable.has(PublicName):
if lib_name:
FullName = f'{lib_name}.{PublicName}'
FullName: str = f'{lib_name}.{PublicName}'
else:
FullName = PublicName
TypedefNode = CTypeInfo()
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = PublicName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = attr().CName
TypedefNode.OriginalType = attr.__name__
TypedefNode.set('source', 'annotation_module')
TypedefNode.library_name = lib_name
TypedefNode.file = source_file
self.SymbolTable.insert(PublicName, TypedefNode)
if lib_name and FullName != PublicName:
FullTypedef_node = CTypeInfo()
FullTypedef_node: CTypeInfo = CTypeInfo()
FullTypedef_node.Name = FullName
FullTypedef_node.IsTypedef = True
FullTypedef_node.OriginalType = attr().CName
FullTypedef_node.OriginalType = attr.__name__
FullTypedef_node.set('source', 'annotation_module')
FullTypedef_node.library_name = lib_name
FullTypedef_node.file = source_file
@@ -145,7 +147,7 @@ class AnnotationLoaderMixin:
return count
# 确定解析方法
use_file_mode = False
use_file_mode: bool = False
if parse_method == 'file':
use_file_mode = True
elif parse_method == 'module':
@@ -154,7 +156,7 @@ class AnnotationLoaderMixin:
use_file_mode = os.path.isfile(ModuleName)
# 确定库名称
lib_name = library_name
lib_name: str | None = library_name
if lib_name is None:
if use_file_mode:
# 从文件路径推断库名称
@@ -168,8 +170,8 @@ class AnnotationLoaderMixin:
# AST 模式:使用 AST 解析文件,不执行代码
try:
# 临时保存当前的 EmbeddedAssignments 和 TypedefAssignments
saved_embedded = self.EmbeddedAssignments.copy()
saved_typedef = self.TypedefAssignments.copy()
saved_embedded: dict = self.EmbeddedAssignments.copy()
saved_typedef: dict = self.TypedefAssignments.copy()
# 清空 PD 收集(注解文件不应该收集 PD 语句)
self.EmbeddedAssignments = {}
@@ -185,12 +187,12 @@ class AnnotationLoaderMixin:
self.TypedefAssignments = saved_typedef
# 从文件名推断类型前缀(如 test_t -> test_t.xxx
TypePrefix = lib_name
count = 0
TypePrefix: str = lib_name
count: int = 0
# 检查符号表中新增的类型(注解文件解析后的所有 struct 类型)
# 需要检查这些类型是否继承自 CType如果是则是 typedef 别名
new_types = []
new_types: list[str] = []
for TypeName, TypeInfo in self.SymbolTable.items():
if TypeInfo.IsStruct:
new_types.append(TypeName)
@@ -198,18 +200,18 @@ class AnnotationLoaderMixin:
# 再次遍历 AST检测继承自 CType 的类
try:
with open(ModuleName, 'r', encoding='utf-8') as f:
ann_content = f.read()
ann_tree = ast.parse(ann_content)
ann_content: str = f.read()
ann_tree: ast.Module = ast.parse(ann_content)
for node in ann_tree.body:
if isinstance(node, ast.ClassDef):
ClassName = node.name
ClassName: str = node.name
# 检查是否有基类
for base in node.bases:
if isinstance(base, ast.Name) and base.id == 'CType':
# 这个类继承自 CType是 typedef 别名
# 更新符号表中的类型为 typedef
if self.SymbolTable.has(ClassName):
TypedefNode = CTypeInfo()
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = ClassName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = self.SymbolTable[ClassName].get('OriginalType', f'struct {ClassName}')
@@ -217,17 +219,15 @@ class AnnotationLoaderMixin:
TypedefNode.set('is_ctype_subclass', True)
self.SymbolTable.insert(ClassName, TypedefNode)
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _ConfigMode
if _ConfigMode == "strict":
if _config_mode == "strict":
raise
_vlog().warning(f"解析注解文件类型定义失败: {_e}", "Exception")
# 为所有新增的类型添加库前缀和 source 标记
for TypeName in new_types:
# 添加带前缀的类型名
FullName = f'{TypePrefix}.{TypeName}'
TypeInfo = self.SymbolTable[TypeName].copy()
FullName: str = f'{TypePrefix}.{TypeName}'
TypeInfo: CTypeInfo | dict[str, Any] = self.SymbolTable[TypeName].copy()
TypeInfo['source'] = 'annotation_module'
TypeInfo['original_name'] = TypeName
self.SymbolTable.insert(FullName, TypeInfo)
@@ -235,23 +235,23 @@ class AnnotationLoaderMixin:
# 再次遍历 AST查找注解文件中的 typedef 语句AnnAssign with t.CTypedef
# 注意:必须在类定义处理完之后再处理 typedef
typedef_annots = []
typedef_annots: list[tuple[str, str]] = []
# 查找 CEnum 成员变量AnnAssign with t.CEnum | t.State 或 t.CEnum
cEnumMembers = []
cEnumMembers: list[tuple[str, int | None]] = []
try:
with open(ModuleName, 'r', encoding='utf-8') as f:
ann_content = f.read()
ann_tree = ast.parse(ann_content)
ann_content: str = f.read()
ann_tree: ast.Module = ast.parse(ann_content)
for node in ann_tree.body:
# 检测 xxx: t.CEnum 形式的枚举成员变量
if isinstance(node, ast.AnnAssign):
if isinstance(node.target, ast.Name) and node.annotation:
TargetName = node.target.id
TargetName: str = node.target.id
# 检查注解是否是 BinOp (Union) 或直接是 Attribute
IsCenum = False
IsCenum: bool = False
if isinstance(node.annotation, ast.BinOp):
# 检查是否包含 CEnum
annot_str = ast.dump(node.annotation)
annot_str: str = ast.dump(node.annotation)
if 'CEnum' in annot_str:
IsCenum = True
elif isinstance(node.annotation, ast.Attribute):
@@ -262,21 +262,19 @@ class AnnotationLoaderMixin:
if IsCenum:
# 检查值是否是 Constant (枚举成员值)
if node.value and isinstance(node.value, ast.Constant):
value = node.value.value
value: int | str | float | None = node.value.value
else:
value = None
cEnumMembers.append((TargetName, value))
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _ConfigMode
if _ConfigMode == "strict":
if _config_mode == "strict":
raise
_vlog().warning(f"解析 CEnum 成员变量失败: {_e}", "Exception")
# 处理 CEnum 成员变量
for TargetName, value in cEnumMembers:
# 注册枚举成员
MemberNode = CTypeInfo()
MemberNode: CTypeInfo = CTypeInfo()
MemberNode.Name = TargetName
MemberNode.BaseType = t.CEnum(TypePrefix)
MemberNode.value = value
@@ -289,40 +287,38 @@ class AnnotationLoaderMixin:
try:
with open(ModuleName, 'r', encoding='utf-8') as f:
ann_content = f.read()
ann_tree = ast.parse(ann_content)
ann_content: str = f.read()
ann_tree: ast.Module = ast.parse(ann_content)
for node in ann_tree.body:
# 检测 xxx: t.CTypedef = xxx 形式的 typedef 语句
if isinstance(node, ast.AnnAssign):
if isinstance(node.target, ast.Name) and node.annotation and node.value:
TargetName = node.target.id
TargetName: str = node.target.id
# 检查注解是否是 t.CTypedef
if isinstance(node.annotation, ast.Attribute):
if isinstance(node.annotation.value, ast.Name):
if node.annotation.value.id == 't' and node.annotation.attr == 'CTypedef':
if IsTModule(node.annotation.value.id) and node.annotation.attr == 'CTypedef':
# 检查值是否是 Name
if isinstance(node.value, ast.Name):
original_name = node.value.id
original_name: str = node.value.id
typedef_annots.append((TargetName, original_name))
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _ConfigMode
if _ConfigMode == "strict":
if _config_mode == "strict":
raise
_vlog().warning(f"解析 typedef 语句失败: {_e}", "Exception")
# 处理 typedef 注解
for TargetName, original_name in typedef_annots:
# 检查原始类型是否在符号表中(带前缀或不带前缀)
orig_with_prefix = f'{TypePrefix}.{original_name}'
orig_with_prefix: str = f'{TypePrefix}.{original_name}'
if self.SymbolTable.has(orig_with_prefix):
# 添加带前缀的 typedef 别名
FullTypedef_name = f'{TypePrefix}.{TargetName}'
TypedefNode = CTypeInfo()
FullTypedef_name: str = f'{TypePrefix}.{TargetName}'
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = FullTypedef_name
TypedefNode.IsTypedef = True
orig_entry = self.SymbolTable.lookup(orig_with_prefix)
orig_type_str = f'struct {original_name}'
orig_entry: CTypeInfo | dict[str, Any] = self.SymbolTable.lookup(orig_with_prefix)
orig_type_str: str = f'struct {original_name}'
if isinstance(orig_entry, dict):
if orig_entry.get('type') == 'typedef':
orig_type_str = orig_entry.get('OriginalType', f'struct {original_name}')
@@ -349,8 +345,8 @@ class AnnotationLoaderMixin:
else:
# importlib 模式:导入模块
try:
module = importlib.import_module(ModuleName)
count = register_to_symboltable(module, lib_name, None)
module: types.ModuleType = importlib.import_module(ModuleName)
count: int = register_to_symboltable(module, lib_name, None)
self.AnnotationModules.add(lib_name)
return count
except ImportError:
@@ -360,7 +356,7 @@ class AnnotationLoaderMixin:
self.LogWarning(f"加载注解模块失败: {ModuleName}, 错误: {e}")
return 0
def _LoadAnnotationFiles(self, FilePaths: list):
def _LoadAnnotationFiles(self, FilePaths: list[str | tuple]) -> None:
"""加载多个注解文件并注册到符号表
Args:
@@ -371,15 +367,20 @@ class AnnotationLoaderMixin:
for item in FilePaths:
if isinstance(item, tuple):
if len(item) >= 3:
path: str
library_name: str
parse_method: str
path, library_name, parse_method = item[:3]
count = self._loadAnnotationModule(path, library_name, parse_method)
count: int = self._LoadAnnotationModule(path, library_name, parse_method)
elif len(item) == 2:
path: str
library_name: str
path, library_name = item
count = self._loadAnnotationModule(path, library_name, 'auto')
count: int = self._LoadAnnotationModule(path, library_name, 'auto')
else:
count = self._loadAnnotationModule(item)
count: int = self._LoadAnnotationModule(item)
else:
count = self._loadAnnotationModule(item)
count: int = self._LoadAnnotationModule(item)
# 别名,保持向后兼容
LoadAnnotationFiles = _LoadAnnotationFiles