Files
TransPyC/_check_imports.py
T
2026-08-22 02:35:30 +08:00

109 lines
4.9 KiB
Python

# -*- coding: utf-8 -*-
"""扫描 TPV .vp 文件:找出"跨模块前缀引用但未 import"的模块(识别 as 别名)。
用法: python _check_imports.py
"""
import os
import re
ROOT = r"d:\Users\TermiNexus\Desktop\TransPyC\TransPyV\App\lib\core"
DIRS = [os.path.join(ROOT, "Gen"), os.path.join(ROOT, "Handles")]
# 忽略列表:基础库/枚举成员/llvmlite 属性/类名(大写开头且非模块)
IGNORE = {
"ast", "t", "c", "stdint", "stdio", "string", "stdlib", "memhub", "llvmlite",
"viperlib", "sys", "math", "time", "hashlib", "vthreading", "subprocess",
"argparse", "w32", "fileio", "win32", "win32console", "win32file",
"win32base", "win32process", "win32sync", "win32thread", "win32time",
"win32heap", "win32job", "win32namedpipe", "win32registry", "win32security",
"win32service", "win32socket", "win32handle", "win32pipe", "win32io",
"ASTKind", "ASTCtx", "OpKind", "CONST_NONE", "CONST_INT", "CONST_FLOAT",
"CONST_STR", "CONST_BOOL", "MODE", "ASM_DESCR", "Alloca", "Subscript",
"DefaultVal", "Arguments", "GenericClassFiles", "GenericClassNames",
"GenericClassNodes", "GenericClassSha1s", "GenericTpNames", "GenericTypeArgs",
"CDefineNames", "CDefineValues", "CDefineDoubleFlags", "CDefineStrFlags",
"XmodCdefNames", "XmodCdefValues", "XmodCdefDoubleFlags", "XmodCdefStrFlags",
"CTypedefNames", "CTypedefTypeStrs", "CTypedefVisiting", "VisibleStructs",
"Node", "Pool", "T", "Current", "Scope", "Constant", "List", "Int", "Struct",
"LocalClass", "RemoteClass", "Trans", "ExprHandle", "Type", "Value", "Function",
"BasicBlock", "Param", "ParamNode", "GlobalVariable", "LLVMType", "IRBuilder",
"LLVMModule", "MemBuddy", "Translator", "Generator", "Logger", "File",
"SymbolTable", "VarEntry", "StructEntry", "FieldEntry", "EnumEntry",
"EnumMember", "AsmOperand", "FuncEntry", "FuncDefaultsEntry", "TraceFrame",
"Mixin", "TypeKind", "TypeInfo", "TypeRegistry", "Config", "Exporter",
"Module", "State", "Default", "Utf8", "Case", "Error", "Handle",
}
# Gen Mixin 自引用(同包内类名)
GEN_MIXINS = {
"Generator", "BaseGenMixin", "TypeGenMixin", "TypeGenBase", "TypeGenCDef",
"TypeGenCType", "TypeGenResolve", "TypeGenErr", "StructGenMixin",
"ExprGenMixin", "ExprGenBase", "ExprGenConst", "ExprGenFstr", "ExprGenOps",
"ExprGenCdef", "ExprGenName", "ExprGenAttr", "ExprGenCls", "CallGenMixin",
"CallGenBase", "CallGenLeafKit", "CallGenCBuiltin", "CallGenCtor", "CallGenCall",
"CallGenProp", "CallGenFd", "CallGenVt", "CallGenVa", "CallGenLib",
"CallGenDispatch", "FuncGenBase", "FuncGenDef", "FuncGenMixin", "ClassGenMixin",
"ClassGenBase", "ClassGenEnum", "ClassGenGeneric", "ClassGenVTable",
"ClassGenDef", "ImportsGenMixin", "StmtGenMixin", "StmtGenDeclMixin",
"StmtGenCifMixin", "AssignGenMixin", "VarGenMixin", "TranslatorGenMixin",
"MatchGenMixin", "GenGenerator",
}
# 单字母/短名枚举等
SHORT = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"T", "U", "V", "W", "X", "Y", "Z", "N", "M", "I", "J", "K", "L", "O",
"P", "Q", "R", "S", "A", "B", "C", "D", "E", "F", "G", "H"}
def collect():
result = {}
pat_import = re.compile(r'^\s*(?:import|from)\s+([\w\.]+)(?:\s+as\s+(\w+))?')
pat_ref = re.compile(r'\b([A-Z][A-Za-z0-9_]*)\s*\.')
for d in DIRS:
for fn in sorted(os.listdir(d)):
if not fn.endswith(".vp"):
continue
fp = os.path.join(d, fn)
with open(fp, encoding="utf-8", errors="replace") as f:
lines = f.readlines()
imports = set()
refs = set()
for ln in lines:
s = ln.strip()
if s.startswith("#"):
continue
m = pat_import.match(s)
if m:
mod = m.group(1)
alias = m.group(2)
short = mod.split(".")[-1]
if alias:
imports.add(alias)
imports.add(short)
imports.add(mod)
continue
for rm in pat_ref.finditer(ln):
refs.add(rm.group(1))
result[fp] = (imports, refs)
return result
def main():
files = collect()
print("=== 使用但未 import(已去误报) ===")
any_hit = False
for fp, (imports, refs) in files.items():
missing = []
for r in sorted(refs):
if r in IGNORE or r in GEN_MIXINS or r in SHORT:
continue
if r in imports:
continue
missing.append(r)
if missing:
any_hit = True
print(f"\n{os.path.relpath(fp, ROOT)}")
for m in missing:
print(f" MISSING: {m}")
if not any_hit:
print("(无)")
print("\n=== 完成 ===")
if __name__ == "__main__":
main()