Skip to content

Commit effcc07

Browse files
authored
[move-ide] Symbolication refactoring (#22102)
## Description This is a long overdue refactoring of the symbolicator. No code was changed, only moved around. ## Test plan All tests must pass
1 parent 42badaf commit effcc07

24 files changed

+4025
-3757
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,166 @@
11
// Copyright (c) The Move Contributors
22
// SPDX-License-Identifier: Apache-2.0
33

4+
use crate::{
5+
compiler_info::CompilerInfo,
6+
symbols::{
7+
compilation::{CompiledPkgInfo, SymbolsComputationData},
8+
cursor::CursorContext,
9+
def_info::DefInfo,
10+
mod_defs::ModuleDefs,
11+
use_def::{References, UseDef, UseDefMap},
12+
},
13+
utils::expansion_mod_ident_to_map_key,
14+
};
15+
16+
use im::ordmap::OrdMap;
17+
use lsp_types::Position;
18+
use std::collections::BTreeMap;
19+
20+
use move_compiler::{
21+
expansion::ast::ModuleIdent,
22+
parser::ast as P,
23+
shared::{NamedAddressMap, files::MappedFiles, unique_map::UniqueMap},
24+
typing::{ast::ModuleDefinition, visitor::TypingVisitorContext},
25+
};
26+
use move_ir_types::location::Loc;
27+
use move_symbol_pool::Symbol;
28+
429
pub mod parsing_analysis;
530
pub mod typing_analysis;
31+
32+
pub type DefMap = BTreeMap<Loc, DefInfo>;
33+
34+
/// Run parsing analysis for either main program or dependencies
35+
pub fn run_parsing_analysis(
36+
computation_data: &mut SymbolsComputationData,
37+
compiled_pkg_info: &CompiledPkgInfo,
38+
cursor_context: Option<&mut CursorContext>,
39+
parsed_program: &P::Program,
40+
) {
41+
let mut parsing_symbolicator = parsing_analysis::ParsingAnalysisContext {
42+
mod_outer_defs: &mut computation_data.mod_outer_defs,
43+
files: &compiled_pkg_info.mapped_files,
44+
references: &mut computation_data.references,
45+
def_info: &mut computation_data.def_info,
46+
use_defs: UseDefMap::new(),
47+
current_mod_ident_str: None,
48+
alias_lengths: BTreeMap::new(),
49+
pkg_addresses: &NamedAddressMap::new(),
50+
cursor: cursor_context,
51+
};
52+
53+
parsing_symbolicator.prog_symbols(
54+
parsed_program,
55+
&mut computation_data.mod_use_defs,
56+
&mut computation_data.mod_to_alias_lengths,
57+
);
58+
}
59+
60+
/// Run typing analysis for either main program or dependencies
61+
pub fn run_typing_analysis(
62+
mut computation_data: SymbolsComputationData,
63+
mapped_files: &MappedFiles,
64+
compiler_info: &mut CompilerInfo,
65+
typed_program_modules: &UniqueMap<ModuleIdent, ModuleDefinition>,
66+
) -> SymbolsComputationData {
67+
let mut typing_symbolicator = typing_analysis::TypingAnalysisContext {
68+
mod_outer_defs: &mut computation_data.mod_outer_defs,
69+
files: mapped_files,
70+
references: &mut computation_data.references,
71+
def_info: &mut computation_data.def_info,
72+
use_defs: UseDefMap::new(),
73+
current_mod_ident_str: None,
74+
alias_lengths: &BTreeMap::new(),
75+
traverse_only: false,
76+
compiler_info,
77+
type_params: BTreeMap::new(),
78+
expression_scope: OrdMap::new(),
79+
};
80+
81+
process_typed_modules(
82+
typed_program_modules,
83+
&computation_data.mod_to_alias_lengths,
84+
&mut typing_symbolicator,
85+
&mut computation_data.mod_use_defs,
86+
);
87+
computation_data
88+
}
89+
90+
pub fn find_datatype(mod_defs: &ModuleDefs, datatype_name: &Symbol) -> Option<Loc> {
91+
mod_defs.structs.get(datatype_name).map_or_else(
92+
|| {
93+
mod_defs
94+
.enums
95+
.get(datatype_name)
96+
.map(|enum_def| enum_def.name_loc)
97+
},
98+
|struct_def| Some(struct_def.name_loc),
99+
)
100+
}
101+
102+
fn process_typed_modules<'a>(
103+
typed_modules: &UniqueMap<ModuleIdent, ModuleDefinition>,
104+
mod_to_alias_lengths: &'a BTreeMap<String, BTreeMap<Position, usize>>,
105+
typing_symbolicator: &mut typing_analysis::TypingAnalysisContext<'a>,
106+
mod_use_defs: &mut BTreeMap<String, UseDefMap>,
107+
) {
108+
for (module_ident, module_def) in typed_modules.key_cloned_iter() {
109+
let mod_ident_str = expansion_mod_ident_to_map_key(&module_ident.value);
110+
typing_symbolicator.use_defs = mod_use_defs.remove(&mod_ident_str).unwrap();
111+
typing_symbolicator.alias_lengths = mod_to_alias_lengths.get(&mod_ident_str).unwrap();
112+
typing_symbolicator.visit_module(module_ident, module_def);
113+
114+
let use_defs = std::mem::replace(&mut typing_symbolicator.use_defs, UseDefMap::new());
115+
mod_use_defs.insert(mod_ident_str, use_defs);
116+
}
117+
}
118+
119+
/// Add use of a function, method, struct or enum identifier
120+
fn add_member_use_def(
121+
member_def_name: &Symbol, // may be different from use_name for methods
122+
files: &MappedFiles,
123+
mod_defs: &ModuleDefs,
124+
use_name: &Symbol,
125+
use_loc: &Loc,
126+
references: &mut References,
127+
def_info: &DefMap,
128+
use_defs: &mut UseDefMap,
129+
alias_lengths: &BTreeMap<Position, usize>,
130+
) -> Option<UseDef> {
131+
let Some(name_file_start) = files.start_position_opt(use_loc) else {
132+
debug_assert!(false);
133+
return None;
134+
};
135+
let name_start = Position {
136+
line: name_file_start.line_offset() as u32,
137+
character: name_file_start.column_offset() as u32,
138+
};
139+
if let Some(member_def) = mod_defs
140+
.functions
141+
.get(member_def_name)
142+
.or_else(|| mod_defs.structs.get(member_def_name))
143+
.or_else(|| mod_defs.enums.get(member_def_name))
144+
{
145+
let member_info = def_info.get(&member_def.name_loc).unwrap();
146+
// type def location exists only for structs and enums (and not for functions)
147+
let ident_type_def_loc = match member_info {
148+
DefInfo::Struct(_, name, ..) | DefInfo::Enum(_, name, ..) => {
149+
find_datatype(mod_defs, name)
150+
}
151+
_ => None,
152+
};
153+
let ud = UseDef::new(
154+
references,
155+
alias_lengths,
156+
use_loc.file_hash(),
157+
name_start,
158+
member_def.name_loc,
159+
use_name,
160+
ident_type_def_loc,
161+
);
162+
use_defs.insert(name_start.line, ud.clone());
163+
return Some(ud);
164+
}
165+
None
166+
}

