mirror of https://github.com/astral-sh/ruff
[ty] Fix missing registration of identifiers during semantic index construction
Fixes #572
This commit is contained in:
parent
f23d2c9b9e
commit
cc466be6a6
|
|
@ -4,6 +4,10 @@ extend-exclude = [
|
||||||
"crates/ty_vendored/vendor/**/*",
|
"crates/ty_vendored/vendor/**/*",
|
||||||
"**/resources/**/*",
|
"**/resources/**/*",
|
||||||
"**/snapshots/**/*",
|
"**/snapshots/**/*",
|
||||||
|
# Completion tests tend to have a lot of incomplete
|
||||||
|
# words naturally. It's annoying to have to make all
|
||||||
|
# of them actually words. So just ignore typos here.
|
||||||
|
"crates/ty_ide/src/completion.rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
[default.extend-words]
|
[default.extend-words]
|
||||||
|
|
|
||||||
|
|
@ -861,6 +861,181 @@ print(f\"{some<CURSOR>
|
||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ref: https://github.com/astral-sh/ty/issues/572
|
||||||
|
#[test]
|
||||||
|
fn scope_id_missing_function_identifier1() {
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
def m<CURSOR>
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.completions(), @r"
|
||||||
|
m
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref: https://github.com/astral-sh/ty/issues/572
|
||||||
|
#[test]
|
||||||
|
fn scope_id_missing_function_identifier2() {
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
def m<CURSOR>(): pass
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.completions(), @r"
|
||||||
|
m
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref: https://github.com/astral-sh/ty/issues/572
|
||||||
|
#[test]
|
||||||
|
fn fscope_id_missing_function_identifier3() {
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
def m(): pass
|
||||||
|
<CURSOR>
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.completions(), @r"
|
||||||
|
m
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref: https://github.com/astral-sh/ty/issues/572
|
||||||
|
#[test]
|
||||||
|
fn scope_id_missing_class_identifier1() {
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
class M<CURSOR>
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.completions(), @r"
|
||||||
|
M
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref: https://github.com/astral-sh/ty/issues/572
|
||||||
|
#[test]
|
||||||
|
fn scope_id_missing_type_alias1() {
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
Fo<CURSOR> = float
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.completions(), @r"
|
||||||
|
Fo
|
||||||
|
float
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref: https://github.com/astral-sh/ty/issues/572
|
||||||
|
#[test]
|
||||||
|
fn scope_id_missing_import1() {
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
import fo<CURSOR>
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.completions(), @r"
|
||||||
|
fo
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref: https://github.com/astral-sh/ty/issues/572
|
||||||
|
#[test]
|
||||||
|
fn scope_id_missing_import2() {
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
import foo as ba<CURSOR>
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.completions(), @r"
|
||||||
|
ba
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref: https://github.com/astral-sh/ty/issues/572
|
||||||
|
#[test]
|
||||||
|
fn scope_id_missing_from_import1() {
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
from fo<CURSOR> import wat
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.completions(), @r"
|
||||||
|
wat
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref: https://github.com/astral-sh/ty/issues/572
|
||||||
|
#[test]
|
||||||
|
fn scope_id_missing_from_import2() {
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
from foo import wa<CURSOR>
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.completions(), @r"
|
||||||
|
wa
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref: https://github.com/astral-sh/ty/issues/572
|
||||||
|
#[test]
|
||||||
|
fn scope_id_missing_from_import3() {
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
from foo import wat as ba<CURSOR>
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.completions(), @r"
|
||||||
|
ba
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref: https://github.com/astral-sh/ty/issues/572
|
||||||
|
#[test]
|
||||||
|
fn scope_id_missing_try_except1() {
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except Type<CURSOR>:
|
||||||
|
pass
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.completions(), @r"
|
||||||
|
Type
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref: https://github.com/astral-sh/ty/issues/572
|
||||||
|
#[test]
|
||||||
|
fn scope_id_missing_global1() {
|
||||||
|
let test = cursor_test(
|
||||||
|
"\
|
||||||
|
def _():
|
||||||
|
global fo<CURSOR>
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_snapshot!(test.completions(), @r"
|
||||||
|
_
|
||||||
|
fo
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
impl CursorTest {
|
impl CursorTest {
|
||||||
fn completions(&self) -> String {
|
fn completions(&self) -> String {
|
||||||
let completions = completion(&self.db, self.file, self.cursor_offset);
|
let completions = completion(&self.db, self.file, self.cursor_offset);
|
||||||
|
|
|
||||||
|
|
@ -1040,6 +1040,11 @@ impl<'db> SemanticIndexBuilder<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn record_scope_for_identifier(&mut self, name: &ast::Identifier) {
|
||||||
|
self.scopes_by_expression
|
||||||
|
.insert(name.into(), self.current_scope());
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn build(mut self) -> SemanticIndex<'db> {
|
pub(super) fn build(mut self) -> SemanticIndex<'db> {
|
||||||
let module = self.module;
|
let module = self.module;
|
||||||
self.visit_body(module.suite());
|
self.visit_body(module.suite());
|
||||||
|
|
@ -1139,6 +1144,7 @@ where
|
||||||
is_async: _,
|
is_async: _,
|
||||||
range: _,
|
range: _,
|
||||||
} = function_def;
|
} = function_def;
|
||||||
|
self.record_scope_for_identifier(name);
|
||||||
for decorator in decorator_list {
|
for decorator in decorator_list {
|
||||||
self.visit_decorator(decorator);
|
self.visit_decorator(decorator);
|
||||||
}
|
}
|
||||||
|
|
@ -1221,6 +1227,7 @@ where
|
||||||
self.add_definition(symbol, function_def);
|
self.add_definition(symbol, function_def);
|
||||||
}
|
}
|
||||||
ast::Stmt::ClassDef(class) => {
|
ast::Stmt::ClassDef(class) => {
|
||||||
|
self.record_scope_for_identifier(&class.name);
|
||||||
for decorator in &class.decorator_list {
|
for decorator in &class.decorator_list {
|
||||||
self.visit_decorator(decorator);
|
self.visit_decorator(decorator);
|
||||||
}
|
}
|
||||||
|
|
@ -1270,6 +1277,10 @@ where
|
||||||
.record_node_reachability(NodeKey::from_node(node));
|
.record_node_reachability(NodeKey::from_node(node));
|
||||||
|
|
||||||
for (alias_index, alias) in node.names.iter().enumerate() {
|
for (alias_index, alias) in node.names.iter().enumerate() {
|
||||||
|
self.record_scope_for_identifier(&alias.name);
|
||||||
|
if let Some(ref asname) = alias.asname {
|
||||||
|
self.record_scope_for_identifier(asname);
|
||||||
|
}
|
||||||
// Mark the imported module, and all of its parents, as being imported in this
|
// Mark the imported module, and all of its parents, as being imported in this
|
||||||
// file.
|
// file.
|
||||||
if let Some(module_name) = ModuleName::new(&alias.name) {
|
if let Some(module_name) = ModuleName::new(&alias.name) {
|
||||||
|
|
@ -1294,6 +1305,9 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::Stmt::ImportFrom(node) => {
|
ast::Stmt::ImportFrom(node) => {
|
||||||
|
if let Some(ref module) = node.module {
|
||||||
|
self.record_scope_for_identifier(module);
|
||||||
|
}
|
||||||
self.current_use_def_map_mut()
|
self.current_use_def_map_mut()
|
||||||
.record_node_reachability(NodeKey::from_node(node));
|
.record_node_reachability(NodeKey::from_node(node));
|
||||||
|
|
||||||
|
|
@ -1378,6 +1392,10 @@ where
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.record_scope_for_identifier(&alias.name);
|
||||||
|
if let Some(ref asname) = alias.asname {
|
||||||
|
self.record_scope_for_identifier(asname);
|
||||||
|
}
|
||||||
let (symbol_name, is_reexported) = if let Some(asname) = &alias.asname {
|
let (symbol_name, is_reexported) = if let Some(asname) = &alias.asname {
|
||||||
(&asname.id, asname.id == alias.name.id)
|
(&asname.id, asname.id == alias.name.id)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1919,6 +1937,7 @@ where
|
||||||
}
|
}
|
||||||
ast::Stmt::Global(ast::StmtGlobal { range: _, names }) => {
|
ast::Stmt::Global(ast::StmtGlobal { range: _, names }) => {
|
||||||
for name in names {
|
for name in names {
|
||||||
|
self.record_scope_for_identifier(name);
|
||||||
let symbol_id = self.add_symbol(name.id.clone());
|
let symbol_id = self.add_symbol(name.id.clone());
|
||||||
let symbol_table = self.current_symbol_table();
|
let symbol_table = self.current_symbol_table();
|
||||||
let symbol = symbol_table.symbol(symbol_id);
|
let symbol = symbol_table.symbol(symbol_id);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue