Compare commits
2 Commits
0.14.8
...
gankra/fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3744087c6 | ||
|
|
cccb0bbaa4 |
@@ -1906,4 +1906,211 @@ func<CURSOR>_alias()
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn references_submodule_import_from_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.submod import val
|
||||
|
||||
x = sub<CURSOR>pkg
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// TODO(submodule-imports): this should light up both instances of `subpkg`
|
||||
assert_snapshot!(test.references(), @r"
|
||||
info[references]: Reference 1
|
||||
--> mypackage/__init__.py:4:5
|
||||
|
|
||||
2 | from .subpkg.submod import val
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
| ^^^^^^
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn references_submodule_import_from_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .sub<CURSOR>pkg.submod import val
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// TODO(submodule-imports): this should light up both instances of `subpkg`
|
||||
assert_snapshot!(test.references(), @"No references found");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn references_submodule_import_from_wrong_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.submod import val
|
||||
|
||||
x = sub<CURSOR>mod
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// No references is actually correct (or it should only see itself)
|
||||
assert_snapshot!(test.references(), @"No references found");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn references_submodule_import_from_wrong_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.sub<CURSOR>mod import val
|
||||
|
||||
x = submod
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// No references is actually correct (or it should only see itself)
|
||||
assert_snapshot!(test.references(), @"No references found");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn references_submodule_import_from_confusing_shadowed_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .sub<CURSOR>pkg import subpkg
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// No references is actually correct (or it should only see itself)
|
||||
assert_snapshot!(test.references(), @"No references found");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn references_submodule_import_from_confusing_real_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg import sub<CURSOR>pkg
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
assert_snapshot!(test.references(), @r"
|
||||
info[references]: Reference 1
|
||||
--> mypackage/__init__.py:2:21
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
| ^^^^^^
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
|
|
||||
|
||||
info[references]: Reference 2
|
||||
--> mypackage/__init__.py:4:5
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
| ^^^^^^
|
||||
|
|
||||
|
||||
info[references]: Reference 3
|
||||
--> mypackage/subpkg/__init__.py:2:1
|
||||
|
|
||||
2 | subpkg: int = 10
|
||||
| ^^^^^^
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn references_submodule_import_from_confusing_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg import subpkg
|
||||
|
||||
x = sub<CURSOR>pkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// TODO: this should also highlight the RHS subpkg in the import
|
||||
assert_snapshot!(test.references(), @r"
|
||||
info[references]: Reference 1
|
||||
--> mypackage/__init__.py:4:5
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
| ^^^^^^
|
||||
|
|
||||
");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2602,6 +2602,295 @@ def ab(a: int, *, c: int): ...
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_declaration_submodule_import_from_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.submod import val
|
||||
|
||||
x = sub<CURSOR>pkg
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
assert_snapshot!(test.goto_declaration(), @r"
|
||||
info[goto-declaration]: Declaration
|
||||
--> mypackage/__init__.py:2:7
|
||||
|
|
||||
2 | from .subpkg.submod import val
|
||||
| ^^^^^^
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
|
|
||||
info: Source
|
||||
--> mypackage/__init__.py:4:5
|
||||
|
|
||||
2 | from .subpkg.submod import val
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
| ^^^^^^
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_declaration_submodule_import_from_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .sub<CURSOR>pkg.submod import val
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// TODO(submodule-imports): I don't *think* this is what we want..?
|
||||
// It's a bit confusing because this symbol is essentially the LHS *and* RHS of
|
||||
// `subpkg = mypackage.subpkg`. As in, it's both defining a local `subpkg` and
|
||||
// loading the module `mypackage.subpkg`, so, it's understandable to get confused!
|
||||
assert_snapshot!(test.goto_declaration(), @r"
|
||||
info[goto-declaration]: Declaration
|
||||
--> mypackage/subpkg/__init__.py:1:1
|
||||
|
|
||||
|
|
||||
info: Source
|
||||
--> mypackage/__init__.py:2:7
|
||||
|
|
||||
2 | from .subpkg.submod import val
|
||||
| ^^^^^^
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_declaration_submodule_import_from_wrong_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.submod import val
|
||||
|
||||
x = sub<CURSOR>mod
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// No result is correct!
|
||||
assert_snapshot!(test.goto_declaration(), @"No goto target found");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_declaration_submodule_import_from_wrong_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.sub<CURSOR>mod import val
|
||||
|
||||
x = submod
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// Going to the submod module is correct!
|
||||
assert_snapshot!(test.goto_declaration(), @r"
|
||||
info[goto-declaration]: Declaration
|
||||
--> mypackage/subpkg/submod.py:1:1
|
||||
|
|
||||
1 |
|
||||
| ^
|
||||
2 | val: int = 0
|
||||
|
|
||||
info: Source
|
||||
--> mypackage/__init__.py:2:14
|
||||
|
|
||||
2 | from .subpkg.submod import val
|
||||
| ^^^^^^
|
||||
3 |
|
||||
4 | x = submod
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_declaration_submodule_import_from_confusing_shadowed_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .sub<CURSOR>pkg import subpkg
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// Going to the subpkg module is correct!
|
||||
assert_snapshot!(test.goto_declaration(), @r"
|
||||
info[goto-declaration]: Declaration
|
||||
--> mypackage/subpkg/__init__.py:1:1
|
||||
|
|
||||
1 |
|
||||
| ^
|
||||
2 | subpkg: int = 10
|
||||
|
|
||||
info: Source
|
||||
--> mypackage/__init__.py:2:7
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
| ^^^^^^
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_declaration_submodule_import_from_confusing_real_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg import sub<CURSOR>pkg
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// Going to the subpkg `int` is correct!
|
||||
assert_snapshot!(test.goto_declaration(), @r"
|
||||
info[goto-declaration]: Declaration
|
||||
--> mypackage/subpkg/__init__.py:2:1
|
||||
|
|
||||
2 | subpkg: int = 10
|
||||
| ^^^^^^
|
||||
|
|
||||
info: Source
|
||||
--> mypackage/__init__.py:2:21
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
| ^^^^^^
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_declaration_submodule_import_from_confusing_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg import subpkg
|
||||
|
||||
x = sub<CURSOR>pkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// TODO(submodule-imports): Ok this one is FASCINATING but definitely wrong!
|
||||
//
|
||||
// So there's 3 relevant definitions here:
|
||||
//
|
||||
// * `subpkg: int = 10` in the other file is in fact the original definition.
|
||||
// Including it here is accurate and possibly useful?
|
||||
//
|
||||
// * the LHS `subpkg` in the import is an instance of `subpkg = ...`
|
||||
// because it's a `DefinitionKind::ImportFromSubmodle`.
|
||||
// Including it here is Pedantically Correct but Unhelpful.
|
||||
//
|
||||
// * `the RHS `subpkg` in the import is a second instance of `subpkg = ...`
|
||||
// that *immediately* overwrites the `ImportFromSubmodule`'s definition.
|
||||
// This is the most important one and doesn't show up at all! Sadness!
|
||||
assert_snapshot!(test.goto_declaration(), @r"
|
||||
info[goto-declaration]: Declaration
|
||||
--> mypackage/__init__.py:2:7
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
| ^^^^^^
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
|
|
||||
info: Source
|
||||
--> mypackage/__init__.py:4:5
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
| ^^^^^^
|
||||
|
|
||||
|
||||
info[goto-declaration]: Declaration
|
||||
--> mypackage/subpkg/__init__.py:2:1
|
||||
|
|
||||
2 | subpkg: int = 10
|
||||
| ^^^^^^
|
||||
|
|
||||
info: Source
|
||||
--> mypackage/__init__.py:4:5
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
| ^^^^^^
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
impl CursorTest {
|
||||
fn goto_declaration(&self) -> String {
|
||||
let Some(targets) = goto_declaration(&self.db, self.cursor.file, self.cursor.offset)
|
||||
|
||||
@@ -1672,6 +1672,283 @@ def function():
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_type_submodule_import_from_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.submod import val
|
||||
|
||||
x = sub<CURSOR>pkg
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// The module is the correct type definition
|
||||
assert_snapshot!(test.goto_type_definition(), @r"
|
||||
info[goto-type-definition]: Type definition
|
||||
--> mypackage/subpkg/__init__.py:1:1
|
||||
|
|
||||
|
|
||||
info: Source
|
||||
--> mypackage/__init__.py:4:5
|
||||
|
|
||||
2 | from .subpkg.submod import val
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
| ^^^^^^
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_type_submodule_import_from_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .sub<CURSOR>pkg.submod import val
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// The module is the correct type definition
|
||||
assert_snapshot!(test.goto_type_definition(), @r"
|
||||
info[goto-type-definition]: Type definition
|
||||
--> mypackage/subpkg/__init__.py:1:1
|
||||
|
|
||||
|
|
||||
info: Source
|
||||
--> mypackage/__init__.py:2:7
|
||||
|
|
||||
2 | from .subpkg.submod import val
|
||||
| ^^^^^^
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_type_submodule_import_from_wrong_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.submod import val
|
||||
|
||||
x = sub<CURSOR>mod
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// Unknown is correct, `submod` is not in scope
|
||||
assert_snapshot!(test.goto_type_definition(), @r"
|
||||
info[goto-type-definition]: Type definition
|
||||
--> stdlib/ty_extensions.pyi:20:1
|
||||
|
|
||||
19 | # Types
|
||||
20 | Unknown = object()
|
||||
| ^^^^^^^
|
||||
21 | AlwaysTruthy = object()
|
||||
22 | AlwaysFalsy = object()
|
||||
|
|
||||
info: Source
|
||||
--> mypackage/__init__.py:4:5
|
||||
|
|
||||
2 | from .subpkg.submod import val
|
||||
3 |
|
||||
4 | x = submod
|
||||
| ^^^^^^
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_type_submodule_import_from_wrong_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.sub<CURSOR>mod import val
|
||||
|
||||
x = submod
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// The module is correct
|
||||
assert_snapshot!(test.goto_type_definition(), @r"
|
||||
info[goto-type-definition]: Type definition
|
||||
--> mypackage/subpkg/submod.py:1:1
|
||||
|
|
||||
1 | /
|
||||
2 | | val: int = 0
|
||||
| |_____________^
|
||||
|
|
||||
info: Source
|
||||
--> mypackage/__init__.py:2:14
|
||||
|
|
||||
2 | from .subpkg.submod import val
|
||||
| ^^^^^^
|
||||
3 |
|
||||
4 | x = submod
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_type_submodule_import_from_confusing_shadowed_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .sub<CURSOR>pkg import subpkg
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// The module is correct
|
||||
assert_snapshot!(test.goto_type_definition(), @r"
|
||||
info[goto-type-definition]: Type definition
|
||||
--> mypackage/subpkg/__init__.py:1:1
|
||||
|
|
||||
1 | /
|
||||
2 | | subpkg: int = 10
|
||||
| |_________________^
|
||||
|
|
||||
info: Source
|
||||
--> mypackage/__init__.py:2:7
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
| ^^^^^^
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_type_submodule_import_from_confusing_real_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg import sub<CURSOR>pkg
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// `int` is correct
|
||||
assert_snapshot!(test.goto_type_definition(), @r#"
|
||||
info[goto-type-definition]: Type definition
|
||||
--> stdlib/builtins.pyi:348:7
|
||||
|
|
||||
347 | @disjoint_base
|
||||
348 | class int:
|
||||
| ^^^
|
||||
349 | """int([x]) -> integer
|
||||
350 | int(x, base=10) -> integer
|
||||
|
|
||||
info: Source
|
||||
--> mypackage/__init__.py:2:21
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
| ^^^^^^
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
|
|
||||
"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_type_submodule_import_from_confusing_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg import subpkg
|
||||
|
||||
x = sub<CURSOR>pkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// `int` is correct
|
||||
assert_snapshot!(test.goto_type_definition(), @r#"
|
||||
info[goto-type-definition]: Type definition
|
||||
--> stdlib/builtins.pyi:348:7
|
||||
|
|
||||
347 | @disjoint_base
|
||||
348 | class int:
|
||||
| ^^^
|
||||
349 | """int([x]) -> integer
|
||||
350 | int(x, base=10) -> integer
|
||||
|
|
||||
info: Source
|
||||
--> mypackage/__init__.py:4:5
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
| ^^^^^^
|
||||
|
|
||||
"#);
|
||||
}
|
||||
|
||||
impl CursorTest {
|
||||
fn goto_type_definition(&self) -> String {
|
||||
let Some(targets) =
|
||||
|
||||
@@ -3321,6 +3321,297 @@ def function():
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_submodule_import_from_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.submod import val
|
||||
|
||||
x = sub<CURSOR>pkg
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// The module is correct
|
||||
assert_snapshot!(test.hover(), @r"
|
||||
<module 'mypackage.subpkg'>
|
||||
---------------------------------------------
|
||||
```python
|
||||
<module 'mypackage.subpkg'>
|
||||
```
|
||||
---------------------------------------------
|
||||
info[hover]: Hovered content is
|
||||
--> mypackage/__init__.py:4:5
|
||||
|
|
||||
2 | from .subpkg.submod import val
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
| ^^^-^^
|
||||
| | |
|
||||
| | Cursor offset
|
||||
| source
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_submodule_import_from_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .sub<CURSOR>pkg.submod import val
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// The module is correct
|
||||
assert_snapshot!(test.hover(), @r"
|
||||
<module 'mypackage.subpkg'>
|
||||
---------------------------------------------
|
||||
```python
|
||||
<module 'mypackage.subpkg'>
|
||||
```
|
||||
---------------------------------------------
|
||||
info[hover]: Hovered content is
|
||||
--> mypackage/__init__.py:2:7
|
||||
|
|
||||
2 | from .subpkg.submod import val
|
||||
| ^^^-^^
|
||||
| | |
|
||||
| | Cursor offset
|
||||
| source
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_submodule_import_from_wrong_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.submod import val
|
||||
|
||||
x = sub<CURSOR>mod
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// Unknown is correct
|
||||
assert_snapshot!(test.hover(), @r"
|
||||
Unknown
|
||||
---------------------------------------------
|
||||
```python
|
||||
Unknown
|
||||
```
|
||||
---------------------------------------------
|
||||
info[hover]: Hovered content is
|
||||
--> mypackage/__init__.py:4:5
|
||||
|
|
||||
2 | from .subpkg.submod import val
|
||||
3 |
|
||||
4 | x = submod
|
||||
| ^^^-^^
|
||||
| | |
|
||||
| | Cursor offset
|
||||
| source
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_submodule_import_from_wrong_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.sub<CURSOR>mod import val
|
||||
|
||||
x = submod
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// The submodule is correct
|
||||
assert_snapshot!(test.hover(), @r"
|
||||
<module 'mypackage.subpkg.submod'>
|
||||
---------------------------------------------
|
||||
```python
|
||||
<module 'mypackage.subpkg.submod'>
|
||||
```
|
||||
---------------------------------------------
|
||||
info[hover]: Hovered content is
|
||||
--> mypackage/__init__.py:2:14
|
||||
|
|
||||
2 | from .subpkg.submod import val
|
||||
| ^^^-^^
|
||||
| | |
|
||||
| | Cursor offset
|
||||
| source
|
||||
3 |
|
||||
4 | x = submod
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_submodule_import_from_confusing_shadowed_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .sub<CURSOR>pkg import subpkg
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// The module is correct
|
||||
assert_snapshot!(test.hover(), @r"
|
||||
<module 'mypackage.subpkg'>
|
||||
---------------------------------------------
|
||||
```python
|
||||
<module 'mypackage.subpkg'>
|
||||
```
|
||||
---------------------------------------------
|
||||
info[hover]: Hovered content is
|
||||
--> mypackage/__init__.py:2:7
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
| ^^^-^^
|
||||
| | |
|
||||
| | Cursor offset
|
||||
| source
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_submodule_import_from_confusing_real_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg import sub<CURSOR>pkg
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// int is correct
|
||||
assert_snapshot!(test.hover(), @r"
|
||||
int
|
||||
---------------------------------------------
|
||||
```python
|
||||
int
|
||||
```
|
||||
---------------------------------------------
|
||||
info[hover]: Hovered content is
|
||||
--> mypackage/__init__.py:2:21
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
| ^^^-^^
|
||||
| | |
|
||||
| | Cursor offset
|
||||
| source
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_submodule_import_from_confusing_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg import subpkg
|
||||
|
||||
x = sub<CURSOR>pkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// int is correct
|
||||
assert_snapshot!(test.hover(), @r"
|
||||
int
|
||||
---------------------------------------------
|
||||
```python
|
||||
int
|
||||
```
|
||||
---------------------------------------------
|
||||
info[hover]: Hovered content is
|
||||
--> mypackage/__init__.py:4:5
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
| ^^^-^^
|
||||
| | |
|
||||
| | Cursor offset
|
||||
| source
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
impl CursorTest {
|
||||
fn hover(&self) -> String {
|
||||
use std::fmt::Write;
|
||||
|
||||
@@ -1223,4 +1223,207 @@ result = func(10, y=20)
|
||||
|
||||
assert_snapshot!(test.rename("z"), @"Cannot rename");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_submodule_import_from_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.submod import val
|
||||
|
||||
x = sub<CURSOR>pkg
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// TODO(submodule-imports): we should refuse to rename this (it's the name of a module)
|
||||
assert_snapshot!(test.rename("mypkg"), @r"
|
||||
info[rename]: Rename symbol (found 1 locations)
|
||||
--> mypackage/__init__.py:4:5
|
||||
|
|
||||
2 | from .subpkg.submod import val
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
| ^^^^^^
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_submodule_import_from_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .sub<CURSOR>pkg.submod import val
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// Refusing to rename is correct
|
||||
assert_snapshot!(test.rename("mypkg"), @"Cannot rename");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_submodule_import_from_wrong_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.submod import val
|
||||
|
||||
x = sub<CURSOR>mod
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// Refusing to rename is good/fine here, it's an undefined reference
|
||||
assert_snapshot!(test.rename("mypkg"), @"Cannot rename");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_submodule_import_from_wrong_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg.sub<CURSOR>mod import val
|
||||
|
||||
x = submod
|
||||
"#,
|
||||
)
|
||||
.source("mypackage/subpkg/__init__.py", r#""#)
|
||||
.source(
|
||||
"mypackage/subpkg/submod.py",
|
||||
r#"
|
||||
val: int = 0
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// Refusing to rename is good here, it's a module name
|
||||
assert_snapshot!(test.rename("mypkg"), @"Cannot rename");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_submodule_import_from_confusing_shadowed_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .sub<CURSOR>pkg import subpkg
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// Refusing to rename is good here, it's the name of a module
|
||||
assert_snapshot!(test.rename("mypkg"), @"Cannot rename");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_submodule_import_from_confusing_real_def() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg import sub<CURSOR>pkg
|
||||
|
||||
x = subpkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// Renaming the integer is correct
|
||||
assert_snapshot!(test.rename("mypkg"), @r"
|
||||
info[rename]: Rename symbol (found 3 locations)
|
||||
--> mypackage/__init__.py:2:21
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
| ^^^^^^
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
| ------
|
||||
|
|
||||
::: mypackage/subpkg/__init__.py:2:1
|
||||
|
|
||||
2 | subpkg: int = 10
|
||||
| ------
|
||||
|
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rename_submodule_import_from_confusing_use() {
|
||||
let test = CursorTest::builder()
|
||||
.source(
|
||||
"mypackage/__init__.py",
|
||||
r#"
|
||||
from .subpkg import subpkg
|
||||
|
||||
x = sub<CURSOR>pkg
|
||||
"#,
|
||||
)
|
||||
.source(
|
||||
"mypackage/subpkg/__init__.py",
|
||||
r#"
|
||||
subpkg: int = 10
|
||||
"#,
|
||||
)
|
||||
.build();
|
||||
|
||||
// TODO(submodule-imports): this is incorrect, we should rename the `subpkg` int
|
||||
// and the RHS of the import statement (but *not* rename the LHS).
|
||||
//
|
||||
// However us being cautious here *would* be good as the rename will actually
|
||||
// result in a `subpkg` variable still existing in this code, as the import's LHS
|
||||
// `DefinitionKind::ImportFromSubmodule` would stop being overwritten by the RHS!
|
||||
assert_snapshot!(test.rename("mypkg"), @r"
|
||||
info[rename]: Rename symbol (found 1 locations)
|
||||
--> mypackage/__init__.py:4:5
|
||||
|
|
||||
2 | from .subpkg import subpkg
|
||||
3 |
|
||||
4 | x = subpkg
|
||||
| ^^^^^^
|
||||
|
|
||||
");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1529,7 +1529,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
||||
// Record whether this is equivalent to `from . import ...`
|
||||
is_self_import = module_name == thispackage;
|
||||
|
||||
if node.module.is_some()
|
||||
if let Some(module_node) = &node.module
|
||||
&& let Some(relative_submodule) = module_name.relative_to(&thispackage)
|
||||
&& let Some(direct_submodule) = relative_submodule.components().next()
|
||||
&& !self.seen_submodule_imports.contains(direct_submodule)
|
||||
@@ -1540,9 +1540,23 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
||||
|
||||
let direct_submodule_name = Name::new(direct_submodule);
|
||||
let symbol = self.add_symbol(direct_submodule_name);
|
||||
|
||||
let module_index = if node.level == 0 {
|
||||
// "whatever.thispackage.x.y" we want `x`
|
||||
thispackage.components().count()
|
||||
} else {
|
||||
// ".x.y" we want `x` (level 1 => index 0)
|
||||
// "..x.y" we want `y` (level 2 => index 1)
|
||||
// (The Identifier doesn't include the prefix dots)
|
||||
node.level as usize - 1
|
||||
};
|
||||
self.add_definition(
|
||||
symbol.into(),
|
||||
ImportFromSubmoduleDefinitionNodeRef { node },
|
||||
ImportFromSubmoduleDefinitionNodeRef {
|
||||
node,
|
||||
module: module_node,
|
||||
module_index,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::ops::Deref;
|
||||
use ruff_db::files::{File, FileRange};
|
||||
use ruff_db::parsed::{ParsedModuleRef, parsed_module};
|
||||
use ruff_python_ast as ast;
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
|
||||
|
||||
use crate::Db;
|
||||
use crate::ast_node_ref::AstNodeRef;
|
||||
@@ -374,6 +374,8 @@ pub(crate) struct ImportFromDefinitionNodeRef<'ast> {
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub(crate) struct ImportFromSubmoduleDefinitionNodeRef<'ast> {
|
||||
pub(crate) node: &'ast ast::StmtImportFrom,
|
||||
pub(crate) module: &'ast ast::Identifier,
|
||||
pub(crate) module_index: usize,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@@ -456,8 +458,12 @@ impl<'db> DefinitionNodeRef<'_, 'db> {
|
||||
}),
|
||||
DefinitionNodeRef::ImportFromSubmodule(ImportFromSubmoduleDefinitionNodeRef {
|
||||
node,
|
||||
module,
|
||||
module_index,
|
||||
}) => DefinitionKind::ImportFromSubmodule(ImportFromSubmoduleDefinitionKind {
|
||||
node: AstNodeRef::new(parsed, node),
|
||||
module: AstNodeRef::new(parsed, module),
|
||||
module_index,
|
||||
}),
|
||||
DefinitionNodeRef::ImportStar(star_import) => {
|
||||
let StarImportDefinitionNodeRef { node, symbol_id } = star_import;
|
||||
@@ -584,7 +590,9 @@ impl<'db> DefinitionNodeRef<'_, 'db> {
|
||||
alias_index,
|
||||
is_reexported: _,
|
||||
}) => (&node.names[alias_index]).into(),
|
||||
Self::ImportFromSubmodule(ImportFromSubmoduleDefinitionNodeRef { node }) => node.into(),
|
||||
Self::ImportFromSubmodule(ImportFromSubmoduleDefinitionNodeRef { node, .. }) => {
|
||||
node.into()
|
||||
}
|
||||
// INVARIANT: for an invalid-syntax statement such as `from foo import *, bar, *`,
|
||||
// we only create a `StarImportDefinitionKind` for the *first* `*` alias in the names list.
|
||||
Self::ImportStar(StarImportDefinitionNodeRef { node, symbol_id: _ }) => node
|
||||
@@ -755,7 +763,7 @@ impl DefinitionKind<'_> {
|
||||
match self {
|
||||
DefinitionKind::Import(import) => import.alias(module).range(),
|
||||
DefinitionKind::ImportFrom(import) => import.alias(module).range(),
|
||||
DefinitionKind::ImportFromSubmodule(import) => import.import(module).range(),
|
||||
DefinitionKind::ImportFromSubmodule(import) => import.target_range(module),
|
||||
DefinitionKind::StarImport(import) => import.alias(module).range(),
|
||||
DefinitionKind::Function(function) => function.node(module).name.range(),
|
||||
DefinitionKind::Class(class) => class.node(module).name.range(),
|
||||
@@ -793,7 +801,7 @@ impl DefinitionKind<'_> {
|
||||
match self {
|
||||
DefinitionKind::Import(import) => import.alias(module).range(),
|
||||
DefinitionKind::ImportFrom(import) => import.alias(module).range(),
|
||||
DefinitionKind::ImportFromSubmodule(import) => import.import(module).range(),
|
||||
DefinitionKind::ImportFromSubmodule(import) => import.module(module).range(),
|
||||
DefinitionKind::StarImport(import) => import.import(module).range(),
|
||||
DefinitionKind::Function(function) => function.node(module).range(),
|
||||
DefinitionKind::Class(class) => class.node(module).range(),
|
||||
@@ -1033,12 +1041,37 @@ impl ImportFromDefinitionKind {
|
||||
#[derive(Clone, Debug, get_size2::GetSize)]
|
||||
pub struct ImportFromSubmoduleDefinitionKind {
|
||||
node: AstNodeRef<ast::StmtImportFrom>,
|
||||
module: AstNodeRef<ast::Identifier>,
|
||||
module_index: usize,
|
||||
}
|
||||
|
||||
impl ImportFromSubmoduleDefinitionKind {
|
||||
pub fn import<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::StmtImportFrom {
|
||||
self.node.node(module)
|
||||
}
|
||||
|
||||
pub fn module<'ast>(&self, module: &'ast ParsedModuleRef) -> &'ast ast::Identifier {
|
||||
self.module.node(module)
|
||||
}
|
||||
|
||||
pub fn target_range(&self, module: &ParsedModuleRef) -> TextRange {
|
||||
let module_ident = self.module(module);
|
||||
let module_str = module_ident.as_str();
|
||||
let Some(component_str) = module_str.split('.').nth(self.module_index) else {
|
||||
// This shouldn't happen but just in case, provide a safe default
|
||||
return module_ident.range();
|
||||
};
|
||||
let base_addr = module_str.as_ptr().addr();
|
||||
let component_addr = component_str.as_ptr().addr();
|
||||
let offset = base_addr.saturating_sub(component_addr);
|
||||
let Ok(offset_size) = TextSize::try_from(offset) else {
|
||||
// This shouldn't happen but just in case, provide a safe default
|
||||
return module_ident.range();
|
||||
};
|
||||
let start = module_ident.start().saturating_add(offset_size);
|
||||
let end = start.saturating_add(component_str.text_len());
|
||||
TextRange::new(start, end)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, get_size2::GetSize)]
|
||||
|
||||
Reference in New Issue
Block a user