Skip to content

Commit 7e0e326

Browse files
kinto0meta-codesync[bot]
authored andcommitted
Add tests for go-to-definition on relative import module names
Summary: Go-to-definition on the module name part of a relative import (e.g., clicking on `bar` in `from .bar import value`) returns empty results because `find_definition` does not resolve relative imports via `new_maybe_relative`. This adds two LSP interaction tests that reproduce the bug with a nested config layout (pyrefly.toml at both root and src/), and a unit test for relative import resolution. The tests currently assert the broken behavior (empty response). Reviewed By: yangdanny97 Differential Revision: D95303805 fbshipit-source-id: f0bea8f64e76996440bf77bb9f1cf106bab11c3a
1 parent 79c9b38 commit 7e0e326

File tree

7 files changed

+98
-0
lines changed

7 files changed

+98
-0
lines changed

pyrefly/lib/test/imports.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,3 +1272,20 @@ assert_type(x, int)
12721272
assert_type(y, str)
12731273
"#,
12741274
);
1275+
1276+
fn env_relative_import_in_subdirectory() -> TestEnv {
1277+
let mut t = TestEnv::new();
1278+
t.add_with_path("test.foo", "test/foo.py", "from .foo2 import bar");
1279+
t.add_with_path("test.foo2", "test/foo2.py", "bar: int = 100");
1280+
t
1281+
}
1282+
1283+
testcase!(
1284+
test_relative_import_in_subdirectory,
1285+
env_relative_import_in_subdirectory(),
1286+
r#"
1287+
from typing import assert_type
1288+
from test.foo import bar
1289+
assert_type(bar, int)
1290+
"#,
1291+
);

pyrefly/lib/test/lsp/lsp_interaction/definition.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use lsp_server::RequestId;
1111
use lsp_types::GotoDefinitionResponse;
1212
use lsp_types::Location;
1313
use lsp_types::Url;
14+
use pyrefly::commands::lsp::IndexingMode;
1415
use pyrefly::lsp::non_wasm::protocol::Message;
1516
use pyrefly::lsp::non_wasm::protocol::Request;
1617
use serde_json::json;
@@ -652,3 +653,63 @@ fn test_goto_def_dunder_all_submodule() {
652653
.unwrap();
653654
interaction.shutdown().unwrap();
654655
}
656+
657+
/// Go-to-definition on the module name part of a relative import
658+
/// (e.g., clicking on `bar` in `from .bar import value`) does not resolve
659+
/// because `find_definition` does not resolve relative imports.
660+
#[test]
661+
fn definition_relative_import_with_nested_config() {
662+
let root = get_test_files_root();
663+
let root_path = root
664+
.path()
665+
.join("nested_config_relative_import/src")
666+
.to_path_buf();
667+
let scope_uri = Url::from_file_path(&root_path).unwrap();
668+
let mut interaction = LspInteraction::new_with_indexing_mode(IndexingMode::LazyBlocking);
669+
interaction.set_root(root_path);
670+
interaction
671+
.initialize(InitializeSettings {
672+
workspace_folders: Some(vec![("test".to_owned(), scope_uri)]),
673+
..Default::default()
674+
})
675+
.unwrap();
676+
interaction.client.did_open("main.py");
677+
interaction.client.did_open("pkg/foo.py");
678+
// Go-to-definition on `bar` module in `from .bar import value` (line 5, char 6)
679+
// BUG: returns null because find_definition doesn't resolve relative imports.
680+
interaction
681+
.client
682+
.definition("pkg/foo.py", 5, 6)
683+
.expect_response(json!([]))
684+
.unwrap();
685+
interaction.shutdown().unwrap();
686+
}
687+
688+
/// Same as above but with workspace root above src/.
689+
#[test]
690+
fn definition_relative_import_with_nested_config_workspace_at_root() {
691+
let root = get_test_files_root();
692+
let root_path = root
693+
.path()
694+
.join("nested_config_relative_import")
695+
.to_path_buf();
696+
let scope_uri = Url::from_file_path(&root_path).unwrap();
697+
let mut interaction = LspInteraction::new_with_indexing_mode(IndexingMode::LazyBlocking);
698+
interaction.set_root(root_path);
699+
interaction
700+
.initialize(InitializeSettings {
701+
workspace_folders: Some(vec![("test".to_owned(), scope_uri)]),
702+
..Default::default()
703+
})
704+
.unwrap();
705+
interaction.client.did_open("src/main.py");
706+
interaction.client.did_open("src/pkg/foo.py");
707+
// Go-to-definition on `bar` module in `from .bar import value` (line 5, char 6)
708+
// BUG: returns empty because find_definition doesn't resolve relative imports.
709+
interaction
710+
.client
711+
.definition("src/pkg/foo.py", 5, 6)
712+
.expect_response(json!([]))
713+
.unwrap();
714+
interaction.shutdown().unwrap();
715+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
project_includes = ["src"]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
#
3+
# This source code is licensed under the MIT license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
from pkg.foo import value
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
#
3+
# This source code is licensed under the MIT license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
value: int = 42
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
#
3+
# This source code is licensed under the MIT license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
from .bar import value
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
project_includes = ["."]

0 commit comments

Comments
 (0)