fix: vpi stub 注解解析改用被读模块自己的 imports 上下文,根治跨模块误报

This commit is contained in:
TermiNexus committed 2026-08-08 00:51:19 +08:00
1 parent 95a52bb9f6
commit 3197152d4e
1 file changed
+109 -4
+109 -4
View File
@@ -437,6 +437,60 @@ def _extract_sha1_from_path(vpi_path: str) -> str:
return sha1_buf return sha1_buf
# ============================================================
# _stub_add_imported - 追加模块名到空格分隔列表(stub 上下文收集用)
#
# 与 HandlesImports.add_imported_module 逻辑一致,但内联在本模块,
# 避免 VpiReader → HandlesImports → StubMerger → VpiReader 循环依赖。
# ============================================================
def _stub_add_imported(pool: memhub.MemBuddy | t.CPtr,
cur: str, name: str) -> str:
"""追加模块名到空格分隔列表(pool 分配),返回新列表"""
if name is None:
return cur
if cur is None:
nlen: t.CSizeT = string.strlen(name)
buf: str = pool.alloc(nlen + 1)
if buf is not None:
string.strcpy(buf, name)
return buf
old_len: t.CSizeT = string.strlen(cur)
name_len: t.CSizeT = string.strlen(name)
buf2: str = pool.alloc(old_len + 1 + name_len + 1)
if buf2 is not None:
string.strcpy(buf2, cur)
buf2[old_len] = ' '
string.strcpy(buf2 + old_len + 1, name)
return buf2
# ============================================================
# _stub_add_from - 追加 from-import 映射("local:mod[:orig]" 空格分隔)
# ============================================================
def _stub_add_from(pool: memhub.MemBuddy | t.CPtr,
cur: str, local: str, mod: str, orig: str) -> str:
"""追加 from-import 映射(pool 分配),返回新列表"""
if local is None or mod is None:
return cur
entry: str = pool.alloc(256)
if entry is None:
return cur
if orig is not None and string.strcmp(orig, local) != 0:
viperlib.snprintf(entry, 256, "%s:%s:%s", local, mod, orig)
else:
viperlib.snprintf(entry, 256, "%s:%s", local, mod)
if cur is None:
return entry
old_len: t.CSizeT = string.strlen(cur)
entry_len: t.CSizeT = string.strlen(entry)
buf: str = pool.alloc(old_len + 1 + entry_len + 1)
if buf is not None:
string.strcpy(buf, cur)
buf[old_len] = ' '
string.strcpy(buf + old_len + 1, entry)
return buf
# ============================================================ # ============================================================
# ParseVpiIntoModule - 解析 .vpi 文件,将函数声明注入到当前模块 # ParseVpiIntoModule - 解析 .vpi 文件,将函数声明注入到当前模块
# #
@@ -486,10 +540,6 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy | t.CPtr,
if pool is None or mod is None or vpi_path is None or trans is None: if pool is None or mod is None or vpi_path is None or trans is None:
return 0 return 0
# 获取当前翻译器的导入信息(供 resolve_annotation_type 使用)
imported_modules: str = trans._imported_modules
from_imports: str = trans._from_imports
# 1. 读取 .vpi 文件 # 1. 读取 .vpi 文件
f: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R) f: fileio.File | t.CPtr = fileio.File(vpi_path, fileio.MODE.R)
if f.closed: if f.closed:
@@ -539,6 +589,61 @@ def _ParseVpiIntoModuleImpl(pool: memhub.MemBuddy | t.CPtr,
return 1 return 1
n: t.CSizeT = ch.__len__() n: t.CSizeT = ch.__len__()
# 收集 stub 内被读模块自己的 import 语句,构建独立的注解解析上下文。
# .vpi stub 顶部含被读模块的 import(Converter 已写入,如 string.vp 的
# "import t, c"),用它替代当前模块的 imported_modules/from_imports 去
# 解析注解——根治跨上下文误报(如 t.CArray[str] 需要 't' 已导入)。
stub_imported_modules: str = None
stub_from_imports: str = None
si: t.CSizeT
for si in range(n):
schild: ast.AST | t.CPtr = ch.get(si)
if schild is None:
continue
sk: int = schild.kind()
if sk == ast.ASTKind.Import:
simp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(schild)
if simp.names is not None:
sn_n: t.CSizeT = simp.names.__len__()
sni: t.CSizeT
for sni in range(sn_n):
sal: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(simp.names.get(sni))
if sal is not None and sal.name is not None:
stub_imported_modules = _stub_add_imported(
pool, stub_imported_modules, sal.name)
if sal.asname is not None:
stub_imported_modules = _stub_add_imported(
pool, stub_imported_modules, sal.asname)
elif sk == ast.ASTKind.ImportFrom:
sifr: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(schild)
sifr_mod: str = sifr.module
if sifr_mod is not None:
stub_imported_modules = _stub_add_imported(
pool, stub_imported_modules, sifr_mod)
if sifr.names is not None:
sifr_nn: t.CSizeT = sifr.names.__len__()
sifri: t.CSizeT
for sifri in range(sifr_nn):
sial: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(sifr.names.get(sifri))
if sial is not None and sial.name is not None:
# '*' star import 不建 from 映射(lookup 有 star 回退)
if string.strcmp(sial.name, "*") != 0:
slocal: str = sial.name
sorig: str = None
if sial.asname is not None:
slocal = sial.asname
sorig = sial.name
stub_from_imports = _stub_add_from(
pool, stub_from_imports, slocal, sifr_mod, sorig)
# 用 stub 自己的 imports 替代当前模块的(stub 注解解析上下文正确性)
imported_modules: str = trans._imported_modules
from_imports: str = trans._from_imports
if stub_imported_modules is not None:
imported_modules = stub_imported_modules
if stub_from_imports is not None:
from_imports = stub_from_imports
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)