external-crates/move/crates/move-analyzer/src/analysis/parsing_analysis.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
use crate::{
5+
analysis::{DefMap, add_member_use_def},
56
symbols::{
6-
AutoImportInsertionInfo, AutoImportInsertionKind, CallInfo, CursorContext,
7-
CursorDefinition, CursorPosition, DefMap, ModuleDefs, References, UseDef, UseDefMap,
8-
add_member_use_def, ignored_function, parsed_address,
9-
parsing_leading_and_mod_names_to_map_key, parsing_mod_def_to_map_key,
7+
cursor::{CursorContext, CursorDefinition, CursorPosition},
8+
ignored_function,
9+
mod_defs::{AutoImportInsertionInfo, AutoImportInsertionKind, CallInfo, ModuleDefs},
10+
parsed_address,
11+
use_def::{References, UseDef, UseDefMap},
1012
},
1113
utils::{loc_end_to_lsp_position_opt, loc_start_to_lsp_position_opt},
1214
};
@@ -921,6 +923,34 @@ impl<'a> ParsingAnalysisContext<'a> {
921923
}
922924
}
923925

926+
/// Produces module ident string of the form pkg::module to be used as a map key.
927+
/// It's important that these are consistent between parsing AST and typed AST.
928+
pub fn parsing_mod_def_to_map_key(
929+
pkg_addresses: &NamedAddressMap,
930+
mod_def: &P::ModuleDefinition,
931+
) -> Option<String> {
932+
// we assume that modules are declared using the PkgName::ModName pattern (which seems to be the
933+
// standard practice) and while Move allows other ways of defining modules (i.e., with address
934+
// preceding a sequence of modules), this method is now deprecated.
935+
//
936+
// TODO: make this function simply return String when the other way of defining modules is
937+
// removed
938+
mod_def
939+
.address
940+
.map(|a| parsing_leading_and_mod_names_to_map_key(pkg_addresses, a, mod_def.name))
941+
}
942+
943+
/// Produces module ident string of the form pkg::module to be used as a map key.
944+
/// It's important that these are consistent between parsing AST and typed AST.
945+
fn parsing_leading_and_mod_names_to_map_key(
946+
pkg_addresses: &NamedAddressMap,
947+
ln: P::LeadingNameAccess,
948+
name: P::ModuleName,
949+
) -> String {
950+
let parsed_addr = parsed_address(ln, pkg_addresses);
951+
format!("{}::{}", parsed_addr, name).to_string()
952+
}
953+
924954
/// Produces module ident string of the form pkg::module to be used as a map key.
925955
/// It's important that these are consistent between parsing AST and typed AST,
926956
fn parsing_mod_ident_to_map_key(

external-crates/move/crates/move-analyzer/src/analysis/typing_analysis.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
use crate::{
5+
analysis::{DefMap, add_member_use_def, find_datatype},
56
compiler_info::CompilerInfo,
67
symbols::{
7-
DefInfo, DefMap, LocalDef, MemberDefInfo, ModuleDefs, References, UseDef, UseDefMap,
8-
add_member_use_def, expansion_mod_ident_to_map_key, find_datatype, type_def_loc,
8+
def_info::DefInfo,
9+
mod_defs::{MemberDefInfo, ModuleDefs},
10+
type_def_loc,
11+
use_def::{References, UseDef, UseDefMap},
912
},
10-
utils::{ignored_function, loc_start_to_lsp_position_opt},
13+
utils::{expansion_mod_ident_to_map_key, ignored_function, loc_start_to_lsp_position_opt},
1114
};
1215

1316
use move_compiler::{
@@ -26,7 +29,7 @@ use move_symbol_pool::Symbol;
2629

2730
use im::OrdMap;
2831
use lsp_types::Position;
29-
use std::collections::BTreeMap;
32+
use std::{cmp, collections::BTreeMap};
3033

3134
/// Data used during anlysis over typed AST
3235
pub struct TypingAnalysisContext<'a> {
@@ -61,6 +64,26 @@ pub struct TypingAnalysisContext<'a> {
6164
pub compiler_info: &'a mut CompilerInfo,
6265
}
6366

67+
/// Definition of a local (or parameter)
68+
#[derive(Debug, Clone, Eq, PartialEq)]
69+
pub struct LocalDef {
70+
/// Location of the definition
71+
pub def_loc: Loc,
72+
/// Type of definition
73+
pub def_type: N::Type,
74+
}
75+
76+
impl PartialOrd for LocalDef {
77+
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
78+
Some(self.cmp(other))
79+
}
80+
}
81+
impl Ord for LocalDef {
82+
fn cmp(&self, other: &Self) -> cmp::Ordering {
83+
self.def_loc.cmp(&other.def_loc)
84+
}
85+
}
86+
6487
fn def_info_to_type_def_loc(
6588
mod_outer_defs: &BTreeMap<String, ModuleDefs>,
6689
def_info: &DefInfo,

external-crates/move/crates/move-analyzer/src/analyzer.rs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,19 @@ use std::{
2121
};
2222

2323
use crate::{
24-
code_action, completions::on_completion_request, context::Context, inlay_hints, symbols,
24+
code_action,
25+
completions::on_completion_request,
26+
context::Context,
27+
inlay_hints,
28+
symbols::{
29+
self,
30+
compilation::PrecomputedPkgInfo,
31+
requests::{
32+
on_document_symbol_request, on_go_to_def_request, on_go_to_type_def_request,
33+
on_hover_request, on_references_request,
34+
},
35+
runner::SymbolicatorRunner,
36+
},
2537
vfs::on_text_document_sync_notification,
2638
};
2739
use url::Url;
@@ -47,9 +59,7 @@ pub fn run(implicit_deps: Dependencies) {
4759

4860
let (connection, io_threads) = Connection::stdio();
4961
let symbols_map = Arc::new(Mutex::new(BTreeMap::new()));
50-
let pkg_deps = Arc::new(Mutex::new(
51-
BTreeMap::<PathBuf, symbols::PrecomputedPkgInfo>::new(),
52-
));
62+
let pkg_deps = Arc::new(Mutex::new(BTreeMap::<PathBuf, PrecomputedPkgInfo>::new()));
5363
let ide_files_root: VfsPath = MemoryFS::new().into();
5464

5565
let (id, client_response) = connection
@@ -142,7 +152,7 @@ pub fn run(implicit_deps: Dependencies) {
142152
};
143153
eprintln!("linting level {:?}", lint);
144154

145-
let symbolicator_runner = symbols::SymbolicatorRunner::new(
155+
let symbolicator_runner = SymbolicatorRunner::new(
146156
ide_files_root.clone(),
147157
symbols_map.clone(),
148158
pkg_deps.clone(),
@@ -158,7 +168,7 @@ pub fn run(implicit_deps: Dependencies) {
158168
// to be available right after the client is initialized.
159169
if let Some(uri) = initialize_params.root_uri {
160170
let build_path = uri.to_file_path().unwrap();
161-
if let Some(p) = symbols::SymbolicatorRunner::root_dir(&build_path) {
171+
if let Some(p) = SymbolicatorRunner::root_dir(&build_path) {
162172
if let Ok((Some(new_symbols), _)) = symbols::get_symbols(
163173
Arc::new(Mutex::new(BTreeMap::new())),
164174
ide_files_root.clone(),
@@ -300,7 +310,7 @@ fn on_request(
300310
context: &Context,
301311
request: &Request,
302312
ide_files_root: VfsPath,
303-
pkg_dependencies: Arc<Mutex<BTreeMap<PathBuf, symbols::PrecomputedPkgInfo>>>,
313+
pkg_dependencies: Arc<Mutex<BTreeMap<PathBuf, PrecomputedPkgInfo>>>,
304314
shutdown_request_received: bool,
305315
implicit_deps: Dependencies,
306316
) -> bool {
@@ -328,19 +338,19 @@ fn on_request(
328338
implicit_deps,
329339
),
330340
lsp_types::request::GotoDefinition::METHOD => {
331-
symbols::on_go_to_def_request(context, request);
341+
on_go_to_def_request(context, request);
332342
}
333343
lsp_types::request::GotoTypeDefinition::METHOD => {
334-
symbols::on_go_to_type_def_request(context, request);
344+
on_go_to_type_def_request(context, request);
335345
}
336346
lsp_types::request::References::METHOD => {
337-
symbols::on_references_request(context, request);
347+
on_references_request(context, request);
338348
}
339349
lsp_types::request::HoverRequest::METHOD => {
340-
symbols::on_hover_request(context, request);
350+
on_hover_request(context, request);
341351
}
342352
lsp_types::request::DocumentSymbolRequest::METHOD => {
343-
symbols::on_document_symbol_request(context, request);
353+
on_document_symbol_request(context, request);
344354
}
345355
lsp_types::request::InlayHintRequest::METHOD => {
346356
inlay_hints::on_inlay_hint_request(context, request);
@@ -378,7 +388,7 @@ fn on_response(_context: &Context, _response: &Response) {
378388

379389
fn on_notification(
380390
ide_files_root: VfsPath,
381-
symbolicator_runner: &symbols::SymbolicatorRunner,
391+
symbolicator_runner: &SymbolicatorRunner,
382392
notification: &Notification,
383393
) {
384394
match notification.method.as_str() {

external-crates/move/crates/move-analyzer/src/code_action.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ use crate::{
88
},
99
context::Context,
1010
symbols::{
11-
ChainInfo, CompiledPkgInfo, CursorContext, PrecomputedPkgInfo, SymbolicatorRunner, Symbols,
12-
get_compiled_pkg,
11+
Symbols,
12+
compilation::{CompiledPkgInfo, PrecomputedPkgInfo, get_compiled_pkg},
13+
cursor::{ChainInfo, CursorContext},
14+
runner::SymbolicatorRunner,
1315
},
1416
utils::loc_start_to_lsp_position_opt,
1517
};

external-crates/move/crates/move-analyzer/src/completions/dot.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55

66
use crate::{
77
completions::utils::{call_completion_item, mod_defs},
8-
symbols::{DefInfo, FunType, Symbols, type_to_ide_string},
8+
symbols::{
9+
Symbols,
10+
def_info::{DefInfo, FunType},
11+
ide_strings::type_to_ide_string,
12+
},
913
utils::lsp_position_to_loc,
1014
};
1115
use lsp_types::{

0 commit comments

Comments
 (0)