fix(lsp): 通配导入链式重导出可解析
from A import * 的符号没有本地声明,C.b 查 C 的成员失败后原来直接返回;现在沿目标文件的 wildcard 链继续解析(带 hop 上限),模块属性与裸名字两条路径都覆盖。gate10 增加三级通配重导出 token/跳转断言(使用大小写不冲突的夹具名)。
This commit is contained in:
1 parent
8e86eea159
commit
c87f1b6f3c
7 files changed
+57
-5
No files matched your search
+31
-4
@@ -893,7 +893,8 @@ def _ChainFromModule(ws: LspWorkspace.LspWorkspace*, pool: memhub.MemManager*,
|
||||
if cur_is_file != 0:
|
||||
member: LspSymbols.LspSymbol* = ResolveInFile(pool, table_pool, cur, None, h)
|
||||
if member is None:
|
||||
return None
|
||||
# A module file may re-export the name through `from X import *`.
|
||||
return _ResolveWildcardsInFile(ws, pool, table_pool, cur, segs, hops + 1)
|
||||
if r is None:
|
||||
if member.import_kind != LspSymbols.LSP_IMPORT_NONE:
|
||||
if member.import_kind == LspSymbols.LSP_IMPORT_FROM:
|
||||
@@ -980,12 +981,37 @@ def _ModuleFile(ws: LspWorkspace.LspWorkspace*, pool: memhub.MemManager*,
|
||||
return _ModulePath(ws, pool, s.import_mod)
|
||||
|
||||
|
||||
def _ResolveWildcardsInFile(ws: LspWorkspace.LspWorkspace*, pool: memhub.MemManager*,
|
||||
table_pool: memhub.MemManager*, file: str,
|
||||
name: str, hops: int) -> LspTarget*:
|
||||
"""Follow the `from X import *` wildcards declared in file to resolve name (bounded)."""
|
||||
if file is None or name is None or hops > LSP_IMPORT_HOPS:
|
||||
return None
|
||||
text: str = LspFiles.ReadSource(pool, file)
|
||||
if text is None:
|
||||
return None
|
||||
doc: LspDocuments.LspDocument* = LspSource.NewTempDoc(pool, text)
|
||||
if doc is None:
|
||||
return None
|
||||
a: LspSymbols.LspAnalysis* = LspSymbols.Analyze(pool, table_pool, doc, file)
|
||||
if a is None or a.wildcards is None:
|
||||
return None
|
||||
wi: int = 0
|
||||
while wi < int(len(a.wildcards)):
|
||||
w: LspSymbols.LspSymbol* = a.wildcards.get(sizet(wi))
|
||||
wi += 1
|
||||
t: LspTarget* = ResolveWildcard(ws, pool, table_pool, file, w, name, hops + 1)
|
||||
if t is not None:
|
||||
return t
|
||||
return None
|
||||
|
||||
|
||||
def ResolveWildcard(ws: LspWorkspace.LspWorkspace*, pool: memhub.MemManager*,
|
||||
table_pool: memhub.MemManager*, from_file: str,
|
||||
wildcard: LspSymbols.LspSymbol*,
|
||||
name: str) -> LspTarget*:
|
||||
name: str, hops: int = 0) -> LspTarget*:
|
||||
"""Resolve a name (optionally `Name.member...`) supplied by `from module import *`."""
|
||||
if wildcard is None or name is None:
|
||||
if wildcard is None or name is None or hops > LSP_IMPORT_HOPS:
|
||||
return None
|
||||
file: str = _ResolveFromFile(ws, pool, from_file, wildcard)
|
||||
if file is None or not os.isfile(file):
|
||||
@@ -997,7 +1023,8 @@ def ResolveWildcard(ws: LspWorkspace.LspWorkspace*, pool: memhub.MemManager*,
|
||||
return None
|
||||
member: LspSymbols.LspSymbol* = ResolveInFile(pool, table_pool, file, None, h)
|
||||
if member is None:
|
||||
return None
|
||||
# The target file may itself re-export the name through `from X import *`.
|
||||
return _ResolveWildcardsInFile(ws, pool, table_pool, file, name, hops + 1)
|
||||
base: LspTarget* = None
|
||||
if member.import_kind != LspSymbols.LSP_IMPORT_NONE:
|
||||
base = _ResolveFromTarget(ws, pool, table_pool, member.file, member, 0)
|
||||
|
||||
@@ -5,6 +5,7 @@ from .gate10_stub import StubThing
|
||||
from .gate10_extra import *
|
||||
import gate10_types
|
||||
import gate10_pkg
|
||||
import gate10_wild_c
|
||||
import gate10_pkg.sub.mod
|
||||
import gate10_pkg.sub as pkgsub
|
||||
import gate10_pkg.sub as sub
|
||||
@@ -48,6 +49,10 @@ def ternary_use(flag: int) -> int:
|
||||
return extra_fn(EXTRA_CONST) if flag != 0 else extra_fn(EXTRA_CONST + 1)
|
||||
|
||||
|
||||
def wild_use() -> int:
|
||||
return gate10_wild_c.wild_b()
|
||||
|
||||
|
||||
def else_block(flag: int) -> int:
|
||||
if flag != 0:
|
||||
return 1
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
from gate10_wild_reexport import *
|
||||
@@ -0,0 +1 @@
|
||||
from gate10_wild_b import *
|
||||
@@ -0,0 +1,2 @@
|
||||
def wild_b() -> int:
|
||||
return 1
|
||||
@@ -0,0 +1 @@
|
||||
from gate10_wild_leaf import wild_b
|
||||
+16
-1
@@ -1455,7 +1455,9 @@ def gate10(exe: str) -> int:
|
||||
# The fixtures live outside the project's source roots; copy them into an isolated workspace
|
||||
# so the cross-file index contains the module, the stub and the consumer.
|
||||
workspace = Path(tempfile.mkdtemp(prefix="transpyc_lsp_gate10_"))
|
||||
names = ("gate10_types.vp", "gate10_stub.vpi", "gate10_extra.vp", "gate10_use.vp")
|
||||
names = ("gate10_types.vp", "gate10_stub.vpi", "gate10_extra.vp", "gate10_use.vp",
|
||||
"gate10_wild_leaf.vp", "gate10_wild_reexport.vp",
|
||||
"gate10_wild_b.vp", "gate10_wild_c.vp")
|
||||
for name in names:
|
||||
shutil.copy(fixtures / name, workspace / name)
|
||||
shutil.copytree(fixtures / "gate10_pkg", workspace / "gate10_pkg")
|
||||
@@ -1552,6 +1554,19 @@ def gate10(exe: str) -> int:
|
||||
raise AssertionError(f"missing definition in {label}: {t_def}")
|
||||
if not t_def[0]["uri"].replace("\\", "/").endswith("gate10_extra.vp"):
|
||||
raise AssertionError(f"wrong definition in {label}: {t_def}")
|
||||
wild_pos = _position(text, "gate10_wild_c.wild_b")
|
||||
wild_pos["character"] += len("gate10_wild_c.")
|
||||
if not _find_token(sem_tokens, wild_pos["line"], wild_pos["character"], sem_types.index("function")):
|
||||
raise AssertionError(f"wildcard re-export chain member is not highlighted: {wild_pos}")
|
||||
wild_def = client.request(
|
||||
"textDocument/definition",
|
||||
{"textDocument": {"uri": uri}, "position": wild_pos},
|
||||
timeout=120.0,
|
||||
).get("result")
|
||||
if not isinstance(wild_def, list) or not wild_def:
|
||||
raise AssertionError(f"wildcard re-export chain definition failed: {wild_def}")
|
||||
if not wild_def[0]["uri"].replace("\\", "/").endswith("gate10_wild_leaf.vp"):
|
||||
raise AssertionError(f"wildcard re-export chain definition is wrong: {wild_def}")
|
||||
const_pos = _position(text, "EXTRA_CONST")
|
||||
if not _find_token_mods(sem_tokens, const_pos["line"], const_pos["character"],
|
||||
sem_types.index("variable"),
|
||||
|
||||
Reference in new issue
Block a user