diff --git a/Cargo.lock b/Cargo.lock index 6d7f6042deca..1aca43a9bd92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1705,6 +1705,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", + "span", "stdx", "syntax", "syntax-bridge", diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 3b6e3c5916e3..89ce5f838e05 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -67,7 +67,7 @@ use intern::Symbol; use itertools::Itertools; use la_arena::Arena; use rustc_hash::{FxHashMap, FxHashSet}; -use span::{Edition, EditionedFileId, FileAstId, FileId, ROOT_ERASED_FILE_AST_ID}; +use span::{Edition, EditionedFileId, FileAstId, FileId, MacroFileId, ROOT_ERASED_FILE_AST_ID}; use stdx::format_to; use syntax::{ast, AstNode, SmolStr, SyntaxNode}; use triomphe::Arc; @@ -441,6 +441,23 @@ impl DefMap { .map(|(id, _data)| id) } + pub fn inline_modules_for_macro_file( + &self, + file_id: MacroFileId, + ) -> impl Iterator + '_ { + self.modules + .iter() + .filter(move |(_id, data)| { + (match data.origin { + ModuleOrigin::Inline { definition_tree_id, .. } => { + definition_tree_id.file_id().macro_file() + } + _ => None, + }) == Some(file_id) + }) + .map(|(id, _data)| id) + } + pub fn modules(&self) -> impl Iterator + '_ { self.modules.iter() } diff --git a/crates/hir-expand/src/files.rs b/crates/hir-expand/src/files.rs index 13ddb0d4acce..075ac78fffb8 100644 --- a/crates/hir-expand/src/files.rs +++ b/crates/hir-expand/src/files.rs @@ -38,11 +38,51 @@ pub type HirFilePosition = FilePositionWrapper; pub type MacroFilePosition = FilePositionWrapper; pub type FilePosition = FilePositionWrapper; -impl From> for FilePositionWrapper { - fn from(value: FilePositionWrapper) -> Self { +impl From for FilePositionWrapper { + fn from(value: FilePosition) -> Self { FilePositionWrapper { file_id: value.file_id.into(), offset: value.offset } } } + +impl From for HirFileRange { + fn from(value: FileRange) -> Self { + HirFileRange { file_id: value.file_id.into(), range: value.range } + } +} + +impl From for HirFilePosition { + fn from(value: FilePosition) -> Self { + HirFilePosition { file_id: value.file_id.into(), offset: value.offset } + } +} + +impl FilePositionWrapper { + pub fn with_edition(self, edition: span::Edition) -> FilePosition { + FilePositionWrapper { + file_id: EditionedFileId::new(self.file_id, edition), + offset: self.offset, + } + } +} + +impl FileRangeWrapper { + pub fn with_edition(self, edition: span::Edition) -> FileRange { + FileRangeWrapper { file_id: EditionedFileId::new(self.file_id, edition), range: self.range } + } +} + +impl InFileWrapper { + pub fn with_edition(self, edition: span::Edition) -> InRealFile { + InRealFile { file_id: EditionedFileId::new(self.file_id, edition), value: self.value } + } +} + +impl HirFileRange { + pub fn file_range(self) -> Option { + Some(FileRange { file_id: self.file_id.file_id()?, range: self.range }) + } +} + #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub struct FileRangeWrapper { pub file_id: FileKind, @@ -191,6 +231,9 @@ impl InFileWrapper { pub fn syntax(&self) -> InFileWrapper { self.with_value(self.value.syntax()) } + pub fn node_file_range(&self) -> FileRangeWrapper { + FileRangeWrapper { file_id: self.file_id, range: self.value.syntax().text_range() } + } } impl InFileWrapper { @@ -201,9 +244,9 @@ impl InFileWrapper { } // region:specific impls -impl> InRealFile { - pub fn file_range(&self) -> FileRange { - FileRange { file_id: self.file_id, range: self.value.borrow().text_range() } +impl> InFileWrapper { + pub fn file_range(&self) -> FileRangeWrapper { + FileRangeWrapper { file_id: self.file_id, range: self.value.borrow().text_range() } } } diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index 2c664029f615..f5e9d0b44096 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -347,6 +347,7 @@ pub trait HirFileIdExt { /// If this is a macro call, returns the syntax node of the very first macro call this file resides in. fn original_call_node(self, db: &dyn ExpandDatabase) -> Option>; + fn call_node(self, db: &dyn ExpandDatabase) -> Option>; fn as_builtin_derive_attr_node(&self, db: &dyn ExpandDatabase) -> Option>; } @@ -405,6 +406,10 @@ impl HirFileIdExt for HirFileId { } } + fn call_node(self, db: &dyn ExpandDatabase) -> Option> { + Some(db.lookup_intern_macro_call(self.macro_file()?.macro_call_id).to_node(db)) + } + fn as_builtin_derive_attr_node(&self, db: &dyn ExpandDatabase) -> Option> { let macro_file = self.macro_file()?; let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); @@ -873,7 +878,10 @@ impl ExpansionInfo { map_node_range_up(db, &self.exp_map, range) } - /// Maps up the text range out of the expansion into is macro call. + /// Maps up the text range out of the expansion into its macro call. + /// + /// Note that this may return multiple ranges as we lose the precise association between input to output + /// and as such we may consider inputs that are unrelated. pub fn map_range_up_once( &self, db: &dyn ExpandDatabase, @@ -889,11 +897,10 @@ impl ExpansionInfo { InFile { file_id, value: smallvec::smallvec![span.range + anchor_offset] } } SpanMap::ExpansionSpanMap(arg_map) => { - let arg_range = self - .arg - .value - .as_ref() - .map_or_else(|| TextRange::empty(TextSize::from(0)), |it| it.text_range()); + let Some(arg_node) = &self.arg.value else { + return InFile::new(self.arg.file_id, smallvec::smallvec![]); + }; + let arg_range = arg_node.text_range(); InFile::new( self.arg.file_id, arg_map diff --git a/crates/hir-expand/src/prettify_macro_expansion_.rs b/crates/hir-expand/src/prettify_macro_expansion_.rs index c744fbce77b7..3907884f99c3 100644 --- a/crates/hir-expand/src/prettify_macro_expansion_.rs +++ b/crates/hir-expand/src/prettify_macro_expansion_.rs @@ -21,43 +21,47 @@ pub fn prettify_macro_expansion( let crate_graph = db.crate_graph(); let target_crate = &crate_graph[target_crate_id]; let mut syntax_ctx_id_to_dollar_crate_replacement = FxHashMap::default(); - syntax_bridge::prettify_macro_expansion::prettify_macro_expansion(syn, &mut |dollar_crate| { - let ctx = span_map.span_at(dollar_crate.text_range().start() + span_offset).ctx; - let replacement = - syntax_ctx_id_to_dollar_crate_replacement.entry(ctx).or_insert_with(|| { - let ctx_data = db.lookup_intern_syntax_context(ctx); - let macro_call_id = - ctx_data.outer_expn.expect("`$crate` cannot come from `SyntaxContextId::ROOT`"); - let macro_call = db.lookup_intern_macro_call(macro_call_id); - let macro_def_crate = macro_call.def.krate; - // First, if this is the same crate as the macro, nothing will work but `crate`. - // If not, if the target trait has the macro's crate as a dependency, using the dependency name - // will work in inserted code and match the user's expectation. - // If not, the crate's display name is what the dependency name is likely to be once such dependency - // is inserted, and also understandable to the user. - // Lastly, if nothing else found, resort to leaving `$crate`. - if target_crate_id == macro_def_crate { - make::tokens::crate_kw() - } else if let Some(dep) = - target_crate.dependencies.iter().find(|dep| dep.crate_id == macro_def_crate) - { - make::tokens::ident(dep.name.as_str()) - } else if let Some(crate_name) = &crate_graph[macro_def_crate].display_name { - make::tokens::ident(crate_name.crate_name().as_str()) - } else { - return dollar_crate.clone(); - } - }); - if replacement.text() == "$crate" { - // The parent may have many children, and looking for the token may yield incorrect results. - return dollar_crate.clone(); - } - // We need to `clone_subtree()` but rowan doesn't provide such operation for tokens. - let parent = replacement.parent().unwrap().clone_subtree().clone_for_update(); - parent - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|it| it.kind() == replacement.kind()) - .unwrap() - }) + syntax_bridge::prettify_macro_expansion::prettify_macro_expansion( + syn, + &mut |dollar_crate| { + let ctx = span_map.span_at(dollar_crate.text_range().start() + span_offset).ctx; + let replacement = + syntax_ctx_id_to_dollar_crate_replacement.entry(ctx).or_insert_with(|| { + let ctx_data = db.lookup_intern_syntax_context(ctx); + let macro_call_id = ctx_data + .outer_expn + .expect("`$crate` cannot come from `SyntaxContextId::ROOT`"); + let macro_call = db.lookup_intern_macro_call(macro_call_id); + let macro_def_crate = macro_call.def.krate; + // First, if this is the same crate as the macro, nothing will work but `crate`. + // If not, if the target trait has the macro's crate as a dependency, using the dependency name + // will work in inserted code and match the user's expectation. + // If not, the crate's display name is what the dependency name is likely to be once such dependency + // is inserted, and also understandable to the user. + // Lastly, if nothing else found, resort to leaving `$crate`. + if target_crate_id == macro_def_crate { + make::tokens::crate_kw() + } else if let Some(dep) = + target_crate.dependencies.iter().find(|dep| dep.crate_id == macro_def_crate) + { + make::tokens::ident(dep.name.as_str()) + } else if let Some(crate_name) = &crate_graph[macro_def_crate].display_name { + make::tokens::ident(crate_name.crate_name().as_str()) + } else { + return dollar_crate.clone(); + } + }); + if replacement.text() == "$crate" { + // The parent may have many children, and looking for the token may yield incorrect results. + return None; + } + // We need to `clone_subtree()` but rowan doesn't provide such operation for tokens. + let parent = replacement.parent().unwrap().clone_subtree().clone_for_update(); + parent + .children_with_tokens() + .filter_map(NodeOrToken::into_token) + .find(|it| it.kind() == replacement.kind()) + }, + |_| (), + ) } diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index c9145f7d212d..ae55ee0689a5 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -24,11 +24,11 @@ use hir_expand::{ attrs::collect_attrs, builtin::{BuiltinFnLikeExpander, EagerExpander}, db::ExpandDatabase, - files::InRealFile, + files::{HirFileRange, InRealFile}, hygiene::SyntaxContextExt as _, inert_attr_macro::find_builtin_attr_idx, name::AsName, - ExpandResult, FileRange, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt, + ExpandResult, FileRange, HirFileIdExt, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt, }; use intern::{sym, Symbol}; use itertools::Itertools; @@ -235,14 +235,28 @@ impl Semantics<'_, DB> { self.imp.resolve_variant(record_lit).map(VariantDef::from) } - pub fn file_to_module_def(&self, file: impl Into) -> Option { + pub fn file_to_module_def(&self, file: impl Into) -> Option { self.imp.file_to_module_defs(file.into()).next() } - pub fn file_to_module_defs(&self, file: impl Into) -> impl Iterator { + pub fn hir_file_to_module_def(&self, file: impl Into) -> Option { + self.imp.hir_file_to_module_defs(file.into()).next() + } + + pub fn file_to_module_defs( + &self, + file: impl Into, + ) -> impl Iterator { self.imp.file_to_module_defs(file.into()) } + pub fn hir_file_to_module_defs( + &self, + file: impl Into, + ) -> impl Iterator { + self.imp.hir_file_to_module_defs(file.into()) + } + pub fn to_adt_def(&self, a: &ast::Adt) -> Option { self.imp.to_def(a) } @@ -314,7 +328,10 @@ impl<'db> SemanticsImpl<'db> { pub fn attach_first_edition(&self, file: FileId) -> Option { Some(EditionedFileId::new( file, - self.file_to_module_defs(file).next()?.krate().edition(self.db), + self.file_to_module_defs(EditionedFileId::new(file, span::Edition::CURRENT)) + .next()? + .krate() + .edition(self.db), )) } @@ -327,10 +344,18 @@ impl<'db> SemanticsImpl<'db> { tree } + pub fn adjust_edition(&self, file_id: HirFileId) -> HirFileId { + if let Some(editioned_file_id) = file_id.file_id() { + self.attach_first_edition(editioned_file_id.file_id()).map_or(file_id, Into::into) + } else { + file_id + } + } + pub fn find_parent_file(&self, file_id: HirFileId) -> Option> { match file_id.repr() { HirFileIdRepr::FileId(file_id) => { - let module = self.file_to_module_defs(file_id.file_id()).next()?; + let module = self.file_to_module_defs(file_id).next()?; let def_map = self.db.crate_def_map(module.krate().id); match def_map[module.id.local_id].origin { ModuleOrigin::CrateRoot { .. } => None, @@ -399,9 +424,7 @@ impl<'db> SemanticsImpl<'db> { pub fn check_cfg_attr(&self, attr: &ast::TokenTree) -> Option { let file_id = self.find_file(attr.syntax()).file_id; let krate = match file_id.repr() { - HirFileIdRepr::FileId(file_id) => { - self.file_to_module_defs(file_id.file_id()).next()?.krate().id - } + HirFileIdRepr::FileId(file_id) => self.file_to_module_defs(file_id).next()?.krate().id, HirFileIdRepr::MacroFile(macro_file) => { self.db.lookup_intern_macro_call(macro_file.macro_call_id).krate } @@ -637,7 +660,7 @@ impl<'db> SemanticsImpl<'db> { string: &ast::String, ) -> Option>)>> { let string_start = string.syntax().text_range().start(); - let token = self.wrap_token_infile(string.syntax().clone()).into_real_file().ok()?; + let token = self.wrap_token_infile(string.syntax().clone()); self.descend_into_macros_breakable(token, |token, _| { (|| { let token = token.value; @@ -677,50 +700,82 @@ impl<'db> SemanticsImpl<'db> { } /// Retrieves the formatting part of the format_args! template string at the given offset. + /// + /// Returns absolute file range of the part in the format string, the corresponding string token + /// and the resolution if it exists. + // FIXME: Check that callers check for the returned file id pub fn check_for_format_args_template( &self, original_token: SyntaxToken, offset: TextSize, - ) -> Option<(TextRange, Option>)> { - let string_start = original_token.text_range().start(); - let original_token = self.wrap_token_infile(original_token).into_real_file().ok()?; - self.descend_into_macros_breakable(original_token, |token, _| { - (|| { - let token = token.value; - self.resolve_offset_in_format_args( - ast::String::cast(token)?, - offset.checked_sub(string_start)?, - ) - .map(|(range, res)| (range + string_start, res)) - })() - .map_or(ControlFlow::Continue(()), ControlFlow::Break) - }) + ) -> Option<(HirFileRange, ast::String, Option>)> { + let original_token = + self.wrap_token_infile(original_token).map(ast::String::cast).transpose()?; + self.check_for_format_args_template_with_file(original_token, offset) + } + + /// Retrieves the formatting part of the format_args! template string at the given offset. + /// + /// Returns absolute file range of the part in the format string, the corresponding string token + /// and the resolution if it exists. + // FIXME: Check that callers check for the returned file id + pub fn check_for_format_args_template_with_file( + &self, + original_token: InFile, + offset: TextSize, + ) -> Option<(HirFileRange, ast::String, Option>)> { + let relative_offset = + offset.checked_sub(original_token.value.syntax().text_range().start())?; + self.descend_into_macros_breakable( + original_token.map(|it| it.syntax().clone()), + |token, _| { + (|| { + let token = token.map(ast::String::cast).transpose()?; + self.resolve_offset_in_format_args(token.as_ref(), relative_offset).map( + |(HirFileRange { file_id, range }, res)| { + ( + HirFileRange { + file_id, + range: range + token.value.syntax().text_range().start(), + }, + token.value, + res, + ) + }, + ) + })() + .map_or(ControlFlow::Continue(()), ControlFlow::Break) + }, + ) } fn resolve_offset_in_format_args( &self, - string: ast::String, + InFile { value: string, file_id }: InFile<&ast::String>, offset: TextSize, - ) -> Option<(TextRange, Option>)> { + ) -> Option<(HirFileRange, Option>)> { debug_assert!(offset <= string.syntax().text_range().len()); let literal = string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?; let parent = literal.parent()?; if let Some(format_args) = ast::FormatArgsExpr::cast(parent.clone()) { - let source_analyzer = &self.analyze_no_infer(format_args.syntax())?; - let format_args = self.wrap_node_infile(format_args); + let source_analyzer = + &self.analyze_impl(InFile::new(file_id, format_args.syntax()), None, false)?; source_analyzer - .resolve_offset_in_format_args(self.db, format_args.as_ref(), offset) - .map(|(range, res)| (range, res.map(Either::Left))) + .resolve_offset_in_format_args(self.db, InFile::new(file_id, &format_args), offset) + .map(|(range, res)| (HirFileRange { file_id, range }, res.map(Either::Left))) } else { let asm = ast::AsmExpr::cast(parent)?; - let source_analyzer = &self.analyze_no_infer(asm.syntax())?; + let source_analyzer = + self.analyze_impl(InFile::new(file_id, asm.syntax()), None, false)?; let line = asm.template().position(|it| *it.syntax() == literal)?; - let asm = self.wrap_node_infile(asm); - source_analyzer.resolve_offset_in_asm_template(asm.as_ref(), line, offset).map( - |(owner, (expr, range, index))| { - (range, Some(Either::Right(InlineAsmOperand { owner, expr, index }))) - }, - ) + source_analyzer + .resolve_offset_in_asm_template(InFile::new(file_id, &asm), line, offset) + .map(|(owner, (expr, range, index))| { + ( + HirFileRange { file_id, range }, + Some(Either::Right(InlineAsmOperand { owner, expr, index })), + ) + }) } } @@ -739,14 +794,10 @@ impl<'db> SemanticsImpl<'db> { None => return res, }; let file = self.find_file(node.syntax()); - let Some(file_id) = file.file_id.file_id() else { - return res; - }; - if first == last { // node is just the token, so descend the token self.descend_into_macros_impl( - InRealFile::new(file_id, first), + InFile::new(file.file_id, first), &mut |InFile { value, .. }, _ctx| { if let Some(node) = value .parent_ancestors() @@ -761,14 +812,14 @@ impl<'db> SemanticsImpl<'db> { } else { // Descend first and last token, then zip them to look for the node they belong to let mut scratch: SmallVec<[_; 1]> = smallvec![]; - self.descend_into_macros_impl(InRealFile::new(file_id, first), &mut |token, _ctx| { + self.descend_into_macros_impl(InFile::new(file.file_id, first), &mut |token, _ctx| { scratch.push(token); CONTINUE_NO_BREAKS }); let mut scratch = scratch.into_iter(); self.descend_into_macros_impl( - InRealFile::new(file_id, last), + InFile::new(file.file_id, last), &mut |InFile { value: last, file_id: last_fid }, _ctx| { if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() { if first_fid == last_fid { @@ -844,22 +895,18 @@ impl<'db> SemanticsImpl<'db> { token: SyntaxToken, mut cb: impl FnMut(InFile, SyntaxContextId), ) { - if let Ok(token) = self.wrap_token_infile(token).into_real_file() { - self.descend_into_macros_impl(token, &mut |t, ctx| { - cb(t, ctx); - CONTINUE_NO_BREAKS - }); - } + self.descend_into_macros_impl(self.wrap_token_infile(token), &mut |t, ctx| { + cb(t, ctx); + CONTINUE_NO_BREAKS + }); } pub fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> { let mut res = smallvec![]; - if let Ok(token) = self.wrap_token_infile(token.clone()).into_real_file() { - self.descend_into_macros_impl(token, &mut |t, _ctx| { - res.push(t.value); - CONTINUE_NO_BREAKS - }); - } + self.descend_into_macros_impl(self.wrap_token_infile(token.clone()), &mut |t, _ctx| { + res.push(t.value); + CONTINUE_NO_BREAKS + }); if res.is_empty() { res.push(token); } @@ -868,15 +915,13 @@ impl<'db> SemanticsImpl<'db> { pub fn descend_into_macros_no_opaque(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> { let mut res = smallvec![]; - if let Ok(token) = self.wrap_token_infile(token.clone()).into_real_file() { - self.descend_into_macros_impl(token, &mut |t, ctx| { - if !ctx.is_opaque(self.db.upcast()) { - // Don't descend into opaque contexts - res.push(t.value); - } - CONTINUE_NO_BREAKS - }); - } + self.descend_into_macros_impl(self.wrap_token_infile(token.clone()), &mut |t, ctx| { + if !ctx.is_opaque(self.db.upcast()) { + // Don't descend into opaque contexts + res.push(t.value); + } + CONTINUE_NO_BREAKS + }); if res.is_empty() { res.push(token); } @@ -885,7 +930,7 @@ impl<'db> SemanticsImpl<'db> { pub fn descend_into_macros_breakable( &self, - token: InRealFile, + token: InFile, mut cb: impl FnMut(InFile, SyntaxContextId) -> ControlFlow, ) -> Option { self.descend_into_macros_impl(token.clone(), &mut cb) @@ -914,41 +959,62 @@ impl<'db> SemanticsImpl<'db> { r } + /// Descends the token into expansions, returning the tokens that matches the input + /// token's [`SyntaxKind`] and text. + pub fn descend_into_macros_exact_with_file( + &self, + token: SyntaxToken, + ) -> SmallVec<[InFile; 1]> { + let mut r = smallvec![]; + let text = token.text(); + let kind = token.kind(); + + self.descend_into_macros_cb(token.clone(), |InFile { value, file_id }, ctx| { + let mapped_kind = value.kind(); + let any_ident_match = || kind.is_any_identifier() && value.kind().is_any_identifier(); + let matches = (kind == mapped_kind || any_ident_match()) + && text == value.text() + && !ctx.is_opaque(self.db.upcast()); + if matches { + r.push(InFile { value, file_id }); + } + }); + if r.is_empty() { + r.push(self.wrap_token_infile(token)); + } + r + } + /// Descends the token into expansions, returning the first token that matches the input /// token's [`SyntaxKind`] and text. pub fn descend_into_macros_single_exact(&self, token: SyntaxToken) -> SyntaxToken { let text = token.text(); let kind = token.kind(); - if let Ok(token) = self.wrap_token_infile(token.clone()).into_real_file() { - self.descend_into_macros_breakable( - token.clone(), - |InFile { value, file_id: _ }, _ctx| { - let mapped_kind = value.kind(); - let any_ident_match = - || kind.is_any_identifier() && value.kind().is_any_identifier(); - let matches = - (kind == mapped_kind || any_ident_match()) && text == value.text(); - if matches { - ControlFlow::Break(value) - } else { - ControlFlow::Continue(()) - } - }, - ) - } else { - None - } + self.descend_into_macros_breakable( + self.wrap_token_infile(token.clone()), + |InFile { value, file_id: _ }, _ctx| { + let mapped_kind = value.kind(); + let any_ident_match = + || kind.is_any_identifier() && value.kind().is_any_identifier(); + let matches = (kind == mapped_kind || any_ident_match()) && text == value.text(); + if matches { + ControlFlow::Break(value) + } else { + ControlFlow::Continue(()) + } + }, + ) .unwrap_or(token) } fn descend_into_macros_impl( &self, - InRealFile { value: token, file_id }: InRealFile, + InFile { value: token, file_id }: InFile, f: &mut dyn FnMut(InFile, SyntaxContextId) -> ControlFlow, ) -> Option { let _p = tracing::info_span!("descend_into_macros_impl").entered(); - let span = self.db.real_span_map(file_id).span_for_range(token.text_range()); + let span = self.db.span_map(file_id).span_for_range(token.text_range()); // Process the expansion of a call, pushing all tokens with our span in the expansion back onto our stack let process_expansion_for_token = |stack: &mut Vec<_>, macro_file| { @@ -972,17 +1038,16 @@ impl<'db> SemanticsImpl<'db> { // the tokens themselves aren't that interesting as the span that is being used to map // things down never changes. let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![]; - let include = self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, file_id); + let include = file_id.file_id().and_then(|file_id| { + self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, file_id) + }); match include { Some(include) => { // include! inputs are always from real files, so they only need to be handled once upfront process_expansion_for_token(&mut stack, include)?; } None => { - stack.push(( - file_id.into(), - smallvec![(token, SyntaxContextId::root(file_id.edition()))], - )); + stack.push((file_id, smallvec![(token, span.ctx)])); } } @@ -1644,8 +1709,13 @@ impl<'db> SemanticsImpl<'db> { T::to_def(self, src) } - fn file_to_module_defs(&self, file: FileId) -> impl Iterator { - self.with_ctx(|ctx| ctx.file_to_def(file).to_owned()).into_iter().map(Module::from) + fn file_to_module_defs(&self, file: EditionedFileId) -> impl Iterator { + self.with_ctx(|ctx| ctx.file_to_def(file.into()).to_owned()).into_iter().map(Module::from) + } + + fn hir_file_to_module_defs(&self, file: HirFileId) -> impl Iterator { + // FIXME: Do we need to care about inline modules for macro expansions? + self.file_to_module_defs(file.original_file_respecting_includes(self.db.upcast())) } pub fn scope(&self, node: &SyntaxNode) -> Option> { diff --git a/crates/ide-assists/src/handlers/bool_to_enum.rs b/crates/ide-assists/src/handlers/bool_to_enum.rs index cbd39796241b..cb6487d9fd88 100644 --- a/crates/ide-assists/src/handlers/bool_to_enum.rs +++ b/crates/ide-assists/src/handlers/bool_to_enum.rs @@ -208,7 +208,7 @@ fn replace_usages( target_module: &hir::Module, delayed_mutations: &mut Vec<(ImportScope, ast::Path)>, ) { - for (file_id, references) in usages { + for (file_id, references) in usages.map_out_of_macros(&ctx.sema) { edit.edit_file(file_id.file_id()); let refs_with_imports = augment_references_with_imports(ctx, references, target_module); diff --git a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs index 8d4ff84084bd..d83b202948d7 100644 --- a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs +++ b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs @@ -147,7 +147,7 @@ fn edit_struct_references( }; let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); - for (file_id, refs) in usages { + for (file_id, refs) in usages.map_out_of_macros(&ctx.sema) { edit.edit_file(file_id.file_id()); for r in refs { process_struct_name_reference(ctx, r, edit); @@ -225,7 +225,7 @@ fn edit_field_references( }; let def = Definition::Field(field); let usages = def.usages(&ctx.sema).all(); - for (file_id, refs) in usages { + for (file_id, refs) in usages.map_out_of_macros(&ctx.sema) { edit.edit_file(file_id.file_id()); for r in refs { if let Some(name_ref) = r.name.as_name_ref() { diff --git a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs index 91af9b05bbb8..0f4f569f929d 100644 --- a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs +++ b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs @@ -5,7 +5,7 @@ use ide_db::{ defs::Definition, helpers::mod_path_to_ast, imports::insert_use::{insert_use, ImportScope}, - search::{FileReference, UsageSearchResult}, + search::{FileReference, RealFileUsageSearchResult}, source_change::SourceChangeBuilder, syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, FxHashSet, @@ -69,7 +69,8 @@ pub(crate) fn convert_tuple_return_type_to_struct( let ret_type = edit.make_mut(ret_type); let fn_ = edit.make_mut(fn_); - let usages = Definition::Function(fn_def).usages(&ctx.sema).all(); + let usages = + Definition::Function(fn_def).usages(&ctx.sema).all().map_out_of_macros(&ctx.sema); let struct_name = format!("{}Result", stdx::to_camel_case(&fn_name.to_string())); let parent = fn_.syntax().ancestors().find_map(>::cast); add_tuple_struct_def( @@ -100,7 +101,7 @@ pub(crate) fn convert_tuple_return_type_to_struct( fn replace_usages( edit: &mut SourceChangeBuilder, ctx: &AssistContext<'_>, - usages: &UsageSearchResult, + usages: &RealFileUsageSearchResult, struct_name: &str, target_module: &hir::Module, ) { @@ -230,7 +231,7 @@ fn augment_references_with_imports( fn add_tuple_struct_def( edit: &mut SourceChangeBuilder, ctx: &AssistContext<'_>, - usages: &UsageSearchResult, + usages: &RealFileUsageSearchResult, parent: &SyntaxNode, tuple_ty: &ast::TupleType, struct_name: &str, diff --git a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index f6e516db8883..270b8d9c7747 100644 --- a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -134,7 +134,8 @@ fn edit_struct_references( Either::Left(s) => Definition::Adt(hir::Adt::Struct(s)), Either::Right(v) => Definition::Variant(v), }; - let usages = strukt_def.usages(&ctx.sema).include_self_refs().all(); + let usages = + strukt_def.usages(&ctx.sema).include_self_refs().all().map_out_of_macros(&ctx.sema); let edit_node = |edit: &mut SourceChangeBuilder, node: SyntaxNode| -> Option<()> { match_ast! { @@ -219,7 +220,7 @@ fn edit_field_references( None => continue, }; let def = Definition::Field(field); - let usages = def.usages(&ctx.sema).all(); + let usages = def.usages(&ctx.sema).all().map_out_of_macros(&ctx.sema); for (file_id, refs) in usages { edit.edit_file(file_id.file_id()); for r in refs { diff --git a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index 39142d606207..f98ba8498ce8 100644 --- a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -128,6 +128,7 @@ fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option) -> "Inline into all callers", name.syntax().text_range(), |builder| { - let mut usages = usages.all(); + let mut usages = usages.all().map_out_of_macros(&ctx.sema); let current_file_usage = usages.references.remove(&def_file); let mut remove_def = true; @@ -136,7 +136,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) -> remove_def = false; } }; - for (file_id, refs) in usages.into_iter() { + for (file_id, refs) in usages { inline_refs_for_file(file_id, refs); } match current_file_usage { @@ -338,6 +338,7 @@ fn inline( Definition::Local(local) .usages(sema) .all() + .map_out_of_macros(sema) .references .remove(&function_def_file_id) .unwrap_or_default() diff --git a/crates/ide-assists/src/handlers/inline_local_variable.rs b/crates/ide-assists/src/handlers/inline_local_variable.rs index b9fc075ae838..e8c29e97900d 100644 --- a/crates/ide-assists/src/handlers/inline_local_variable.rs +++ b/crates/ide-assists/src/handlers/inline_local_variable.rs @@ -1,7 +1,7 @@ use hir::{PathResolution, Semantics}; use ide_db::{ defs::Definition, - search::{FileReference, FileReferenceNode, UsageSearchResult}, + search::{FileReference, FileReferenceNode, RealFileUsageSearchResult}, EditionedFileId, RootDatabase, }; use syntax::{ @@ -165,7 +165,8 @@ fn inline_let( } let local = sema.to_def(&bind_pat)?; - let UsageSearchResult { mut references } = Definition::Local(local).usages(sema).all(); + let RealFileUsageSearchResult { mut references } = + Definition::Local(local).usages(sema).all().map_out_of_macros(sema); match references.remove(&file_id) { Some(references) => Some(InlineData { let_stmt, @@ -212,7 +213,8 @@ fn inline_usage( let let_stmt = ast::LetStmt::cast(bind_pat.syntax().parent()?)?; - let UsageSearchResult { mut references } = Definition::Local(local).usages(sema).all(); + let RealFileUsageSearchResult { mut references } = + Definition::Local(local).usages(sema).all().map_out_of_macros(sema); let mut references = references.remove(&file_id)?; let delete_let = references.len() == 1; references.retain(|fref| fref.name.as_name_ref() == Some(&name)); diff --git a/crates/ide-assists/src/handlers/inline_type_alias.rs b/crates/ide-assists/src/handlers/inline_type_alias.rs index 66dffde505c1..19476ce329d3 100644 --- a/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -92,7 +92,7 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) } }; - for (file_id, refs) in usages.into_iter() { + for (file_id, refs) in usages.map_out_of_macros(&ctx.sema) { inline_refs_for_file(file_id.file_id(), refs); } if !definition_deleted { diff --git a/crates/ide-assists/src/handlers/move_const_to_impl.rs b/crates/ide-assists/src/handlers/move_const_to_impl.rs index 743ea9476150..f19c0cd6e0a1 100644 --- a/crates/ide-assists/src/handlers/move_const_to_impl.rs +++ b/crates/ide-assists/src/handlers/move_const_to_impl.rs @@ -93,7 +93,8 @@ pub(crate) fn move_const_to_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> file_id: ctx.file_id(), range: parent_fn.syntax().text_range(), })) - .all(); + .all() + .map_out_of_macros(&ctx.sema); let range_to_delete = match const_.syntax().next_sibling_or_token() { Some(s) if matches!(s.kind(), SyntaxKind::WHITESPACE) => { diff --git a/crates/ide-assists/src/handlers/promote_local_to_const.rs b/crates/ide-assists/src/handlers/promote_local_to_const.rs index 0cc771ff3979..1abc54fdf59a 100644 --- a/crates/ide-assists/src/handlers/promote_local_to_const.rs +++ b/crates/ide-assists/src/handlers/promote_local_to_const.rs @@ -72,7 +72,8 @@ pub(crate) fn promote_local_to_const(acc: &mut Assists, ctx: &AssistContext<'_>) let_stmt.syntax().text_range(), |edit| { let name = to_upper_snake_case(&name.to_string()); - let usages = Definition::Local(local).usages(&ctx.sema).all(); + let usages = + Definition::Local(local).usages(&ctx.sema).all().map_out_of_macros(&ctx.sema); if let Some(usages) = usages.references.get(&ctx.file_id()) { let name_ref = make::name_ref(&name); diff --git a/crates/ide-assists/src/handlers/remove_unused_param.rs b/crates/ide-assists/src/handlers/remove_unused_param.rs index 75120768da0f..81ac31a9d630 100644 --- a/crates/ide-assists/src/handlers/remove_unused_param.rs +++ b/crates/ide-assists/src/handlers/remove_unused_param.rs @@ -80,7 +80,8 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> param.syntax().text_range(), |builder| { builder.delete(range_to_remove(param.syntax())); - for (file_id, references) in fn_def.usages(&ctx.sema).all() { + for (file_id, references) in fn_def.usages(&ctx.sema).all().map_out_of_macros(&ctx.sema) + { process_usages(ctx, builder, file_id, references, param_position, is_self_present); } }, diff --git a/crates/ide-assists/src/handlers/unnecessary_async.rs b/crates/ide-assists/src/handlers/unnecessary_async.rs index abe7fb132f0b..2905d5cd1ebd 100644 --- a/crates/ide-assists/src/handlers/unnecessary_async.rs +++ b/crates/ide-assists/src/handlers/unnecessary_async.rs @@ -94,9 +94,9 @@ fn find_all_references( ctx: &AssistContext<'_>, def: &Definition, ) -> impl Iterator { - def.usages(&ctx.sema).all().into_iter().flat_map(|(file_id, references)| { - references.into_iter().map(move |reference| (file_id, reference)) - }) + def.usages(&ctx.sema).all().map_out_of_macros(&ctx.sema).into_iter().flat_map( + |(file_id, references)| references.into_iter().map(move |reference| (file_id, reference)), + ) } /// Finds the await expression for the given `NameRef`. diff --git a/crates/ide-db/src/helpers.rs b/crates/ide-db/src/helpers.rs index 84fa58d743bb..5876c9163e26 100644 --- a/crates/ide-db/src/helpers.rs +++ b/crates/ide-db/src/helpers.rs @@ -3,8 +3,8 @@ use std::collections::VecDeque; use base_db::SourceRootDatabase; -use hir::{Crate, ItemInNs, ModuleDef, Name, Semantics}; -use span::{Edition, FileId}; +use hir::{Crate, HirFileId, ItemInNs, ModuleDef, Name, Semantics}; +use span::Edition; use syntax::{ ast::{self, make}, AstToken, SyntaxKind, SyntaxToken, ToSmolStr, TokenAtOffset, @@ -59,11 +59,11 @@ pub fn mod_path_to_ast(path: &hir::ModPath, edition: Edition) -> ast::Path { /// Iterates all `ModuleDef`s and `Impl` blocks of the given file. pub fn visit_file_defs( sema: &Semantics<'_, RootDatabase>, - file_id: FileId, + file_id: HirFileId, cb: &mut dyn FnMut(Definition), ) { let db = sema.db; - let module = match sema.file_to_module_def(file_id) { + let module = match sema.hir_file_to_module_def(file_id) { Some(it) => it, None => return, }; diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs index 59914bedde43..699b125c0296 100644 --- a/crates/ide-db/src/rename.rs +++ b/crates/ide-db/src/rename.rs @@ -309,7 +309,7 @@ fn rename_mod( } let def = Definition::Module(module); - let usages = def.usages(sema).all(); + let usages = def.usages(sema).all().map_out_of_macros(sema); let ref_edits = usages.iter().map(|(file_id, references)| { ( EditionedFileId::file_id(file_id), @@ -350,7 +350,7 @@ fn rename_reference( } let def = convert_to_def_in_trait(sema.db, def); - let usages = def.usages(sema).all(); + let usages = def.usages(sema).all().map_out_of_macros(sema); if !usages.is_empty() && ident_kind == IdentifierKind::Underscore { cov_mark::hit!(rename_underscore_multiple); diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 7963e8ae4f78..e0f56ec88260 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -9,9 +9,10 @@ use std::{cell::LazyCell, cmp::Reverse}; use base_db::{ra_salsa::Database, SourceDatabase, SourceRootDatabase}; use either::Either; +use hir::db::ExpandDatabase; use hir::{ - sym, Adt, AsAssocItem, DefWithBody, FileRange, FileRangeWrapper, HasAttrs, HasContainer, - HasSource, HirFileIdExt, InFile, InFileWrapper, InRealFile, InlineAsmOperand, ItemContainer, + sym, Adt, AsAssocItem, DefWithBody, FileRange, HasAttrs, HasContainer, HasSource, HirFileId, + HirFileIdExt, HirFileRange, InFile, InFileWrapper, InRealFile, InlineAsmOperand, ItemContainer, ModuleSource, PathResolution, Semantics, Visibility, }; use memchr::memmem::Finder; @@ -33,7 +34,7 @@ use crate::{ #[derive(Debug, Default, Clone)] pub struct UsageSearchResult { - pub references: FxHashMap>, + pub references: FxHashMap>, } impl UsageSearchResult { @@ -45,6 +46,80 @@ impl UsageSearchResult { self.references.len() } + pub fn iter(&self) -> impl Iterator + '_ { + self.references.iter().map(|(&file_id, refs)| (file_id, &**refs)) + } + + pub fn file_ranges(&self) -> impl Iterator + '_ { + self.references.iter().flat_map(|(&file_id, refs)| { + refs.iter().map(move |&FileReference { range, .. }| HirFileRange { file_id, range }) + }) + } + + pub fn map_out_of_macros( + self, + sema: &Semantics<'_, RootDatabase>, + ) -> RealFileUsageSearchResult { + let mut references = >>::default(); + self.references + .into_iter() + .flat_map(|(file_id, refs)| { + refs.into_iter().map(move |reference| { + if let FileReferenceNode::FormatStringEntry(ast, name_range) = reference.name { + // FIXME: Clean this up + let r = ast.syntax().text_range(); + let FileRange { file_id, range } = + InFile::new(file_id, r).original_node_file_range_rooted(sema.db); + let relative = name_range - r.start(); + let mut new_range = relative + range.start(); + if new_range.end() > range.end() { + new_range = TextRange::new(new_range.start(), range.end()); + } + return ( + file_id, + FileReference { + range: new_range, + name: FileReferenceNode::FormatStringEntry(ast, new_range), + category: reference.category, + }, + ); + } + let FileRange { file_id, range } = InFile::new(file_id, reference.range) + .original_node_file_range_rooted(sema.db); + ( + file_id, + FileReference { range, name: reference.name, category: reference.category }, + ) + }) + }) + .for_each(|(file_id, ref_)| references.entry(file_id).or_default().push(ref_)); + RealFileUsageSearchResult { references } + } +} + +impl IntoIterator for UsageSearchResult { + type Item = (HirFileId, Vec); + type IntoIter = > as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.references.into_iter() + } +} + +#[derive(Debug, Default, Clone)] +pub struct RealFileUsageSearchResult { + pub references: FxHashMap>, +} + +impl RealFileUsageSearchResult { + pub fn is_empty(&self) -> bool { + self.references.is_empty() + } + + pub fn len(&self) -> usize { + self.references.len() + } + pub fn iter(&self) -> impl Iterator + '_ { self.references.iter().map(|(&file_id, refs)| (file_id, &**refs)) } @@ -56,7 +131,7 @@ impl UsageSearchResult { } } -impl IntoIterator for UsageSearchResult { +impl IntoIterator for RealFileUsageSearchResult { type Item = (EditionedFileId, Vec); type IntoIter = > as IntoIterator>::IntoIter; @@ -149,11 +224,11 @@ bitflags::bitflags! { /// e.g. for things like local variables. #[derive(Clone, Debug)] pub struct SearchScope { - entries: FxHashMap>, + entries: FxHashMap>, } impl SearchScope { - fn new(entries: FxHashMap>) -> SearchScope { + fn new(entries: FxHashMap>) -> SearchScope { SearchScope { entries } } @@ -167,7 +242,9 @@ impl SearchScope { let source_root_id = db.file_source_root(root_file); let source_root = db.source_root(source_root_id); entries.extend( - source_root.iter().map(|id| (EditionedFileId::new(id, graph[krate].edition), None)), + source_root + .iter() + .map(|id| (EditionedFileId::new(id, graph[krate].edition).into(), None)), ); } SearchScope { entries } @@ -181,7 +258,9 @@ impl SearchScope { let source_root_id = db.file_source_root(root_file); let source_root = db.source_root(source_root_id); entries.extend( - source_root.iter().map(|id| (EditionedFileId::new(id, rev_dep.edition(db)), None)), + source_root + .iter() + .map(|id| (EditionedFileId::new(id, rev_dep.edition(db)).into(), None)), ); } SearchScope { entries } @@ -195,7 +274,7 @@ impl SearchScope { SearchScope { entries: source_root .iter() - .map(|id| (EditionedFileId::new(id, of.edition(db)), None)) + .map(|id| (EditionedFileId::new(id, of.edition(db)).into(), None)) .collect(), } } @@ -213,12 +292,12 @@ impl SearchScope { (file_id.original_file(db), Some(value)) } }; - entries.entry(file_id).or_insert(range); + entries.entry(file_id.into()).or_insert(range); let mut to_visit: Vec<_> = module.children(db).collect(); while let Some(module) = to_visit.pop() { if let Some(file_id) = module.as_source_file_id(db) { - entries.insert(file_id, None); + entries.insert(file_id.into(), None); } to_visit.extend(module.children(db)); } @@ -232,17 +311,27 @@ impl SearchScope { /// Build a empty search scope spanning the given file. pub fn single_file(file: EditionedFileId) -> SearchScope { + SearchScope::new(std::iter::once((file.into(), None)).collect()) + } + + /// Build a empty search scope spanning the given file. + pub fn single_hir_file(file: HirFileId) -> SearchScope { SearchScope::new(std::iter::once((file, None)).collect()) } /// Build a empty search scope spanning the text range of the given file. pub fn file_range(range: FileRange) -> SearchScope { + SearchScope::new(std::iter::once((range.file_id.into(), Some(range.range))).collect()) + } + + /// Build a empty search scope spanning the text range of the given file. + pub fn hir_file_range(range: HirFileRange) -> SearchScope { SearchScope::new(std::iter::once((range.file_id, Some(range.range))).collect()) } /// Build a empty search scope spanning the given files. pub fn files(files: &[EditionedFileId]) -> SearchScope { - SearchScope::new(files.iter().map(|f| (*f, None)).collect()) + SearchScope::new(files.iter().map(|&f| (f.into(), None)).collect()) } pub fn intersection(&self, other: &SearchScope) -> SearchScope { @@ -272,8 +361,8 @@ impl SearchScope { } impl IntoIterator for SearchScope { - type Item = (EditionedFileId, Option); - type IntoIter = std::collections::hash_map::IntoIter>; + type Item = (HirFileId, Option); + type IntoIter = std::collections::hash_map::IntoIter>; fn into_iter(self) -> Self::IntoIter { self.entries.into_iter() @@ -479,13 +568,24 @@ impl<'a> FindUsages<'a> { fn scope_files<'b>( db: &'b RootDatabase, scope: &'b SearchScope, - ) -> impl Iterator, EditionedFileId, TextRange)> + 'b { - scope.entries.iter().map(|(&file_id, &search_range)| { - let text = db.file_text(file_id.file_id()); - let search_range = - search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(&*text))); + ) -> impl Iterator, HirFileId, TextRange)> + 'b { + scope.entries.iter().map(|(&file_id, &search_range)| match file_id.repr() { + span::HirFileIdRepr::FileId(editioned_file_id) => { + let text = db.file_text(editioned_file_id.file_id()); + let search_range = + search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(&*text))); + + (text, file_id, search_range) + } + span::HirFileIdRepr::MacroFile(macro_file_id) => { + let text = Arc::from( + db.parse_macro_expansion(macro_file_id).value.0.syntax_node().to_string(), + ); - (text, file_id, search_range) + let search_range = + search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(&*text))); + (text, file_id, search_range) + } }) } @@ -521,8 +621,9 @@ impl<'a> FindUsages<'a> { sema: &'b Semantics<'_, RootDatabase>, name: &str, node: &syntax::SyntaxNode, + file_id: HirFileId, offset: TextSize, - ) -> impl Iterator + 'b { + ) -> impl Iterator> + 'b { node.token_at_offset(offset) .find(|it| { // `name` is stripped of raw ident prefix. See the comment on name retrieval below. @@ -531,15 +632,26 @@ impl<'a> FindUsages<'a> { .into_iter() .flat_map(move |token| { if sema.might_be_inside_macro_call(&token) { - sema.descend_into_macros_exact(token) + sema.descend_into_macros_exact_with_file(token) } else { - <_>::from([token]) + <_>::from([InFile::new(file_id, token)]) } .into_iter() - .filter_map(|it| it.parent()) + .filter_map(|it| it.map(|it| it.parent()).transpose()) }) } + fn find_name_refs<'b>( + sema: &'b Semantics<'_, RootDatabase>, + name: &str, + node: &syntax::SyntaxNode, + file_id: HirFileId, + offset: TextSize, + ) -> impl Iterator> + 'b { + Self::find_nodes(sema, name, node, file_id, offset) + .filter_map(|it| it.map(ast::NameRef::cast).transpose()) + } + /// Performs a special fast search for associated functions. This is mainly intended /// to speed up `new()` which can take a long time. /// @@ -557,7 +669,7 @@ impl<'a> FindUsages<'a> { // FIXME: Extend this to other cases, such as associated types/consts/enum variants (note those can be `use`d). fn short_associated_function_fast_search( &self, - sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, + sink: &mut dyn FnMut(HirFileId, FileReference) -> bool, search_scope: &SearchScope, name: &str, ) -> bool { @@ -611,7 +723,7 @@ impl<'a> FindUsages<'a> { fn collect_possible_aliases( sema: &Semantics<'_, RootDatabase>, container: Adt, - ) -> Option<(FxHashSet, Vec>)> { + ) -> Option<(FxHashSet, Vec)> { fn insert_type_alias( db: &RootDatabase, to_process: &mut Vec<(SmolStr, SearchScope)>, @@ -647,15 +759,19 @@ impl<'a> FindUsages<'a> { for (file_text, file_id, search_range) in FindUsages::scope_files(db, ¤t_to_process_search_scope) { - let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone()); + let tree = LazyCell::new(move || sema.parse_or_expand(file_id)); for offset in FindUsages::match_indices(&file_text, &finder, search_range) { - let usages = - FindUsages::find_nodes(sema, ¤t_to_process, &tree, offset) - .filter(|it| { - matches!(it.kind(), SyntaxKind::NAME | SyntaxKind::NAME_REF) - }); + let usages = FindUsages::find_nodes( + sema, + ¤t_to_process, + &tree, + file_id, + offset, + ) + .filter(|it| matches!(it.kind(), SyntaxKind::NAME | SyntaxKind::NAME_REF)); for usage in usages { + let InFileWrapper { file_id, value: usage } = usage; if let Some(alias) = usage.parent().and_then(|it| { let path = ast::PathSegment::cast(it)?.parent_path(); let use_tree = ast::UseTree::cast(path.syntax().parent()?)?; @@ -726,7 +842,10 @@ impl<'a> FindUsages<'a> { }; (|| { let impl_ = impl_?; - is_possibly_self.push(sema.original_range(impl_.syntax())); + is_possibly_self.push(HirFileRange { + file_id, + range: impl_.syntax().text_range(), + }); let assoc_items = impl_.assoc_item_list()?; let type_aliases = assoc_items .syntax() @@ -798,21 +917,22 @@ impl<'a> FindUsages<'a> { this: &FindUsages<'_>, finder: &Finder<'_>, name: &str, - files: impl Iterator, EditionedFileId, TextRange)>, + files: impl Iterator, HirFileId, TextRange)>, mut container_predicate: impl FnMut( &SyntaxNode, - InFileWrapper, + InFileWrapper, ) -> bool, - sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, + sink: &mut dyn FnMut(HirFileId, FileReference) -> bool, ) { for (file_text, file_id, search_range) in files { - let tree = LazyCell::new(move || this.sema.parse(file_id).syntax().clone()); + let tree = LazyCell::new(move || this.sema.parse_or_expand(file_id)); for offset in FindUsages::match_indices(&file_text, finder, search_range) { - let usages = FindUsages::find_nodes(this.sema, name, &tree, offset) - .filter_map(ast::NameRef::cast); + let usages = + FindUsages::find_name_refs(this.sema, name, &tree, file_id, offset); for usage in usages { let found_usage = usage + .value .syntax() .parent() .and_then(ast::PathSegment::cast) @@ -824,7 +944,7 @@ impl<'a> FindUsages<'a> { }) .unwrap_or(false); if found_usage { - this.found_name_ref(&usage, sink); + this.found_name_ref(&usage.value, &mut |it| sink(usage.file_id, it)); } } } @@ -851,7 +971,21 @@ impl<'a> FindUsages<'a> { name, is_possibly_self.into_iter().map(|position| { ( - self.sema.db.file_text(position.file_id.file_id()), + match position.file_id.repr() { + span::HirFileIdRepr::FileId(editioned_file_id) => { + self.sema.db.file_text(editioned_file_id.file_id()) + } + + span::HirFileIdRepr::MacroFile(macro_file_id) => Arc::from( + self.sema + .db + .parse_macro_expansion(macro_file_id) + .value + .0 + .syntax_node() + .to_string(), + ), + }, position.file_id, position.range, ) @@ -885,7 +1019,7 @@ impl<'a> FindUsages<'a> { true } - pub fn search(&self, sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool) { + pub fn search(&self, sink: &mut dyn FnMut(HirFileId, FileReference) -> bool) { let _p = tracing::info_span!("FindUsages:search").entered(); let sema = self.sema; @@ -946,17 +1080,24 @@ impl<'a> FindUsages<'a> { self.include_self_kw_refs.as_ref().map(|ty| (ty, Finder::new("Self"))); for (text, file_id, search_range) in Self::scope_files(sema.db, &search_scope) { self.sema.db.unwind_if_cancelled(); - let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone()); + let tree = LazyCell::new(move || sema.parse_or_expand(file_id)); // Search for occurrences of the items name for offset in Self::match_indices(&text, finder, search_range) { let ret = tree.token_at_offset(offset).any(|token| { let Some(str_token) = ast::String::cast(token.clone()) else { return false }; - if let Some((range, Some(nameres))) = - sema.check_for_format_args_template(token, offset) + if let Some((range, str_token, Some(nameres))) = sema + .check_for_format_args_template_with_file( + InFile::new(file_id, str_token), + offset, + ) { - return self - .found_format_args_ref(file_id, range, str_token, nameres, sink); + return self.found_format_args_ref( + range.range, + str_token, + nameres, + &mut |it| sink(range.file_id, it), + ); } false }); @@ -964,13 +1105,19 @@ impl<'a> FindUsages<'a> { return; } - for name in - Self::find_nodes(sema, name, &tree, offset).filter_map(ast::NameLike::cast) + for node in Self::find_nodes(sema, name, &tree, file_id, offset) + .filter_map(|it| it.map(ast::NameLike::cast).transpose()) { - if match name { - ast::NameLike::NameRef(name_ref) => self.found_name_ref(&name_ref, sink), - ast::NameLike::Name(name) => self.found_name(&name, sink), - ast::NameLike::Lifetime(lifetime) => self.found_lifetime(&lifetime, sink), + if match node.value { + ast::NameLike::NameRef(name_ref) => { + self.found_name_ref(&name_ref, &mut |it| sink(node.file_id, it)) + } + ast::NameLike::Name(name) => { + self.found_name(&name, &mut |it| sink(node.file_id, it)) + } + ast::NameLike::Lifetime(lifetime) => { + self.found_lifetime(&lifetime, &mut |it| sink(node.file_id, it)) + } } { return; } @@ -979,10 +1126,10 @@ impl<'a> FindUsages<'a> { // Search for occurrences of the `Self` referring to our type if let Some((self_ty, finder)) = &include_self_kw_refs { for offset in Self::match_indices(&text, finder, search_range) { - for name_ref in - Self::find_nodes(sema, "Self", &tree, offset).filter_map(ast::NameRef::cast) - { - if self.found_self_ty_name_ref(self_ty, &name_ref, sink) { + for name_ref in Self::find_name_refs(sema, "Self", &tree, file_id, offset) { + if self.found_self_ty_name_ref(self_ty, &name_ref.value, &mut |it| { + sink(name_ref.file_id, it) + }) { return; } } @@ -1000,23 +1147,24 @@ impl<'a> FindUsages<'a> { for (text, file_id, search_range) in Self::scope_files(sema.db, &scope) { self.sema.db.unwind_if_cancelled(); - let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone()); + let tree = LazyCell::new(move || sema.parse_or_expand(file_id)); for offset in Self::match_indices(&text, finder, search_range) { - for name_ref in Self::find_nodes(sema, "super", &tree, offset) - .filter_map(ast::NameRef::cast) - { - if self.found_name_ref(&name_ref, sink) { + for name_ref in Self::find_name_refs(sema, "super", &tree, file_id, offset) { + if self + .found_name_ref(&name_ref.value, &mut |it| sink(name_ref.file_id, it)) + { return; } } } if let Some(finder) = &is_crate_root { for offset in Self::match_indices(&text, finder, search_range) { - for name_ref in Self::find_nodes(sema, "crate", &tree, offset) - .filter_map(ast::NameRef::cast) + for name_ref in Self::find_name_refs(sema, "crate", &tree, file_id, offset) { - if self.found_name_ref(&name_ref, sink) { + if self.found_name_ref(&name_ref.value, &mut |it| { + sink(name_ref.file_id, it) + }) { return; } } @@ -1029,14 +1177,13 @@ impl<'a> FindUsages<'a> { match self.def { Definition::Module(module) if self.search_self_mod => { let src = module.definition_source(sema.db); - let file_id = src.file_id.original_file(sema.db); - let (file_id, search_range) = match src.value { - ModuleSource::Module(m) => (file_id, Some(m.syntax().text_range())), - ModuleSource::BlockExpr(b) => (file_id, Some(b.syntax().text_range())), - ModuleSource::SourceFile(_) => (file_id, None), + let search_range = match src.value { + ModuleSource::Module(m) => Some(m.syntax().text_range()), + ModuleSource::BlockExpr(b) => Some(b.syntax().text_range()), + ModuleSource::SourceFile(_) => None, }; - let search_range = if let Some(&range) = search_scope.entries.get(&file_id) { + let search_range = if let Some(&range) = search_scope.entries.get(&src.file_id) { match (range, search_range) { (None, range) | (range, None) => range, (Some(range), Some(search_range)) => match range.intersect(search_range) { @@ -1048,18 +1195,35 @@ impl<'a> FindUsages<'a> { return; }; - let text = sema.db.file_text(file_id.file_id()); + let (t1_, t2_); + let text = match src.file_id.repr() { + span::HirFileIdRepr::FileId(editioned_file_id) => { + t1_ = sema.db.file_text(editioned_file_id.file_id()); + &*t1_ + } + + span::HirFileIdRepr::MacroFile(macro_file_id) => { + t2_ = sema + .db + .parse_macro_expansion(macro_file_id) + .value + .0 + .syntax_node() + .to_string(); + &*t2_ + } + }; let search_range = - search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(&*text))); + search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text))); - let tree = LazyCell::new(|| sema.parse(file_id).syntax().clone()); + let tree = LazyCell::new(|| sema.parse_or_expand(src.file_id)); let finder = &Finder::new("self"); - for offset in Self::match_indices(&text, finder, search_range) { - for name_ref in - Self::find_nodes(sema, "self", &tree, offset).filter_map(ast::NameRef::cast) - { - if self.found_self_module_name_ref(&name_ref, sink) { + for offset in Self::match_indices(text, finder, search_range) { + for name_ref in Self::find_name_refs(sema, "self", &tree, src.file_id, offset) { + if self.found_self_module_name_ref(&name_ref.value, &mut |it| { + sink(name_ref.file_id, it) + }) { return; } } @@ -1073,7 +1237,7 @@ impl<'a> FindUsages<'a> { &self, self_ty: &hir::Type, name_ref: &ast::NameRef, - sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, + sink: &mut dyn FnMut(FileReference) -> bool, ) -> bool { // See https://github.com/rust-lang/rust-analyzer/pull/15864/files/e0276dc5ddc38c65240edb408522bb869f15afb4#r1389848845 let ty_eq = |ty: hir::Type| match (ty.as_adt(), self_ty.as_adt()) { @@ -1086,13 +1250,12 @@ impl<'a> FindUsages<'a> { Some(NameRefClass::Definition(Definition::SelfType(impl_), _)) if ty_eq(impl_.self_ty(self.sema.db)) => { - let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let reference = FileReference { - range, + range: name_ref.syntax().text_range(), name: FileReferenceNode::NameRef(name_ref.clone()), category: ReferenceCategory::empty(), }; - sink(file_id, reference) + sink(reference) } _ => false, } @@ -1101,22 +1264,21 @@ impl<'a> FindUsages<'a> { fn found_self_module_name_ref( &self, name_ref: &ast::NameRef, - sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, + sink: &mut dyn FnMut(FileReference) -> bool, ) -> bool { match NameRefClass::classify(self.sema, name_ref) { Some(NameRefClass::Definition(def @ Definition::Module(_), _)) if def == self.def => { - let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let category = if is_name_ref_in_import(name_ref) { ReferenceCategory::IMPORT } else { ReferenceCategory::empty() }; let reference = FileReference { - range, + range: name_ref.syntax().text_range(), name: FileReferenceNode::NameRef(name_ref.clone()), category, }; - sink(file_id, reference) + sink(reference) } _ => false, } @@ -1124,11 +1286,10 @@ impl<'a> FindUsages<'a> { fn found_format_args_ref( &self, - file_id: EditionedFileId, range: TextRange, token: ast::String, res: Either, - sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, + sink: &mut dyn FnMut(FileReference) -> bool, ) -> bool { let def = res.either(Definition::from, Definition::from); if def == self.def { @@ -1137,7 +1298,7 @@ impl<'a> FindUsages<'a> { name: FileReferenceNode::FormatStringEntry(token, range), category: ReferenceCategory::READ, }; - sink(file_id, reference) + sink(reference) } else { false } @@ -1146,17 +1307,16 @@ impl<'a> FindUsages<'a> { fn found_lifetime( &self, lifetime: &ast::Lifetime, - sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, + sink: &mut dyn FnMut(FileReference) -> bool, ) -> bool { match NameRefClass::classify_lifetime(self.sema, lifetime) { Some(NameRefClass::Definition(def, _)) if def == self.def => { - let FileRange { file_id, range } = self.sema.original_range(lifetime.syntax()); let reference = FileReference { - range, + range: lifetime.syntax().text_range(), name: FileReferenceNode::Lifetime(lifetime.clone()), category: ReferenceCategory::empty(), }; - sink(file_id, reference) + sink(reference) } _ => false, } @@ -1165,7 +1325,7 @@ impl<'a> FindUsages<'a> { fn found_name_ref( &self, name_ref: &ast::NameRef, - sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, + sink: &mut dyn FnMut(FileReference) -> bool, ) -> bool { match NameRefClass::classify(self.sema, name_ref) { Some(NameRefClass::Definition(def, _)) @@ -1174,13 +1334,12 @@ impl<'a> FindUsages<'a> { || matches!(self.assoc_item_container, Some(hir::AssocItemContainer::Trait(_))) && convert_to_def_in_trait(self.sema.db, def) == self.def => { - let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let reference = FileReference { - range, + range: name_ref.syntax().text_range(), name: FileReferenceNode::NameRef(name_ref.clone()), category: ReferenceCategory::new(self.sema, &def, name_ref), }; - sink(file_id, reference) + sink(reference) } // FIXME: special case type aliases, we can't filter between impl and trait defs here as we lack the substitutions // so we always resolve all assoc type aliases to both their trait def and impl defs @@ -1190,23 +1349,21 @@ impl<'a> FindUsages<'a> { && convert_to_def_in_trait(self.sema.db, def) == convert_to_def_in_trait(self.sema.db, self.def) => { - let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let reference = FileReference { - range, + range: name_ref.syntax().text_range(), name: FileReferenceNode::NameRef(name_ref.clone()), category: ReferenceCategory::new(self.sema, &def, name_ref), }; - sink(file_id, reference) + sink(reference) } Some(NameRefClass::Definition(def, _)) if self.include_self_kw_refs.is_some() => { if self.include_self_kw_refs == def_to_ty(self.sema, &def) { - let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); let reference = FileReference { - range, + range: name_ref.syntax().text_range(), name: FileReferenceNode::NameRef(name_ref.clone()), category: ReferenceCategory::new(self.sema, &def, name_ref), }; - sink(file_id, reference) + sink(reference) } else { false } @@ -1216,8 +1373,6 @@ impl<'a> FindUsages<'a> { field_ref: field, adt_subst: _, }) => { - let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); - let field = Definition::Field(field); let local = Definition::Local(local); let access = match self.def { @@ -1230,44 +1385,38 @@ impl<'a> FindUsages<'a> { _ => return false, }; let reference = FileReference { - range, + range: name_ref.syntax().text_range(), name: FileReferenceNode::NameRef(name_ref.clone()), category: access, }; - sink(file_id, reference) + sink(reference) } _ => false, } } - fn found_name( - &self, - name: &ast::Name, - sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, - ) -> bool { + fn found_name(&self, name: &ast::Name, sink: &mut dyn FnMut(FileReference) -> bool) -> bool { match NameClass::classify(self.sema, name) { Some(NameClass::PatFieldShorthand { local_def: _, field_ref, adt_subst: _ }) if matches!( self.def, Definition::Field(_) if Definition::Field(field_ref) == self.def ) => { - let FileRange { file_id, range } = self.sema.original_range(name.syntax()); let reference = FileReference { - range, + range: name.syntax().text_range(), name: FileReferenceNode::Name(name.clone()), // FIXME: mutable patterns should have `Write` access category: ReferenceCategory::READ, }; - sink(file_id, reference) + sink(reference) } Some(NameClass::ConstReference(def)) if self.def == def => { - let FileRange { file_id, range } = self.sema.original_range(name.syntax()); let reference = FileReference { - range, + range: name.syntax().text_range(), name: FileReferenceNode::Name(name.clone()), category: ReferenceCategory::empty(), }; - sink(file_id, reference) + sink(reference) } Some(NameClass::Definition(def)) if def != self.def => { match (&self.assoc_item_container, self.def) { @@ -1286,13 +1435,12 @@ impl<'a> FindUsages<'a> { if convert_to_def_in_trait(self.sema.db, def) == self.def => {} _ => return false, } - let FileRange { file_id, range } = self.sema.original_range(name.syntax()); let reference = FileReference { - range, + range: name.syntax().text_range(), name: FileReferenceNode::Name(name.clone()), category: ReferenceCategory::empty(), }; - sink(file_id, reference) + sink(reference) } _ => false, } diff --git a/crates/ide-db/src/test_data/test_doc_alias.txt b/crates/ide-db/src/test_data/test_doc_alias.txt index efcf53ded64f..eca1f0f891fe 100644 --- a/crates/ide-db/src/test_data/test_doc_alias.txt +++ b/crates/ide-db/src/test_data/test_doc_alias.txt @@ -21,9 +21,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -54,9 +52,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -87,9 +83,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -120,9 +114,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -153,9 +145,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -186,9 +176,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -219,9 +207,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { diff --git a/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/crates/ide-db/src/test_data/test_symbol_index_collection.txt index 7dce95592b81..c421be286477 100644 --- a/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -19,9 +19,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -50,9 +48,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -81,9 +77,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -114,9 +108,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -147,9 +139,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -180,9 +170,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -211,9 +199,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -244,9 +230,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -307,9 +291,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -342,9 +324,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -377,9 +357,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -410,9 +388,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -441,9 +417,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -474,9 +448,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -507,9 +479,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -540,9 +510,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -573,9 +541,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -606,9 +572,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -637,9 +601,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -670,9 +632,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -705,9 +665,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -736,9 +694,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -769,9 +725,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -800,9 +754,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -846,9 +798,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 0, - ), + 0, Edition2021, ), ptr: SyntaxNodePtr { @@ -888,9 +838,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 1, - ), + 1, Edition2021, ), ptr: SyntaxNodePtr { @@ -921,9 +869,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 1, - ), + 1, Edition2021, ), ptr: SyntaxNodePtr { @@ -954,9 +900,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 1, - ), + 1, Edition2021, ), ptr: SyntaxNodePtr { @@ -987,9 +931,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 1, - ), + 1, Edition2021, ), ptr: SyntaxNodePtr { @@ -1020,9 +962,7 @@ ), loc: DeclarationLocation { hir_file_id: EditionedFileId( - FileId( - 1, - ), + 1, Edition2021, ), ptr: SyntaxNodePtr { diff --git a/crates/ide-ssr/src/search.rs b/crates/ide-ssr/src/search.rs index b1cade39266a..f5dc62e21c35 100644 --- a/crates/ide-ssr/src/search.rs +++ b/crates/ide-ssr/src/search.rs @@ -8,7 +8,7 @@ use crate::{ use hir::FileRange; use ide_db::{ defs::Definition, - search::{SearchScope, UsageSearchResult}, + search::{RealFileUsageSearchResult, SearchScope}, EditionedFileId, FileId, FxHashSet, }; use syntax::{ast, AstNode, SyntaxKind, SyntaxNode}; @@ -19,7 +19,7 @@ use syntax::{ast, AstNode, SyntaxKind, SyntaxNode}; /// them more than once. #[derive(Default)] pub(crate) struct UsageCache { - usages: Vec<(Definition, UsageSearchResult)>, + usages: Vec<(Definition, RealFileUsageSearchResult)>, } impl MatchFinder<'_> { @@ -115,14 +115,14 @@ impl MatchFinder<'_> { &self, usage_cache: &'a mut UsageCache, definition: Definition, - ) -> &'a UsageSearchResult { + ) -> &'a RealFileUsageSearchResult { // Logically if a lookup succeeds we should just return it. Unfortunately returning it would // extend the lifetime of the borrow, then we wouldn't be able to do the insertion on a // cache miss. This is a limitation of NLL and is fixed with Polonius. For now we do two // lookups in the case of a cache hit. if usage_cache.find(&definition).is_none() { let usages = definition.usages(&self.sema).in_scope(&self.search_scope()).all(); - usage_cache.usages.push((definition, usages)); + usage_cache.usages.push((definition, usages.map_out_of_macros(&self.sema))); return &usage_cache.usages.last().unwrap().1; } usage_cache.find(&definition).unwrap() @@ -258,7 +258,7 @@ fn is_search_permitted(node: &SyntaxNode) -> bool { } impl UsageCache { - fn find(&mut self, definition: &Definition) -> Option<&UsageSearchResult> { + fn find(&mut self, definition: &Definition) -> Option<&RealFileUsageSearchResult> { // We expect a very small number of cache entries (generally 1), so a linear scan should be // fast enough and avoids the need to implement Hash for Definition. for (d, refs) in &self.usages { diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index e47891bbdfe7..fad311d4e530 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs @@ -1,17 +1,15 @@ -use hir::{HasSource, InFile, InRealFile, Semantics}; -use ide_db::{ - defs::Definition, helpers::visit_file_defs, FileId, FilePosition, FileRange, FxIndexSet, - RootDatabase, -}; +use hir::{HasSource, HirFileId, HirFilePosition, HirFileRange, InFile, Semantics}; +use ide_db::{defs::Definition, helpers::visit_file_defs, FxIndexSet, RootDatabase}; use itertools::Itertools; use syntax::{ast::HasName, AstNode, TextRange}; use crate::{ annotations::fn_references::find_all_methods, goto_implementation::goto_implementation, + navigation_target::HirNavigationTarget, references::find_all_refs, runnables::{runnables, Runnable}, - NavigationTarget, RunnableKind, + RunnableKind, }; mod fn_references; @@ -31,8 +29,8 @@ pub struct Annotation { #[derive(Debug, Hash, PartialEq, Eq)] pub enum AnnotationKind { Runnable(Runnable), - HasImpls { pos: FilePosition, data: Option> }, - HasReferences { pos: FilePosition, data: Option> }, + HasImpls { pos: HirFilePosition, data: Option> }, + HasReferences { pos: HirFilePosition, data: Option> }, } pub struct AnnotationConfig { @@ -53,7 +51,7 @@ pub enum AnnotationLocation { pub(crate) fn annotations( db: &RootDatabase, config: &AnnotationConfig, - file_id: FileId, + file_id: HirFileId, ) -> Vec { let mut annotations = FxIndexSet::default(); @@ -75,17 +73,17 @@ pub(crate) fn annotations( AnnotationLocation::AboveName => cmd_target, AnnotationLocation::AboveWholeItem => range, }; - let target_pos = FilePosition { file_id, offset: cmd_target.start() }; + let target_pos = HirFilePosition { file_id, offset: cmd_target.start() }; (annotation_range, target_pos) }; visit_file_defs(&Semantics::new(db), file_id, &mut |def| { let range = match def { Definition::Const(konst) if config.annotate_references => { - konst.source(db).and_then(|node| name_range(db, node, file_id)) + konst.source(db).and_then(|node| name_range(node, file_id)) } Definition::Trait(trait_) if config.annotate_references || config.annotate_impls => { - trait_.source(db).and_then(|node| name_range(db, node, file_id)) + trait_.source(db).and_then(|node| name_range(node, file_id)) } Definition::Adt(adt) => match adt { hir::Adt::Enum(enum_) => { @@ -94,7 +92,7 @@ pub(crate) fn annotations( .variants(db) .into_iter() .filter_map(|variant| { - variant.source(db).and_then(|node| name_range(db, node, file_id)) + variant.source(db).and_then(|node| name_range(node, file_id)) }) .for_each(|range| { let (annotation_range, target_position) = mk_ranges(range); @@ -108,14 +106,14 @@ pub(crate) fn annotations( }) } if config.annotate_references || config.annotate_impls { - enum_.source(db).and_then(|node| name_range(db, node, file_id)) + enum_.source(db).and_then(|node| name_range(node, file_id)) } else { None } } _ => { if config.annotate_references || config.annotate_impls { - adt.source(db).and_then(|node| name_range(db, node, file_id)) + adt.source(db).and_then(|node| name_range(node, file_id)) } else { None } @@ -144,17 +142,14 @@ pub(crate) fn annotations( } fn name_range( - db: &RootDatabase, node: InFile, - source_file_id: FileId, + source_file_id: HirFileId, ) -> Option<(TextRange, Option)> { - if let Some(InRealFile { file_id, value }) = node.original_ast_node_rooted(db) { - if file_id == source_file_id { - return Some(( - value.syntax().text_range(), - value.name().map(|name| name.syntax().text_range()), - )); - } + if node.file_id == source_file_id { + return Some(( + node.value.syntax().text_range(), + node.value.name().map(|name| name.syntax().text_range()), + )); } None } @@ -189,7 +184,7 @@ pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) .into_iter() .flat_map(|res| res.references) .flat_map(|(file_id, access)| { - access.into_iter().map(move |(range, _)| FileRange { file_id, range }) + access.into_iter().map(move |(range, _)| HirFileRange { file_id, range }) }) .collect() }); @@ -233,7 +228,7 @@ mod tests { let (analysis, file_id) = fixture::file(ra_fixture); let annotations: Vec = analysis - .annotations(config, file_id) + .annotations(config, file_id.into()) .unwrap() .into_iter() .map(|annotation| analysis.resolve_annotation(annotation).unwrap()) @@ -264,16 +259,18 @@ fn main() { range: 6..10, kind: HasReferences { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 6, }, data: Some( [ FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 78..82, }, @@ -285,8 +282,9 @@ fn main() { range: 30..36, kind: HasReferences { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 30, }, @@ -299,8 +297,9 @@ fn main() { range: 53..57, kind: HasReferences { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 53, }, @@ -315,8 +314,9 @@ fn main() { Runnable { use_name_in_title: false, nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 50..85, focus_range: 53..57, @@ -354,8 +354,9 @@ fn main() { range: 7..11, kind: HasImpls { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 7, }, @@ -368,16 +369,18 @@ fn main() { range: 7..11, kind: HasReferences { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 7, }, data: Some( [ FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 41..45, }, @@ -389,8 +392,9 @@ fn main() { range: 17..21, kind: HasReferences { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 17, }, @@ -405,8 +409,9 @@ fn main() { Runnable { use_name_in_title: false, nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 14..48, focus_range: 17..21, @@ -448,16 +453,18 @@ fn main() { range: 7..11, kind: HasImpls { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 7, }, data: Some( [ NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 36..64, focus_range: 57..61, @@ -472,22 +479,25 @@ fn main() { range: 7..11, kind: HasReferences { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 7, }, data: Some( [ FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 57..61, }, FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 93..97, }, @@ -499,16 +509,18 @@ fn main() { range: 20..31, kind: HasImpls { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 20, }, data: Some( [ NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 36..64, focus_range: 57..61, @@ -523,16 +535,18 @@ fn main() { range: 20..31, kind: HasReferences { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 20, }, data: Some( [ FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 41..52, }, @@ -544,8 +558,9 @@ fn main() { range: 69..73, kind: HasReferences { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 69, }, @@ -560,8 +575,9 @@ fn main() { Runnable { use_name_in_title: false, nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 66..100, focus_range: 69..73, @@ -595,8 +611,9 @@ fn main() {} range: 3..7, kind: HasReferences { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 3, }, @@ -611,8 +628,9 @@ fn main() {} Runnable { use_name_in_title: false, nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..12, focus_range: 3..7, @@ -654,16 +672,18 @@ fn main() { range: 7..11, kind: HasImpls { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 7, }, data: Some( [ NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 14..56, focus_range: 19..23, @@ -678,22 +698,25 @@ fn main() { range: 7..11, kind: HasReferences { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 7, }, data: Some( [ FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 19..23, }, FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 74..78, }, @@ -705,16 +728,18 @@ fn main() { range: 33..44, kind: HasReferences { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 33, }, data: Some( [ FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 79..90, }, @@ -726,8 +751,9 @@ fn main() { range: 61..65, kind: HasReferences { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 61, }, @@ -742,8 +768,9 @@ fn main() { Runnable { use_name_in_title: false, nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 58..95, focus_range: 61..65, @@ -782,8 +809,9 @@ mod tests { range: 3..7, kind: HasReferences { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 3, }, @@ -798,8 +826,9 @@ mod tests { Runnable { use_name_in_title: false, nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..12, focus_range: 3..7, @@ -822,8 +851,9 @@ mod tests { Runnable { use_name_in_title: false, nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 14..64, focus_range: 18..23, @@ -849,8 +879,9 @@ mod tests { Runnable { use_name_in_title: false, nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 30..62, focus_range: 45..57, @@ -927,8 +958,9 @@ struct Foo; range: 0..71, kind: HasImpls { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 67, }, @@ -941,8 +973,9 @@ struct Foo; range: 0..71, kind: HasReferences { pos: FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 67, }, diff --git a/crates/ide/src/annotations/fn_references.rs b/crates/ide/src/annotations/fn_references.rs index 08cc10509cb8..4014f20a6914 100644 --- a/crates/ide/src/annotations/fn_references.rs +++ b/crates/ide/src/annotations/fn_references.rs @@ -1,20 +1,19 @@ //! This module implements a methods and free functions search in the specified file. //! We have to skip tests, so cannot reuse file_structure module. -use hir::Semantics; +use hir::{HirFileId, Semantics}; use ide_assists::utils::test_related_attribute_syn; use ide_db::RootDatabase; use syntax::{ast, ast::HasName, AstNode, SyntaxNode, TextRange}; -use crate::FileId; - pub(super) fn find_all_methods( db: &RootDatabase, - file_id: FileId, + file_id: HirFileId, ) -> Vec<(TextRange, Option)> { let sema = Semantics::new(db); - let source_file = sema.parse_guess_edition(file_id); - source_file.syntax().descendants().filter_map(method_range).collect() + let file_id = sema.adjust_edition(file_id); + let syntax = sema.parse_or_expand(sema.adjust_edition(file_id)); + syntax.descendants().filter_map(method_range).collect() } fn method_range(item: SyntaxNode) -> Option<(TextRange, Option)> { @@ -50,7 +49,7 @@ mod tests { "#, ); - let refs = super::find_all_methods(&analysis.db, pos.file_id); + let refs = super::find_all_methods(&analysis.db, pos.file_id.into()); check_result(&refs, &[3..=13, 27..=33, 47..=57]); } @@ -65,7 +64,7 @@ mod tests { "#, ); - let refs = super::find_all_methods(&analysis.db, pos.file_id); + let refs = super::find_all_methods(&analysis.db, pos.file_id.into()); check_result(&refs, &[19..=22, 35..=38]); } @@ -86,7 +85,7 @@ mod tests { "#, ); - let refs = super::find_all_methods(&analysis.db, pos.file_id); + let refs = super::find_all_methods(&analysis.db, pos.file_id.into()); check_result(&refs, &[28..=34]); } diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs index afd6f740c42c..9cf8cf7a2350 100644 --- a/crates/ide/src/call_hierarchy.rs +++ b/crates/ide/src/call_hierarchy.rs @@ -1,22 +1,22 @@ //! Entry point for call-hierarchy -use std::iter; - -use hir::Semantics; +use hir::{HirFileRange, Semantics}; use ide_db::{ defs::{Definition, NameClass, NameRefClass}, helpers::pick_best_token, search::FileReference, - FileRange, FxIndexMap, RootDatabase, + FxIndexMap, RootDatabase, }; use syntax::{ast, AstNode, SyntaxKind::IDENT}; -use crate::{goto_definition, FilePosition, NavigationTarget, RangeInfo, TryToNav}; +use crate::{ + goto_definition, navigation_target::HirNavigationTarget, HirFilePosition, RangeInfo, TryToNav, +}; #[derive(Debug, Clone)] pub struct CallItem { - pub target: NavigationTarget, - pub ranges: Vec, + pub target: HirNavigationTarget, + pub ranges: Vec, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -27,20 +27,19 @@ pub struct CallHierarchyConfig { pub(crate) fn call_hierarchy( db: &RootDatabase, - position: FilePosition, -) -> Option>> { + position: HirFilePosition, +) -> Option>> { goto_definition::goto_definition(db, position) } pub(crate) fn incoming_calls( db: &RootDatabase, CallHierarchyConfig { exclude_tests }: CallHierarchyConfig, - FilePosition { file_id, offset }: FilePosition, + HirFilePosition { file_id, offset }: HirFilePosition, ) -> Option> { let sema = &Semantics::new(db); - let file = sema.parse_guess_edition(file_id); - let file = file.syntax(); + let file = &sema.parse_or_expand(sema.adjust_edition(file_id)); let mut calls = CallLocations::default(); let references = sema @@ -58,7 +57,7 @@ pub(crate) fn incoming_calls( }) .flat_map(|func| func.usages(sema).all()); - for (_, references) in references { + for (file_id, references) in references { let references = references.iter().filter_map(|FileReference { name, .. }| name.as_name_ref()); for name in references { @@ -67,7 +66,7 @@ pub(crate) fn incoming_calls( let def = ast::Fn::cast(node).and_then(|fn_| sema.to_def(&fn_))?; // We should return def before check if it is a test, so that we // will not continue to search for outer fn in nested fns - def.try_to_nav(sema.db).map(|nav| (def, nav)) + def.try_to_nav_hir(sema.db).map(|nav| (def, nav)) }); if let Some((def, nav)) = def_nav { @@ -75,11 +74,8 @@ pub(crate) fn incoming_calls( continue; } - let range = sema.original_range(name.syntax()); - calls.add(nav.call_site, range.into()); - if let Some(other) = nav.def_site { - calls.add(other, range.into()); - } + let range = HirFileRange { file_id, range: name.syntax().text_range() }; + calls.add(nav, range); } } } @@ -90,11 +86,10 @@ pub(crate) fn incoming_calls( pub(crate) fn outgoing_calls( db: &RootDatabase, CallHierarchyConfig { exclude_tests }: CallHierarchyConfig, - FilePosition { file_id, offset }: FilePosition, + HirFilePosition { file_id, offset }: HirFilePosition, ) -> Option> { let sema = Semantics::new(db); - let file = sema.parse_guess_edition(file_id); - let file = file.syntax(); + let file = &sema.parse_or_expand(sema.adjust_edition(file_id)); let token = pick_best_token(file.token_at_offset(offset), |kind| match kind { IDENT => 1, _ => 0, @@ -122,39 +117,39 @@ pub(crate) fn outgoing_calls( if exclude_tests && it.is_test(db) { return None; } - it.try_to_nav(db) + it.try_to_nav_hir(db) } - hir::CallableKind::TupleEnumVariant(it) => it.try_to_nav(db), - hir::CallableKind::TupleStruct(it) => it.try_to_nav(db), + hir::CallableKind::TupleEnumVariant(it) => it.try_to_nav_hir(db), + hir::CallableKind::TupleStruct(it) => it.try_to_nav_hir(db), _ => None, } - .zip(Some(sema.original_range(expr.syntax()))) + .zip(Some(HirFileRange { file_id, range: expr.syntax().text_range() })) } ast::CallableExpr::MethodCall(expr) => { let function = sema.resolve_method_call(&expr)?; if exclude_tests && function.is_test(db) { return None; } - function - .try_to_nav(db) - .zip(Some(sema.original_range(expr.name_ref()?.syntax()))) + function.try_to_nav_hir(db).zip(Some(HirFileRange { + file_id, + range: expr.name_ref()?.syntax().text_range(), + })) } }?; - Some(nav_target.into_iter().zip(iter::repeat(range))) + Some((nav_target, range)) }) - .flatten() - .for_each(|(nav, range)| calls.add(nav, range.into())); + .for_each(|(nav, range)| calls.add(nav, range)); Some(calls.into_items()) } #[derive(Default)] struct CallLocations { - funcs: FxIndexMap>, + funcs: FxIndexMap>, } impl CallLocations { - fn add(&mut self, target: NavigationTarget, range: FileRange) { + fn add(&mut self, target: HirNavigationTarget, range: HirFileRange) { self.funcs.entry(target).or_default().push(range); } @@ -166,7 +161,7 @@ impl CallLocations { #[cfg(test)] mod tests { use expect_test::{expect, Expect}; - use ide_db::FilePosition; + use hir::HirFilePosition; use itertools::Itertools; use crate::fixture; @@ -191,7 +186,7 @@ mod tests { let (analysis, pos) = fixture::position(ra_fixture); - let mut navs = analysis.call_hierarchy(pos).unwrap().unwrap().info; + let mut navs = analysis.call_hierarchy(pos.into()).unwrap().unwrap().info; assert_eq!(navs.len(), 1); let nav = navs.pop().unwrap(); expected_nav.assert_eq(&nav.debug_render()); @@ -199,7 +194,7 @@ mod tests { let config = crate::CallHierarchyConfig { exclude_tests }; let item_pos = - FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() }; + HirFilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() }; let incoming_calls = analysis.incoming_calls(config, item_pos).unwrap().unwrap(); expected_incoming.assert_eq(&incoming_calls.into_iter().map(debug_render).join("\n")); @@ -218,8 +213,8 @@ fn caller() { call$0ee(); } "#, - expect![["callee Function FileId(0) 0..14 3..9"]], - expect!["caller Function FileId(0) 15..44 18..24 : FileId(0):33..39"], + expect!["callee Function EditionedFileId(0, Edition2021) 0..14 3..9"], + expect!["caller Function EditionedFileId(0, Edition2021) 15..44 18..24 : EditionedFileId(0, Edition2021):33..39"], expect![[]], ); } @@ -235,8 +230,8 @@ fn caller() { callee(); } "#, - expect![["callee Function FileId(0) 0..14 3..9"]], - expect!["caller Function FileId(0) 15..44 18..24 : FileId(0):33..39"], + expect!["callee Function EditionedFileId(0, Edition2021) 0..14 3..9"], + expect!["caller Function EditionedFileId(0, Edition2021) 15..44 18..24 : EditionedFileId(0, Edition2021):33..39"], expect![[]], ); } @@ -253,8 +248,8 @@ fn caller() { callee(); } "#, - expect![["callee Function FileId(0) 0..14 3..9"]], - expect!["caller Function FileId(0) 15..58 18..24 : FileId(0):33..39, FileId(0):47..53"], + expect!["callee Function EditionedFileId(0, Edition2021) 0..14 3..9"], + expect!["caller Function EditionedFileId(0, Edition2021) 15..58 18..24 : EditionedFileId(0, Edition2021):33..39, EditionedFileId(0, Edition2021):47..53"], expect![[]], ); } @@ -274,10 +269,10 @@ fn caller2() { callee(); } "#, - expect![["callee Function FileId(0) 0..14 3..9"]], + expect!["callee Function EditionedFileId(0, Edition2021) 0..14 3..9"], expect![[r#" - caller1 Function FileId(0) 15..45 18..25 : FileId(0):34..40 - caller2 Function FileId(0) 47..77 50..57 : FileId(0):66..72"#]], + caller1 Function EditionedFileId(0, Edition2021) 15..45 18..25 : EditionedFileId(0, Edition2021):34..40 + caller2 Function EditionedFileId(0, Edition2021) 47..77 50..57 : EditionedFileId(0, Edition2021):66..72"#]], expect![[]], ); } @@ -303,10 +298,10 @@ mod tests { } } "#, - expect![["callee Function FileId(0) 0..14 3..9"]], + expect!["callee Function EditionedFileId(0, Edition2021) 0..14 3..9"], expect![[r#" - caller1 Function FileId(0) 15..45 18..25 : FileId(0):34..40 - test_caller Function FileId(0) 95..149 110..121 tests : FileId(0):134..140"#]], + caller1 Function EditionedFileId(0, Edition2021) 15..45 18..25 : EditionedFileId(0, Edition2021):34..40 + test_caller Function EditionedFileId(0, Edition2021) 95..149 110..121 tests : EditionedFileId(0, Edition2021):134..140"#]], expect![[]], ); } @@ -327,8 +322,8 @@ fn caller() { //- /foo/mod.rs pub fn callee() {} "#, - expect!["callee Function FileId(1) 0..18 7..13 foo"], - expect!["caller Function FileId(0) 27..56 30..36 : FileId(0):45..51"], + expect!["callee Function EditionedFileId(1, Edition2021) 0..18 7..13 foo"], + expect!["caller Function EditionedFileId(0, Edition2021) 27..56 30..36 : EditionedFileId(0, Edition2021):45..51"], expect![[]], ); } @@ -345,9 +340,9 @@ fn call$0er() { callee(); } "#, - expect![["caller Function FileId(0) 15..58 18..24"]], + expect!["caller Function EditionedFileId(0, Edition2021) 15..58 18..24"], expect![[]], - expect!["callee Function FileId(0) 0..14 3..9 : FileId(0):33..39, FileId(0):47..53"], + expect!["callee Function EditionedFileId(0, Edition2021) 0..14 3..9 : EditionedFileId(0, Edition2021):33..39, EditionedFileId(0, Edition2021):47..53"], ); } @@ -367,9 +362,9 @@ fn call$0er() { //- /foo/mod.rs pub fn callee() {} "#, - expect![["caller Function FileId(0) 27..56 30..36"]], + expect!["caller Function EditionedFileId(0, Edition2021) 27..56 30..36"], expect![[]], - expect!["callee Function FileId(1) 0..18 7..13 foo : FileId(0):45..51"], + expect!["callee Function EditionedFileId(1, Edition2021) 0..18 7..13 foo : EditionedFileId(0, Edition2021):45..51"], ); } @@ -391,9 +386,9 @@ fn caller3() { } "#, - expect![["caller2 Function FileId(0) 33..64 36..43"]], - expect!["caller1 Function FileId(0) 0..31 3..10 : FileId(0):19..26"], - expect!["caller3 Function FileId(0) 66..83 69..76 : FileId(0):52..59"], + expect!["caller2 Function EditionedFileId(0, Edition2021) 33..64 36..43"], + expect!["caller1 Function EditionedFileId(0, Edition2021) 0..31 3..10 : EditionedFileId(0, Edition2021):19..26"], + expect!["caller3 Function EditionedFileId(0, Edition2021) 66..83 69..76 : EditionedFileId(0, Edition2021):52..59"], ); } @@ -412,9 +407,9 @@ fn main() { a$0() } "#, - expect![["a Function FileId(0) 0..18 3..4"]], - expect!["main Function FileId(0) 31..52 34..38 : FileId(0):47..48"], - expect!["b Function FileId(0) 20..29 23..24 : FileId(0):13..14"], + expect!["a Function EditionedFileId(0, Edition2021) 0..18 3..4"], + expect!["main Function EditionedFileId(0, Edition2021) 31..52 34..38 : EditionedFileId(0, Edition2021):47..48"], + expect!["b Function EditionedFileId(0, Edition2021) 20..29 23..24 : EditionedFileId(0, Edition2021):13..14"], ); check_hierarchy( @@ -430,8 +425,8 @@ fn main() { a() } "#, - expect![["b Function FileId(0) 20..29 23..24"]], - expect!["a Function FileId(0) 0..18 3..4 : FileId(0):13..14"], + expect!["b Function EditionedFileId(0, Edition2021) 20..29 23..24"], + expect!["a Function EditionedFileId(0, Edition2021) 0..18 3..4 : EditionedFileId(0, Edition2021):13..14"], expect![[]], ); } @@ -456,8 +451,8 @@ fn caller() { call!(call$0ee); } "#, - expect![[r#"callee Function FileId(0) 144..159 152..158"#]], - expect!["caller Function FileId(0) 160..194 163..169 : FileId(0):184..190"], + expect!["callee Function MacroFile(0) 0..10 2..8"], + expect!["caller Function EditionedFileId(0, Edition2021) 160..194 163..169 : MacroFile(1):0..6"], expect![[]], ); check_hierarchy( @@ -478,8 +473,8 @@ fn caller() { call!(callee); } "#, - expect![[r#"callee Function FileId(0) 144..159 152..158"#]], - expect!["caller Function FileId(0) 160..194 163..169 : FileId(0):184..190"], + expect!["callee Function MacroFile(0) 0..10 2..8"], + expect!["caller Function EditionedFileId(0, Edition2021) 160..194 163..169 : MacroFile(1):0..6"], expect![[]], ); } @@ -504,7 +499,7 @@ fn caller$0() { call!(callee); } "#, - expect![[r#"caller Function FileId(0) 160..194 163..169"#]], + expect!["caller Function EditionedFileId(0, Edition2021) 160..194 163..169"], expect![[]], // FIXME expect![[]], @@ -535,8 +530,8 @@ macro_rules! call { } } "#, - expect!["callee Function FileId(0) 22..37 30..36"], - expect!["caller Function FileId(0) 38..72 41..47 : FileId(0):62..68"], + expect!["callee Function MacroFile(0) 0..10 2..8"], + expect!["caller Function EditionedFileId(0, Edition2021) 38..72 41..47 : MacroFile(1):0..6"], expect![[]], ); check_hierarchy( @@ -561,8 +556,8 @@ macro_rules! call { } } "#, - expect!["callee Function FileId(0) 22..37 30..36"], - expect!["caller Function FileId(0) 38..72 41..47 : FileId(0):62..68"], + expect!["callee Function MacroFile(0) 0..10 2..8"], + expect!["caller Function EditionedFileId(0, Edition2021) 38..72 41..47 : MacroFile(1):0..6"], expect![[]], ); check_hierarchy( @@ -590,11 +585,10 @@ macro_rules! call { } } "#, - expect!["callee Function FileId(0) 22..37 30..36"], + expect!["callee Function MacroFile(0) 0..10 2..8"], expect![[r#" - caller Function FileId(0) 38..52 : FileId(0):44..50 - caller Function FileId(1) 130..136 130..136 : FileId(0):44..50 - callee Function FileId(0) 38..52 44..50 : FileId(0):44..50"#]], + caller Function MacroFile(1) 0..20 2..8 : MacroFile(1):11..17 + callee Function MacroFile(1) 20..40 22..28 : MacroFile(1):31..37"#]], expect![[]], ); } @@ -624,7 +618,7 @@ macro_rules! call { } } "#, - expect!["caller Function FileId(0) 38..72 41..47"], + expect!["caller Function EditionedFileId(0, Edition2021) 38..72 41..47"], expect![[]], // FIXME expect![[]], @@ -652,7 +646,7 @@ macro_rules! call { } } "#, - expect!["caller Function FileId(0) 38..72 41..47"], + expect!["caller Function EditionedFileId(0, Edition2021) 38..72 41..47"], expect![[]], // FIXME expect![[]], @@ -678,8 +672,8 @@ fn caller() { S1::callee(); } "#, - expect!["callee Function FileId(0) 15..27 18..24 T1"], - expect!["caller Function FileId(0) 82..115 85..91 : FileId(0):104..110"], + expect!["callee Function EditionedFileId(0, Edition2021) 15..27 18..24 T1"], + expect!["caller Function EditionedFileId(0, Edition2021) 82..115 85..91 : EditionedFileId(0, Edition2021):104..110"], expect![[]], ); } @@ -706,14 +700,14 @@ fn f3() { f1(); f2(); } "#, - expect!["f1 Function FileId(0) 25..52 28..30"], + expect!["f1 Function EditionedFileId(0, Edition2021) 25..52 28..30"], expect![[r#" - main Function FileId(0) 0..23 3..7 : FileId(0):16..18 - f2 Function FileId(0) 54..81 57..59 : FileId(0):68..70 - f3 Function FileId(0) 83..118 94..96 : FileId(0):105..107"#]], + main Function EditionedFileId(0, Edition2021) 0..23 3..7 : EditionedFileId(0, Edition2021):16..18 + f2 Function EditionedFileId(0, Edition2021) 54..81 57..59 : EditionedFileId(0, Edition2021):68..70 + f3 Function EditionedFileId(0, Edition2021) 83..118 94..96 : EditionedFileId(0, Edition2021):105..107"#]], expect![[r#" - f2 Function FileId(0) 54..81 57..59 : FileId(0):39..41 - f3 Function FileId(0) 83..118 94..96 : FileId(0):45..47"#]], + f2 Function EditionedFileId(0, Edition2021) 54..81 57..59 : EditionedFileId(0, Edition2021):39..41 + f3 Function EditionedFileId(0, Edition2021) 83..118 94..96 : EditionedFileId(0, Edition2021):45..47"#]], ); check_hierarchy( @@ -736,11 +730,11 @@ fn f3() { f1(); f2(); } "#, - expect!["f1 Function FileId(0) 25..52 28..30"], + expect!["f1 Function EditionedFileId(0, Edition2021) 25..52 28..30"], expect![[r#" - main Function FileId(0) 0..23 3..7 : FileId(0):16..18 - f2 Function FileId(0) 54..81 57..59 : FileId(0):68..70"#]], - expect!["f2 Function FileId(0) 54..81 57..59 : FileId(0):39..41"], + main Function EditionedFileId(0, Edition2021) 0..23 3..7 : EditionedFileId(0, Edition2021):16..18 + f2 Function EditionedFileId(0, Edition2021) 54..81 57..59 : EditionedFileId(0, Edition2021):68..70"#]], + expect!["f2 Function EditionedFileId(0, Edition2021) 54..81 57..59 : EditionedFileId(0, Edition2021):39..41"], ); } } diff --git a/crates/ide/src/doc_links/tests.rs b/crates/ide/src/doc_links/tests.rs index d7291c4b9f32..8f0b9be3c6f1 100644 --- a/crates/ide/src/doc_links/tests.rs +++ b/crates/ide/src/doc_links/tests.rs @@ -23,7 +23,7 @@ fn check_external_docs( sysroot: Option<&str>, ) { let (analysis, position) = fixture::position(ra_fixture); - let links = analysis.external_docs(position, target_dir, sysroot).unwrap(); + let links = analysis.external_docs(position.into(), target_dir, sysroot).unwrap(); let web_url = links.web_url; let local_url = links.local_url; @@ -44,7 +44,7 @@ fn check_external_docs( fn check_rewrite(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let sema = &Semantics::new(&*analysis.db); - let (cursor_def, docs) = def_under_cursor(sema, &position); + let (cursor_def, docs) = def_under_cursor(sema, position.into()); let res = rewrite_links(sema.db, docs.as_str(), cursor_def); expect.assert_eq(&res) } @@ -52,10 +52,11 @@ fn check_rewrite(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let key_fn = |&(FileRange { file_id, range }, _): &_| (file_id, range.start()); - let (analysis, position, mut expected) = fixture::annotations(ra_fixture); + let (analysis, position, expected) = fixture::annotations(ra_fixture); + let mut expected = expected.into_iter().map(|(range, s)| (range.into(), s)).collect::>(); expected.sort_by_key(key_fn); let sema = &Semantics::new(&*analysis.db); - let (cursor_def, docs) = def_under_cursor(sema, &position); + let (cursor_def, docs) = def_under_cursor(sema, position.into()); let defs = extract_definitions_from_docs(&docs); let actual: Vec<_> = defs .into_iter() @@ -76,7 +77,7 @@ fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) { fn def_under_cursor( sema: &Semantics<'_, RootDatabase>, - position: &FilePosition, + position: FilePosition, ) -> (Definition, Documentation) { let (docs, def) = sema .parse_guess_edition(position.file_id) diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs index ad4308e06a14..c42f5e166a7f 100644 --- a/crates/ide/src/expand_macro.rs +++ b/crates/ide/src/expand_macro.rs @@ -1,15 +1,11 @@ use hir::db::ExpandDatabase; -use hir::{ExpandResult, InFile, MacroFileIdExt, Semantics}; -use ide_db::base_db::CrateId; -use ide_db::{ - helpers::pick_best_token, syntax_helpers::prettify_macro_expansion, FileId, RootDatabase, -}; -use span::{Edition, SpanMap, SyntaxContextId, TextRange, TextSize}; +use hir::{ExpandResult, HirFilePosition, InFile, MacroFileIdExt, Semantics}; +use ide_db::base_db::{CrateId, SourceDatabase}; +use ide_db::{helpers::pick_best_token, syntax_helpers::prettify_macro_expansion, RootDatabase}; +use span::{SpanMap, SyntaxContextId, TextRange, TextSize}; use stdx::format_to; use syntax::{ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T}; -use crate::FilePosition; - pub struct ExpandedMacro { pub name: String, pub expansion: String, @@ -24,12 +20,21 @@ pub struct ExpandedMacro { // | VS Code | **rust-analyzer: Expand macro recursively at caret** | // // ![Expand Macro Recursively](https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif) -pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option { +pub(crate) fn expand_macro( + db: &RootDatabase, + mut position: HirFilePosition, +) -> Option { let sema = Semantics::new(db); - let file = sema.parse_guess_edition(position.file_id); - let krate = sema.file_to_module_def(position.file_id)?.krate().into(); + position.file_id = sema.adjust_edition(position.file_id); + let file = &sema.parse_or_expand(position.file_id); + let krate = match position.file_id.repr() { + span::HirFileIdRepr::FileId(file_id) => sema.file_to_module_def(file_id)?.krate().into(), + span::HirFileIdRepr::MacroFile(macro_file_id) => { + db.lookup_intern_macro_call(macro_file_id.macro_call_id).def.krate + } + }; - let tok = pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind { + let tok = pick_best_token(file.token_at_offset(position.offset), |kind| match kind { SyntaxKind::IDENT => 1, _ => 0, })?; @@ -65,14 +70,8 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< let ExpandResult { err, value: expansion } = expansions.get(idx)?.clone(); let expansion_file_id = sema.hir_file_for(&expansion).macro_file()?; let expansion_span_map = db.expansion_span_map(expansion_file_id); - let mut expansion = format( - db, - SyntaxKind::MACRO_ITEMS, - position.file_id, - expansion, - &expansion_span_map, - krate, - ); + let mut expansion = + format(db, SyntaxKind::MACRO_ITEMS, expansion, &expansion_span_map, krate); if let Some(err) = err { expansion.insert_str( 0, @@ -95,14 +94,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< if let Some(item) = ast::Item::cast(node.clone()) { if let Some(def) = sema.resolve_attr_macro_call(&item) { break ( - def.name(db) - .display( - db, - sema.attach_first_edition(position.file_id) - .map(|it| it.edition()) - .unwrap_or(Edition::CURRENT), - ) - .to_string(), + def.name(db).display(db, db.crate_graph()[krate].edition).to_string(), expand_macro_recur(&sema, &item, &mut error, &mut span_map, TextSize::new(0))?, SyntaxKind::MACRO_ITEMS, ); @@ -130,7 +122,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< // FIXME: // macro expansion may lose all white space information // But we hope someday we can use ra_fmt for that - let mut expansion = format(db, kind, position.file_id, expanded, &span_map, krate); + let mut expansion = format(db, kind, expanded, &span_map, krate); if !error.is_empty() { expansion.insert_str(0, &format!("Expansion had errors:{error}\n\n")); @@ -205,22 +197,21 @@ fn expand( fn format( db: &RootDatabase, kind: SyntaxKind, - file_id: FileId, expanded: SyntaxNode, span_map: &SpanMap, krate: CrateId, ) -> String { let expansion = prettify_macro_expansion(db, expanded, span_map, krate).to_string(); - _format(db, kind, file_id, &expansion).unwrap_or(expansion) + _format(db, kind, &expansion, krate).unwrap_or(expansion) } #[cfg(any(test, target_arch = "wasm32", target_os = "emscripten"))] fn _format( _db: &RootDatabase, _kind: SyntaxKind, - _file_id: FileId, expansion: &str, + _krate: CrateId, ) -> Option { // remove trailing spaces for test use itertools::Itertools; @@ -231,10 +222,10 @@ fn _format( fn _format( db: &RootDatabase, kind: SyntaxKind, - file_id: FileId, expansion: &str, + crate_id: CrateId, ) -> Option { - use ide_db::base_db::{FileLoader, SourceDatabase}; + use ide_db::base_db::SourceDatabase; // hack until we get hygiene working (same character amount to preserve formatting as much as possible) const DOLLAR_CRATE_REPLACE: &str = "__r_a_"; const BUILTIN_REPLACE: &str = "builtin__POUND"; @@ -248,7 +239,6 @@ fn _format( }; let expansion = format!("{prefix}{expansion}{suffix}"); - let &crate_id = db.relevant_crates(file_id).iter().next()?; let edition = db.crate_graph()[crate_id].edition; #[allow(clippy::disallowed_methods)] @@ -296,7 +286,7 @@ mod tests { #[track_caller] fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, pos) = fixture::position(ra_fixture); - let expansion = analysis.expand_macro(pos).unwrap().unwrap(); + let expansion = analysis.expand_macro(pos.into()).unwrap().unwrap(); let actual = format!("{}\n{}", expansion.name, expansion.expansion); expect.assert_eq(&actual); } @@ -320,7 +310,7 @@ $0concat!("test", 10, 'b', true);"#, //- minicore: asm $0asm!("0x300, x0");"#, ); - let expansion = analysis.expand_macro(pos).unwrap(); + let expansion = analysis.expand_macro(pos.into()).unwrap(); assert!(expansion.is_none()); } diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs index 76414854e91e..116ccbd18101 100644 --- a/crates/ide/src/extend_selection.rs +++ b/crates/ide/src/extend_selection.rs @@ -334,9 +334,9 @@ mod tests { fn do_check(before: &str, afters: &[&str]) { let (analysis, position) = fixture::position(before); - let before = analysis.file_text(position.file_id).unwrap(); + let before = analysis.file_text(position.file_id.into()).unwrap(); let range = TextRange::empty(position.offset); - let mut frange = FileRange { file_id: position.file_id, range }; + let mut frange = FileRange { file_id: position.file_id.into(), range }; for &after in afters { frange.range = analysis.extend_selection(frange).unwrap(); diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs index 52fbab6fa12b..835eed6137a8 100644 --- a/crates/ide/src/file_structure.rs +++ b/crates/ide/src/file_structure.rs @@ -1,8 +1,7 @@ use ide_db::SymbolKind; use syntax::{ ast::{self, HasAttrs, HasGenericParams, HasName}, - match_ast, AstNode, AstToken, NodeOrToken, SourceFile, SyntaxNode, SyntaxToken, TextRange, - WalkEvent, + match_ast, AstNode, AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, WalkEvent, }; #[derive(Debug, Clone)] @@ -36,11 +35,11 @@ pub enum StructureNodeKind { // | VS Code | Ctrl+Shift+O | // // ![File Structure](https://user-images.githubusercontent.com/48062697/113020654-b42fc800-917a-11eb-8388-e7dc4d92b02e.gif) -pub(crate) fn file_structure(file: &SourceFile) -> Vec { +pub(crate) fn file_structure(file: &SyntaxNode) -> Vec { let mut res = Vec::new(); let mut stack = Vec::new(); - for event in file.syntax().preorder_with_tokens() { + for event in file.preorder_with_tokens() { match event { WalkEvent::Enter(NodeOrToken::Node(node)) => { if let Some(mut symbol) = structure_node(&node) { @@ -251,12 +250,13 @@ fn structure_token(token: SyntaxToken) -> Option { #[cfg(test)] mod tests { use expect_test::{expect, Expect}; + use syntax::SourceFile; use super::*; fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let file = SourceFile::parse(ra_fixture, span::Edition::CURRENT).ok().unwrap(); - let structure = file_structure(&file); + let structure = file_structure(file.syntax()); expect.assert_debug_eq(&structure) } diff --git a/crates/ide/src/fixture.rs b/crates/ide/src/fixture.rs index a0612f48d37e..945928f19b06 100644 --- a/crates/ide/src/fixture.rs +++ b/crates/ide/src/fixture.rs @@ -1,16 +1,18 @@ //! Utilities for creating `Analysis` instances for tests. +use hir::{FilePosition, FileRange}; +use span::EditionedFileId; use test_fixture::ChangeFixture; use test_utils::{extract_annotations, RangeOrOffset}; -use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange}; +use crate::{Analysis, AnalysisHost}; /// Creates analysis for a single file. -pub(crate) fn file(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (Analysis, FileId) { +pub(crate) fn file(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (Analysis, EditionedFileId) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); host.db.enable_proc_attr_macros(); host.db.apply_change(change_fixture.change); - (host.analysis(), change_fixture.files[0].into()) + (host.analysis(), change_fixture.files[0]) } /// Creates analysis from a multi-file fixture, returns positions marked with $0. @@ -23,7 +25,7 @@ pub(crate) fn position( host.db.apply_change(change_fixture.change); let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); let offset = range_or_offset.expect_offset(); - (host.analysis(), FilePosition { file_id: file_id.into(), offset }) + (host.analysis(), FilePosition { file_id, offset }) } /// Creates analysis for a single file, returns range marked with a pair of $0. @@ -34,19 +36,19 @@ pub(crate) fn range(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (Analysi host.db.apply_change(change_fixture.change); let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); let range = range_or_offset.expect_range(); - (host.analysis(), FileRange { file_id: file_id.into(), range }) + (host.analysis(), FileRange { file_id, range }) } /// Creates analysis for a single file, returns range marked with a pair of $0 or a position marked with $0. pub(crate) fn range_or_position( #[rust_analyzer::rust_fixture] ra_fixture: &str, -) -> (Analysis, FileId, RangeOrOffset) { +) -> (Analysis, EditionedFileId, RangeOrOffset) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); host.db.enable_proc_attr_macros(); host.db.apply_change(change_fixture.change); let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)"); - (host.analysis(), file_id.into(), range_or_offset) + (host.analysis(), file_id, range_or_offset) } /// Creates analysis from a multi-file fixture, returns positions marked with $0. @@ -66,12 +68,10 @@ pub(crate) fn annotations( .flat_map(|&file_id| { let file_text = host.analysis().file_text(file_id.into()).unwrap(); let annotations = extract_annotations(&file_text); - annotations - .into_iter() - .map(move |(range, data)| (FileRange { file_id: file_id.into(), range }, data)) + annotations.into_iter().map(move |(range, data)| (FileRange { file_id, range }, data)) }) .collect(); - (host.analysis(), FilePosition { file_id: file_id.into(), offset }, annotations) + (host.analysis(), FilePosition { file_id, offset }, annotations) } /// Creates analysis from a multi-file fixture with annotations without $0 @@ -89,9 +89,7 @@ pub(crate) fn annotations_without_marker( .flat_map(|&file_id| { let file_text = host.analysis().file_text(file_id.into()).unwrap(); let annotations = extract_annotations(&file_text); - annotations - .into_iter() - .map(move |(range, data)| (FileRange { file_id: file_id.into(), range }, data)) + annotations.into_iter().map(move |(range, data)| (FileRange { file_id, range }, data)) }) .collect(); (host.analysis(), annotations) diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs index e5a94ff9fe96..6e3b99fdebec 100755 --- a/crates/ide/src/folding_ranges.rs +++ b/crates/ide/src/folding_ranges.rs @@ -1,9 +1,9 @@ use ide_db::{syntax_helpers::node_ext::vis_eq, FxHashSet}; use syntax::{ ast::{self, AstNode, AstToken}, - match_ast, Direction, NodeOrToken, SourceFile, + match_ast, Direction, NodeOrToken, SyntaxKind::{self, *}, - TextRange, TextSize, + SyntaxNode, TextRange, TextSize, }; use std::hash::Hash; @@ -37,7 +37,7 @@ pub struct Fold { // // Defines folding regions for curly braced blocks, runs of consecutive use, mod, const or static // items, and `region` / `endregion` comment markers. -pub(crate) fn folding_ranges(file: &SourceFile) -> Vec { +pub(crate) fn folding_ranges(file: &SyntaxNode) -> Vec { let mut res = vec![]; let mut visited_comments = FxHashSet::default(); let mut visited_imports = FxHashSet::default(); @@ -48,7 +48,7 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec { // regions can be nested, here is a LIFO buffer let mut region_starts: Vec = vec![]; - for element in file.syntax().descendants_with_tokens() { + for element in file.descendants_with_tokens() { // Fold items that span multiple lines if let Some(kind) = fold_kind(element.kind()) { let is_multiline = match &element { @@ -282,6 +282,7 @@ fn fold_range_for_multiline_match_arm(match_arm: ast::MatchArm) -> Option Option>> { + position @ HirFilePosition { file_id, offset }: HirFilePosition, +) -> Option>> { let sema = Semantics::new(db); - let file = sema.parse_guess_edition(file_id).syntax().clone(); + let file_id = sema.adjust_edition(file_id); + let file = sema.parse_or_expand(sema.adjust_edition(file_id)); let original_token = file .token_at_offset(offset) .find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate] | T![Self]))?; let range = original_token.text_range(); - let info: Vec = sema + let info: Vec = sema .descend_into_macros_no_opaque(original_token) .iter() .filter_map(|token| { @@ -38,35 +40,34 @@ pub(crate) fn goto_declaration( ast::NameRef(name_ref) => match NameRefClass::classify(&sema, &name_ref)? { NameRefClass::Definition(it, _) => Some(it), NameRefClass::FieldShorthand { field_ref, .. } => - return field_ref.try_to_nav(db), + return field_ref.try_to_nav_hir(db), NameRefClass::ExternCrateShorthand { decl, .. } => - return decl.try_to_nav(db), + return decl.try_to_nav_hir(db), }, ast::Name(name) => match NameClass::classify(&sema, &name)? { NameClass::Definition(it) | NameClass::ConstReference(it) => Some(it), NameClass::PatFieldShorthand { field_ref, .. } => - return field_ref.try_to_nav(db), + return field_ref.try_to_nav_hir(db), }, _ => None } }; let assoc = match def? { Definition::Module(module) => { - return Some(NavigationTarget::from_module_to_decl(db, module)) + return Some(HirNavigationTarget::from_module_to_decl(db, module)) } Definition::Const(c) => c.as_assoc_item(db), Definition::TypeAlias(ta) => ta.as_assoc_item(db), Definition::Function(f) => f.as_assoc_item(db), - Definition::ExternCrateDecl(it) => return it.try_to_nav(db), + Definition::ExternCrateDecl(it) => return it.try_to_nav_hir(db), _ => None, }?; let trait_ = assoc.implemented_trait(db)?; let name = Some(assoc.name(db)?); let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?; - item.try_to_nav(db) + item.try_to_nav_hir(db) }) - .flatten() .collect(); if info.is_empty() { @@ -78,7 +79,7 @@ pub(crate) fn goto_declaration( #[cfg(test)] mod tests { - use ide_db::FileRange; + use hir::HirFileRange; use itertools::Itertools; use crate::fixture; @@ -86,7 +87,7 @@ mod tests { fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, expected) = fixture::annotations(ra_fixture); let navs = analysis - .goto_declaration(position) + .goto_declaration(position.into()) .unwrap() .expect("no declaration or definition found") .info; @@ -94,17 +95,14 @@ mod tests { panic!("unresolved reference") } - let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start()); + let cmp = |&HirFileRange { file_id, range }: &_| (file_id, range.start()); let navs = navs .into_iter() - .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) - .sorted_by_key(cmp) - .collect::>(); - let expected = expected - .into_iter() - .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range }) + .map(|nav| HirFileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) .sorted_by_key(cmp) .collect::>(); + let expected = + expected.into_iter().map(|(r, _)| r.into()).sorted_by_key(cmp).collect::>(); assert_eq!(expected, navs); } diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 60a904233a9a..f056674d97c0 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs @@ -2,12 +2,12 @@ use std::{iter, mem::discriminant}; use crate::{ doc_links::token_as_doc_comment, - navigation_target::{self, ToNav}, - FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult, + navigation_target::{HirNavigationTarget, ToNav}, + RangeInfo, TryToNav, }; use hir::{ - sym, AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, MacroFileIdExt, - ModuleDef, Semantics, + sym, AsAssocItem, AssocItem, CallableKind, HasCrate, HirFileId, HirFileIdExt, HirFilePosition, + InFile, MacroFileIdExt, ModuleDef, Semantics, }; use ide_db::{ base_db::{AnchoredPath, FileLoader, SourceDatabase}, @@ -17,7 +17,7 @@ use ide_db::{ RootDatabase, SymbolKind, }; use itertools::Itertools; -use span::{Edition, FileId}; +use span::EditionedFileId; use syntax::{ ast::{self, HasLoopBody}, match_ast, AstNode, AstToken, @@ -38,12 +38,12 @@ use syntax::{ // ![Go to Definition](https://user-images.githubusercontent.com/48062697/113065563-025fbe00-91b1-11eb-83e4-a5a703610b23.gif) pub(crate) fn goto_definition( db: &RootDatabase, - FilePosition { file_id, offset }: FilePosition, -) -> Option>> { + HirFilePosition { file_id, offset }: HirFilePosition, +) -> Option>> { let sema = &Semantics::new(db); - let file = sema.parse_guess_edition(file_id).syntax().clone(); - let edition = - sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT); + let file_id = sema.adjust_edition(file_id); + let file = sema.parse_or_expand(sema.adjust_edition(file_id)); + let edition = file_id.edition(sema.db); let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind { IDENT | INT_NUMBER @@ -62,16 +62,16 @@ pub(crate) fn goto_definition( })?; if let Some(doc_comment) = token_as_doc_comment(&original_token) { return doc_comment.get_definition_with_descend_at(sema, offset, |def, _, link_range| { - let nav = def.try_to_nav(db)?; - Some(RangeInfo::new(link_range, nav.collect())) + let nav = def.try_to_nav_hir(db)?; + Some(RangeInfo::new(link_range, vec![nav])) }); } - if let Some((range, resolution)) = + if let Some((range, token, resolution)) = sema.check_for_format_args_template(original_token.clone(), offset) { return Some(RangeInfo::new( - range, + range.range, match resolution { Some(res) => def_to_nav(db, Definition::from(res)), None => vec![], @@ -113,9 +113,8 @@ pub(crate) fn goto_definition( if let Definition::ExternCrateDecl(crate_def) = def { return crate_def .resolved_crate(db) - .map(|it| it.root_module().to_nav(sema.db)) + .map(|it| it.root_module().to_nav_hir(sema.db)) .into_iter() - .flatten() .collect(); } try_filter_trait_item_definition(sema, &def) @@ -126,7 +125,7 @@ pub(crate) fn goto_definition( }) .flatten() .unique() - .collect::>(); + .collect::>(); Some(RangeInfo::new(original_token.text_range(), navs)) } @@ -135,7 +134,7 @@ pub(crate) fn goto_definition( fn find_definition_for_known_blanket_dual_impls( sema: &Semantics<'_, RootDatabase>, original_token: &SyntaxToken, -) -> Option> { +) -> Option> { let method_call = ast::MethodCallExpr::cast(original_token.parent()?.parent()?)?; let callable = sema.resolve_method_call_as_callable(&method_call)?; let CallableKind::Function(f) = callable.kind() else { return None }; @@ -205,8 +204,8 @@ fn find_definition_for_known_blanket_dual_impls( fn try_lookup_include_path( sema: &Semantics<'_, RootDatabase>, token: ast::String, - file_id: FileId, -) -> Option { + hir_file_id: HirFileId, +) -> Option { let file = sema.hir_file_for(&token.syntax().parent()?).macro_file()?; if !iter::successors(Some(file), |file| file.parent(sema.db).macro_file()) // Check that we are in the eager argument expansion of an include macro @@ -216,10 +215,13 @@ fn try_lookup_include_path( } let path = token.value().ok()?; - let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?; + let file_id = sema.db.resolve_path(AnchoredPath { + anchor: hir_file_id.original_file(sema.db).file_id(), + path: &path, + })?; let size = sema.db.file_text(file_id).len().try_into().ok()?; - Some(NavigationTarget { - file_id, + Some(HirNavigationTarget { + file_id: EditionedFileId::new(file_id, hir_file_id.edition(sema.db)).into(), full_range: TextRange::new(0.into(), size), name: path.into(), alias: None, @@ -234,7 +236,7 @@ fn try_lookup_include_path( fn try_lookup_macro_def_in_macro_use( sema: &Semantics<'_, RootDatabase>, token: SyntaxToken, -) -> Option { +) -> Option { let extern_crate = token.parent()?.ancestors().find_map(ast::ExternCrate::cast)?; let extern_crate = sema.to_def(&extern_crate)?; let krate = extern_crate.resolved_crate(sema.db)?; @@ -242,8 +244,8 @@ fn try_lookup_macro_def_in_macro_use( for mod_def in krate.root_module().declarations(sema.db) { if let ModuleDef::Macro(mac) = mod_def { if mac.name(sema.db).as_str() == token.text() { - if let Some(nav) = mac.try_to_nav(sema.db) { - return Some(nav.call_site); + if let Some(nav) = mac.try_to_nav_hir(sema.db) { + return Some(nav); } } } @@ -262,7 +264,7 @@ fn try_lookup_macro_def_in_macro_use( fn try_filter_trait_item_definition( sema: &Semantics<'_, RootDatabase>, def: &Definition, -) -> Option> { +) -> Option> { let db = sema.db; let assoc = def.as_assoc_item(db)?; match assoc { @@ -275,8 +277,8 @@ fn try_filter_trait_item_definition( .items(db) .iter() .filter(|itm| discriminant(*itm) == discriminant_value) - .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten()) - .map(|it| it.collect()) + .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav_hir(db)).flatten()) + .map(|it| vec![it]) } } } @@ -284,7 +286,7 @@ fn try_filter_trait_item_definition( fn handle_control_flow_keywords( sema: &Semantics<'_, RootDatabase>, token: &SyntaxToken, -) -> Option> { +) -> Option> { match token.kind() { // For `fn` / `loop` / `while` / `for` / `async`, return the keyword it self, // so that VSCode will find the references when using `ctrl + click` @@ -331,7 +333,7 @@ pub(crate) fn find_fn_or_blocks( fn nav_for_exit_points( sema: &Semantics<'_, RootDatabase>, token: &SyntaxToken, -) -> Option> { +) -> Option> { let db = sema.db; let token_kind = token.kind(); @@ -343,31 +345,16 @@ fn nav_for_exit_points( match_ast! { match node { ast::Fn(fn_) => { - let mut nav = sema.to_def(&fn_)?.try_to_nav(db)?; + let mut nav = sema.to_def(&fn_)?.try_to_nav_hir(db)?; // For async token, we navigate to itself, which triggers // VSCode to find the references - let focus_token = if matches!(token_kind, T![async]) { + let range = if matches!(token_kind, T![async]) { fn_.async_token()? } else { fn_.fn_token()? - }; - - let focus_frange = InFile::new(file_id, focus_token.text_range()) - .original_node_file_range_opt(db) - .map(|(frange, _)| frange); - - if let Some(FileRange { file_id, range }) = focus_frange { - let contains_frange = |nav: &NavigationTarget| { - nav.file_id == file_id && nav.full_range.contains_range(range) - }; - - if let Some(def_site) = nav.def_site.as_mut() { - if contains_frange(def_site) { - def_site.focus_range = Some(range); - } - } else if contains_frange(&nav.call_site) { - nav.call_site.focus_range = Some(range); - } + }.text_range(); + if nav.file_id == file_id && nav.full_range.contains_range(range) { + nav.focus_range = Some(range); } Some(nav) @@ -375,19 +362,19 @@ fn nav_for_exit_points( ast::ClosureExpr(c) => { let pipe_tok = c.param_list().and_then(|it| it.pipe_token())?.text_range(); let closure_in_file = InFile::new(file_id, c.into()); - Some(expr_to_nav(db, closure_in_file, Some(pipe_tok))) + Some(expr_to_nav(closure_in_file, Some(pipe_tok))) }, ast::BlockExpr(blk) => { match blk.modifier() { Some(ast::BlockModifier::Async(_)) => { let async_tok = blk.async_token()?.text_range(); let blk_in_file = InFile::new(file_id, blk.into()); - Some(expr_to_nav(db, blk_in_file, Some(async_tok))) + Some(expr_to_nav(blk_in_file, Some(async_tok))) }, Some(ast::BlockModifier::Try(_)) if token_kind != T![return] => { let try_tok = blk.try_token()?.text_range(); let blk_in_file = InFile::new(file_id, blk.into()); - Some(expr_to_nav(db, blk_in_file, Some(try_tok))) + Some(expr_to_nav(blk_in_file, Some(try_tok))) }, _ => None, } @@ -396,8 +383,7 @@ fn nav_for_exit_points( } } }) - .flatten() - .collect_vec(); + .collect(); Some(navs) } @@ -450,9 +436,7 @@ pub(crate) fn find_loops( fn nav_for_break_points( sema: &Semantics<'_, RootDatabase>, token: &SyntaxToken, -) -> Option> { - let db = sema.db; - +) -> Option> { let navs = find_loops(sema, token)? .into_iter() .filter_map(|expr| { @@ -466,31 +450,26 @@ fn nav_for_break_points( ast::Expr::BlockExpr(blk) => blk.label().unwrap().syntax().text_range(), _ => return None, }; - let nav = expr_to_nav(db, expr_in_file, Some(focus_range)); + let nav = expr_to_nav(expr_in_file, Some(focus_range)); Some(nav) }) - .flatten() - .collect_vec(); + .collect(); Some(navs) } -fn def_to_nav(db: &RootDatabase, def: Definition) -> Vec { - def.try_to_nav(db).map(|it| it.collect()).unwrap_or_default() +fn def_to_nav(db: &RootDatabase, def: Definition) -> Vec { + def.try_to_nav_hir(db).map(|it| vec![it]).unwrap_or_default() } fn expr_to_nav( - db: &RootDatabase, InFile { file_id, value }: InFile, focus_range: Option, -) -> UpmappingResult { +) -> HirNavigationTarget { let kind = SymbolKind::Label; let value_range = value.syntax().text_range(); - let navs = navigation_target::orig_range_with_focus_r(db, file_id, value_range, focus_range); - navs.map(|(hir::FileRangeWrapper { file_id, range }, focus_range)| { - NavigationTarget::from_syntax(file_id, "".into(), focus_range, range, kind) - }) + HirNavigationTarget::from_syntax(file_id, "".into(), focus_range, value_range, kind) } #[cfg(test)] @@ -503,33 +482,34 @@ mod tests { #[track_caller] fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, expected) = fixture::annotations(ra_fixture); - let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info; + let navs = + analysis.goto_definition(position.into()).unwrap().expect("no definition found").info; let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start()); let navs = navs .into_iter() - .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) - .sorted_by_key(cmp) - .collect::>(); - let expected = expected - .into_iter() - .map(|(FileRange { file_id, range }, _)| FileRange { file_id, range }) + .flat_map(|nav| nav.upmap(&analysis.db)) + .map(|nav| nav.focus_or_full_file_range()) .sorted_by_key(cmp) .collect::>(); + let expected = + expected.into_iter().map(|(r, _)| r.into()).sorted_by_key(cmp).collect::>(); assert_eq!(expected, navs); } fn check_unresolved(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position) = fixture::position(ra_fixture); - let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info; + let navs = + analysis.goto_definition(position.into()).unwrap().expect("no definition found").info; assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}") } fn check_name(expected_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, _) = fixture::annotations(ra_fixture); - let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info; + let navs = + analysis.goto_definition(position.into()).unwrap().expect("no definition found").info; assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len()); let Some(target) = navs.into_iter().next() else { panic!("expected single navigation target but encountered none"); diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index e1d834b5d1c6..0be2d45bf7f4 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs @@ -1,4 +1,4 @@ -use hir::{AsAssocItem, Impl, Semantics}; +use hir::{AsAssocItem, HirFilePosition, Impl, Semantics}; use ide_db::{ defs::{Definition, NameClass, NameRefClass}, helpers::pick_best_token, @@ -6,7 +6,7 @@ use ide_db::{ }; use syntax::{ast, AstNode, SyntaxKind::*, T}; -use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav}; +use crate::{navigation_target::HirNavigationTarget, RangeInfo, TryToNav}; // Feature: Go to Implementation // @@ -19,11 +19,11 @@ use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav}; // ![Go to Implementation](https://user-images.githubusercontent.com/48062697/113065566-02f85480-91b1-11eb-9288-aaad8abd8841.gif) pub(crate) fn goto_implementation( db: &RootDatabase, - FilePosition { file_id, offset }: FilePosition, -) -> Option>> { + HirFilePosition { file_id, offset }: HirFilePosition, +) -> Option>> { let sema = Semantics::new(db); - let source_file = sema.parse_guess_edition(file_id); - let syntax = source_file.syntax().clone(); + let file_id = sema.adjust_edition(file_id); + let syntax = sema.parse_or_expand(sema.adjust_edition(file_id)); let original_token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind { IDENT | T![self] | INT_NUMBER => 1, @@ -83,22 +83,20 @@ pub(crate) fn goto_implementation( Some(RangeInfo { range, info: navs }) } -fn impls_for_ty(sema: &Semantics<'_, RootDatabase>, ty: hir::Type) -> Vec { +fn impls_for_ty(sema: &Semantics<'_, RootDatabase>, ty: hir::Type) -> Vec { Impl::all_for_type(sema.db, ty) .into_iter() - .filter_map(|imp| imp.try_to_nav(sema.db)) - .flatten() + .filter_map(|imp| imp.try_to_nav_hir(sema.db)) .collect() } fn impls_for_trait( sema: &Semantics<'_, RootDatabase>, trait_: hir::Trait, -) -> Vec { +) -> Vec { Impl::all_for_trait(sema.db, trait_) .into_iter() - .filter_map(|imp| imp.try_to_nav(sema.db)) - .flatten() + .filter_map(|imp| imp.try_to_nav_hir(sema.db)) .collect() } @@ -106,7 +104,7 @@ fn impls_for_trait_item( sema: &Semantics<'_, RootDatabase>, trait_: hir::Trait, fun_name: hir::Name, -) -> Vec { +) -> Vec { Impl::all_for_trait(sema.db, trait_) .into_iter() .filter_map(|imp| { @@ -114,9 +112,8 @@ fn impls_for_trait_item( let itm_name = itm.name(sema.db)?; (itm_name == fun_name).then_some(*itm) })?; - item.try_to_nav(sema.db) + item.try_to_nav_hir(sema.db) }) - .flatten() .collect() } @@ -130,17 +127,18 @@ mod tests { fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, expected) = fixture::annotations(ra_fixture); - let navs = analysis.goto_implementation(position).unwrap().unwrap().info; + let navs = analysis.goto_implementation(position.into()).unwrap().unwrap().info; - let cmp = |frange: &FileRange| (frange.file_id, frange.range.start()); + let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start()); let actual = navs .into_iter() - .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) + .flat_map(|nav| nav.upmap(&analysis.db)) + .map(|nav| nav.focus_or_full_file_range()) .sorted_by_key(cmp) .collect::>(); let expected = - expected.into_iter().map(|(range, _)| range).sorted_by_key(cmp).collect::>(); + expected.into_iter().map(|(r, _)| r.into()).sorted_by_key(cmp).collect::>(); assert_eq!(expected, actual); } diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index ddc274a83035..7116c661a881 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs @@ -1,8 +1,8 @@ -use hir::GenericParam; +use hir::{GenericParam, HirFilePosition}; use ide_db::{base_db::Upcast, defs::Definition, helpers::pick_best_token, RootDatabase}; use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, T}; -use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav}; +use crate::{navigation_target::HirNavigationTarget, RangeInfo, TryToNav}; // Feature: Go to Type Definition // @@ -15,26 +15,25 @@ use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav}; // ![Go to Type Definition](https://user-images.githubusercontent.com/48062697/113020657-b560f500-917a-11eb-9007-0f809733a338.gif) pub(crate) fn goto_type_definition( db: &RootDatabase, - FilePosition { file_id, offset }: FilePosition, -) -> Option>> { + HirFilePosition { file_id, offset }: HirFilePosition, +) -> Option>> { let sema = hir::Semantics::new(db); - let file: ast::SourceFile = sema.parse_guess_edition(file_id); - let token: SyntaxToken = - pick_best_token(file.syntax().token_at_offset(offset), |kind| match kind { - IDENT | INT_NUMBER | T![self] => 3, - kind if kind.is_trivia() => 0, - T![;] => 1, - _ => 2, - })?; + let file_id = sema.adjust_edition(file_id); + let syntax = sema.parse_or_expand(sema.adjust_edition(file_id)); + + let token: SyntaxToken = pick_best_token(syntax.token_at_offset(offset), |kind| match kind { + IDENT | INT_NUMBER | T![self] => 3, + kind if kind.is_trivia() => 0, + T![;] => 1, + _ => 2, + })?; let mut res = Vec::new(); let mut push = |def: Definition| { - if let Some(navs) = def.try_to_nav(db) { - for nav in navs { - if !res.contains(&nav) { - res.push(nav); - } + if let Some(nav) = def.try_to_nav_hir(db) { + if !res.contains(&nav) { + res.push(nav); } } }; @@ -53,7 +52,9 @@ pub(crate) fn goto_type_definition( } }); }; - if let Some((range, resolution)) = sema.check_for_format_args_template(token.clone(), offset) { + if let Some((range, _token, resolution)) = + sema.check_for_format_args_template(token.clone(), offset) + { if let Some(ty) = resolution.and_then(|res| match Definition::from(res) { Definition::Const(it) => Some(it.ty(db)), Definition::Static(it) => Some(it.ty(db)), @@ -64,7 +65,7 @@ pub(crate) fn goto_type_definition( }) { process_ty(ty); } - return Some(RangeInfo::new(range, res)); + return Some(RangeInfo::new(range.range, res)); } let range = token.text_range(); @@ -119,20 +120,18 @@ mod tests { fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, expected) = fixture::annotations(ra_fixture); - let navs = analysis.goto_type_definition(position).unwrap().unwrap().info; + let navs = analysis.goto_type_definition(position.into()).unwrap().unwrap().info; assert!(!navs.is_empty(), "navigation is empty"); let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start()); let navs = navs .into_iter() - .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) - .sorted_by_key(cmp) - .collect::>(); - let expected = expected - .into_iter() - .map(|(file_range, _)| file_range) + .flat_map(|nav| nav.upmap(&analysis.db)) + .map(|nav| nav.focus_or_full_file_range()) .sorted_by_key(cmp) .collect::>(); + let expected = + expected.into_iter().map(|(r, _)| r.into()).sorted_by_key(cmp).collect::>(); assert_eq!(expected, navs); } diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs index 6463206596af..4fdc2d5eca21 100644 --- a/crates/ide/src/highlight_related.rs +++ b/crates/ide/src/highlight_related.rs @@ -1,6 +1,8 @@ use std::iter; -use hir::{db, FilePosition, FileRange, HirFileId, InFile, Semantics}; +use hir::{ + db, FileRange, HirFileId, HirFileIdExt, HirFilePosition, HirFileRange, InFile, Semantics, +}; use ide_db::{ defs::{Definition, IdentClass}, helpers::pick_best_token, @@ -11,7 +13,6 @@ use ide_db::{ }, FxHashMap, FxHashSet, RootDatabase, }; -use span::EditionedFileId; use syntax::{ ast::{self, HasLoopBody}, match_ast, AstNode, @@ -19,7 +20,11 @@ use syntax::{ SyntaxToken, TextRange, WalkEvent, T, }; -use crate::{goto_definition, navigation_target::ToNav, NavigationTarget, TryToNav}; +use crate::{ + goto_definition, + navigation_target::{HirNavigationTarget, ToNav}, + TryToNav, +}; #[derive(PartialEq, Eq, Hash)] pub struct HighlightedRange { @@ -54,18 +59,17 @@ pub struct HighlightRelatedConfig { pub(crate) fn highlight_related( sema: &Semantics<'_, RootDatabase>, config: HighlightRelatedConfig, - ide_db::FilePosition { offset, file_id }: ide_db::FilePosition, + HirFilePosition { offset, file_id }: HirFilePosition, ) -> Option> { let _p = tracing::info_span!("highlight_related").entered(); - let file_id = sema - .attach_first_edition(file_id) - .unwrap_or_else(|| EditionedFileId::current_edition(file_id)); - let syntax = sema.parse(file_id).syntax().clone(); + + let file_id = sema.adjust_edition(file_id); + let syntax = sema.parse_or_expand(sema.adjust_edition(file_id)); let token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind { T![?] => 4, // prefer `?` when the cursor is sandwiched like in `await$0?` T![->] => 4, - kind if kind.is_keyword(file_id.edition()) => 3, + kind if kind.is_keyword(file_id.edition(sema.db)) => 3, IDENT | INT_NUMBER => 2, T![|] => 1, _ => 0, @@ -90,7 +94,7 @@ pub(crate) fn highlight_related( T![|] if config.closure_captures => highlight_closure_captures(sema, token, file_id), T![move] if config.closure_captures => highlight_closure_captures(sema, token, file_id), _ if config.references => { - highlight_references(sema, token, FilePosition { file_id, offset }) + highlight_references(sema, token, HirFilePosition { file_id, offset }) } _ => None, } @@ -99,7 +103,7 @@ pub(crate) fn highlight_related( fn highlight_closure_captures( sema: &Semantics<'_, RootDatabase>, token: SyntaxToken, - file_id: EditionedFileId, + file_id: HirFileId, ) -> Option> { let closure = token.parent_ancestors().take(2).find_map(ast::ClosureExpr::cast)?; let search_range = closure.body()?.syntax().text_range(); @@ -112,7 +116,10 @@ fn highlight_closure_captures( .flat_map(|local| { let usages = Definition::Local(local) .usages(sema) - .in_scope(&SearchScope::file_range(FileRange { file_id, range: search_range })) + .in_scope(&SearchScope::hir_file_range(HirFileRange { + file_id, + range: search_range, + })) .include_self_refs() .all() .references @@ -131,8 +138,9 @@ fn highlight_closure_captures( local .sources(sema.db) .into_iter() - .flat_map(|x| x.to_nav(sema.db)) - .filter(|decl| decl.file_id == file_id) + .map(|x| x.to_nav_hir(sema.db)) + .filter_map(|it| it.upmap_to(sema.db, file_id)) + .flatten() .filter_map(|decl| decl.focus_range) .map(move |range| HighlightedRange { range, category }) .chain(usages) @@ -144,32 +152,23 @@ fn highlight_closure_captures( fn highlight_references( sema: &Semantics<'_, RootDatabase>, token: SyntaxToken, - FilePosition { file_id, offset }: FilePosition, + HirFilePosition { file_id, offset }: HirFilePosition, ) -> Option> { - let defs = if let Some((range, resolution)) = + let defs = if let Some((range, _token, resolution)) = sema.check_for_format_args_template(token.clone(), offset) { match resolution.map(Definition::from) { Some(def) => iter::once(def).collect(), None => { - return Some(vec![HighlightedRange { range, category: ReferenceCategory::empty() }]) + return Some(vec![HighlightedRange { + range: range.range, + category: ReferenceCategory::empty(), + }]) } } } else { find_defs(sema, token.clone()) }; - let usages = defs - .iter() - .filter_map(|&d| { - d.usages(sema) - .in_scope(&SearchScope::single_file(file_id)) - .include_self_refs() - .all() - .references - .remove(&file_id) - }) - .flatten() - .map(|FileReference { category, range, .. }| HighlightedRange { range, category }); let mut res = FxHashSet::default(); for &def in &defs { // highlight trait usages @@ -206,7 +205,7 @@ fn highlight_references( .filter_map(|item| { Definition::from(item) .usages(sema) - .set_scope(Some(&SearchScope::file_range(FileRange { + .set_scope(Some(&SearchScope::hir_file_range(HirFileRange { file_id, range: trait_item_use_scope.text_range(), }))) @@ -235,28 +234,27 @@ fn highlight_references( local .sources(sema.db) .into_iter() - .flat_map(|x| x.to_nav(sema.db)) - .filter(|decl| decl.file_id == file_id) + .map(|x| x.to_nav_hir(sema.db)) + .filter_map(|it| it.upmap_to(sema.db, file_id)) + .flatten() .filter_map(|decl| decl.focus_range) .map(|range| HighlightedRange { range, category }) - .for_each(|x| { - res.insert(x); - }); + .for_each(|x| _ = res.insert(x)); } def => { - let navs = match def { + let nav = match def { Definition::Module(module) => { - NavigationTarget::from_module_to_decl(sema.db, module) + HirNavigationTarget::from_module_to_decl(sema.db, module) } - def => match def.try_to_nav(sema.db) { + def => match def.try_to_nav_hir(sema.db) { Some(it) => it, None => continue, }, }; + let Some(navs) = nav.upmap_to(sema.db, file_id) else { + continue; + }; for nav in navs { - if nav.file_id != file_id { - continue; - } let hl_range = nav.focus_range.map(|range| { let category = if matches!(def, Definition::Local(l) if l.is_mut(sema.db)) { ReferenceCategory::WRITE @@ -273,6 +271,18 @@ fn highlight_references( } } + let usages = defs + .iter() + .filter_map(|&d| { + d.usages(sema) + .in_scope(&SearchScope::single_hir_file(file_id)) + .include_self_refs() + .all() + .references + .remove(&file_id) + }) + .flatten() + .map(|FileReference { category, range, .. }| HighlightedRange { range, category }); res.extend(usages); if res.is_empty() { None @@ -285,13 +295,13 @@ fn hl_exit_points( sema: &Semantics<'_, RootDatabase>, def_token: Option, body: ast::Expr, -) -> Option>> { - let mut highlights: FxHashMap> = FxHashMap::default(); +) -> Option>> { + let mut highlights: FxHashMap> = FxHashMap::default(); let mut push_to_highlights = |file_id, range| { if let Some(FileRange { file_id, range }) = original_frange(sema.db, file_id, range) { let hrange = HighlightedRange { category: ReferenceCategory::empty(), range }; - highlights.entry(file_id).or_default().insert(hrange); + highlights.entry(file_id.into()).or_default().insert(hrange); } }; @@ -356,7 +366,7 @@ fn hl_exit_points( pub(crate) fn highlight_exit_points( sema: &Semantics<'_, RootDatabase>, token: SyntaxToken, -) -> FxHashMap> { +) -> FxHashMap> { let mut res = FxHashMap::default(); for def in goto_definition::find_fn_or_blocks(sema, &token) { let new_map = match_ast! { @@ -385,20 +395,20 @@ pub(crate) fn highlight_exit_points( pub(crate) fn highlight_break_points( sema: &Semantics<'_, RootDatabase>, token: SyntaxToken, -) -> FxHashMap> { +) -> FxHashMap> { pub(crate) fn hl( sema: &Semantics<'_, RootDatabase>, cursor_token_kind: SyntaxKind, loop_token: Option, label: Option, expr: ast::Expr, - ) -> Option>> { - let mut highlights: FxHashMap> = FxHashMap::default(); + ) -> Option>> { + let mut highlights: FxHashMap> = FxHashMap::default(); let mut push_to_highlights = |file_id, range| { if let Some(FileRange { file_id, range }) = original_frange(sema.db, file_id, range) { let hrange = HighlightedRange { category: ReferenceCategory::empty(), range }; - highlights.entry(file_id).or_default().insert(hrange); + highlights.entry(file_id.into()).or_default().insert(hrange); } }; @@ -468,18 +478,18 @@ pub(crate) fn highlight_break_points( pub(crate) fn highlight_yield_points( sema: &Semantics<'_, RootDatabase>, token: SyntaxToken, -) -> FxHashMap> { +) -> FxHashMap> { fn hl( sema: &Semantics<'_, RootDatabase>, async_token: Option, body: Option, - ) -> Option>> { - let mut highlights: FxHashMap> = FxHashMap::default(); + ) -> Option>> { + let mut highlights: FxHashMap> = FxHashMap::default(); let mut push_to_highlights = |file_id, range| { if let Some(FileRange { file_id, range }) = original_frange(sema.db, file_id, range) { let hrange = HighlightedRange { category: ReferenceCategory::empty(), range }; - highlights.entry(file_id).or_default().insert(hrange); + highlights.entry(file_id.into()).or_default().insert(hrange); } }; @@ -567,8 +577,8 @@ fn original_frange( } fn merge_map( - res: &mut FxHashMap>, - new: Option>>, + res: &mut FxHashMap>, + new: Option>>, ) { let Some(new) = new else { return; @@ -695,7 +705,7 @@ mod tests { ) { let (analysis, pos, annotations) = fixture::annotations(ra_fixture); - let hls = analysis.highlight_related(config, pos).unwrap().unwrap_or_default(); + let hls = analysis.highlight_related(config, pos.into()).unwrap().unwrap_or_default(); let mut expected = annotations.into_iter().map(|(r, access)| (r.range, access)).collect::>(); diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 95a720e7e452..864dfa4bbd11 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs @@ -7,13 +7,14 @@ use std::{iter, ops::Not}; use either::Either; use hir::{ - db::DefDatabase, GenericDef, GenericSubstitution, HasCrate, HasSource, LangItem, Semantics, + db::DefDatabase, GenericDef, GenericSubstitution, HasCrate, HasSource, HirFileId, HirFileIdExt, + HirFileRange, LangItem, Semantics, }; use ide_db::{ defs::{Definition, IdentClass, NameRefClass, OperatorClass}, famous_defs::FamousDefs, helpers::pick_best_token, - FileRange, FxIndexSet, Ranker, RootDatabase, + FxIndexSet, Ranker, RootDatabase, }; use itertools::{multizip, Itertools}; use span::Edition; @@ -23,9 +24,9 @@ use crate::{ doc_links::token_as_doc_comment, markdown_remove::remove_markdown, markup::Markup, - navigation_target::UpmappingResult, + navigation_target::HirNavigationTarget, runnables::{runnable_fn, runnable_mod}, - FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav, + HirFilePosition, RangeInfo, Runnable, TryToNav, }; #[derive(Clone, Debug, PartialEq, Eq)] pub struct HoverConfig { @@ -71,8 +72,8 @@ pub enum HoverDocFormat { #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub enum HoverAction { Runnable(Runnable), - Implementation(FilePosition), - Reference(FilePosition), + Implementation(HirFilePosition), + Reference(HirFilePosition), GoToType(Vec), } @@ -92,7 +93,7 @@ impl HoverAction { it.name(db).map(|name| name.display(db, edition).to_string()), edition, ), - nav: it.try_to_nav(db)?.call_site(), + nav: it.try_to_nav_hir(db)?, }) }) .collect::>(); @@ -103,7 +104,7 @@ impl HoverAction { #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct HoverGotoTypeData { pub mod_path: String, - pub nav: NavigationTarget, + pub nav: HirNavigationTarget, } /// Contains the results when hovering over an item @@ -121,15 +122,22 @@ pub struct HoverResult { // ![Hover](https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif) pub(crate) fn hover( db: &RootDatabase, - frange @ FileRange { file_id, range }: FileRange, + frange @ HirFileRange { file_id, range }: HirFileRange, config: &HoverConfig, ) -> Option> { let sema = &hir::Semantics::new(db); - let file = sema.parse_guess_edition(file_id).syntax().clone(); - let edition = - sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT); + let file_id = sema.adjust_edition(file_id); + let file = sema.parse_or_expand(sema.adjust_edition(file_id)); + + let edition = file_id.edition(db); let mut res = if range.is_empty() { - hover_offset(sema, FilePosition { file_id, offset: range.start() }, file, config, edition) + hover_offset( + sema, + HirFilePosition { file_id, offset: range.start() }, + file, + config, + edition, + ) } else { hover_ranged(sema, frange, file, config, edition) }?; @@ -143,7 +151,7 @@ pub(crate) fn hover( #[allow(clippy::field_reassign_with_default)] fn hover_offset( sema: &Semantics<'_, RootDatabase>, - FilePosition { file_id, offset }: FilePosition, + HirFilePosition { file_id, offset }: HirFilePosition, file: SyntaxNode, config: &HoverConfig, edition: Edition, @@ -168,13 +176,12 @@ fn hover_offset( if let Some(doc_comment) = token_as_doc_comment(&original_token) { cov_mark::hit!(no_highlight_on_comment_hover); return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| { - let res = - hover_for_definition(sema, file_id, def, None, &node, None, false, config, edition); + let res = hover_for_definition(sema, file_id, def, None, &node, None, false, config); Some(RangeInfo::new(range, res)) }); } - if let Some((range, resolution)) = + if let Some((range, _token, resolution)) = sema.check_for_format_args_template(original_token.clone(), offset) { let res = hover_for_definition( @@ -186,9 +193,8 @@ fn hover_offset( None, false, config, - edition, ); - return Some(RangeInfo::new(range, res)); + return Some(RangeInfo::new(range.range, res)); } // prefer descending the same token kind in attribute expansions, in normal macros text @@ -275,7 +281,6 @@ fn hover_offset( macro_arm, hovered_definition, config, - edition, ) }) .collect::>(), @@ -357,7 +362,7 @@ fn hover_offset( fn hover_ranged( sema: &Semantics<'_, RootDatabase>, - FileRange { range, .. }: FileRange, + HirFileRange { range, .. }: HirFileRange, file: SyntaxNode, config: &HoverConfig, edition: Edition, @@ -392,14 +397,13 @@ fn hover_ranged( // FIXME: Why is this pub(crate)? pub(crate) fn hover_for_definition( sema: &Semantics<'_, RootDatabase>, - file_id: FileId, + file_id: HirFileId, def: Definition, subst: Option, scope_node: &SyntaxNode, macro_arm: Option, hovered_definition: bool, config: &HoverConfig, - edition: Edition, ) -> HoverResult { let famous_defs = match &def { Definition::BuiltinType(_) => sema.scope(scope_node).map(|it| FamousDefs(sema, it.krate())), @@ -433,7 +437,7 @@ pub(crate) fn hover_for_definition( hovered_definition, subst_types.as_ref(), config, - edition, + file_id.edition(db), ); HoverResult { markup: render::process_markup(sema.db, def, &markup, config), @@ -441,7 +445,13 @@ pub(crate) fn hover_for_definition( show_fn_references_action(sema.db, def), show_implementations_action(sema.db, def), runnable_action(sema, def, file_id), - goto_type_action_for_def(sema.db, def, ¬able_traits, subst_types, edition), + goto_type_action_for_def( + sema.db, + def, + ¬able_traits, + subst_types, + file_id.edition(db), + ), ] .into_iter() .flatten() @@ -476,34 +486,30 @@ fn notable_traits( } fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option { - fn to_action(nav_target: NavigationTarget) -> HoverAction { - HoverAction::Implementation(FilePosition { + fn to_action(nav_target: HirNavigationTarget) -> HoverAction { + HoverAction::Implementation(HirFilePosition { file_id: nav_target.file_id, offset: nav_target.focus_or_full_range().start(), }) } let adt = match def { - Definition::Trait(it) => { - return it.try_to_nav(db).map(UpmappingResult::call_site).map(to_action) - } + Definition::Trait(it) => return it.try_to_nav_hir(db).map(to_action), Definition::Adt(it) => Some(it), Definition::SelfType(it) => it.self_ty(db).as_adt(), _ => None, }?; - adt.try_to_nav(db).map(UpmappingResult::call_site).map(to_action) + adt.try_to_nav_hir(db).map(to_action) } fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option { match def { - Definition::Function(it) => { - it.try_to_nav(db).map(UpmappingResult::call_site).map(|nav_target| { - HoverAction::Reference(FilePosition { - file_id: nav_target.file_id, - offset: nav_target.focus_or_full_range().start(), - }) + Definition::Function(it) => it.try_to_nav_hir(db).map(|nav_target| { + HoverAction::Reference(HirFilePosition { + file_id: nav_target.file_id, + offset: nav_target.focus_or_full_range().start(), }) - } + }), _ => None, } } @@ -511,7 +517,7 @@ fn show_fn_references_action(db: &RootDatabase, def: Definition) -> Option, def: Definition, - file_id: FileId, + file_id: HirFileId, ) -> Option { match def { Definition::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable), diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 8c32cc9720af..d35e8fcb3d25 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -1,5 +1,6 @@ use expect_test::{expect, Expect}; -use ide_db::{base_db::SourceDatabase, FileRange}; +use hir::HirFileRange; +use ide_db::base_db::SourceDatabase; use syntax::TextRange; use crate::{ @@ -28,7 +29,10 @@ fn check_hover_no_result(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let hover = analysis .hover( &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, - FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, + HirFileRange { + file_id: position.file_id.into(), + range: TextRange::empty(position.offset), + }, ) .unwrap(); assert!(hover.is_none(), "hover not expected but found: {:?}", hover.unwrap()); @@ -40,12 +44,15 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let hover = analysis .hover( &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, - FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, + HirFileRange { + file_id: position.file_id.into(), + range: TextRange::empty(position.offset), + }, ) .unwrap() .unwrap(); - let content = analysis.db.file_text(position.file_id); + let content = analysis.db.file_text(position.file_id.into()); let hovered_element = &content[hover.range]; let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); @@ -66,12 +73,15 @@ fn check_hover_fields_limit( max_fields_count: fields_count.into(), ..HOVER_BASE_CONFIG }, - FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, + HirFileRange { + file_id: position.file_id.into(), + range: TextRange::empty(position.offset), + }, ) .unwrap() .unwrap(); - let content = analysis.db.file_text(position.file_id); + let content = analysis.db.file_text(position.file_id.into()); let hovered_element = &content[hover.range]; let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); @@ -92,12 +102,15 @@ fn check_hover_enum_variants_limit( max_enum_variants_count: variants_count.into(), ..HOVER_BASE_CONFIG }, - FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, + HirFileRange { + file_id: position.file_id.into(), + range: TextRange::empty(position.offset), + }, ) .unwrap() .unwrap(); - let content = analysis.db.file_text(position.file_id); + let content = analysis.db.file_text(position.file_id.into()); let hovered_element = &content[hover.range]; let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); @@ -118,12 +131,15 @@ fn check_assoc_count( max_trait_assoc_items_count: Some(count), ..HOVER_BASE_CONFIG }, - FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, + HirFileRange { + file_id: position.file_id.into(), + range: TextRange::empty(position.offset), + }, ) .unwrap() .unwrap(); - let content = analysis.db.file_text(position.file_id); + let content = analysis.db.file_text(position.file_id.into()); let hovered_element = &content[hover.range]; let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); @@ -135,12 +151,15 @@ fn check_hover_no_links(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: let hover = analysis .hover( &HOVER_BASE_CONFIG, - FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, + HirFileRange { + file_id: position.file_id.into(), + range: TextRange::empty(position.offset), + }, ) .unwrap() .unwrap(); - let content = analysis.db.file_text(position.file_id); + let content = analysis.db.file_text(position.file_id.into()); let hovered_element = &content[hover.range]; let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); @@ -152,12 +171,15 @@ fn check_hover_no_memory_layout(#[rust_analyzer::rust_fixture] ra_fixture: &str, let hover = analysis .hover( &HoverConfig { memory_layout: None, ..HOVER_BASE_CONFIG }, - FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, + HirFileRange { + file_id: position.file_id.into(), + range: TextRange::empty(position.offset), + }, ) .unwrap() .unwrap(); - let content = analysis.db.file_text(position.file_id); + let content = analysis.db.file_text(position.file_id.into()); let hovered_element = &content[hover.range]; let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); @@ -173,12 +195,15 @@ fn check_hover_no_markdown(#[rust_analyzer::rust_fixture] ra_fixture: &str, expe format: HoverDocFormat::PlainText, ..HOVER_BASE_CONFIG }, - FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) }, + HirFileRange { + file_id: position.file_id.into(), + range: TextRange::empty(position.offset), + }, ) .unwrap() .unwrap(); - let content = analysis.db.file_text(position.file_id); + let content = analysis.db.file_text(position.file_id.into()); let hovered_element = &content[hover.range]; let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup); @@ -190,7 +215,7 @@ fn check_actions(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect let mut hover = analysis .hover( &HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, - FileRange { file_id, range: position.range_or_empty() }, + HirFileRange { file_id: file_id.into(), range: position.range_or_empty() }, ) .unwrap() .unwrap(); @@ -212,14 +237,14 @@ fn check_actions(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect fn check_hover_range(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, range) = fixture::range(ra_fixture); - let hover = analysis.hover(&HOVER_BASE_CONFIG, range).unwrap().unwrap(); + let hover = analysis.hover(&HOVER_BASE_CONFIG, range.into()).unwrap().unwrap(); expect.assert_eq(hover.info.markup.as_str()) } fn check_hover_range_actions(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, range) = fixture::range(ra_fixture); let mut hover = analysis - .hover(&HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, range) + .hover(&HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, range.into()) .unwrap() .unwrap(); // stub out ranges into minicore as they can change every now and then @@ -240,7 +265,7 @@ fn check_hover_range_actions(#[rust_analyzer::rust_fixture] ra_fixture: &str, ex fn check_hover_range_no_results(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, range) = fixture::range(ra_fixture); - let hover = analysis.hover(&HOVER_BASE_CONFIG, range).unwrap(); + let hover = analysis.hover(&HOVER_BASE_CONFIG, range.into()).unwrap(); assert!(hover.is_none()); } @@ -490,8 +515,9 @@ fn main() { HoverGotoTypeData { mod_path: "ra_test_fixture::S2", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 10..20, focus_range: 17..19, @@ -503,8 +529,9 @@ fn main() { HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..9, focus_range: 7..8, @@ -516,8 +543,9 @@ fn main() { HoverGotoTypeData { mod_path: "core::ops::function::FnOnce", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 1, + Edition2021, ), full_range: 4294967295..4294967295, focus_range: 4294967295..4294967295, @@ -2305,8 +2333,9 @@ fn foo(Foo { b$0ar }: &Foo) {} HoverGotoTypeData { mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..11, focus_range: 7..10, @@ -2341,8 +2370,9 @@ fn test() { [ Reference( FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 3, }, @@ -2352,8 +2382,9 @@ fn test() { HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 20..29, focus_range: 27..28, @@ -2387,8 +2418,9 @@ fn test() { [ Reference( FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 15, }, @@ -2398,8 +2430,9 @@ fn test() { HoverGotoTypeData { mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..11, focus_range: 7..10, @@ -2432,8 +2465,9 @@ fn test() { [ Reference( FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 16, }, @@ -2443,8 +2477,9 @@ fn test() { HoverGotoTypeData { mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..12, focus_range: 6..9, @@ -2647,8 +2682,9 @@ fn test_hover_trait_show_qualifiers() { [ Implementation( FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 13, }, @@ -3225,8 +3261,9 @@ fn test_hover_trait_has_impl_action() { [ Implementation( FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 6, }, @@ -3244,8 +3281,9 @@ fn test_hover_struct_has_impl_action() { [ Implementation( FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 7, }, @@ -3263,8 +3301,9 @@ fn test_hover_union_has_impl_action() { [ Implementation( FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 6, }, @@ -3282,8 +3321,9 @@ fn test_hover_enum_has_impl_action() { [ Implementation( FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 5, }, @@ -3301,8 +3341,9 @@ fn test_hover_self_has_impl_action() { [ Implementation( FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 7, }, @@ -3323,8 +3364,9 @@ fn foo_$0test() {} [ Reference( FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 11, }, @@ -3333,8 +3375,9 @@ fn foo_$0test() {} Runnable { use_name_in_title: false, nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..24, focus_range: 11..19, @@ -3377,8 +3420,9 @@ mod tests$0 { Runnable { use_name_in_title: false, nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..46, focus_range: 4..9, @@ -3417,8 +3461,9 @@ fn main() { let s$0t = S{ f1:0 }; } HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..19, focus_range: 7..8, @@ -3450,8 +3495,9 @@ fn main() { let s$0t = S{ f1:Arg(0) }; } HoverGotoTypeData { mod_path: "ra_test_fixture::Arg", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..16, focus_range: 7..10, @@ -3463,8 +3509,9 @@ fn main() { let s$0t = S{ f1:Arg(0) }; } HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 17..37, focus_range: 24..25, @@ -3509,8 +3556,9 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; } HoverGotoTypeData { mod_path: "ra_test_fixture::Arg", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..16, focus_range: 7..10, @@ -3522,8 +3570,9 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; } HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 17..37, focus_range: 24..25, @@ -3558,8 +3607,9 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); } HoverGotoTypeData { mod_path: "ra_test_fixture::A", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..14, focus_range: 7..8, @@ -3571,8 +3621,9 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); } HoverGotoTypeData { mod_path: "ra_test_fixture::B", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 15..29, focus_range: 22..23, @@ -3584,8 +3635,9 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); } HoverGotoTypeData { mod_path: "ra_test_fixture::M::C", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 42..60, focus_range: 53..54, @@ -3618,8 +3670,9 @@ fn main() { let s$0t = foo(); } HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..12, focus_range: 6..9, @@ -3652,8 +3705,9 @@ fn main() { let s$0t = foo(); } HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..15, focus_range: 6..9, @@ -3665,8 +3719,9 @@ fn main() { let s$0t = foo(); } HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 16..25, focus_range: 23..24, @@ -3699,8 +3754,9 @@ fn main() { let s$0t = foo(); } HoverGotoTypeData { mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 13..25, focus_range: 19..22, @@ -3712,8 +3768,9 @@ fn main() { let s$0t = foo(); } HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..12, focus_range: 6..9, @@ -3749,8 +3806,9 @@ fn main() { let s$0t = foo(); } HoverGotoTypeData { mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 16..31, focus_range: 22..25, @@ -3762,8 +3820,9 @@ fn main() { let s$0t = foo(); } HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..15, focus_range: 6..9, @@ -3775,8 +3834,9 @@ fn main() { let s$0t = foo(); } HoverGotoTypeData { mod_path: "ra_test_fixture::S1", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 32..44, focus_range: 39..41, @@ -3788,8 +3848,9 @@ fn main() { let s$0t = foo(); } HoverGotoTypeData { mod_path: "ra_test_fixture::S2", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 45..57, focus_range: 52..54, @@ -3819,8 +3880,9 @@ fn foo(ar$0g: &impl Foo) {} HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..12, focus_range: 6..9, @@ -3853,8 +3915,9 @@ fn foo(ar$0g: &impl Foo + Bar) {} HoverGotoTypeData { mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 13..28, focus_range: 19..22, @@ -3866,8 +3929,9 @@ fn foo(ar$0g: &impl Foo + Bar) {} HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..12, focus_range: 6..9, @@ -3879,8 +3943,9 @@ fn foo(ar$0g: &impl Foo + Bar) {} HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 29..39, focus_range: 36..37, @@ -3920,8 +3985,9 @@ pub mod future { HoverGotoTypeData { mod_path: "core::future::Future", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 1, + Edition2021, ), full_range: 4294967295..4294967295, focus_range: 4294967295..4294967295, @@ -3934,8 +4000,9 @@ pub mod future { HoverGotoTypeData { mod_path: "main::S", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..110, focus_range: 108..109, @@ -3966,8 +4033,9 @@ fn foo(ar$0g: &impl Foo) {} HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..15, focus_range: 6..9, @@ -3979,8 +4047,9 @@ fn foo(ar$0g: &impl Foo) {} HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 16..27, focus_range: 23..24, @@ -4016,8 +4085,9 @@ fn main() { let s$0t = foo(); } HoverGotoTypeData { mod_path: "ra_test_fixture::B", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 48..61, focus_range: 55..56, @@ -4029,8 +4099,9 @@ fn main() { let s$0t = foo(); } HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..15, focus_range: 6..9, @@ -4042,8 +4113,9 @@ fn main() { let s$0t = foo(); } HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 16..25, focus_range: 23..24, @@ -4073,8 +4145,9 @@ fn foo(ar$0g: &dyn Foo) {} HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..12, focus_range: 6..9, @@ -4105,8 +4178,9 @@ fn foo(ar$0g: &dyn Foo) {} HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..15, focus_range: 6..9, @@ -4118,8 +4192,9 @@ fn foo(ar$0g: &dyn Foo) {} HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 16..27, focus_range: 23..24, @@ -4153,8 +4228,9 @@ fn foo(a$0rg: &impl ImplTrait>>>) {} HoverGotoTypeData { mod_path: "ra_test_fixture::B", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 43..57, focus_range: 50..51, @@ -4166,8 +4242,9 @@ fn foo(a$0rg: &impl ImplTrait>>>) {} HoverGotoTypeData { mod_path: "ra_test_fixture::DynTrait", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 22..42, focus_range: 28..36, @@ -4179,8 +4256,9 @@ fn foo(a$0rg: &impl ImplTrait>>>) {} HoverGotoTypeData { mod_path: "ra_test_fixture::ImplTrait", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..21, focus_range: 6..15, @@ -4192,8 +4270,9 @@ fn foo(a$0rg: &impl ImplTrait>>>) {} HoverGotoTypeData { mod_path: "ra_test_fixture::S", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 58..69, focus_range: 65..66, @@ -4234,8 +4313,9 @@ fn main() { let s$0t = test().get(); } HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..62, focus_range: 6..9, @@ -4267,8 +4347,9 @@ impl Foo {} HoverGotoTypeData { mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..11, focus_range: 7..10, @@ -4299,8 +4380,9 @@ fn foo(t: T$0){} HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..12, focus_range: 6..9, @@ -4332,8 +4414,9 @@ impl Foo { HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..11, focus_range: 7..10, @@ -7161,8 +7244,9 @@ fn foo() { HoverGotoTypeData { mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..11, focus_range: 7..10, @@ -9008,8 +9092,9 @@ impl Iterator for S { [ Implementation( FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 7, }, @@ -9019,8 +9104,9 @@ impl Iterator for S { HoverGotoTypeData { mod_path: "core::future::Future", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 1, + Edition2021, ), full_range: 4294967295..4294967295, focus_range: 4294967295..4294967295, @@ -9033,8 +9119,9 @@ impl Iterator for S { HoverGotoTypeData { mod_path: "core::iter::traits::iterator::Iterator", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 1, + Edition2021, ), full_range: 4294967295..4294967295, focus_range: 4294967295..4294967295, @@ -9047,8 +9134,9 @@ impl Iterator for S { HoverGotoTypeData { mod_path: "ra_test_fixture::Notable", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 21..59, focus_range: 49..56, @@ -9060,8 +9148,9 @@ impl Iterator for S { HoverGotoTypeData { mod_path: "ra_test_fixture::S2", nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 10..20, focus_range: 17..19, @@ -10315,8 +10404,9 @@ macro_rules! str { [ Reference( FilePositionWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), offset: 92, }, @@ -10325,8 +10415,9 @@ macro_rules! str { Runnable { use_name_in_title: false, nav: NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 81..301, focus_range: 92..96, diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 63039b1cd34e..6920d24d9606 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -5,21 +5,21 @@ use std::{ use either::Either; use hir::{ - sym, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef, - ModuleDefId, Semantics, + sym, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirFileId, HirFileIdExt, + HirFileRange, HirWrite, ModuleDef, ModuleDefId, Semantics, }; -use ide_db::{famous_defs::FamousDefs, FileRange, RootDatabase}; +use ide_db::{famous_defs::FamousDefs, RootDatabase}; use ide_db::{text_edit::TextEdit, FxHashSet}; use itertools::Itertools; use smallvec::{smallvec, SmallVec}; -use span::{Edition, EditionedFileId}; +use span::Edition; use stdx::never; use syntax::{ ast::{self, AstNode, HasGenericParams}, format_smolstr, match_ast, SmolStr, SyntaxNode, TextRange, TextSize, WalkEvent, }; -use crate::{navigation_target::TryToNav, FileId}; +use crate::navigation_target::TryToNav; mod adjustment; mod bind_pat; @@ -77,17 +77,15 @@ mod range_exclusive; // ![Inlay hints](https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png) pub(crate) fn inlay_hints( db: &RootDatabase, - file_id: FileId, + file_id: HirFileId, range_limit: Option, config: &InlayHintsConfig, ) -> Vec { let _p = tracing::info_span!("inlay_hints").entered(); let sema = Semantics::new(db); - let file_id = sema - .attach_first_edition(file_id) - .unwrap_or_else(|| EditionedFileId::current_edition(file_id)); - let file = sema.parse(file_id); - let file = file.syntax(); + + let file_id = sema.adjust_edition(file_id); + let file = &sema.parse_or_expand(file_id); let mut acc = Vec::new(); @@ -126,7 +124,7 @@ struct InlayHintCtx { pub(crate) fn inlay_hints_resolve( db: &RootDatabase, - file_id: FileId, + file_id: HirFileId, resolve_range: TextRange, hash: u64, config: &InlayHintsConfig, @@ -134,11 +132,8 @@ pub(crate) fn inlay_hints_resolve( ) -> Option { let _p = tracing::info_span!("inlay_hints_resolve").entered(); let sema = Semantics::new(db); - let file_id = sema - .attach_first_edition(file_id) - .unwrap_or_else(|| EditionedFileId::current_edition(file_id)); - let file = sema.parse(file_id); - let file = file.syntax(); + let file_id = sema.adjust_edition(file_id); + let file = &sema.parse_or_expand(file_id); let scope = sema.scope(file)?; let famous_defs = FamousDefs(&sema, scope.krate()); @@ -204,10 +199,11 @@ fn hints( ctx: &mut InlayHintCtx, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: EditionedFileId, + file_id: HirFileId, node: SyntaxNode, ) { - closing_brace::hints(hints, sema, config, file_id, node.clone()); + let edition = file_id.edition(sema.db); + closing_brace::hints(hints, sema, config, file_id, edition, node.clone()); if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) { generic_param::hints(hints, famous_defs, config, any_has_generic_args); } @@ -215,8 +211,8 @@ fn hints( match_ast! { match node { ast::Expr(expr) => { - chaining::hints(hints, famous_defs, config, file_id, &expr); - adjustment::hints(hints, famous_defs, config, file_id, &expr); + chaining::hints(hints, famous_defs, config, edition, &expr); + adjustment::hints(hints, famous_defs, config, edition, &expr); match expr { ast::Expr::CallExpr(it) => param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it)), ast::Expr::MethodCallExpr(it) => { @@ -224,7 +220,7 @@ fn hints( } ast::Expr::ClosureExpr(it) => { closure_captures::hints(hints, famous_defs, config, file_id, it.clone()); - closure_ret::hints(hints, famous_defs, config, file_id, it) + closure_ret::hints(hints, famous_defs, config, edition, it) }, ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, file_id, it), _ => Some(()), @@ -234,7 +230,7 @@ fn hints( binding_mode::hints(hints, famous_defs, config, file_id, &it); match it { ast::Pat::IdentPat(it) => { - bind_pat::hints(hints, famous_defs, config, file_id, &it); + bind_pat::hints(hints, famous_defs, config, edition, &it); } ast::Pat::RangePat(it) => { range_exclusive::hints(hints, famous_defs, config, file_id, it); @@ -245,7 +241,7 @@ fn hints( }, ast::Item(it) => match it { ast::Item::Fn(it) => { - implicit_drop::hints(hints, famous_defs, config, file_id, &it); + implicit_drop::hints(hints, famous_defs, config, edition, &it); if let Some(extern_block) = &ctx.extern_block_parent { extern_block::fn_hints(hints, famous_defs, config, file_id, &it, extern_block); } @@ -336,8 +332,8 @@ impl InlayHintsConfig { /// location link to actually resolve but where computing `finish` would be costly. fn lazy_location_opt( &self, - finish: impl FnOnce() -> Option, - ) -> Option> { + finish: impl FnOnce() -> Option, + ) -> Option> { if self.fields_to_resolve.resolve_label_location { Some(LazyProperty::Lazy) } else { @@ -524,7 +520,7 @@ impl InlayHintLabel { pub fn simple( s: impl Into, tooltip: Option>, - linked_location: Option>, + linked_location: Option>, ) -> InlayHintLabel { InlayHintLabel { parts: smallvec![InlayHintLabelPart { text: s.into(), linked_location, tooltip }], @@ -608,7 +604,7 @@ pub struct InlayHintLabelPart { /// refers to (not necessarily the location itself). /// When setting this, no tooltip must be set on the containing hint, or VS Code will display /// them both. - pub linked_location: Option>, + pub linked_location: Option>, /// The tooltip to show when hovering over the inlay hint, this may invoke other actions like /// hover requests to show. pub tooltip: Option>, @@ -652,7 +648,7 @@ struct InlayHintLabelBuilder<'a> { result: InlayHintLabel, last_part: String, resolve: bool, - location: Option>, + location: Option>, } impl fmt::Write for InlayHintLabelBuilder<'_> { @@ -670,9 +666,8 @@ impl HirWrite for InlayHintLabelBuilder<'_> { LazyProperty::Lazy } else { LazyProperty::Computed({ - let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return }; - let location = location.call_site(); - FileRange { file_id: location.file_id, range: location.focus_or_full_range() } + let Some(location) = ModuleDef::from(def).try_to_nav_hir(self.db) else { return }; + HirFileRange { file_id: location.file_id, range: location.focus_or_full_range() } }) }); } @@ -891,8 +886,8 @@ mod tests { #[rust_analyzer::rust_fixture] ra_fixture: &str, ) { let (analysis, file_id) = fixture::file(ra_fixture); - let mut expected = extract_annotations(&analysis.file_text(file_id).unwrap()); - let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); + let mut expected = extract_annotations(&analysis.file_text(file_id.into()).unwrap()); + let inlay_hints = analysis.inlay_hints(&config, file_id.into(), None).unwrap(); let actual = inlay_hints .into_iter() // FIXME: We trim the start because some inlay produces leading whitespace which is not properly supported by our annotation extraction @@ -911,7 +906,7 @@ mod tests { expect: Expect, ) { let (analysis, file_id) = fixture::file(ra_fixture); - let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); + let inlay_hints = analysis.inlay_hints(&config, file_id.into(), None).unwrap(); let filtered = inlay_hints.into_iter().map(|hint| (hint.range, hint.label)).collect::>(); expect.assert_debug_eq(&filtered) @@ -926,7 +921,7 @@ mod tests { expect: Expect, ) { let (analysis, file_id) = fixture::file(ra_fixture); - let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); + let inlay_hints = analysis.inlay_hints(&config, file_id.into(), None).unwrap(); let edits = inlay_hints .into_iter() @@ -937,7 +932,7 @@ mod tests { }) .expect("no edit returned"); - let mut actual = analysis.file_text(file_id).unwrap().to_string(); + let mut actual = analysis.file_text(file_id.into()).unwrap().to_string(); edits.apply(&mut actual); expect.assert_eq(&actual); } @@ -948,7 +943,7 @@ mod tests { #[rust_analyzer::rust_fixture] ra_fixture: &str, ) { let (analysis, file_id) = fixture::file(ra_fixture); - let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); + let inlay_hints = analysis.inlay_hints(&config, file_id.into(), None).unwrap(); let edits: Vec<_> = inlay_hints.into_iter().filter_map(|hint| hint.text_edit?.computed()).collect(); diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs index d3b95750f7e1..89080094402e 100644 --- a/crates/ide/src/inlay_hints/adjustment.rs +++ b/crates/ide/src/inlay_hints/adjustment.rs @@ -12,7 +12,7 @@ use hir::{ use ide_db::famous_defs::FamousDefs; use ide_db::text_edit::TextEditBuilder; -use span::EditionedFileId; +use span::Edition; use syntax::ast::{self, prec::ExprPrecedence, AstNode}; use crate::{ @@ -24,7 +24,7 @@ pub(super) fn hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: EditionedFileId, + edition: Edition, expr: &ast::Expr, ) -> Option<()> { if config.adjustment_hints_hide_outside_unsafe && !sema.is_inside_unsafe(expr) { @@ -163,8 +163,8 @@ pub(super) fn hints( tooltip: Some(config.lazy_tooltip(|| { InlayTooltip::Markdown(format!( "`{}` → `{}` ({coercion} coercion)", - source.display(sema.db, file_id.edition()), - target.display(sema.db, file_id.edition()), + source.display(sema.db, edition), + target.display(sema.db, edition), )) })), }; diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs index c2986a9aa662..8307c060f6e5 100644 --- a/crates/ide/src/inlay_hints/bind_pat.rs +++ b/crates/ide/src/inlay_hints/bind_pat.rs @@ -7,7 +7,7 @@ use hir::Semantics; use ide_db::{famous_defs::FamousDefs, RootDatabase}; use itertools::Itertools; -use span::EditionedFileId; +use span::Edition; use syntax::{ ast::{self, AstNode, HasGenericArgs, HasName}, match_ast, @@ -22,7 +22,7 @@ pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: EditionedFileId, + edition: Edition, pat: &ast::IdentPat, ) -> Option<()> { if !config.type_hints { @@ -70,7 +70,7 @@ pub(super) fn hints( return None; } - let mut label = label_of_ty(famous_defs, config, &ty, file_id.edition())?; + let mut label = label_of_ty(famous_defs, config, &ty, edition)?; if config.hide_named_constructor_hints && is_named_constructor(sema, pat, &label.to_string()).is_some() @@ -310,7 +310,7 @@ fn main(a: SliceIter<'_, Container>) { analysis .inlay_hints( &InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG }, - file_id, + file_id.into(), None, ) .unwrap(); @@ -420,11 +420,11 @@ fn main() { } "#; let (analysis, file_id) = fixture::file(fixture); - let expected = extract_annotations(&analysis.file_text(file_id).unwrap()); + let expected = extract_annotations(&analysis.file_text(file_id.into()).unwrap()); let inlay_hints = analysis .inlay_hints( &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, - file_id, + file_id.into(), Some(TextRange::new(TextSize::from(491), TextSize::from(640))), ) .unwrap(); diff --git a/crates/ide/src/inlay_hints/binding_mode.rs b/crates/ide/src/inlay_hints/binding_mode.rs index 5bbb4fe4e66e..941639b7c11b 100644 --- a/crates/ide/src/inlay_hints/binding_mode.rs +++ b/crates/ide/src/inlay_hints/binding_mode.rs @@ -8,7 +8,7 @@ use hir::Mutability; use ide_db::famous_defs::FamousDefs; use ide_db::text_edit::TextEditBuilder; -use span::EditionedFileId; +use span::HirFileId; use syntax::ast::{self, AstNode}; use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind}; @@ -17,7 +17,7 @@ pub(super) fn hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, + _file_id: HirFileId, pat: &ast::Pat, ) -> Option<()> { if !config.binding_mode_hints { diff --git a/crates/ide/src/inlay_hints/bounds.rs b/crates/ide/src/inlay_hints/bounds.rs index e9b728bcaa75..ce92645703de 100644 --- a/crates/ide/src/inlay_hints/bounds.rs +++ b/crates/ide/src/inlay_hints/bounds.rs @@ -1,9 +1,10 @@ //! Implementation of trait bound hints. //! //! Currently this renders the implied `Sized` bound. -use ide_db::{famous_defs::FamousDefs, FileRange}; +use hir::HirFileRange; +use ide_db::famous_defs::FamousDefs; -use span::EditionedFileId; +use span::HirFileId; use syntax::ast::{self, AstNode, HasTypeBounds}; use crate::{ @@ -15,7 +16,7 @@ pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, + _file_id: HirFileId, params: ast::GenericParamList, ) -> Option<()> { if !config.sized_bound { @@ -46,12 +47,10 @@ pub(super) fn hints( text: "Sized".to_owned(), linked_location: sized_trait.and_then(|it| { config.lazy_location_opt(|| { - it.try_to_nav(sema.db).map(|it| { - let n = it.call_site(); - FileRange { - file_id: n.file_id, - range: n.focus_or_full_range(), - } + // FIXME: Replace with a range fetch only + it.try_to_nav_hir(sema.db).map(|it| HirFileRange { + file_id: it.file_id, + range: it.focus_or_full_range(), }) }) }), @@ -142,8 +141,9 @@ fn foo() {} linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 1, + Edition2021, ), range: 135..140, }, diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs index 8471547727fe..db9e7da81b5a 100644 --- a/crates/ide/src/inlay_hints/chaining.rs +++ b/crates/ide/src/inlay_hints/chaining.rs @@ -1,6 +1,6 @@ //! Implementation of "chaining" inlay hints. use ide_db::famous_defs::FamousDefs; -use span::EditionedFileId; +use span::Edition; use syntax::{ ast::{self, AstNode}, Direction, NodeOrToken, SyntaxKind, T, @@ -14,7 +14,7 @@ pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: EditionedFileId, + edition: Edition, expr: &ast::Expr, ) -> Option<()> { if !config.chaining_hints { @@ -58,7 +58,7 @@ pub(super) fn hints( } } } - let label = label_of_ty(famous_defs, config, &ty, file_id.edition())?; + let label = label_of_ty(famous_defs, config, &ty, edition)?; acc.push(InlayHint { range: expr.syntax().text_range(), kind: InlayKind::Chaining, @@ -100,7 +100,7 @@ mod tests { expect: Expect, ) { let (analysis, file_id) = fixture::file(ra_fixture); - let mut inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); + let mut inlay_hints = analysis.inlay_hints(&config, file_id.into(), None).unwrap(); inlay_hints.iter_mut().flat_map(|hint| &mut hint.label.parts).for_each(|hint| { if let Some(LazyProperty::Computed(loc)) = &mut hint.linked_location { loc.range = TextRange::empty(TextSize::from(0)); @@ -139,8 +139,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 63..64, }, @@ -158,8 +159,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 7..8, }, @@ -222,8 +224,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 51..52, }, @@ -241,8 +244,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 29..30, }, @@ -289,8 +293,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 51..52, }, @@ -308,8 +313,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 29..30, }, @@ -357,8 +363,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 23..24, }, @@ -372,8 +379,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 55..56, }, @@ -392,8 +400,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 7..8, }, @@ -407,8 +416,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 55..56, }, @@ -460,8 +470,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 1, + Edition2021, ), range: 0..0, }, @@ -475,8 +486,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 1, + Edition2021, ), range: 0..0, }, @@ -496,8 +508,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 1, + Edition2021, ), range: 0..0, }, @@ -511,8 +524,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 1, + Edition2021, ), range: 0..0, }, @@ -532,8 +546,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 1, + Edition2021, ), range: 0..0, }, @@ -547,8 +562,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 1, + Edition2021, ), range: 0..0, }, @@ -568,8 +584,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 0..0, }, @@ -616,8 +633,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 7..13, }, @@ -635,8 +653,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 7..13, }, @@ -654,8 +673,9 @@ fn main() { linked_location: Some( Computed( FileRangeWrapper { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), range: 7..13, }, @@ -665,25 +685,6 @@ fn main() { }, ], ), - ( - 222..228, - [ - InlayHintLabelPart { - text: "self", - linked_location: Some( - Computed( - FileRangeWrapper { - file_id: FileId( - 0, - ), - range: 42..46, - }, - ), - ), - tooltip: "", - }, - ], - ), ] "#]], ); diff --git a/crates/ide/src/inlay_hints/closing_brace.rs b/crates/ide/src/inlay_hints/closing_brace.rs index 3767d34e2c7a..8dc0005bf554 100644 --- a/crates/ide/src/inlay_hints/closing_brace.rs +++ b/crates/ide/src/inlay_hints/closing_brace.rs @@ -3,9 +3,9 @@ //! fn g() { //! } /* fn g */ //! ``` -use hir::{HirDisplay, Semantics}; -use ide_db::{FileRange, RootDatabase}; -use span::EditionedFileId; +use hir::{HirDisplay, HirFileRange, Semantics}; +use ide_db::RootDatabase; +use span::{Edition, HirFileId}; use syntax::{ ast::{self, AstNode, HasLoopBody, HasName}, match_ast, SyntaxKind, SyntaxNode, T, @@ -20,7 +20,8 @@ pub(super) fn hints( acc: &mut Vec, sema: &Semantics<'_, RootDatabase>, config: &InlayHintsConfig, - file_id: EditionedFileId, + file_id: HirFileId, + edition: Edition, original_node: SyntaxNode, ) -> Option<()> { let min_lines = config.closing_brace_hints_min_lines?; @@ -42,10 +43,10 @@ pub(super) fn hints( let hint_text = match trait_ { Some(tr) => format!( "impl {} for {}", - tr.name(sema.db).display(sema.db, file_id.edition()), - ty.display_truncated(sema.db, config.max_length, file_id.edition(), + tr.name(sema.db).display(sema.db, edition), + ty.display_truncated(sema.db, config.max_length, edition, )), - None => format!("impl {}", ty.display_truncated(sema.db, config.max_length, file_id.edition())), + None => format!("impl {}", ty.display_truncated(sema.db, config.max_length, edition)), }; (hint_text, None) }, @@ -140,7 +141,7 @@ pub(super) fn hints( return None; } - let linked_location = name_range.map(|range| FileRange { file_id: file_id.into(), range }); + let linked_location = name_range.map(|range| HirFileRange { file_id, range }); acc.push(InlayHint { range: closing_token.text_range(), kind: InlayKind::ClosingBrace, diff --git a/crates/ide/src/inlay_hints/closure_captures.rs b/crates/ide/src/inlay_hints/closure_captures.rs index 9b981c0a3acf..956ae019e8f2 100644 --- a/crates/ide/src/inlay_hints/closure_captures.rs +++ b/crates/ide/src/inlay_hints/closure_captures.rs @@ -1,10 +1,11 @@ //! Implementation of "closure captures" inlay hints. //! //! Tests live in [`bind_pat`][super::bind_pat] module. +use hir::HirFileRange; use ide_db::famous_defs::FamousDefs; use ide_db::text_edit::{TextRange, TextSize}; -use span::EditionedFileId; -use stdx::{never, TupleExt}; +use span::HirFileId; +use stdx::never; use syntax::ast::{self, AstNode}; use crate::{ @@ -15,7 +16,7 @@ pub(super) fn hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, + _file_id: HirFileId, closure: ast::ClosureExpr, ) -> Option<()> { if !config.closure_capture_hints { @@ -74,11 +75,9 @@ pub(super) fn hints( // force cache the source file, otherwise sema lookup will potentially panic _ = sema.parse_or_expand(source.file()); - source.name().and_then(|name| { - name.syntax() - .original_file_range_opt(sema.db) - .map(TupleExt::head) - .map(Into::into) + Some(HirFileRange { + file_id: source.file(), + range: source.name()?.syntax().text_range(), }) }), tooltip: None, diff --git a/crates/ide/src/inlay_hints/closure_ret.rs b/crates/ide/src/inlay_hints/closure_ret.rs index 7858b1d90a38..0ebf7c509219 100644 --- a/crates/ide/src/inlay_hints/closure_ret.rs +++ b/crates/ide/src/inlay_hints/closure_ret.rs @@ -2,7 +2,7 @@ //! //! Tests live in [`bind_pat`][super::bind_pat] module. use ide_db::famous_defs::FamousDefs; -use span::EditionedFileId; +use span::Edition; use syntax::ast::{self, AstNode}; use crate::{ @@ -14,7 +14,7 @@ pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: EditionedFileId, + edition: Edition, closure: ast::ClosureExpr, ) -> Option<()> { if config.closure_return_type_hints == ClosureReturnTypeHints::Never { @@ -43,7 +43,7 @@ pub(super) fn hints( return None; } - let mut label = label_of_ty(famous_defs, config, &ty, file_id.edition())?; + let mut label = label_of_ty(famous_defs, config, &ty, edition)?; if arrow.is_none() { label.prepend_str(" -> "); diff --git a/crates/ide/src/inlay_hints/discriminant.rs b/crates/ide/src/inlay_hints/discriminant.rs index f1e1955d14ca..8e644b54ebd8 100644 --- a/crates/ide/src/inlay_hints/discriminant.rs +++ b/crates/ide/src/inlay_hints/discriminant.rs @@ -7,7 +7,7 @@ use hir::Semantics; use ide_db::text_edit::TextEdit; use ide_db::{famous_defs::FamousDefs, RootDatabase}; -use span::EditionedFileId; +use span::HirFileId; use syntax::ast::{self, AstNode, HasName}; use crate::{ @@ -19,7 +19,7 @@ pub(super) fn enum_hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _: EditionedFileId, + _: HirFileId, enum_: ast::Enum, ) -> Option<()> { if let DiscriminantHints::Never = config.discriminant_hints { diff --git a/crates/ide/src/inlay_hints/extern_block.rs b/crates/ide/src/inlay_hints/extern_block.rs index 652dff0bc56e..d0f253013d6d 100644 --- a/crates/ide/src/inlay_hints/extern_block.rs +++ b/crates/ide/src/inlay_hints/extern_block.rs @@ -1,6 +1,6 @@ //! Extern block hints use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit}; -use span::EditionedFileId; +use span::HirFileId; use syntax::{ast, AstNode, SyntaxToken}; use crate::{InlayHint, InlayHintsConfig}; @@ -9,7 +9,7 @@ pub(super) fn extern_block_hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, + _file_id: HirFileId, extern_block: ast::ExternBlock, ) -> Option<()> { if extern_block.unsafe_token().is_some() { @@ -36,7 +36,7 @@ pub(super) fn fn_hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, + _file_id: HirFileId, fn_: &ast::Fn, extern_block: &ast::ExternBlock, ) -> Option<()> { @@ -55,7 +55,7 @@ pub(super) fn static_hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, + _file_id: HirFileId, static_: &ast::Static, extern_block: &ast::ExternBlock, ) -> Option<()> { diff --git a/crates/ide/src/inlay_hints/generic_param.rs b/crates/ide/src/inlay_hints/generic_param.rs index 762a4c265518..d48bc72e1412 100644 --- a/crates/ide/src/inlay_hints/generic_param.rs +++ b/crates/ide/src/inlay_hints/generic_param.rs @@ -1,4 +1,5 @@ //! Implementation of inlay hints for generic parameters. +use hir::HirFileRange; use ide_db::{active_parameter::generic_def_for_node, famous_defs::FamousDefs}; use syntax::{ ast::{self, AnyHasGenericArgs, HasGenericArgs, HasName}, @@ -70,28 +71,27 @@ pub(crate) fn hints( return None; } - let range = sema.original_range_opt(arg.syntax())?.range; + let range = arg.syntax().text_range(); let colon = if config.render_colons { ":" } else { "" }; let label = InlayHintLabel::simple( format!("{}{colon}", param_name.display(sema.db, krate.edition(sema.db))), None, - config.lazy_location_opt(|| { - let source_syntax = match param { - hir::GenericParam::TypeParam(it) => { - sema.source(it.merge()).map(|it| it.value.syntax().clone()) - } - hir::GenericParam::ConstParam(it) => { - let syntax = sema.source(it.merge())?.value.syntax().clone(); - let const_param = ast::ConstParam::cast(syntax)?; - const_param.name().map(|it| it.syntax().clone()) - } - hir::GenericParam::LifetimeParam(it) => { - sema.source(it).map(|it| it.value.syntax().clone()) - } - }; - let linked_location = source_syntax.and_then(|it| sema.original_range_opt(&it)); - linked_location.map(Into::into) + config.lazy_location_opt(|| match param { + hir::GenericParam::TypeParam(it) => { + sema.source(it.merge()).map(|it| it.node_file_range()) + } + hir::GenericParam::ConstParam(it) => { + let syntax = sema.source(it.merge())?; + let const_param = ast::ConstParam::cast(syntax.value.syntax().clone())?; + const_param.name().map(|it| HirFileRange { + file_id: syntax.file_id, + range: it.syntax().text_range(), + }) + } + hir::GenericParam::LifetimeParam(it) => { + sema.source(it).map(|it| it.node_file_range()) + } }), ); diff --git a/crates/ide/src/inlay_hints/implicit_drop.rs b/crates/ide/src/inlay_hints/implicit_drop.rs index 390139d214eb..b1014750be08 100644 --- a/crates/ide/src/inlay_hints/implicit_drop.rs +++ b/crates/ide/src/inlay_hints/implicit_drop.rs @@ -8,11 +8,11 @@ use hir::{ db::{DefDatabase as _, HirDatabase as _}, mir::{MirSpan, TerminatorKind}, - ChalkTyInterner, DefWithBody, + ChalkTyInterner, DefWithBody, HirFileRange, }; -use ide_db::{famous_defs::FamousDefs, FileRange}; +use ide_db::famous_defs::FamousDefs; -use span::EditionedFileId; +use span::Edition; use syntax::{ ast::{self, AstNode}, match_ast, ToSmolStr, @@ -24,7 +24,7 @@ pub(super) fn hints( acc: &mut Vec, FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: EditionedFileId, + edition: Edition, node: &ast::Fn, ) -> Option<()> { if !config.implicit_drop_hints { @@ -93,7 +93,7 @@ pub(super) fn hints( MirSpan::Unknown => continue, }; let binding = &hir.bindings[binding_idx]; - let name = binding.name.display_no_db(file_id.edition()).to_smolstr(); + let name = binding.name.display_no_db(edition).to_smolstr(); if name.starts_with(", FamousDefs(_sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, + _file_id: HirFileId, statik_or_const: Either, ) -> Option<()> { if config.lifetime_elision_hints != LifetimeElisionHints::Always { diff --git a/crates/ide/src/inlay_hints/lifetime.rs b/crates/ide/src/inlay_hints/lifetime.rs index 1fdd69899171..2a3595fb63c4 100644 --- a/crates/ide/src/inlay_hints/lifetime.rs +++ b/crates/ide/src/inlay_hints/lifetime.rs @@ -6,7 +6,7 @@ use std::iter; use ide_db::{famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap}; use itertools::Itertools; -use span::EditionedFileId; +use span::HirFileId; use syntax::{ ast::{self, AstNode, HasGenericParams, HasName}, SyntaxKind, SyntaxToken, @@ -23,7 +23,7 @@ pub(super) fn fn_hints( ctx: &mut InlayHintCtx, fd: &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: EditionedFileId, + file_id: HirFileId, func: ast::Fn, ) -> Option<()> { if config.lifetime_elision_hints == LifetimeElisionHints::Never { @@ -74,7 +74,7 @@ pub(super) fn fn_ptr_hints( ctx: &mut InlayHintCtx, fd: &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: EditionedFileId, + file_id: HirFileId, func: ast::FnPtrType, ) -> Option<()> { if config.lifetime_elision_hints == LifetimeElisionHints::Never { @@ -140,7 +140,7 @@ pub(super) fn fn_path_hints( ctx: &mut InlayHintCtx, fd: &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: EditionedFileId, + file_id: HirFileId, func: ast::PathType, ) -> Option<()> { if config.lifetime_elision_hints == LifetimeElisionHints::Never { @@ -202,7 +202,7 @@ fn hints_( ctx: &mut InlayHintCtx, FamousDefs(_, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, + _file_id: HirFileId, params: impl Iterator, ast::Type)>, generic_param_list: Option, ret_type: Option, diff --git a/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs index 8f01b1bd38b5..70cf5a87aae0 100644 --- a/crates/ide/src/inlay_hints/param_name.rs +++ b/crates/ide/src/inlay_hints/param_name.rs @@ -5,10 +5,10 @@ //! ``` use either::Either; -use hir::{Callable, Semantics}; +use hir::{Callable, InFile, Semantics}; use ide_db::{famous_defs::FamousDefs, RootDatabase}; -use span::EditionedFileId; +use span::HirFileId; use stdx::to_lower_snake_case; use syntax::{ ast::{self, AstNode, HasArgList, HasName, UnaryOp}, @@ -21,28 +21,31 @@ pub(super) fn hints( acc: &mut Vec, FamousDefs(sema, krate): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, + file_id: HirFileId, expr: ast::Expr, ) -> Option<()> { if !config.parameter_hints { return None; } - let (callable, arg_list) = get_callable(sema, &expr)?; + let InFile { file_id: arg_file, value: (callable, arg_list) } = get_callable(sema, &expr)?; let hints = callable .params() .into_iter() .zip(arg_list.args()) .filter_map(|(p, arg)| { - // Only annotate hints for expressions that exist in the original file - let range = sema.original_range_opt(arg.syntax())?; + // FIXME: macro mapping for the arg range + if arg_file != file_id { + return None; + } + let range = arg.syntax().text_range(); let param_name = p.name(sema.db)?; Some((p, param_name, arg, range)) }) .filter(|(_, param_name, arg, _)| { !should_hide_param_name_hint(sema, &callable, param_name.as_str(), arg) }) - .map(|(param, param_name, _, hir::FileRange { range, .. })| { + .map(|(param, param_name, _, range)| { let colon = if config.render_colons { ":" } else { "" }; let label = InlayHintLabel::simple( format!("{}{colon}", param_name.display(sema.db, krate.edition(sema.db))), @@ -56,7 +59,7 @@ pub(super) fn hints( _ => None, }, }?; - sema.original_range_opt(name_syntax.syntax()).map(Into::into) + Some(source.with_value(name_syntax).node_file_range()) }), ); InlayHint { @@ -78,17 +81,25 @@ pub(super) fn hints( fn get_callable( sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr, -) -> Option<(hir::Callable, ast::ArgList)> { +) -> Option> { match expr { ast::Expr::CallExpr(expr) => { let descended = sema.descend_node_into_attributes(expr.clone()).pop(); let expr = descended.as_ref().unwrap_or(expr); - sema.type_of_expr(&expr.expr()?)?.original.as_callable(sema.db).zip(expr.arg_list()) + let file_id = sema.hir_file_for(expr.syntax()); + sema.type_of_expr(&expr.expr()?)? + .original + .as_callable(sema.db) + .zip(expr.arg_list()) + .map(|it| InFile::new(file_id, it)) } ast::Expr::MethodCallExpr(expr) => { let descended = sema.descend_node_into_attributes(expr.clone()).pop(); let expr = descended.as_ref().unwrap_or(expr); - sema.resolve_method_call_as_callable(expr).zip(expr.arg_list()) + let file_id = sema.hir_file_for(expr.syntax()); + sema.resolve_method_call_as_callable(expr) + .zip(expr.arg_list()) + .map(|it| InFile::new(file_id, it)) } _ => None, } diff --git a/crates/ide/src/inlay_hints/range_exclusive.rs b/crates/ide/src/inlay_hints/range_exclusive.rs index de9b0e98a4be..41a7493e72ff 100644 --- a/crates/ide/src/inlay_hints/range_exclusive.rs +++ b/crates/ide/src/inlay_hints/range_exclusive.rs @@ -4,7 +4,7 @@ //! if let ../* < */100 = 50 {} //! ``` use ide_db::famous_defs::FamousDefs; -use span::EditionedFileId; +use span::HirFileId; use syntax::{ast, SyntaxToken, T}; use crate::{InlayHint, InlayHintsConfig}; @@ -13,7 +13,7 @@ pub(super) fn hints( acc: &mut Vec, FamousDefs(_sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, + _file_id: HirFileId, range: impl ast::RangeItem, ) -> Option<()> { (config.range_exclusive_hints && range.end().is_some()) diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index e942f5a6aac7..d38fe74ac1d2 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -61,7 +61,9 @@ use std::{iter, panic::UnwindSafe}; use cfg::CfgOptions; use fetch_crates::CrateInfo; -use hir::{sym, ChangeWithProcMacros}; +use hir::{ + db::ExpandDatabase, sym, ChangeWithProcMacros, HirFileId, HirFilePosition, HirFileRange, +}; use ide_db::{ base_db::{ ra_salsa::{self, ParallelDatabase}, @@ -101,7 +103,7 @@ pub use crate::{ PackageInformation, SymbolInformationKind, }, move_item::Direction, - navigation_target::{NavigationTarget, TryToNav, UpmappingResult}, + navigation_target::{HirNavigationTarget, NavigationTarget, TryToNav, UpmappingResult}, references::ReferenceSearchResult, rename::RenameError, runnables::{Runnable, RunnableKind, TestId}, @@ -230,7 +232,7 @@ impl Analysis { // Creates an analysis instance for a single file, without any external // dependencies, stdlib support or ability to apply changes. See // `AnalysisHost` for creating a fully-featured analysis. - pub fn from_single_file(text: String) -> (Analysis, FileId) { + pub fn from_single_file(text: String) -> (Analysis, EditionedFileId) { let mut host = AnalysisHost::default(); let file_id = FileId::from_raw(0); let mut file_set = FileSet::default(); @@ -267,7 +269,7 @@ impl Analysis { change.set_crate_graph(crate_graph, ws_data); host.apply_change(change); - (host.analysis(), file_id) + (host.analysis(), EditionedFileId::new(file_id, Edition::CURRENT)) } /// Debug info about the current state of the analysis. @@ -375,7 +377,7 @@ impl Analysis { self.with_db(fetch_crates::fetch_crates) } - pub fn expand_macro(&self, position: FilePosition) -> Cancellable> { + pub fn expand_macro(&self, position: HirFilePosition) -> Cancellable> { self.with_db(|db| expand_macro::expand_macro(db, position)) } @@ -416,20 +418,16 @@ impl Analysis { /// Returns a tree representation of symbols in the file. Useful to draw a /// file outline. - pub fn file_structure(&self, file_id: FileId) -> Cancellable> { + pub fn file_structure(&self, file_id: HirFileId) -> Cancellable> { // FIXME: Edition - self.with_db(|db| { - file_structure::file_structure( - &db.parse(EditionedFileId::current_edition(file_id)).tree(), - ) - }) + self.with_db(|db| file_structure::file_structure(&db.parse_or_expand(file_id))) } /// Returns a list of the places in the file where type hints can be displayed. pub fn inlay_hints( &self, config: &InlayHintsConfig, - file_id: FileId, + file_id: HirFileId, range: Option, ) -> Cancellable> { self.with_db(|db| inlay_hints::inlay_hints(db, file_id, range, config)) @@ -437,7 +435,7 @@ impl Analysis { pub fn inlay_hints_resolve( &self, config: &InlayHintsConfig, - file_id: FileId, + file_id: HirFileId, resolve_range: TextRange, hash: u64, hasher: impl Fn(&InlayHint) -> u64 + Send + UnwindSafe, @@ -448,22 +446,21 @@ impl Analysis { } /// Returns the set of folding ranges. - pub fn folding_ranges(&self, file_id: FileId) -> Cancellable> { - self.with_db(|db| { - folding_ranges::folding_ranges( - &db.parse(EditionedFileId::current_edition(file_id)).tree(), - ) - }) + pub fn folding_ranges(&self, file_id: HirFileId) -> Cancellable> { + self.with_db(|db| folding_ranges::folding_ranges(&db.parse_or_expand(file_id))) } /// Fuzzy searches for a symbol. - pub fn symbol_search(&self, query: Query, limit: usize) -> Cancellable> { + pub fn symbol_search( + &self, + query: Query, + limit: usize, + ) -> Cancellable> { self.with_db(|db| { symbol_index::world_symbols(db, query) - .into_iter() // xx: should we make this a par iter? - .filter_map(|s| s.try_to_nav(db)) + .into_iter() + .filter_map(|s| s.try_to_nav_hir(db)) .take(limit) - .map(UpmappingResult::call_site) .collect::>() }) } @@ -471,39 +468,39 @@ impl Analysis { /// Returns the definitions from the symbol at `position`. pub fn goto_definition( &self, - position: FilePosition, - ) -> Cancellable>>> { + position: HirFilePosition, + ) -> Cancellable>>> { self.with_db(|db| goto_definition::goto_definition(db, position)) } /// Returns the declaration from the symbol at `position`. pub fn goto_declaration( &self, - position: FilePosition, - ) -> Cancellable>>> { + position: HirFilePosition, + ) -> Cancellable>>> { self.with_db(|db| goto_declaration::goto_declaration(db, position)) } /// Returns the impls from the symbol at `position`. pub fn goto_implementation( &self, - position: FilePosition, - ) -> Cancellable>>> { + position: HirFilePosition, + ) -> Cancellable>>> { self.with_db(|db| goto_implementation::goto_implementation(db, position)) } /// Returns the type definitions for the symbol at `position`. pub fn goto_type_definition( &self, - position: FilePosition, - ) -> Cancellable>>> { + position: HirFilePosition, + ) -> Cancellable>>> { self.with_db(|db| goto_type_definition::goto_type_definition(db, position)) } /// Finds all usages of the reference at point. pub fn find_all_refs( &self, - position: FilePosition, + position: HirFilePosition, search_scope: Option, ) -> Cancellable>> { self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, search_scope)) @@ -513,7 +510,7 @@ impl Analysis { pub fn hover( &self, config: &HoverConfig, - range: FileRange, + range: HirFileRange, ) -> Cancellable>> { self.with_db(|db| hover::hover(db, range, config)) } @@ -549,8 +546,8 @@ impl Analysis { /// Computes call hierarchy candidates for the given file position. pub fn call_hierarchy( &self, - position: FilePosition, - ) -> Cancellable>>> { + position: HirFilePosition, + ) -> Cancellable>>> { self.with_db(|db| call_hierarchy::call_hierarchy(db, position)) } @@ -558,7 +555,7 @@ impl Analysis { pub fn incoming_calls( &self, config: CallHierarchyConfig, - position: FilePosition, + position: HirFilePosition, ) -> Cancellable>> { self.with_db(|db| call_hierarchy::incoming_calls(db, config, position)) } @@ -567,13 +564,16 @@ impl Analysis { pub fn outgoing_calls( &self, config: CallHierarchyConfig, - position: FilePosition, + position: HirFilePosition, ) -> Cancellable>> { self.with_db(|db| call_hierarchy::outgoing_calls(db, config, position)) } /// Returns a `mod name;` declaration which created the current module. - pub fn parent_module(&self, position: FilePosition) -> Cancellable> { + pub fn parent_module( + &self, + position: HirFilePosition, + ) -> Cancellable> { self.with_db(|db| parent_module::parent_module(db, position)) } @@ -608,7 +608,7 @@ impl Analysis { } /// Returns the set of possible targets to run for the current file. - pub fn runnables(&self, file_id: FileId) -> Cancellable> { + pub fn runnables(&self, file_id: HirFileId) -> Cancellable> { self.with_db(|db| runnables::runnables(db, file_id)) } @@ -625,7 +625,7 @@ impl Analysis { pub fn highlight( &self, highlight_config: HighlightConfig, - file_id: FileId, + file_id: HirFileId, ) -> Cancellable> { self.with_db(|db| syntax_highlighting::highlight(db, highlight_config, file_id, None)) } @@ -634,7 +634,7 @@ impl Analysis { pub fn highlight_related( &self, config: HighlightRelatedConfig, - position: FilePosition, + position: HirFilePosition, ) -> Cancellable>> { self.with_db(|db| { highlight_related::highlight_related(&Semantics::new(db), config, position) @@ -645,7 +645,7 @@ impl Analysis { pub fn highlight_range( &self, highlight_config: HighlightConfig, - frange: FileRange, + frange: HirFileRange, ) -> Cancellable> { self.with_db(|db| { syntax_highlighting::highlight(db, highlight_config, frange.file_id, Some(frange.range)) @@ -653,7 +653,7 @@ impl Analysis { } /// Computes syntax highlighting for the given file. - pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancellable { + pub fn highlight_as_html(&self, file_id: HirFileId, rainbow: bool) -> Cancellable { self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id, rainbow)) } @@ -787,7 +787,7 @@ impl Analysis { pub fn annotations( &self, config: &AnnotationConfig, - file_id: FileId, + file_id: HirFileId, ) -> Cancellable> { self.with_db(|db| annotations::annotations(db, config, file_id)) } @@ -824,7 +824,7 @@ impl Analysis { /// /// Salsa implements cancellation by unwinding with a special value and /// catching it on the API boundary. - fn with_db(&self, f: F) -> Cancellable + pub fn with_db(&self, f: F) -> Cancellable where F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe, { diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 66ea49a98a08..a50d17bbd8e0 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -419,7 +419,7 @@ mod tests { #[track_caller] fn no_moniker(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position) = fixture::position(ra_fixture); - if let Some(x) = analysis.moniker(position).unwrap() { + if let Some(x) = analysis.moniker(position.into()).unwrap() { assert_eq!(x.info.len(), 0, "Moniker found but no moniker expected: {x:?}"); } } @@ -432,7 +432,7 @@ mod tests { kind: MonikerKind, ) { let (analysis, position) = fixture::position(ra_fixture); - let x = analysis.moniker(position).unwrap().expect("no moniker found").info; + let x = analysis.moniker(position.into()).unwrap().expect("no moniker found").info; assert_eq!(x.len(), 1); match x.into_iter().next().unwrap() { MonikerResult::Local { enclosing_moniker: Some(x) } => { @@ -457,7 +457,7 @@ mod tests { kind: MonikerKind, ) { let (analysis, position) = fixture::position(ra_fixture); - let x = analysis.moniker(position).unwrap().expect("no moniker found").info; + let x = analysis.moniker(position.into()).unwrap().expect("no moniker found").info; assert_eq!(x.len(), 1); match x.into_iter().next().unwrap() { MonikerResult::Local { enclosing_moniker } => { diff --git a/crates/ide/src/move_item.rs b/crates/ide/src/move_item.rs index 3fb3a788b918..13f1e4967e9e 100644 --- a/crates/ide/src/move_item.rs +++ b/crates/ide/src/move_item.rs @@ -184,8 +184,8 @@ mod tests { direction: Direction, ) { let (analysis, range) = fixture::range(ra_fixture); - let edit = analysis.move_item(range, direction).unwrap().unwrap_or_default(); - let mut file = analysis.file_text(range.file_id).unwrap().to_string(); + let edit = analysis.move_item(range.into(), direction).unwrap().unwrap_or_default(); + let mut file = analysis.file_text(range.file_id.into()).unwrap().to_string(); edit.apply(&mut file); expect.assert_eq(&file); } diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs index d9f80cb53dd6..b49a6ad490b4 100644 --- a/crates/ide/src/navigation_target.rs +++ b/crates/ide/src/navigation_target.rs @@ -1,32 +1,36 @@ //! See [`NavigationTarget`]. -use std::fmt; +use std::{fmt, iter}; use arrayvec::ArrayVec; use either::Either; use hir::{ db::ExpandDatabase, symbols::FileSymbol, AssocItem, FieldSource, HasContainer, HasCrate, - HasSource, HirDisplay, HirFileId, HirFileIdExt, InFile, LocalSource, ModuleSource, + HasSource, HirDisplay, HirFileId, HirFileIdExt, InFile, InFileWrapper, LocalSource, + MacroFileIdExt, ModuleSource, }; use ide_db::{ defs::Definition, documentation::{Documentation, HasDocs}, - FileId, FileRange, RootDatabase, SymbolKind, + FileRange, RootDatabase, SymbolKind, }; -use span::Edition; -use stdx::never; +use span::{Edition, FileId}; +use stdx::{never, TupleExt}; use syntax::{ ast::{self, HasName}, - format_smolstr, AstNode, SmolStr, SyntaxNode, TextRange, ToSmolStr, + format_smolstr, AstNode, SmolStr, TextRange, ToSmolStr, }; +pub type RealNavigationTarget = NavigationTarget; +pub type HirNavigationTarget = NavigationTarget; + /// `NavigationTarget` represents an element in the editor's UI which you can /// click on to navigate to a particular piece of code. /// /// Typically, a `NavigationTarget` corresponds to some element in the source /// code, like a function or a struct, but this is not strictly required. #[derive(Clone, PartialEq, Eq, Hash)] -pub struct NavigationTarget { +pub struct NavigationTarget { pub file_id: FileId, /// Range which encompasses the whole element. /// @@ -57,7 +61,7 @@ pub struct NavigationTarget { pub alias: Option, } -impl fmt::Debug for NavigationTarget { +impl fmt::Debug for NavigationTarget { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut f = f.debug_struct("NavigationTarget"); macro_rules! opt { @@ -76,56 +80,94 @@ impl fmt::Debug for NavigationTarget { } pub(crate) trait ToNav { - fn to_nav(&self, db: &RootDatabase) -> UpmappingResult; + fn to_nav_hir(&self, db: &RootDatabase) -> HirNavigationTarget; } pub trait TryToNav { - fn try_to_nav(&self, db: &RootDatabase) -> Option>; + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option; + fn try_to_nav(&self, db: &RootDatabase) -> Option> { + self.try_to_nav_hir(db).map(|it| HirNavigationTarget::upmap(it, db)) + } } impl TryToNav for Either { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { match self { - Either::Left(it) => it.try_to_nav(db), - Either::Right(it) => it.try_to_nav(db), + Either::Left(it) => it.try_to_nav_hir(db), + Either::Right(it) => it.try_to_nav_hir(db), } } } -impl NavigationTarget { - pub fn focus_or_full_range(&self) -> TextRange { - self.focus_range.unwrap_or(self.full_range) +impl RealNavigationTarget { + pub fn focus_or_full_file_range(&self) -> FileRange { + FileRange { file_id: self.file_id, range: self.focus_or_full_range() } } +} - pub(crate) fn from_module_to_decl( +impl HirNavigationTarget { + pub fn focus_or_full_file_range(&self, db: &RootDatabase) -> FileRange { + InFile { file_id: self.file_id, value: self.focus_or_full_range() } + .original_node_file_range(db) + .0 + .into() + } + + /// Upmaps this nav target to the `target` [`HirFileId`] if possible. + /// + /// If successful, the result entries are guaranteed to have the `target` file id. + pub fn upmap_to( + self, db: &RootDatabase, - module: hir::Module, - ) -> UpmappingResult { - let edition = module.krate().edition(db); - let name = - module.name(db).map(|it| it.display_no_db(edition).to_smolstr()).unwrap_or_default(); - match module.declaration_source(db) { - Some(InFile { value, file_id }) => { - orig_range_with_focus(db, file_id, value.syntax(), value.name()).map( - |(FileRange { file_id, range: full_range }, focus_range)| { - let mut res = NavigationTarget::from_syntax( - file_id, - name.clone(), - focus_range, - full_range, - SymbolKind::Module, - ); - res.docs = module.docs(db); - res.description = Some(module.display(db, edition).to_string()); - res - }, - ) - } - _ => module.to_nav(db), + target: HirFileId, + ) -> Option> { + if self.file_id == target { + return Some(vec![self]); } + let ranges = + orig_ranges_with_focus_in(db, self.file_id, self.full_range, self.focus_range, target)?; + Some( + ranges + .value + .into_iter() + .map(|(range, focus)| { + NavigationTarget { + file_id: target, + full_range: range, + focus_range: focus, + name: self.name.clone(), + kind: self.kind, + container_name: self.container_name.clone(), + description: self.description.clone(), + // FIXME: possibly expensive clone! + docs: self.docs.clone(), + alias: self.alias.clone(), + } + }) + .collect(), + ) + } + + pub fn upmap(self, db: &RootDatabase) -> UpmappingResult { + orig_range_with_focus(db, self.file_id, self.full_range, self.focus_range).map( + |(range, focus)| NavigationTarget { + file_id: range.file_id, + full_range: range.range, + focus_range: focus, + name: self.name.clone(), + kind: self.kind, + container_name: self.container_name.clone(), + description: self.description.clone(), + // FIXME: possibly expensive clone! + docs: self.docs.clone(), + alias: self.alias.clone(), + }, + ) } +} - #[cfg(test)] +#[cfg(test)] +impl NavigationTarget { pub(crate) fn debug_render(&self) -> String { let mut buf = format!( "{} {:?} {:?} {:?}", @@ -142,19 +184,49 @@ impl NavigationTarget { } buf } +} + +impl NavigationTarget { + pub fn focus_or_full_range(&self) -> TextRange { + self.focus_range.unwrap_or(self.full_range) + } + pub(crate) fn from_module_to_decl( + db: &RootDatabase, + module: hir::Module, + ) -> HirNavigationTarget { + let edition = module.krate().edition(db); + let name = + module.name(db).map(|it| it.display_no_db(edition).to_smolstr()).unwrap_or_default(); + match module.declaration_source(db) { + Some(InFile { value, file_id }) => { + let mut res = NavigationTarget::from_syntax( + file_id, + name.clone(), + value.name().map(|it| it.syntax().text_range()), + value.syntax().text_range(), + SymbolKind::Module, + ); + res.docs = module.docs(db); + res.description = Some(module.display(db, edition).to_string()); + res + } + _ => module.to_nav_hir(db), + } + } /// Allows `NavigationTarget` to be created from a `NameOwner` pub(crate) fn from_named( - db: &RootDatabase, - InFile { file_id, value }: InFile<&dyn ast::HasName>, + InFileWrapper { file_id, value }: InFileWrapper, kind: SymbolKind, - ) -> UpmappingResult { + ) -> Self { let name: SmolStr = value.name().map(|it| it.text().into()).unwrap_or_else(|| "_".into()); - orig_range_with_focus(db, file_id, value.syntax(), value.name()).map( - |(FileRange { file_id, range: full_range }, focus_range)| { - NavigationTarget::from_syntax(file_id, name.clone(), focus_range, full_range, kind) - }, + NavigationTarget::from_syntax( + file_id, + name.clone(), + value.name().map(|it| it.syntax().text_range()), + value.syntax().text_range(), + kind, ) } @@ -164,7 +236,7 @@ impl NavigationTarget { focus_range: Option, full_range: TextRange, kind: SymbolKind, - ) -> NavigationTarget { + ) -> Self { NavigationTarget { file_id, name, @@ -180,69 +252,59 @@ impl NavigationTarget { } impl TryToNav for FileSymbol { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { let edition = self.def.module(db).map(|it| it.krate().edition(db)).unwrap_or(Edition::CURRENT); - Some( - orig_range_with_focus_r( - db, - self.loc.hir_file_id, - self.loc.ptr.text_range(), - Some(self.loc.name_ptr.text_range()), - ) - .map(|(FileRange { file_id, range: full_range }, focus_range)| { - NavigationTarget { - file_id, - name: self.is_alias.then(|| self.def.name(db)).flatten().map_or_else( - || self.name.as_str().into(), - |it| it.display_no_db(edition).to_smolstr(), - ), - alias: self.is_alias.then(|| self.name.as_str().into()), - kind: Some(self.def.into()), - full_range, - focus_range, - container_name: self.container_name.clone(), - description: match self.def { - hir::ModuleDef::Module(it) => Some(it.display(db, edition).to_string()), - hir::ModuleDef::Function(it) => Some(it.display(db, edition).to_string()), - hir::ModuleDef::Adt(it) => Some(it.display(db, edition).to_string()), - hir::ModuleDef::Variant(it) => Some(it.display(db, edition).to_string()), - hir::ModuleDef::Const(it) => Some(it.display(db, edition).to_string()), - hir::ModuleDef::Static(it) => Some(it.display(db, edition).to_string()), - hir::ModuleDef::Trait(it) => Some(it.display(db, edition).to_string()), - hir::ModuleDef::TraitAlias(it) => Some(it.display(db, edition).to_string()), - hir::ModuleDef::TypeAlias(it) => Some(it.display(db, edition).to_string()), - hir::ModuleDef::Macro(it) => Some(it.display(db, edition).to_string()), - hir::ModuleDef::BuiltinType(_) => None, - }, - docs: None, - } - }), - ) + Some(NavigationTarget { + file_id: self.loc.hir_file_id, + name: self.is_alias.then(|| self.def.name(db)).flatten().map_or_else( + || self.name.as_str().into(), + |it| it.display_no_db(edition).to_smolstr(), + ), + alias: self.is_alias.then(|| self.name.as_str().into()), + kind: Some(self.def.into()), + full_range: self.loc.ptr.text_range(), + focus_range: Some(self.loc.name_ptr.text_range()), + container_name: self.container_name.clone(), + description: match self.def { + hir::ModuleDef::Module(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::Function(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::Adt(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::Variant(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::Const(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::Static(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::Trait(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::TraitAlias(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::TypeAlias(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::Macro(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::BuiltinType(_) => None, + }, + docs: None, + }) } } impl TryToNav for Definition { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { match self { - Definition::Local(it) => Some(it.to_nav(db)), - Definition::Label(it) => it.try_to_nav(db), - Definition::Module(it) => Some(it.to_nav(db)), - Definition::Crate(it) => Some(it.to_nav(db)), - Definition::Macro(it) => it.try_to_nav(db), - Definition::Field(it) => it.try_to_nav(db), - Definition::SelfType(it) => it.try_to_nav(db), - Definition::GenericParam(it) => it.try_to_nav(db), - Definition::Function(it) => it.try_to_nav(db), - Definition::Adt(it) => it.try_to_nav(db), - Definition::Variant(it) => it.try_to_nav(db), - Definition::Const(it) => it.try_to_nav(db), - Definition::Static(it) => it.try_to_nav(db), - Definition::Trait(it) => it.try_to_nav(db), - Definition::TraitAlias(it) => it.try_to_nav(db), - Definition::TypeAlias(it) => it.try_to_nav(db), - Definition::ExternCrateDecl(it) => it.try_to_nav(db), - Definition::InlineAsmOperand(it) => it.try_to_nav(db), + Definition::Local(it) => Some(it.to_nav_hir(db)), + Definition::Label(it) => it.try_to_nav_hir(db), + Definition::Module(it) => Some(it.to_nav_hir(db)), + Definition::Crate(it) => Some(it.to_nav_hir(db)), + Definition::Macro(it) => it.try_to_nav_hir(db), + Definition::Field(it) => it.try_to_nav_hir(db), + Definition::SelfType(it) => it.try_to_nav_hir(db), + Definition::GenericParam(it) => it.try_to_nav_hir(db), + Definition::Function(it) => it.try_to_nav_hir(db), + Definition::Adt(it) => it.try_to_nav_hir(db), + Definition::Variant(it) => it.try_to_nav_hir(db), + Definition::Const(it) => it.try_to_nav_hir(db), + Definition::Static(it) => it.try_to_nav_hir(db), + Definition::Trait(it) => it.try_to_nav_hir(db), + Definition::TraitAlias(it) => it.try_to_nav_hir(db), + Definition::TypeAlias(it) => it.try_to_nav_hir(db), + Definition::ExternCrateDecl(it) => it.try_to_nav_hir(db), + Definition::InlineAsmOperand(it) => it.try_to_nav_hir(db), Definition::BuiltinLifetime(_) | Definition::BuiltinType(_) | Definition::TupleField(_) @@ -250,24 +312,24 @@ impl TryToNav for Definition { | Definition::InlineAsmRegOrRegClass(_) | Definition::BuiltinAttr(_) => None, // FIXME: The focus range should be set to the helper declaration - Definition::DeriveHelper(it) => it.derive().try_to_nav(db), + Definition::DeriveHelper(it) => it.derive().try_to_nav_hir(db), } } } impl TryToNav for hir::ModuleDef { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { match self { - hir::ModuleDef::Module(it) => Some(it.to_nav(db)), - hir::ModuleDef::Function(it) => it.try_to_nav(db), - hir::ModuleDef::Adt(it) => it.try_to_nav(db), - hir::ModuleDef::Variant(it) => it.try_to_nav(db), - hir::ModuleDef::Const(it) => it.try_to_nav(db), - hir::ModuleDef::Static(it) => it.try_to_nav(db), - hir::ModuleDef::Trait(it) => it.try_to_nav(db), - hir::ModuleDef::TraitAlias(it) => it.try_to_nav(db), - hir::ModuleDef::TypeAlias(it) => it.try_to_nav(db), - hir::ModuleDef::Macro(it) => it.try_to_nav(db), + hir::ModuleDef::Module(it) => Some(it.to_nav_hir(db)), + hir::ModuleDef::Function(it) => it.try_to_nav_hir(db), + hir::ModuleDef::Adt(it) => it.try_to_nav_hir(db), + hir::ModuleDef::Variant(it) => it.try_to_nav_hir(db), + hir::ModuleDef::Const(it) => it.try_to_nav_hir(db), + hir::ModuleDef::Static(it) => it.try_to_nav_hir(db), + hir::ModuleDef::Trait(it) => it.try_to_nav_hir(db), + hir::ModuleDef::TraitAlias(it) => it.try_to_nav_hir(db), + hir::ModuleDef::TypeAlias(it) => it.try_to_nav_hir(db), + hir::ModuleDef::Macro(it) => it.try_to_nav_hir(db), hir::ModuleDef::BuiltinType(_) => None, } } @@ -356,27 +418,20 @@ where D: HasSource + ToNavFromAst + Copy + HasDocs + HirDisplay, D::Ast: ast::HasName, { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { let src = self.source(db)?; let edition = src.file_id.original_file(db).edition(); - Some( - NavigationTarget::from_named( - db, - src.as_ref().map(|it| it as &dyn ast::HasName), - D::KIND, - ) - .map(|mut res| { - res.docs = self.docs(db); - res.description = Some(self.display(db, edition).to_string()); - res.container_name = self.container_name(db); - res - }), - ) + let mut navigation_target = + NavigationTarget::from_named(src.as_ref().map(|it| it as &dyn ast::HasName), D::KIND); + navigation_target.docs = self.docs(db); + navigation_target.description = Some(self.display(db, edition).to_string()); + navigation_target.container_name = self.container_name(db); + Some(navigation_target) } } impl ToNav for hir::Module { - fn to_nav(&self, db: &RootDatabase) -> UpmappingResult { + fn to_nav_hir(&self, db: &RootDatabase) -> HirNavigationTarget { let InFile { file_id, value } = self.definition_source(db); let edition = self.krate(db).edition(db); @@ -388,28 +443,24 @@ impl ToNav for hir::Module { ModuleSource::BlockExpr(node) => (node.syntax(), None), }; - orig_range_with_focus(db, file_id, syntax, focus).map( - |(FileRange { file_id, range: full_range }, focus_range)| { - NavigationTarget::from_syntax( - file_id, - name.clone(), - focus_range, - full_range, - SymbolKind::Module, - ) - }, + NavigationTarget::from_syntax( + file_id, + name.clone(), + focus.map(|it| it.syntax().text_range()), + syntax.text_range(), + SymbolKind::Module, ) } } impl ToNav for hir::Crate { - fn to_nav(&self, db: &RootDatabase) -> UpmappingResult { - self.root_module().to_nav(db) + fn to_nav_hir(&self, db: &RootDatabase) -> HirNavigationTarget { + self.root_module().to_nav_hir(db) } } impl TryToNav for hir::Impl { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { let InFile { file_id, value } = self.source(db)?; let derive_path = self.as_builtin_derive_path(db); @@ -417,201 +468,169 @@ impl TryToNav for hir::Impl { Some(attr) => (attr.file_id.into(), None, attr.value.syntax()), None => (file_id, value.self_ty(), value.syntax()), }; - - Some(orig_range_with_focus(db, file_id, syntax, focus).map( - |(FileRange { file_id, range: full_range }, focus_range)| { - NavigationTarget::from_syntax( - file_id, - "impl".into(), - focus_range, - full_range, - SymbolKind::Impl, - ) - }, + Some(NavigationTarget::from_syntax( + file_id, + "impl".into(), + focus.map(|it| it.syntax().text_range()), + syntax.text_range(), + SymbolKind::Impl, )) } } impl TryToNav for hir::ExternCrateDecl { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { let src = self.source(db)?; let InFile { file_id, value } = src; let focus = value .rename() .map_or_else(|| value.name_ref().map(Either::Left), |it| it.name().map(Either::Right)); let edition = self.module(db).krate().edition(db); + let mut nav = NavigationTarget::from_syntax( + file_id, + self.alias_or_name(db) + .unwrap_or_else(|| self.name(db)) + .display_no_db(edition) + .to_smolstr(), + focus.map(|it| it.syntax().text_range()), + value.syntax().text_range(), + SymbolKind::Module, + ); - Some(orig_range_with_focus(db, file_id, value.syntax(), focus).map( - |(FileRange { file_id, range: full_range }, focus_range)| { - let mut res = NavigationTarget::from_syntax( - file_id, - self.alias_or_name(db) - .unwrap_or_else(|| self.name(db)) - .display_no_db(edition) - .to_smolstr(), - focus_range, - full_range, - SymbolKind::Module, - ); - - res.docs = self.docs(db); - res.description = Some(self.display(db, edition).to_string()); - res.container_name = container_name(db, *self, edition); - res - }, - )) + nav.docs = self.docs(db); + nav.description = Some(self.display(db, edition).to_string()); + nav.container_name = container_name(db, *self, edition); + Some(nav) } } impl TryToNav for hir::Field { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { let src = self.source(db)?; let edition = self.parent_def(db).module(db).krate().edition(db); - let field_source = match &src.value { + Some(match &src.value { FieldSource::Named(it) => { - NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field).map( - |mut res| { - res.docs = self.docs(db); - res.description = Some(self.display(db, edition).to_string()); - res - }, - ) + let mut nav = NavigationTarget::from_named(src.with_value(it), SymbolKind::Field); + nav.docs = self.docs(db); + nav.description = Some(self.display(db, edition).to_string()); + nav } - FieldSource::Pos(it) => orig_range(db, src.file_id, it.syntax()).map( - |(FileRange { file_id, range: full_range }, focus_range)| { - NavigationTarget::from_syntax( - file_id, - format_smolstr!("{}", self.index()), - focus_range, - full_range, - SymbolKind::Field, - ) - }, + FieldSource::Pos(it) => NavigationTarget::from_syntax( + src.file_id, + format_smolstr!("{}", self.index()), + None, + it.syntax().text_range(), + SymbolKind::Field, ), - }; - Some(field_source) + }) } } impl TryToNav for hir::Macro { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { let src = self.source(db)?; let name_owner: &dyn ast::HasName = match &src.value { Either::Left(it) => it, Either::Right(it) => it, }; - Some( - NavigationTarget::from_named( - db, - src.as_ref().with_value(name_owner), - self.kind(db).into(), - ) - .map(|mut res| { - res.docs = self.docs(db); - res - }), - ) + let mut nav = + NavigationTarget::from_named(src.as_ref().with_value(name_owner), self.kind(db).into()); + nav.docs = self.docs(db); + Some(nav) } } impl TryToNav for hir::Adt { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { match self { - hir::Adt::Struct(it) => it.try_to_nav(db), - hir::Adt::Union(it) => it.try_to_nav(db), - hir::Adt::Enum(it) => it.try_to_nav(db), + hir::Adt::Struct(it) => it.try_to_nav_hir(db), + hir::Adt::Union(it) => it.try_to_nav_hir(db), + hir::Adt::Enum(it) => it.try_to_nav_hir(db), } } } impl TryToNav for hir::AssocItem { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { match self { - AssocItem::Function(it) => it.try_to_nav(db), - AssocItem::Const(it) => it.try_to_nav(db), - AssocItem::TypeAlias(it) => it.try_to_nav(db), + AssocItem::Function(it) => it.try_to_nav_hir(db), + AssocItem::Const(it) => it.try_to_nav_hir(db), + AssocItem::TypeAlias(it) => it.try_to_nav_hir(db), } } } impl TryToNav for hir::GenericParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { match self { - hir::GenericParam::TypeParam(it) => it.try_to_nav(db), - hir::GenericParam::ConstParam(it) => it.try_to_nav(db), - hir::GenericParam::LifetimeParam(it) => it.try_to_nav(db), + hir::GenericParam::TypeParam(it) => it.try_to_nav_hir(db), + hir::GenericParam::ConstParam(it) => it.try_to_nav_hir(db), + hir::GenericParam::LifetimeParam(it) => it.try_to_nav_hir(db), } } } impl ToNav for LocalSource { - fn to_nav(&self, db: &RootDatabase) -> UpmappingResult { + fn to_nav_hir(&self, db: &RootDatabase) -> HirNavigationTarget { let InFile { file_id, value } = &self.source; let file_id = *file_id; let local = self.local; - let (node, name) = match &value { + let (node, name_n) = match &value { Either::Left(bind_pat) => (bind_pat.syntax(), bind_pat.name()), Either::Right(it) => (it.syntax(), it.name()), }; let edition = self.local.parent(db).module(db).krate().edition(db); - - orig_range_with_focus(db, file_id, node, name).map( - |(FileRange { file_id, range: full_range }, focus_range)| { - let name = local.name(db).display_no_db(edition).to_smolstr(); - let kind = if local.is_self(db) { - SymbolKind::SelfParam - } else if local.is_param(db) { - SymbolKind::ValueParam - } else { - SymbolKind::Local - }; - NavigationTarget { - file_id, - name, - alias: None, - kind: Some(kind), - full_range, - focus_range, - container_name: None, - description: None, - docs: None, - } - }, - ) + let name = local.name(db).display_no_db(edition).to_smolstr(); + let kind = if local.is_self(db) { + SymbolKind::SelfParam + } else if local.is_param(db) { + SymbolKind::ValueParam + } else { + SymbolKind::Local + }; + NavigationTarget { + file_id, + name, + alias: None, + kind: Some(kind), + full_range: node.text_range(), + focus_range: name_n.map(|it| it.syntax().text_range()), + container_name: None, + description: None, + docs: None, + } } } impl ToNav for hir::Local { - fn to_nav(&self, db: &RootDatabase) -> UpmappingResult { - self.primary_source(db).to_nav(db) + fn to_nav_hir(&self, db: &RootDatabase) -> HirNavigationTarget { + self.primary_source(db).to_nav_hir(db) } } impl TryToNav for hir::Label { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { let InFile { file_id, value } = self.source(db)?; // Labels can't be keywords, so no escaping needed. let name = self.name(db).display_no_db(Edition::Edition2015).to_smolstr(); - Some(orig_range_with_focus(db, file_id, value.syntax(), value.lifetime()).map( - |(FileRange { file_id, range: full_range }, focus_range)| NavigationTarget { - file_id, - name: name.clone(), - alias: None, - kind: Some(SymbolKind::Label), - full_range, - focus_range, - container_name: None, - description: None, - docs: None, - }, - )) + Some(NavigationTarget { + file_id, + name: name.clone(), + alias: None, + kind: Some(SymbolKind::Label), + full_range: value.syntax().text_range(), + focus_range: value.lifetime().map(|it| it.syntax().text_range()), + container_name: None, + description: None, + docs: None, + }) } } impl TryToNav for hir::TypeParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { let InFile { file_id, value } = self.merge().source(db)?; let edition = self.module(db).krate().edition(db); let name = self.name(db).display_no_db(edition).to_smolstr(); @@ -631,52 +650,48 @@ impl TryToNav for hir::TypeParam { }; let focus = value.as_ref().either(|it| it.name(), |it| it.name()); - Some(orig_range_with_focus(db, file_id, syntax, focus).map( - |(FileRange { file_id, range: full_range }, focus_range)| NavigationTarget { - file_id, - name: name.clone(), - alias: None, - kind: Some(SymbolKind::TypeParam), - full_range, - focus_range, - container_name: None, - description: None, - docs: None, - }, - )) + Some(NavigationTarget { + file_id, + name: name.clone(), + alias: None, + kind: Some(SymbolKind::TypeParam), + full_range: syntax.text_range(), + focus_range: focus.map(|it| it.syntax().text_range()), + container_name: None, + description: None, + docs: None, + }) } } impl TryToNav for hir::TypeOrConstParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { - self.split(db).try_to_nav(db) + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { + self.split(db).try_to_nav_hir(db) } } impl TryToNav for hir::LifetimeParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { let InFile { file_id, value } = self.source(db)?; // Lifetimes cannot be keywords, so not escaping needed. let name = self.name(db).display_no_db(Edition::Edition2015).to_smolstr(); - Some(orig_range(db, file_id, value.syntax()).map( - |(FileRange { file_id, range: full_range }, focus_range)| NavigationTarget { - file_id, - name: name.clone(), - alias: None, - kind: Some(SymbolKind::LifetimeParam), - full_range, - focus_range, - container_name: None, - description: None, - docs: None, - }, - )) + Some(NavigationTarget { + file_id, + name: name.clone(), + alias: None, + kind: Some(SymbolKind::LifetimeParam), + full_range: value.syntax().text_range(), + focus_range: value.lifetime().map(|it| it.syntax().text_range()), + container_name: None, + description: None, + docs: None, + }) } } impl TryToNav for hir::ConstParam { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { let InFile { file_id, value } = self.merge().source(db)?; let edition = self.module(db).krate().edition(db); let name = self.name(db).display_no_db(edition).to_smolstr(); @@ -689,44 +704,38 @@ impl TryToNav for hir::ConstParam { } }; - Some(orig_range_with_focus(db, file_id, value.syntax(), value.name()).map( - |(FileRange { file_id, range: full_range }, focus_range)| NavigationTarget { - file_id, - name: name.clone(), - alias: None, - kind: Some(SymbolKind::ConstParam), - full_range, - focus_range, - container_name: None, - description: None, - docs: None, - }, - )) + Some(NavigationTarget { + file_id, + name: name.clone(), + alias: None, + kind: Some(SymbolKind::ConstParam), + full_range: value.syntax().text_range(), + focus_range: value.name().map(|it| it.syntax().text_range()), + container_name: None, + description: None, + docs: None, + }) } } impl TryToNav for hir::InlineAsmOperand { - fn try_to_nav(&self, db: &RootDatabase) -> Option> { + fn try_to_nav_hir(&self, db: &RootDatabase) -> Option { let InFile { file_id, value } = &self.source(db)?; let file_id = *file_id; - Some(orig_range_with_focus(db, file_id, value.syntax(), value.name()).map( - |(FileRange { file_id, range: full_range }, focus_range)| { - let edition = self.parent(db).module(db).krate().edition(db); - NavigationTarget { - file_id, - name: self - .name(db) - .map_or_else(|| "_".into(), |it| it.display(db, edition).to_smolstr()), - alias: None, - kind: Some(SymbolKind::Local), - full_range, - focus_range, - container_name: None, - description: None, - docs: None, - } - }, - )) + let edition = self.parent(db).module(db).krate().edition(db); + Some(NavigationTarget { + file_id, + name: self + .name(db) + .map_or_else(|| "_".into(), |it| it.display(db, edition).to_smolstr()), + alias: None, + kind: Some(SymbolKind::Local), + full_range: value.syntax().text_range(), + focus_range: value.name().map(|it| it.syntax().text_range()), + container_name: None, + description: None, + docs: None, + }) } } @@ -768,39 +777,35 @@ impl UpmappingResult { } } -/// Returns the original range of the syntax node, and the range of the name mapped out of macro expansions -/// May return two results if the mapped node originates from a macro definition in which case the -/// second result is the creating macro call. fn orig_range_with_focus( - db: &RootDatabase, - hir_file: HirFileId, - value: &SyntaxNode, - name: Option, -) -> UpmappingResult<(FileRange, Option)> { - orig_range_with_focus_r( - db, - hir_file, - value.text_range(), - name.map(|it| it.syntax().text_range()), - ) -} - -pub(crate) fn orig_range_with_focus_r( db: &RootDatabase, hir_file: HirFileId, value: TextRange, focus_range: Option, ) -> UpmappingResult<(FileRange, Option)> { - let Some(name) = focus_range else { return orig_range_r(db, hir_file, value) }; + let macro_file = match hir_file.repr() { + span::HirFileIdRepr::FileId(editioned_file_id) => { + return UpmappingResult { + call_site: ( + FileRange { file_id: editioned_file_id.into(), range: value }, + focus_range, + ), + def_site: None, + } + } + span::HirFileIdRepr::MacroFile(macro_file) => macro_file, + }; + let call_site_fallback = || UpmappingResult { + call_site: (InFile::new(hir_file, value).original_node_file_range(db).0.into(), None), + def_site: None, + }; - let call_kind = - || db.lookup_intern_macro_call(hir_file.macro_file().unwrap().macro_call_id).kind; + let Some(name) = focus_range else { return call_site_fallback() }; - let def_range = || { - db.lookup_intern_macro_call(hir_file.macro_file().unwrap().macro_call_id) - .def - .definition_range(db) - }; + let call_kind = || db.lookup_intern_macro_call(macro_file.macro_call_id).kind; + + let def_range = + || db.lookup_intern_macro_call(macro_file.macro_call_id).def.definition_range(db); // FIXME: Also make use of the syntax context to determine which site we are at? let value_range = InFile::new(hir_file, value).original_node_file_range_opt(db); @@ -872,7 +877,7 @@ pub(crate) fn orig_range_with_focus_r( } } // lost name? can't happen for single tokens - None => return orig_range_r(db, hir_file, value), + None => return call_site_fallback(), }; UpmappingResult { @@ -904,25 +909,64 @@ pub(crate) fn orig_range_with_focus_r( } } -fn orig_range( - db: &RootDatabase, - hir_file: HirFileId, - value: &SyntaxNode, -) -> UpmappingResult<(FileRange, Option)> { - UpmappingResult { - call_site: (InFile::new(hir_file, value).original_file_range_rooted(db).into(), None), - def_site: None, - } -} - -fn orig_range_r( +fn orig_ranges_with_focus_in( db: &RootDatabase, hir_file: HirFileId, value: TextRange, -) -> UpmappingResult<(FileRange, Option)> { - UpmappingResult { - call_site: (InFile::new(hir_file, value).original_node_file_range(db).0.into(), None), - def_site: None, + focus_range: Option, + target: HirFileId, +) -> Option)>>> { + let (mut current, target) = match (hir_file.repr(), target.repr()) { + (span::HirFileIdRepr::FileId(file_id), span::HirFileIdRepr::FileId(target_file_id)) + if file_id == target_file_id => + { + return Some(InFile::new(target, vec![(value, focus_range)])); + } + ( + span::HirFileIdRepr::FileId(_), + span::HirFileIdRepr::FileId(_) | span::HirFileIdRepr::MacroFile(_), + ) => return None, + (span::HirFileIdRepr::MacroFile(_), span::HirFileIdRepr::FileId(target_file_id)) => { + let r = orig_range_with_focus(db, hir_file, value, focus_range); + if r.call_site.0.file_id != target_file_id { + return None; + } + let mut ranges = vec![]; + ranges.push((r.call_site.0.range, r.call_site.1)); + + if let Some((def_range, def_focus)) = + r.def_site.filter(|it| it.0.file_id == target_file_id) + { + ranges.push((def_range.range, def_focus)); + } + return Some(InFile::new(target, ranges)); + } + (span::HirFileIdRepr::MacroFile(current), span::HirFileIdRepr::MacroFile(target)) => { + (current, target) + } + }; + let expansion_span_map = db.expansion_span_map(current); + let span = expansion_span_map.span_at(value.start()); + // FIXME: Use this + let _focus_span = + focus_range.map(|focus_range| expansion_span_map.span_at(focus_range.start())); + loop { + let parent = current.parent(db).macro_file()?; + if parent == target { + let arg_map = db.expansion_span_map(parent); + let arg_node = current.call_node(db); + let arg_range = arg_node.text_range(); + break Some(InFile::new( + parent.into(), + arg_map + .ranges_with_span_exact(span) + .filter(|(range, _)| range.intersect(arg_range).is_some()) + .map(TupleExt::head) + .zip(iter::repeat(None)) + .collect(), + )); + } + current = parent; } } @@ -945,8 +989,9 @@ fn foo() { enum FooInner { } } expect![[r#" [ NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 0..17, focus_range: 5..13, @@ -955,8 +1000,9 @@ fn foo() { enum FooInner { } } description: "enum FooInner", }, NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 29..46, focus_range: 34..42, diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs index 6d82f9b0634b..146233c55d5b 100644 --- a/crates/ide/src/parent_module.rs +++ b/crates/ide/src/parent_module.rs @@ -1,7 +1,7 @@ -use hir::{db::DefDatabase, Semantics}; +use hir::{db::DefDatabase, HirFilePosition, Semantics}; use ide_db::{ base_db::{CrateId, FileLoader}, - FileId, FilePosition, RootDatabase, + FileId, RootDatabase, }; use itertools::Itertools; use syntax::{ @@ -9,7 +9,7 @@ use syntax::{ ast::{self, AstNode}, }; -use crate::NavigationTarget; +use crate::navigation_target::HirNavigationTarget; // Feature: Parent Module // @@ -22,11 +22,15 @@ use crate::NavigationTarget; // ![Parent Module](https://user-images.githubusercontent.com/48062697/113065580-04c21800-91b1-11eb-9a32-00086161c0bd.gif) /// This returns `Vec` because a module may be included from several places. -pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec { +pub(crate) fn parent_module( + db: &RootDatabase, + mut position: HirFilePosition, +) -> Vec { let sema = Semantics::new(db); - let source_file = sema.parse_guess_edition(position.file_id); + position.file_id = sema.adjust_edition(position.file_id); + let syntax = sema.parse_or_expand(position.file_id); - let mut module = find_node_at_offset::(source_file.syntax(), position.offset); + let mut module = find_node_at_offset::(&syntax, position.offset); // If cursor is literally on `mod foo`, go to the grandpa. if let Some(m) = &module { @@ -43,11 +47,11 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec sema .to_def(&module) .into_iter() - .flat_map(|module| NavigationTarget::from_module_to_decl(db, module)) + .map(|module| HirNavigationTarget::from_module_to_decl(db, module)) .collect(), None => sema - .file_to_module_defs(position.file_id) - .flat_map(|module| NavigationTarget::from_module_to_decl(db, module)) + .hir_file_to_module_defs(position.file_id) + .map(|module| HirNavigationTarget::from_module_to_decl(db, module)) .collect(), } } @@ -64,18 +68,21 @@ pub(crate) fn crates_for(db: &RootDatabase, file_id: FileId) -> Vec { #[cfg(test)] mod tests { - use ide_db::FileRange; + use hir::HirFileRange; use crate::fixture; fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, expected) = fixture::annotations(ra_fixture); - let navs = analysis.parent_module(position).unwrap(); + let navs = analysis.parent_module(position.into()).unwrap(); let navs = navs .iter() - .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) + .map(|nav| HirFileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) .collect::>(); - assert_eq!(expected.into_iter().map(|(fr, _)| fr).collect::>(), navs); + assert_eq!( + expected.into_iter().map(|(r, _)| r.into()).collect::>(), + navs + ); } #[test] @@ -149,7 +156,7 @@ $0 mod foo; "#, ); - assert_eq!(analysis.crates_for(file_id).unwrap().len(), 1); + assert_eq!(analysis.crates_for(file_id.into()).unwrap().len(), 1); } #[test] @@ -164,6 +171,6 @@ mod baz; mod baz; "#, ); - assert_eq!(analysis.crates_for(file_id).unwrap().len(), 2); + assert_eq!(analysis.crates_for(file_id.into()).unwrap().len(), 2); } } diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 069818d50e76..ff16afff2bda 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -9,15 +9,13 @@ //! at the index that the match starts at and its tree parent is //! resolved to the search element definition, we get a reference. -use hir::{PathResolution, Semantics}; +use hir::{HirFileId, HirFileIdExt, HirFilePosition, PathResolution, Semantics}; use ide_db::{ defs::{Definition, NameClass, NameRefClass}, search::{ReferenceCategory, SearchScope, UsageSearchResult}, - FileId, RootDatabase, + FxHashMap, RootDatabase, }; use itertools::Itertools; -use nohash_hasher::IntMap; -use span::Edition; use syntax::{ ast::{self, HasName}, match_ast, AstNode, @@ -25,17 +23,19 @@ use syntax::{ SyntaxNode, TextRange, TextSize, T, }; -use crate::{highlight_related, FilePosition, HighlightedRange, NavigationTarget, TryToNav}; +use crate::{ + highlight_related, navigation_target::HirNavigationTarget, HighlightedRange, TryToNav, +}; #[derive(Debug, Clone)] pub struct ReferenceSearchResult { pub declaration: Option, - pub references: IntMap>, + pub references: FxHashMap>, } #[derive(Debug, Clone)] pub struct Declaration { - pub nav: NavigationTarget, + pub nav: HirNavigationTarget, pub is_mut: bool, } @@ -50,11 +50,12 @@ pub struct Declaration { // ![Find All References](https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif) pub(crate) fn find_all_refs( sema: &Semantics<'_, RootDatabase>, - position: FilePosition, + mut position: HirFilePosition, search_scope: Option, ) -> Option> { let _p = tracing::info_span!("find_all_refs").entered(); - let syntax = sema.parse_guess_edition(position.file_id).syntax().clone(); + position.file_id = sema.adjust_edition(position.file_id); + let syntax = sema.parse_or_expand(position.file_id); let make_searcher = |literal_search: bool| { move |def: Definition| { let mut usages = @@ -63,11 +64,11 @@ pub(crate) fn find_all_refs( retain_adt_literal_usages(&mut usages, def, sema); } - let mut references: IntMap> = usages + let references: FxHashMap> = usages .into_iter() .map(|(file_id, refs)| { ( - file_id.into(), + file_id, refs.into_iter() .map(|file_ref| (file_ref.range, file_ref.category)) .unique() @@ -77,32 +78,20 @@ pub(crate) fn find_all_refs( .collect(); let declaration = match def { Definition::Module(module) => { - Some(NavigationTarget::from_module_to_decl(sema.db, module)) + Some(HirNavigationTarget::from_module_to_decl(sema.db, module)) } - def => def.try_to_nav(sema.db), + def => def.try_to_nav_hir(sema.db), } - .map(|nav| { - let (nav, extra_ref) = match nav.def_site { - Some(call) => (call, Some(nav.call_site)), - None => (nav.call_site, None), - }; - if let Some(extra_ref) = extra_ref { - references - .entry(extra_ref.file_id) - .or_default() - .push((extra_ref.focus_or_full_range(), ReferenceCategory::empty())); - } - Declaration { - is_mut: matches!(def, Definition::Local(l) if l.is_mut(sema.db)), - nav, - } + .map(|nav| Declaration { + is_mut: matches!(def, Definition::Local(l) if l.is_mut(sema.db)), + nav, }); ReferenceSearchResult { declaration, references } } }; // Find references for control-flow keywords. - if let Some(res) = handle_control_flow_keywords(sema, position) { + if let Some(res) = handle_control_flow_keywords(sema, &syntax, position) { return Some(vec![res]); } @@ -142,7 +131,9 @@ pub(crate) fn find_defs<'a>( ) })?; - if let Some((_, resolution)) = sema.check_for_format_args_template(token.clone(), offset) { + if let Some((_, _token, resolution)) = + sema.check_for_format_args_template(token.clone(), offset) + { return resolution.map(Definition::from).map(|it| vec![it]); } @@ -219,7 +210,10 @@ fn retain_adt_literal_usages( } /// Returns `Some` if the cursor is at a position for an item to search for all its constructor/literal usages -fn name_for_constructor_search(syntax: &SyntaxNode, position: FilePosition) -> Option { +fn name_for_constructor_search( + syntax: &SyntaxNode, + position: HirFilePosition, +) -> Option { let token = syntax.token_at_offset(position.offset).right_biased()?; let token_parent = token.parent()?; let kind = token.kind(); @@ -303,12 +297,11 @@ fn is_lit_name_ref(name_ref: &ast::NameRef) -> bool { fn handle_control_flow_keywords( sema: &Semantics<'_, RootDatabase>, - FilePosition { file_id, offset }: FilePosition, + syntax: &SyntaxNode, + HirFilePosition { file_id, offset }: HirFilePosition, ) -> Option { - let file = sema.parse_guess_edition(file_id); - let edition = - sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT); - let token = file.syntax().token_at_offset(offset).find(|t| t.kind().is_keyword(edition))?; + let edition = file_id.edition(sema.db); + let token = syntax.token_at_offset(offset).find(|t| t.kind().is_keyword(edition))?; let references = match token.kind() { T![fn] | T![return] | T![try] => highlight_related::highlight_exit_points(sema, token), @@ -327,7 +320,7 @@ fn handle_control_flow_keywords( .into_iter() .map(|HighlightedRange { range, category }| (range, category)) .collect(); - (file_id.into(), ranges) + (file_id, ranges) }) .collect(); @@ -359,10 +352,10 @@ fn test() { } "#, expect![[r#" - test_func Function FileId(0) 0..17 3..12 + test_func Function EditionedFileId(0, Edition2021) 0..17 3..12 - FileId(0) 35..44 - FileId(0) 75..84 test + EditionedFileId(0, Edition2021) 35..44 + EditionedFileId(0, Edition2021) 75..84 test "#]], ); @@ -380,10 +373,10 @@ fn test() { } "#, expect![[r#" - test_func Function FileId(0) 0..17 3..12 + test_func Function EditionedFileId(0, Edition2021) 0..17 3..12 - FileId(0) 35..44 - FileId(0) 96..105 test + EditionedFileId(0, Edition2021) 35..44 + EditionedFileId(0, Edition2021) 96..105 test "#]], ); } @@ -401,10 +394,10 @@ fn test() { } "#, expect![[r#" - f Field FileId(0) 11..17 11..12 + f Field EditionedFileId(0, Edition2021) 11..17 11..12 - FileId(0) 61..62 read test - FileId(0) 76..77 write test + EditionedFileId(0, Edition2021) 61..62 read test + EditionedFileId(0, Edition2021) 76..77 write test "#]], ); } @@ -425,9 +418,9 @@ fn main() { } "#, expect![[r#" - Foo Struct FileId(0) 0..26 7..10 + Foo Struct EditionedFileId(0, Edition2021) 0..26 7..10 - FileId(0) 101..104 + EditionedFileId(0, Edition2021) 101..104 "#]], ); } @@ -443,10 +436,10 @@ struct Foo$0 {} } "#, expect![[r#" - Foo Struct FileId(0) 0..13 7..10 + Foo Struct EditionedFileId(0, Edition2021) 0..13 7..10 - FileId(0) 41..44 - FileId(0) 54..57 + EditionedFileId(0, Edition2021) 41..44 + EditionedFileId(0, Edition2021) 54..57 "#]], ); } @@ -462,9 +455,9 @@ struct Foo $0{} } "#, expect![[r#" - Foo Struct FileId(0) 0..16 7..10 + Foo Struct EditionedFileId(0, Edition2021) 0..16 7..10 - FileId(0) 64..67 + EditionedFileId(0, Edition2021) 64..67 "#]], ); } @@ -481,9 +474,9 @@ fn main() { } "#, expect![[r#" - Foo Struct FileId(0) 0..16 7..10 + Foo Struct EditionedFileId(0, Edition2021) 0..16 7..10 - FileId(0) 54..57 + EditionedFileId(0, Edition2021) 54..57 "#]], ); } @@ -502,9 +495,9 @@ fn main() { } "#, expect![[r#" - Foo Union FileId(0) 0..24 6..9 + Foo Union EditionedFileId(0, Edition2021) 0..24 6..9 - FileId(0) 62..65 + EditionedFileId(0, Edition2021) 62..65 "#]], ); } @@ -526,11 +519,11 @@ fn main() { } "#, expect![[r#" - Foo Enum FileId(0) 0..37 5..8 + Foo Enum EditionedFileId(0, Edition2021) 0..37 5..8 - FileId(0) 74..77 - FileId(0) 90..93 - FileId(0) 108..111 + EditionedFileId(0, Edition2021) 74..77 + EditionedFileId(0, Edition2021) 90..93 + EditionedFileId(0, Edition2021) 108..111 "#]], ); } @@ -550,9 +543,9 @@ fn main() { } "#, expect![[r#" - A Variant FileId(0) 15..27 15..16 + A Variant EditionedFileId(0, Edition2021) 15..27 15..16 - FileId(0) 95..96 + EditionedFileId(0, Edition2021) 95..96 "#]], ); } @@ -572,9 +565,9 @@ fn main() { } "#, expect![[r#" - A Variant FileId(0) 15..21 15..16 + A Variant EditionedFileId(0, Edition2021) 15..21 15..16 - FileId(0) 89..90 + EditionedFileId(0, Edition2021) 89..90 "#]], ); } @@ -593,10 +586,10 @@ fn main() { } "#, expect![[r#" - Foo Enum FileId(0) 0..26 5..8 + Foo Enum EditionedFileId(0, Edition2021) 0..26 5..8 - FileId(0) 50..53 - FileId(0) 63..66 + EditionedFileId(0, Edition2021) 50..53 + EditionedFileId(0, Edition2021) 63..66 "#]], ); } @@ -615,9 +608,9 @@ fn main() { } "#, expect![[r#" - Foo Enum FileId(0) 0..32 5..8 + Foo Enum EditionedFileId(0, Edition2021) 0..32 5..8 - FileId(0) 73..76 + EditionedFileId(0, Edition2021) 73..76 "#]], ); } @@ -636,9 +629,9 @@ fn main() { } "#, expect![[r#" - Foo Enum FileId(0) 0..33 5..8 + Foo Enum EditionedFileId(0, Edition2021) 0..33 5..8 - FileId(0) 70..73 + EditionedFileId(0, Edition2021) 70..73 "#]], ); } @@ -659,12 +652,12 @@ fn main() { i = 5; }"#, expect![[r#" - i Local FileId(0) 20..25 24..25 write + i Local EditionedFileId(0, Edition2021) 20..25 24..25 write - FileId(0) 50..51 write - FileId(0) 54..55 read - FileId(0) 76..77 write - FileId(0) 94..95 write + EditionedFileId(0, Edition2021) 50..51 write + EditionedFileId(0, Edition2021) 54..55 read + EditionedFileId(0, Edition2021) 76..77 write + EditionedFileId(0, Edition2021) 94..95 write "#]], ); } @@ -683,10 +676,10 @@ fn bar() { } "#, expect![[r#" - spam Local FileId(0) 19..23 19..23 + spam Local EditionedFileId(0, Edition2021) 19..23 19..23 - FileId(0) 34..38 read - FileId(0) 41..45 read + EditionedFileId(0, Edition2021) 34..38 read + EditionedFileId(0, Edition2021) 41..45 read "#]], ); } @@ -698,9 +691,9 @@ fn bar() { fn foo(i : u32) -> u32 { i$0 } "#, expect![[r#" - i ValueParam FileId(0) 7..8 7..8 + i ValueParam EditionedFileId(0, Edition2021) 7..8 7..8 - FileId(0) 25..26 read + EditionedFileId(0, Edition2021) 25..26 read "#]], ); } @@ -712,9 +705,9 @@ fn foo(i : u32) -> u32 { i$0 } fn foo(i$0 : u32) -> u32 { i } "#, expect![[r#" - i ValueParam FileId(0) 7..8 7..8 + i ValueParam EditionedFileId(0, Edition2021) 7..8 7..8 - FileId(0) 25..26 read + EditionedFileId(0, Edition2021) 25..26 read "#]], ); } @@ -733,9 +726,9 @@ fn main(s: Foo) { } "#, expect![[r#" - spam Field FileId(0) 17..30 21..25 + spam Field EditionedFileId(0, Edition2021) 17..30 21..25 - FileId(0) 67..71 read + EditionedFileId(0, Edition2021) 67..71 read "#]], ); } @@ -750,7 +743,7 @@ impl Foo { } "#, expect![[r#" - f Function FileId(0) 27..43 30..31 + f Function EditionedFileId(0, Edition2021) 27..43 30..31 (no references) "#]], @@ -768,7 +761,7 @@ enum Foo { } "#, expect![[r#" - B Variant FileId(0) 22..23 22..23 + B Variant EditionedFileId(0, Edition2021) 22..23 22..23 (no references) "#]], @@ -786,7 +779,7 @@ enum Foo { } "#, expect![[r#" - field Field FileId(0) 26..35 26..31 + field Field EditionedFileId(0, Edition2021) 26..35 26..31 (no references) "#]], @@ -810,11 +803,11 @@ impl S { } "#, expect![[r#" - S Struct FileId(0) 0..38 7..8 + S Struct EditionedFileId(0, Edition2021) 0..38 7..8 - FileId(0) 48..49 - FileId(0) 71..75 - FileId(0) 86..90 + EditionedFileId(0, Edition2021) 48..49 + EditionedFileId(0, Edition2021) 71..75 + EditionedFileId(0, Edition2021) 86..90 "#]], ) } @@ -836,9 +829,9 @@ impl TestTrait for () { } "#, expect![[r#" - Assoc TypeAlias FileId(0) 92..108 97..102 + Assoc TypeAlias EditionedFileId(0, Edition2021) 92..108 97..102 - FileId(0) 31..36 + EditionedFileId(0, Edition2021) 31..36 "#]], ) } @@ -878,10 +871,10 @@ fn f() { } "#, expect![[r#" - Foo Struct FileId(1) 17..51 28..31 foo + Foo Struct EditionedFileId(1, Edition2021) 17..51 28..31 foo - FileId(0) 53..56 - FileId(2) 79..82 + EditionedFileId(2, Edition2021) 79..82 + EditionedFileId(0, Edition2021) 53..56 "#]], ); } @@ -905,9 +898,9 @@ pub struct Foo { } "#, expect![[r#" - foo Module FileId(0) 0..8 4..7 + foo Module EditionedFileId(0, Edition2021) 0..8 4..7 - FileId(0) 14..17 import + EditionedFileId(0, Edition2021) 14..17 import "#]], ); } @@ -923,9 +916,9 @@ mod foo; use self$0; "#, expect![[r#" - foo Module FileId(0) 0..8 4..7 + foo Module EditionedFileId(0, Edition2021) 0..8 4..7 - FileId(1) 4..8 import + EditionedFileId(1, Edition2021) 4..8 import "#]], ); } @@ -938,9 +931,9 @@ use self$0; use self$0; "#, expect![[r#" - Module FileId(0) 0..10 + Module EditionedFileId(0, Edition2021) 0..10 - FileId(0) 4..8 import + EditionedFileId(0, Edition2021) 4..8 import "#]], ); } @@ -966,10 +959,10 @@ pub(super) struct Foo$0 { } "#, expect![[r#" - Foo Struct FileId(2) 0..41 18..21 some + Foo Struct EditionedFileId(2, Edition2021) 0..41 18..21 some - FileId(1) 20..23 import - FileId(1) 47..50 + EditionedFileId(1, Edition2021) 20..23 import + EditionedFileId(1, Edition2021) 47..50 "#]], ); } @@ -994,10 +987,10 @@ pub(super) struct Foo$0 { code, None, expect![[r#" - quux Function FileId(0) 19..35 26..30 + quux Function EditionedFileId(0, Edition2021) 19..35 26..30 - FileId(1) 16..20 - FileId(2) 16..20 + EditionedFileId(1, Edition2021) 16..20 + EditionedFileId(2, Edition2021) 16..20 "#]], ); @@ -1005,9 +998,9 @@ pub(super) struct Foo$0 { code, Some(SearchScope::single_file(EditionedFileId::current_edition(FileId::from_raw(2)))), expect![[r#" - quux Function FileId(0) 19..35 26..30 + quux Function EditionedFileId(0, Edition2021) 19..35 26..30 - FileId(2) 16..20 + EditionedFileId(2, Edition2021) 16..20 "#]], ); } @@ -1025,10 +1018,10 @@ fn foo() { } "#, expect![[r#" - m1 Macro FileId(0) 0..46 29..31 + m1 Macro EditionedFileId(0, Edition2021) 0..46 29..31 - FileId(0) 63..65 - FileId(0) 73..75 + EditionedFileId(0, Edition2021) 63..65 + EditionedFileId(0, Edition2021) 73..75 "#]], ); } @@ -1043,10 +1036,10 @@ fn foo() { } "#, expect![[r#" - i Local FileId(0) 19..24 23..24 write + i Local EditionedFileId(0, Edition2021) 19..24 23..24 write - FileId(0) 34..35 write - FileId(0) 38..39 read + EditionedFileId(0, Edition2021) 34..35 write + EditionedFileId(0, Edition2021) 38..39 read "#]], ); } @@ -1065,10 +1058,10 @@ fn foo() { } "#, expect![[r#" - f Field FileId(0) 15..21 15..16 + f Field EditionedFileId(0, Edition2021) 15..21 15..16 - FileId(0) 55..56 read - FileId(0) 68..69 write + EditionedFileId(0, Edition2021) 55..56 read + EditionedFileId(0, Edition2021) 68..69 write "#]], ); } @@ -1083,9 +1076,9 @@ fn foo() { } "#, expect![[r#" - i Local FileId(0) 19..20 19..20 + i Local EditionedFileId(0, Edition2021) 19..20 19..20 - FileId(0) 26..27 write + EditionedFileId(0, Edition2021) 26..27 write "#]], ); } @@ -1107,9 +1100,9 @@ fn main() { } "#, expect![[r#" - new Function FileId(0) 54..81 61..64 + new Function EditionedFileId(0, Edition2021) 54..81 61..64 - FileId(0) 126..129 + EditionedFileId(0, Edition2021) 126..129 "#]], ); } @@ -1129,10 +1122,10 @@ use crate::f; fn g() { f(); } "#, expect![[r#" - f Function FileId(0) 22..31 25..26 + f Function EditionedFileId(0, Edition2021) 22..31 25..26 - FileId(1) 11..12 import - FileId(1) 24..25 + EditionedFileId(1, Edition2021) 11..12 import + EditionedFileId(1, Edition2021) 24..25 "#]], ); } @@ -1152,9 +1145,9 @@ fn f(s: S) { } "#, expect![[r#" - field Field FileId(0) 15..24 15..20 + field Field EditionedFileId(0, Edition2021) 15..24 15..20 - FileId(0) 68..73 read + EditionedFileId(0, Edition2021) 68..73 read "#]], ); } @@ -1176,9 +1169,9 @@ fn f(e: En) { } "#, expect![[r#" - field Field FileId(0) 32..41 32..37 + field Field EditionedFileId(0, Edition2021) 32..41 32..37 - FileId(0) 102..107 read + EditionedFileId(0, Edition2021) 102..107 read "#]], ); } @@ -1200,9 +1193,9 @@ fn f() -> m::En { } "#, expect![[r#" - field Field FileId(0) 56..65 56..61 + field Field EditionedFileId(0, Edition2021) 56..65 56..61 - FileId(0) 125..130 read + EditionedFileId(0, Edition2021) 125..130 read "#]], ); } @@ -1225,10 +1218,10 @@ impl Foo { } "#, expect![[r#" - self SelfParam FileId(0) 47..51 47..51 + self SelfParam EditionedFileId(0, Edition2021) 47..51 47..51 - FileId(0) 71..75 read - FileId(0) 152..156 read + EditionedFileId(0, Edition2021) 71..75 read + EditionedFileId(0, Edition2021) 152..156 read "#]], ); } @@ -1246,9 +1239,9 @@ impl Foo { } "#, expect![[r#" - self SelfParam FileId(0) 47..51 47..51 + self SelfParam EditionedFileId(0, Edition2021) 47..51 47..51 - FileId(0) 63..67 read + EditionedFileId(0, Edition2021) 63..67 read "#]], ); } @@ -1263,7 +1256,7 @@ impl Foo { expect: Expect, ) { let (analysis, pos) = fixture::position(ra_fixture); - let refs = analysis.find_all_refs(pos, search_scope).unwrap().unwrap(); + let refs = analysis.find_all_refs(pos.into(), search_scope).unwrap().unwrap(); let mut actual = String::new(); for mut refs in refs { @@ -1307,13 +1300,13 @@ fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> { } "#, expect![[r#" - 'a LifetimeParam FileId(0) 55..57 + 'a LifetimeParam EditionedFileId(0, Edition2021) 55..57 55..57 - FileId(0) 63..65 - FileId(0) 71..73 - FileId(0) 82..84 - FileId(0) 95..97 - FileId(0) 106..108 + EditionedFileId(0, Edition2021) 63..65 + EditionedFileId(0, Edition2021) 71..73 + EditionedFileId(0, Edition2021) 82..84 + EditionedFileId(0, Edition2021) 95..97 + EditionedFileId(0, Edition2021) 106..108 "#]], ); } @@ -1325,10 +1318,10 @@ fn foo<'a, 'b: 'a>(x: &'a$0 ()) -> &'a () where &'a (): Foo<'a> { type Foo<'a, T> where T: 'a$0 = &'a T; "#, expect![[r#" - 'a LifetimeParam FileId(0) 9..11 + 'a LifetimeParam EditionedFileId(0, Edition2021) 9..11 9..11 - FileId(0) 25..27 - FileId(0) 31..33 + EditionedFileId(0, Edition2021) 25..27 + EditionedFileId(0, Edition2021) 31..33 "#]], ); } @@ -1347,11 +1340,11 @@ impl<'a> Foo<'a> for &'a () { } "#, expect![[r#" - 'a LifetimeParam FileId(0) 47..49 + 'a LifetimeParam EditionedFileId(0, Edition2021) 47..49 47..49 - FileId(0) 55..57 - FileId(0) 64..66 - FileId(0) 89..91 + EditionedFileId(0, Edition2021) 55..57 + EditionedFileId(0, Edition2021) 64..66 + EditionedFileId(0, Edition2021) 89..91 "#]], ); } @@ -1367,9 +1360,9 @@ fn main() { } "#, expect![[r#" - a Local FileId(0) 59..60 59..60 + a Local EditionedFileId(0, Edition2021) 59..60 59..60 - FileId(0) 80..81 read + MacroFile(0) 0..1 read "#]], ); } @@ -1385,9 +1378,9 @@ fn main() { } "#, expect![[r#" - a Local FileId(0) 59..60 59..60 + a Local EditionedFileId(0, Edition2021) 59..60 59..60 - FileId(0) 80..81 read + MacroFile(0) 0..1 read "#]], ); } @@ -1406,10 +1399,10 @@ fn foo<'a>() -> &'a () { } "#, expect![[r#" - 'a Label FileId(0) 29..32 29..31 + 'a Label EditionedFileId(0, Edition2021) 29..32 29..31 - FileId(0) 80..82 - FileId(0) 108..110 + EditionedFileId(0, Edition2021) 80..82 + EditionedFileId(0, Edition2021) 108..110 "#]], ); } @@ -1423,9 +1416,9 @@ fn foo() -> usize { } "#, expect![[r#" - FOO ConstParam FileId(0) 7..23 13..16 + FOO ConstParam EditionedFileId(0, Edition2021) 7..23 13..16 - FileId(0) 42..45 + EditionedFileId(0, Edition2021) 42..45 "#]], ); } @@ -1439,9 +1432,9 @@ trait Foo$0 where Self: {} impl Foo for () {} "#, expect![[r#" - Foo Trait FileId(0) 0..24 6..9 + Foo Trait EditionedFileId(0, Edition2021) 0..24 6..9 - FileId(0) 31..34 + EditionedFileId(0, Edition2021) 31..34 "#]], ); } @@ -1457,10 +1450,10 @@ trait Foo where Self$0 { impl Foo for () {} "#, expect![[r#" - Self TypeParam FileId(0) 0..44 6..9 + Self TypeParam EditionedFileId(0, Edition2021) 0..44 6..9 - FileId(0) 16..20 - FileId(0) 37..41 + EditionedFileId(0, Edition2021) 16..20 + EditionedFileId(0, Edition2021) 37..41 "#]], ); } @@ -1476,11 +1469,11 @@ impl Foo for () {} } "#, expect![[r#" - Foo Struct FileId(0) 0..11 7..10 + Foo Struct EditionedFileId(0, Edition2021) 0..11 7..10 - FileId(0) 18..21 - FileId(0) 28..32 - FileId(0) 50..54 + EditionedFileId(0, Edition2021) 18..21 + EditionedFileId(0, Edition2021) 28..32 + EditionedFileId(0, Edition2021) 50..54 "#]], ); check( @@ -1492,11 +1485,11 @@ impl Foo where Self: { } "#, expect![[r#" - impl Impl FileId(0) 13..57 18..21 + impl Impl EditionedFileId(0, Edition2021) 13..57 18..21 - FileId(0) 18..21 - FileId(0) 28..32 - FileId(0) 50..54 + EditionedFileId(0, Edition2021) 18..21 + EditionedFileId(0, Edition2021) 28..32 + EditionedFileId(0, Edition2021) 50..54 "#]], ); } @@ -1516,9 +1509,9 @@ impl Foo { "#, expect![[r#" - Bar Variant FileId(0) 11..16 11..14 + Bar Variant EditionedFileId(0, Edition2021) 11..16 11..14 - FileId(0) 89..92 + EditionedFileId(0, Edition2021) 89..92 "#]], ); } @@ -1532,11 +1525,11 @@ trait Bar$0 = Foo where Self: ; fn foo(_: impl Bar, _: &dyn Bar) {} "#, expect![[r#" - Bar TraitAlias FileId(0) 13..42 19..22 + Bar TraitAlias EditionedFileId(0, Edition2021) 13..42 19..22 - FileId(0) 53..56 - FileId(0) 66..69 - FileId(0) 79..82 + EditionedFileId(0, Edition2021) 53..56 + EditionedFileId(0, Edition2021) 66..69 + EditionedFileId(0, Edition2021) 79..82 "#]], ); } @@ -1548,9 +1541,9 @@ fn foo(_: impl Bar, _: &dyn Bar) {} trait Foo = where Self$0: ; "#, expect![[r#" - Self TypeParam FileId(0) 0..25 6..9 + Self TypeParam EditionedFileId(0, Edition2021) 0..25 6..9 - FileId(0) 18..22 + EditionedFileId(0, Edition2021) 18..22 "#]], ); } @@ -1565,9 +1558,9 @@ fn test$0() { } "#, expect![[r#" - test Function FileId(0) 0..33 11..15 + test Function EditionedFileId(0, Edition2021) 0..33 11..15 - FileId(0) 24..28 test + EditionedFileId(0, Edition2021) 24..28 test "#]], ); } @@ -1587,12 +1580,12 @@ fn main() { } "#, expect![[r#" - A Const FileId(0) 0..18 6..7 + A Const EditionedFileId(0, Edition2021) 0..18 6..7 - FileId(0) 42..43 - FileId(0) 54..55 - FileId(0) 97..98 - FileId(0) 101..102 + EditionedFileId(0, Edition2021) 42..43 + EditionedFileId(0, Edition2021) 54..55 + EditionedFileId(0, Edition2021) 97..98 + EditionedFileId(0, Edition2021) 101..102 "#]], ); } @@ -1604,8 +1597,8 @@ fn main() { fn foo(_: bool) -> bo$0ol { true } "#, expect![[r#" - FileId(0) 10..14 - FileId(0) 19..23 + EditionedFileId(0, Edition2021) 10..14 + EditionedFileId(0, Edition2021) 19..23 "#]], ); } @@ -1624,11 +1617,11 @@ pub use level2::Foo; pub use level1::Foo; "#, expect![[r#" - Foo Struct FileId(0) 0..15 11..14 + Foo Struct EditionedFileId(0, Edition2021) 0..15 11..14 - FileId(1) 16..19 import - FileId(2) 16..19 import - FileId(3) 16..19 import + EditionedFileId(2, Edition2021) 16..19 import + EditionedFileId(1, Edition2021) 16..19 import + EditionedFileId(3, Edition2021) 16..19 import "#]], ); } @@ -1654,11 +1647,11 @@ foo!(); lib::foo!(); "#, expect![[r#" - foo Macro FileId(1) 0..61 29..32 + foo Macro EditionedFileId(1, Edition2021) 0..61 29..32 - FileId(0) 46..49 import - FileId(2) 0..3 - FileId(3) 5..8 + EditionedFileId(3, Edition2021) 5..8 + EditionedFileId(0, Edition2021) 46..49 import + EditionedFileId(2, Edition2021) 0..3 "#]], ); } @@ -1676,9 +1669,9 @@ m$0!(); "#, expect![[r#" - m Macro FileId(0) 0..32 13..14 + m Macro EditionedFileId(0, Edition2021) 0..32 13..14 - FileId(0) 64..65 + EditionedFileId(0, Edition2021) 64..65 "#]], ); } @@ -1705,14 +1698,14 @@ fn f() { } "#, expect![[r#" - func Function FileId(0) 137..146 140..144 module + func Function MacroFile(0) 10..23 15..19 module - FileId(0) 181..185 + EditionedFileId(0, Edition2021) 181..185 - func Function FileId(0) 137..146 140..144 + func Function MacroFile(0) 24..37 29..33 - FileId(0) 161..165 + EditionedFileId(0, Edition2021) 161..165 "#]], ) } @@ -1728,9 +1721,9 @@ fn func$0() { } "#, expect![[r#" - func Function FileId(0) 25..50 28..32 + func Function MacroFile(0) 0..17 2..6 - FileId(0) 41..45 + MacroFile(0) 9..13 "#]], ) } @@ -1749,9 +1742,9 @@ trait Trait { } "#, expect![[r#" - func Function FileId(0) 48..87 51..55 Trait + func Function MacroFile(0) 0..23 2..6 Trait - FileId(0) 74..78 + MacroFile(0) 15..19 "#]], ) } @@ -1768,9 +1761,9 @@ use proc_macros::identity; fn func() {} "#, expect![[r#" - identity Attribute FileId(1) 1..107 32..40 + identity Attribute EditionedFileId(1, Edition2021) 1..107 32..40 - FileId(0) 43..51 + EditionedFileId(0, Edition2021) 43..51 "#]], ); check( @@ -1780,7 +1773,7 @@ fn func() {} fn func$0() {} "#, expect![[r#" - func Attribute FileId(0) 28..64 55..59 + func Attribute EditionedFileId(0, Edition2021) 28..64 55..59 (no references) "#]], @@ -1798,9 +1791,9 @@ use proc_macros::mirror; mirror$0! {} "#, expect![[r#" - mirror ProcMacro FileId(1) 1..77 22..28 + mirror ProcMacro EditionedFileId(1, Edition2021) 1..77 22..28 - FileId(0) 26..32 + EditionedFileId(0, Edition2021) 26..32 "#]], ) } @@ -1817,10 +1810,10 @@ use proc_macros::DeriveIdentity; struct Foo; "#, expect![[r#" - derive_identity Derive FileId(2) 1..107 45..60 + derive_identity Derive EditionedFileId(2, Edition2021) 1..107 45..60 - FileId(0) 17..31 import - FileId(0) 56..70 + MacroFile(0) 17..31 + EditionedFileId(0, Edition2021) 17..31 import "#]], ); check( @@ -1830,7 +1823,7 @@ struct Foo; pub fn deri$0ve(_stream: TokenStream) -> TokenStream {} "#, expect![[r#" - derive Derive FileId(0) 28..125 79..85 + derive Derive EditionedFileId(0, Edition2021) 28..125 79..85 (no references) "#]], @@ -1860,12 +1853,12 @@ fn f() { } "#, expect![[r#" - CONST Const FileId(0) 18..37 24..29 Trait + CONST Const EditionedFileId(0, Edition2021) 18..37 24..29 Trait - FileId(0) 71..76 - FileId(0) 125..130 - FileId(0) 183..188 - FileId(0) 206..211 + EditionedFileId(0, Edition2021) 71..76 + EditionedFileId(0, Edition2021) 125..130 + EditionedFileId(0, Edition2021) 183..188 + EditionedFileId(0, Edition2021) 206..211 "#]], ); check( @@ -1889,12 +1882,12 @@ fn f() { } "#, expect![[r#" - TypeAlias TypeAlias FileId(0) 18..33 23..32 Trait + TypeAlias TypeAlias EditionedFileId(0, Edition2021) 18..33 23..32 Trait - FileId(0) 66..75 - FileId(0) 117..126 - FileId(0) 181..190 - FileId(0) 207..216 + EditionedFileId(0, Edition2021) 66..75 + EditionedFileId(0, Edition2021) 117..126 + EditionedFileId(0, Edition2021) 181..190 + EditionedFileId(0, Edition2021) 207..216 "#]], ); check( @@ -1918,12 +1911,12 @@ fn f() { } "#, expect![[r#" - function Function FileId(0) 18..34 21..29 Trait + function Function EditionedFileId(0, Edition2021) 18..34 21..29 Trait - FileId(0) 65..73 - FileId(0) 112..120 - FileId(0) 166..174 - FileId(0) 192..200 + EditionedFileId(0, Edition2021) 65..73 + EditionedFileId(0, Edition2021) 112..120 + EditionedFileId(0, Edition2021) 166..174 + EditionedFileId(0, Edition2021) 192..200 "#]], ); } @@ -1951,9 +1944,9 @@ fn f() { } "#, expect![[r#" - CONST Const FileId(0) 65..88 71..76 + CONST Const EditionedFileId(0, Edition2021) 65..88 71..76 - FileId(0) 183..188 + EditionedFileId(0, Edition2021) 183..188 "#]], ); check( @@ -1977,12 +1970,12 @@ fn f() { } "#, expect![[r#" - TypeAlias TypeAlias FileId(0) 61..81 66..75 + TypeAlias TypeAlias EditionedFileId(0, Edition2021) 61..81 66..75 - FileId(0) 23..32 - FileId(0) 117..126 - FileId(0) 181..190 - FileId(0) 207..216 + EditionedFileId(0, Edition2021) 23..32 + EditionedFileId(0, Edition2021) 117..126 + EditionedFileId(0, Edition2021) 181..190 + EditionedFileId(0, Edition2021) 207..216 "#]], ); check( @@ -2006,9 +1999,9 @@ fn f() { } "#, expect![[r#" - function Function FileId(0) 62..78 65..73 + function Function EditionedFileId(0, Edition2021) 62..78 65..73 - FileId(0) 166..174 + EditionedFileId(0, Edition2021) 166..174 "#]], ); } @@ -2036,9 +2029,9 @@ fn f() { } "#, expect![[r#" - CONST Const FileId(0) 65..88 71..76 + CONST Const EditionedFileId(0, Edition2021) 65..88 71..76 - FileId(0) 183..188 + EditionedFileId(0, Edition2021) 183..188 "#]], ); check( @@ -2062,12 +2055,12 @@ fn f() { } "#, expect![[r#" - TypeAlias TypeAlias FileId(0) 18..33 23..32 Trait + TypeAlias TypeAlias EditionedFileId(0, Edition2021) 18..33 23..32 Trait - FileId(0) 66..75 - FileId(0) 117..126 - FileId(0) 181..190 - FileId(0) 207..216 + EditionedFileId(0, Edition2021) 66..75 + EditionedFileId(0, Edition2021) 117..126 + EditionedFileId(0, Edition2021) 181..190 + EditionedFileId(0, Edition2021) 207..216 "#]], ); check( @@ -2091,9 +2084,9 @@ fn f() { } "#, expect![[r#" - function Function FileId(0) 62..78 65..73 + function Function EditionedFileId(0, Edition2021) 62..78 65..73 - FileId(0) 166..174 + EditionedFileId(0, Edition2021) 166..174 "#]], ); } @@ -2118,9 +2111,9 @@ impl Foo for Bar { fn method() {} "#, expect![[r#" - method Function FileId(0) 16..39 19..25 Foo + method Function EditionedFileId(0, Edition2021) 16..39 19..25 Foo - FileId(0) 101..107 + EditionedFileId(0, Edition2021) 101..107 "#]], ); check( @@ -2141,9 +2134,9 @@ impl Foo for Bar { fn method() {} "#, expect![[r#" - method Field FileId(0) 60..70 60..66 + method Field EditionedFileId(0, Edition2021) 60..70 60..66 - FileId(0) 136..142 read + EditionedFileId(0, Edition2021) 136..142 read "#]], ); check( @@ -2164,7 +2157,7 @@ impl Foo for Bar { fn method() {} "#, expect![[r#" - method Function FileId(0) 98..148 101..107 + method Function EditionedFileId(0, Edition2021) 98..148 101..107 (no references) "#]], @@ -2187,9 +2180,9 @@ impl Foo for Bar { fn method() {} "#, expect![[r#" - method Field FileId(0) 60..70 60..66 + method Field EditionedFileId(0, Edition2021) 60..70 60..66 - FileId(0) 136..142 read + EditionedFileId(0, Edition2021) 136..142 read "#]], ); check( @@ -2210,7 +2203,7 @@ impl Foo for Bar { fn method$0() {} "#, expect![[r#" - method Function FileId(0) 151..165 154..160 + method Function EditionedFileId(0, Edition2021) 151..165 154..160 (no references) "#]], @@ -2225,9 +2218,9 @@ fn r#fn$0() {} fn main() { r#fn(); } "#, expect![[r#" - r#fn Function FileId(0) 0..12 3..7 + r#fn Function EditionedFileId(0, Edition2021) 0..12 3..7 - FileId(0) 25..29 + EditionedFileId(0, Edition2021) 25..29 "#]], ); } @@ -2246,11 +2239,11 @@ fn test() { } "#, expect![[r#" - a Local FileId(0) 20..21 20..21 + a Local EditionedFileId(0, Edition2021) 20..21 20..21 - FileId(0) 56..57 read - FileId(0) 60..61 read - FileId(0) 68..69 read + MacroFile(7) 28..29 read + MacroFile(7) 32..33 read + MacroFile(7) 39..40 read "#]], ); } @@ -2285,9 +2278,9 @@ fn main() { } "#, expect![[r#" - FileId(0) 136..138 - FileId(0) 207..213 - FileId(0) 264..270 + EditionedFileId(0, Edition2021) 136..138 + EditionedFileId(0, Edition2021) 207..213 + EditionedFileId(0, Edition2021) 264..270 "#]], ) } @@ -2306,10 +2299,10 @@ fn$0 foo() -> u32 { } "#, expect![[r#" - FileId(0) 0..2 - FileId(0) 40..46 - FileId(0) 62..63 - FileId(0) 69..80 + EditionedFileId(0, Edition2021) 0..2 + EditionedFileId(0, Edition2021) 40..46 + EditionedFileId(0, Edition2021) 62..63 + EditionedFileId(0, Edition2021) 69..80 "#]], ); } @@ -2327,10 +2320,10 @@ pub async$0 fn foo() { } "#, expect![[r#" - FileId(0) 4..9 - FileId(0) 48..53 - FileId(0) 63..68 - FileId(0) 114..119 + EditionedFileId(0, Edition2021) 4..9 + EditionedFileId(0, Edition2021) 48..53 + EditionedFileId(0, Edition2021) 63..68 + EditionedFileId(0, Edition2021) 114..119 "#]], ); } @@ -2347,9 +2340,9 @@ fn main() { } "#, expect![[r#" - FileId(0) 16..19 - FileId(0) 40..45 - FileId(0) 55..63 + EditionedFileId(0, Edition2021) 16..19 + EditionedFileId(0, Edition2021) 40..45 + EditionedFileId(0, Edition2021) 55..63 "#]], ) } @@ -2366,8 +2359,8 @@ fn main() { } "#, expect![[r#" - FileId(0) 16..19 - FileId(0) 40..45 + EditionedFileId(0, Edition2021) 16..19 + EditionedFileId(0, Edition2021) 40..45 "#]], ) } @@ -2383,8 +2376,8 @@ fn main() { } "#, expect![[r#" - FileId(0) 16..19 - FileId(0) 29..37 + EditionedFileId(0, Edition2021) 16..19 + EditionedFileId(0, Edition2021) 29..37 "#]], ) } @@ -2407,10 +2400,10 @@ fn foo() { } "#, expect![[r#" - FileId(0) 15..27 - FileId(0) 39..44 - FileId(0) 127..139 - FileId(0) 178..183 + EditionedFileId(0, Edition2021) 15..27 + EditionedFileId(0, Edition2021) 39..44 + EditionedFileId(0, Edition2021) 127..139 + EditionedFileId(0, Edition2021) 178..183 "#]], ); } @@ -2431,9 +2424,9 @@ fn main() { } "#, expect![[r#" - FileId(0) 16..18 - FileId(0) 51..57 - FileId(0) 78..84 + EditionedFileId(0, Edition2021) 16..18 + EditionedFileId(0, Edition2021) 51..57 + EditionedFileId(0, Edition2021) 78..84 "#]], ) } @@ -2451,8 +2444,8 @@ fn main() { } "#, expect![[r#" - FileId(0) 16..19 - FileId(0) 84..89 + EditionedFileId(0, Edition2021) 16..19 + EditionedFileId(0, Edition2021) 84..89 "#]], ) } @@ -2468,8 +2461,8 @@ fn main() { } "#, expect![[r#" - FileId(0) 16..21 - FileId(0) 32..38 + EditionedFileId(0, Edition2021) 16..21 + EditionedFileId(0, Edition2021) 32..38 "#]], ) } @@ -2505,12 +2498,12 @@ fn main() { } "#, expect![[r#" - FileId(0) 46..48 - FileId(0) 106..108 - FileId(0) 122..149 - FileId(0) 135..141 - FileId(0) 165..181 - FileId(1) 6..12 + EditionedFileId(1, Edition2021) 6..12 + EditionedFileId(0, Edition2021) 46..48 + EditionedFileId(0, Edition2021) 106..108 + EditionedFileId(0, Edition2021) 122..149 + EditionedFileId(0, Edition2021) 135..141 + EditionedFileId(0, Edition2021) 165..181 "#]], ) } @@ -2536,10 +2529,10 @@ fn baz() { } "#, expect![[r#" - new Function FileId(0) 27..38 30..33 + new Function EditionedFileId(0, Edition2021) 27..38 30..33 - FileId(0) 62..65 - FileId(0) 91..94 + EditionedFileId(0, Edition2021) 62..65 + EditionedFileId(0, Edition2021) 91..94 "#]], ); } @@ -2586,11 +2579,11 @@ type Itself = T; pub(in super::super) type Baz = Itself; "#, expect![[r#" - new Function FileId(0) 42..53 45..48 + new Function EditionedFileId(0, Edition2021) 42..53 45..48 - FileId(0) 83..86 - FileId(1) 40..43 - FileId(1) 106..109 + EditionedFileId(1, Edition2021) 40..43 + EditionedFileId(1, Edition2021) 106..109 + EditionedFileId(0, Edition2021) 83..86 "#]], ); } @@ -2625,12 +2618,12 @@ impl super::Foo { fn foo() { ::Assoc::new(); } "#, expect![[r#" - new Function FileId(0) 40..51 43..46 + new Function EditionedFileId(0, Edition2021) 40..51 43..46 - FileId(0) 73..76 - FileId(0) 195..198 - FileId(1) 40..43 - FileId(1) 99..102 + EditionedFileId(1, Edition2021) 40..43 + EditionedFileId(1, Edition2021) 99..102 + EditionedFileId(0, Edition2021) 73..76 + EditionedFileId(0, Edition2021) 195..198 "#]], ); } @@ -2651,10 +2644,10 @@ impl Foo { } "#, expect![[r#" - new Function FileId(0) 27..38 30..33 + new Function EditionedFileId(0, Edition2021) 27..38 30..33 - FileId(0) 68..71 - FileId(0) 123..126 + EditionedFileId(0, Edition2021) 68..71 + EditionedFileId(0, Edition2021) 123..126 "#]], ); } @@ -2682,10 +2675,10 @@ impl Foo { } "#, expect![[r#" - new Function FileId(0) 27..38 30..33 + new Function EditionedFileId(0, Edition2021) 27..38 30..33 - FileId(0) 188..191 - FileId(0) 233..236 + EditionedFileId(0, Edition2021) 188..191 + EditionedFileId(0, Edition2021) 233..236 "#]], ); } @@ -2722,7 +2715,7 @@ fn bar() { } "#, expect![[r#" - new Function FileId(0) 27..38 30..33 + new Function EditionedFileId(0, Edition2021) 27..38 30..33 (no references) "#]], @@ -2748,9 +2741,9 @@ impl Foo { } "#, expect![[r#" - new Function FileId(0) 27..38 30..33 + new Function EditionedFileId(0, Edition2021) 27..38 30..33 - FileId(0) 131..134 + EditionedFileId(0, Edition2021) 131..134 "#]], ); } @@ -2769,9 +2762,9 @@ fn howdy() { const FOO$0: i32 = 0; "#, expect![[r#" - FOO Const FileId(1) 0..19 6..9 + FOO Const MacroFile(1) 0..15 5..8 - FileId(0) 45..48 + EditionedFileId(0, Edition2021) 45..48 "#]], ); } diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs index 3e8295e3f08e..f9ac9ee012e2 100644 --- a/crates/ide/src/rename.rs +++ b/crates/ide/src/rename.rs @@ -12,8 +12,9 @@ use ide_db::{ FileId, FileRange, RootDatabase, }; use itertools::Itertools; +use span::EditionedFileId; use stdx::{always, never}; -use syntax::{ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize}; +use syntax::{ast, AstNode, AstToken, SyntaxKind, SyntaxNode, TextRange, TextSize}; use ide_db::text_edit::TextEdit; @@ -30,10 +31,13 @@ pub(crate) fn prepare_rename( position: FilePosition, ) -> RenameResult> { let sema = Semantics::new(db); - let source_file = sema.parse_guess_edition(position.file_id); + let file_id = sema + .attach_first_edition(position.file_id) + .ok_or_else(|| format_err!("No references found at position"))?; + let source_file = sema.parse(file_id); let syntax = source_file.syntax(); - let res = find_definitions(&sema, syntax, position)? + let res = find_definitions(&sema, syntax, file_id, position.offset)? .map(|(frange, kind, def)| { // ensure all ranges are valid @@ -88,7 +92,7 @@ pub(crate) fn rename( let source_file = sema.parse(file_id); let syntax = source_file.syntax(); - let defs = find_definitions(&sema, syntax, position)?; + let defs = find_definitions(&sema, syntax, file_id, position.offset)?; let alias_fallback = alias_fallback(syntax, position, new_name); let ops: RenameResult> = match alias_fallback { @@ -104,7 +108,7 @@ pub(crate) fn rename( IdentifierKind::Underscore => bail!("Cannot alias reference to `_`"), }; - let mut usages = def.usages(&sema).all(); + let mut usages = def.usages(&sema).all().map_out_of_macros(&sema); // FIXME: hack - removes the usage that triggered this rename operation. match usages.references.get_mut(&file_id).and_then(|refs| { @@ -157,7 +161,7 @@ pub(crate) fn will_rename_file( new_name_stem: &str, ) -> Option { let sema = Semantics::new(db); - let module = sema.file_to_module_def(file_id)?; + let module = sema.file_to_module_def(EditionedFileId::current_edition(file_id))?; let def = Definition::Module(module); let mut change = def.rename(&sema, new_name_stem).ok()?; change.file_system_edits.clear(); @@ -199,19 +203,19 @@ fn alias_fallback( fn find_definitions( sema: &Semantics<'_, RootDatabase>, syntax: &SyntaxNode, - FilePosition { file_id, offset }: FilePosition, + file_id: EditionedFileId, + offset: TextSize, ) -> RenameResult> { - let token = syntax.token_at_offset(offset).find(|t| matches!(t.kind(), SyntaxKind::STRING)); + let token = syntax.token_at_offset(offset).find_map(ast::String::cast); - if let Some((range, Some(resolution))) = - token.and_then(|token| sema.check_for_format_args_template(token, offset)) - { - return Ok(vec![( - FileRange { file_id, range }, - SyntaxKind::STRING, - Definition::from(resolution), - )] - .into_iter()); + if let Some((range, _, Some(resolution))) = token.and_then(|token| { + sema.check_for_format_args_template_with_file(InFile::new(file_id.into(), token), offset) + }) { + let frange = + InFile::new(range.file_id, range.range).original_node_file_range_rooted(sema.db); + return Ok( + vec![(frange.into(), SyntaxKind::STRING, Definition::from(resolution))].into_iter() + ); } let symbols = @@ -365,7 +369,7 @@ fn rename_to_self( .ok_or_else(|| format_err!("No source for parameter found"))?; let def = Definition::Local(local); - let usages = def.usages(sema).all(); + let usages = def.usages(sema).all().map_out_of_macros(sema); let mut source_change = SourceChange::default(); source_change.extend(usages.iter().map(|(file_id, references)| { (file_id.into(), source_edit_from_references(references, def, "self", file_id.edition())) @@ -395,7 +399,7 @@ fn rename_self_to_param( sema.source(self_param).ok_or_else(|| format_err!("cannot find function source"))?; let def = Definition::Local(local); - let usages = def.usages(sema).all(); + let usages = def.usages(sema).all().map_out_of_macros(sema); let edit = text_edit_from_self_param(&self_param, new_name) .ok_or_else(|| format_err!("No target type found"))?; if usages.len() > 1 && identifier_kind == IdentifierKind::Underscore { @@ -404,7 +408,10 @@ fn rename_self_to_param( let mut source_change = SourceChange::default(); source_change.insert_source_edit(file_id.original_file(sema.db), edit); source_change.extend(usages.iter().map(|(file_id, references)| { - (file_id.into(), source_edit_from_references(references, def, new_name, file_id.edition())) + ( + file_id.file_id(), + source_edit_from_references(references, def, new_name, file_id.edition()), + ) })); Ok(source_change) } @@ -462,12 +469,12 @@ mod tests { let ra_fixture_after = &trim_indent(ra_fixture_after); let (analysis, position) = fixture::position(ra_fixture_before); if !ra_fixture_after.starts_with("error: ") { - if let Err(err) = analysis.prepare_rename(position).unwrap() { + if let Err(err) = analysis.prepare_rename(position.into()).unwrap() { panic!("Prepare rename to '{new_name}' was failed: {err}") } } let rename_result = analysis - .rename(position, new_name) + .rename(position.into(), new_name) .unwrap_or_else(|err| panic!("Rename to '{new_name}' was cancelled: {err}")); match rename_result { Ok(source_change) => { @@ -502,8 +509,10 @@ mod tests { expect: Expect, ) { let (analysis, position) = fixture::position(ra_fixture); - let source_change = - analysis.rename(position, new_name).unwrap().expect("Expect returned a RenameError"); + let source_change = analysis + .rename(position.into(), new_name) + .unwrap() + .expect("Expect returned a RenameError"); expect.assert_eq(&filter_expect(source_change)) } @@ -514,7 +523,7 @@ mod tests { ) { let (analysis, position) = fixture::position(ra_fixture); let source_change = analysis - .will_rename_file(position.file_id, new_name) + .will_rename_file(position.file_id.into(), new_name) .unwrap() .expect("Expect returned a RenameError"); expect.assert_eq(&filter_expect(source_change)) @@ -523,11 +532,11 @@ mod tests { fn check_prepare(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let result = analysis - .prepare_rename(position) + .prepare_rename(position.into()) .unwrap_or_else(|err| panic!("PrepareRename was cancelled: {err}")); match result { Ok(RangeInfo { range, info: () }) => { - let source = analysis.file_text(position.file_id).unwrap(); + let source = analysis.file_text(position.file_id.into()).unwrap(); expect.assert_eq(&format!("{range:?}: {}", &source[range])) } Err(RenameError(err)) => expect.assert_eq(&err), diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 509ae3204c36..14a35cd01796 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -5,7 +5,7 @@ use ast::HasName; use cfg::{CfgAtom, CfgExpr}; use hir::{ db::HirDatabase, sym, symbols::FxIndexSet, AsAssocItem, AttrsWithOwner, HasAttrs, HasCrate, - HasSource, HirFileIdExt, ModPath, Name, PathKind, Semantics, Symbol, + HasSource, HirFileId, HirFileIdExt, ModPath, Name, PathKind, Semantics, Symbol, }; use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn}; use ide_db::{ @@ -24,12 +24,14 @@ use syntax::{ format_smolstr, SmolStr, SyntaxNode, ToSmolStr, }; -use crate::{references, FileId, NavigationTarget, ToNav, TryToNav}; +use crate::{ + navigation_target::HirNavigationTarget, references, NavigationTarget, ToNav, TryToNav, +}; #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Runnable { pub use_name_in_title: bool, - pub nav: NavigationTarget, + pub nav: HirNavigationTarget, pub kind: RunnableKind, pub cfg: Option, pub update_test: UpdateTest, @@ -124,7 +126,7 @@ impl Runnable { // | VS Code | **rust-analyzer: Run** | // // ![Run](https://user-images.githubusercontent.com/48062697/113065583-055aae80-91b1-11eb-958f-d67efcaf6a2f.gif) -pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { +pub(crate) fn runnables(db: &RootDatabase, file_id: HirFileId) -> Vec { let sema = Semantics::new(db); let mut res = Vec::new(); @@ -171,7 +173,7 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec { } }); - sema.file_to_module_defs(file_id) + sema.hir_file_to_module_defs(file_id) .map(|it| runnable_mod_outline_definition(&sema, it)) .for_each(|it| add_opt(it, None)); @@ -341,11 +343,9 @@ pub(crate) fn runnable_fn( let fn_source = sema.source(def)?; let nav = NavigationTarget::from_named( - sema.db, fn_source.as_ref().map(|it| it as &dyn ast::HasName), SymbolKind::Function, - ) - .call_site(); + ); let file_range = fn_source.syntax().original_file_range_with_macro_call_body(sema.db); let update_test = @@ -376,7 +376,7 @@ pub(crate) fn runnable_mod( let attrs = def.attrs(sema.db); let cfg = attrs.cfg(); - let nav = NavigationTarget::from_module_to_decl(sema.db, def).call_site(); + let nav = HirNavigationTarget::from_module_to_decl(sema.db, def); let module_source = sema.module_definition_node(def); let module_syntax = module_source.file_syntax(sema.db); @@ -405,7 +405,7 @@ pub(crate) fn runnable_impl( return None; } let cfg = attrs.cfg(); - let nav = def.try_to_nav(sema.db)?.call_site(); + let nav = def.try_to_nav_hir(sema.db)?; let ty = def.self_ty(sema.db); let adt_name = ty.as_adt()?.name(sema.db); let mut ty_args = ty.generic_parameters(sema.db, edition).peekable(); @@ -472,7 +472,7 @@ fn runnable_mod_outline_definition( Some(Runnable { use_name_in_title: false, - nav: def.to_nav(sema.db).call_site(), + nav: def.to_nav_hir(sema.db), kind: RunnableKind::TestMod { path }, cfg, update_test, @@ -528,10 +528,9 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { .map_or_else(|| TestId::Name(def_name.display_no_db(edition).to_smolstr()), TestId::Path); let mut nav = match def { - Definition::Module(def) => NavigationTarget::from_module_to_decl(db, def), - def => def.try_to_nav(db)?, - } - .call_site(); + Definition::Module(def) => HirNavigationTarget::from_module_to_decl(db, def), + def => def.try_to_nav_hir(db)?, + }; nav.focus_range = None; nav.description = None; nav.docs = None; @@ -753,7 +752,7 @@ mod tests { fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let result = analysis - .runnables(position.file_id) + .runnables(position.file_id.into()) .unwrap() .into_iter() .map(|runnable| { @@ -773,7 +772,7 @@ mod tests { fn check_tests(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); - let tests = analysis.related_tests(position, None).unwrap(); + let tests = analysis.related_tests(position.into(), None).unwrap(); let navigation_targets = tests.into_iter().map(|runnable| runnable.nav).collect::>(); expect.assert_debug_eq(&navigation_targets); } @@ -811,14 +810,14 @@ mod not_a_root { "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..331, name: \"\", kind: Module })", - "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", - "(Bin, NavigationTarget { file_id: FileId(0), full_range: 15..76, focus_range: 42..71, name: \"__cortex_m_rt_main_trampoline\", kind: Function })", - "(Bin, NavigationTarget { file_id: FileId(0), full_range: 78..154, focus_range: 113..149, name: \"__cortex_m_rt_main_trampoline_unsafe\", kind: Function })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 156..180, focus_range: 167..175, name: \"test_foo\", kind: Function })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 182..233, focus_range: 214..228, name: \"test_full_path\", kind: Function })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 235..269, focus_range: 256..264, name: \"test_foo\", kind: Function })", - "(Bench, NavigationTarget { file_id: FileId(0), full_range: 271..293, focus_range: 283..288, name: \"bench\", kind: Function })", + "(TestMod, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 0..331, name: \"\", kind: Module })", + "(Bin, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(Bin, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 15..76, focus_range: 42..71, name: \"__cortex_m_rt_main_trampoline\", kind: Function })", + "(Bin, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 78..154, focus_range: 113..149, name: \"__cortex_m_rt_main_trampoline_unsafe\", kind: Function })", + "(Test, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 156..180, focus_range: 167..175, name: \"test_foo\", kind: Function })", + "(Test, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 182..233, focus_range: 214..228, name: \"test_full_path\", kind: Function })", + "(Test, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 235..269, focus_range: 256..264, name: \"test_foo\", kind: Function })", + "(Bench, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 271..293, focus_range: 283..288, name: \"bench\", kind: Function })", ] "#]], ); @@ -922,15 +921,15 @@ impl Test for StructWithRunnable {} "#, expect![[r#" [ - "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 15..74, name: \"should_have_runnable\" })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 76..148, name: \"should_have_runnable_1\" })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 150..254, name: \"should_have_runnable_2\" })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 256..320, name: \"should_have_no_runnable_3\" })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 322..398, name: \"should_have_no_runnable_4\" })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 900..965, name: \"StructWithRunnable\" })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 967..1024, focus_range: 1003..1021, name: \"impl\", kind: Impl })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 1088..1154, focus_range: 1133..1151, name: \"impl\", kind: Impl })", + "(Bin, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 15..74, name: \"should_have_runnable\" })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 76..148, name: \"should_have_runnable_1\" })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 150..254, name: \"should_have_runnable_2\" })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 256..320, name: \"should_have_no_runnable_3\" })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 322..398, name: \"should_have_no_runnable_4\" })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 900..965, name: \"StructWithRunnable\" })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 967..1024, focus_range: 1003..1021, name: \"impl\", kind: Impl })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1088..1154, focus_range: 1133..1151, name: \"impl\", kind: Impl })", ] "#]], ); @@ -954,8 +953,8 @@ impl Data { "#, expect![[r#" [ - "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 44..98, name: \"foo\" })", + "(Bin, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 44..98, name: \"foo\" })", ] "#]], ); @@ -979,8 +978,8 @@ impl Data<'a> { "#, expect![[r#" [ - "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 52..106, name: \"foo\" })", + "(Bin, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 52..106, name: \"foo\" })", ] "#]], ); @@ -1004,8 +1003,8 @@ impl Data<'a, T, U> { "#, expect![[r#" [ - "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 70..124, name: \"foo\" })", + "(Bin, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 70..124, name: \"foo\" })", ] "#]], ); @@ -1029,8 +1028,8 @@ impl Data { "#, expect![[r#" [ - "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 79..133, name: \"foo\" })", + "(Bin, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 79..133, name: \"foo\" })", ] "#]], ); @@ -1054,8 +1053,8 @@ impl<'a, T, const N: usize> Data<'a, T, N> { "#, expect![[r#" [ - "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 100..154, name: \"foo\" })", + "(Bin, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 100..154, name: \"foo\" })", ] "#]], ); @@ -1073,8 +1072,8 @@ mod test_mod { "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 1..51, focus_range: 5..13, name: \"test_mod\", kind: Module, description: \"mod test_mod\" })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 20..49, focus_range: 35..44, name: \"test_foo1\", kind: Function })", + "(TestMod, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1..51, focus_range: 5..13, name: \"test_mod\", kind: Module, description: \"mod test_mod\" })", + "(Test, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 20..49, focus_range: 35..44, name: \"test_foo1\", kind: Function })", ] "#]], ); @@ -1109,12 +1108,12 @@ mod root_tests { "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 22..323, focus_range: 26..40, name: \"nested_tests_0\", kind: Module, description: \"mod nested_tests_0\" })", - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 51..192, focus_range: 55..69, name: \"nested_tests_1\", kind: Module, description: \"mod nested_tests_1\" })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 84..126, focus_range: 107..121, name: \"nested_test_11\", kind: Function })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 140..182, focus_range: 163..177, name: \"nested_test_12\", kind: Function })", - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 202..286, focus_range: 206..220, name: \"nested_tests_2\", kind: Module, description: \"mod nested_tests_2\" })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 235..276, focus_range: 258..271, name: \"nested_test_2\", kind: Function })", + "(TestMod, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 22..323, focus_range: 26..40, name: \"nested_tests_0\", kind: Module, description: \"mod nested_tests_0\" })", + "(TestMod, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 51..192, focus_range: 55..69, name: \"nested_tests_1\", kind: Module, description: \"mod nested_tests_1\" })", + "(Test, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 84..126, focus_range: 107..121, name: \"nested_test_11\", kind: Function })", + "(Test, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 140..182, focus_range: 163..177, name: \"nested_test_12\", kind: Function })", + "(TestMod, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 202..286, focus_range: 206..220, name: \"nested_tests_2\", kind: Module, description: \"mod nested_tests_2\" })", + "(Test, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 235..276, focus_range: 258..271, name: \"nested_test_2\", kind: Function })", ] "#]], ); @@ -1132,8 +1131,8 @@ fn test_foo1() {} "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..51, name: \"\", kind: Module })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 1..50, focus_range: 36..45, name: \"test_foo1\", kind: Function }, Atom(KeyValue { key: \"feature\", value: \"foo\" }))", + "(TestMod, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 0..51, name: \"\", kind: Module })", + "(Test, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1..50, focus_range: 36..45, name: \"test_foo1\", kind: Function }, Atom(KeyValue { key: \"feature\", value: \"foo\" }))", ] "#]], ); @@ -1151,8 +1150,8 @@ fn test_foo1() {} "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..73, name: \"\", kind: Module })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 1..72, focus_range: 58..67, name: \"test_foo1\", kind: Function }, All([Atom(KeyValue { key: \"feature\", value: \"foo\" }), Atom(KeyValue { key: \"feature\", value: \"bar\" })]))", + "(TestMod, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 0..73, name: \"\", kind: Module })", + "(Test, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1..72, focus_range: 58..67, name: \"test_foo1\", kind: Function }, All([Atom(KeyValue { key: \"feature\", value: \"foo\" }), Atom(KeyValue { key: \"feature\", value: \"bar\" })]))", ] "#]], ); @@ -1191,7 +1190,7 @@ impl Foo { "#, expect![[r#" [ - "(DocTest, NavigationTarget { file_id: FileId(1), full_range: 27..81, name: \"foo\" })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(1, Edition2021), full_range: 27..81, name: \"foo\" })", ] "#]], ); @@ -1230,12 +1229,8 @@ gen_main!(); "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..315, name: \"\", kind: Module })", - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 267..292, focus_range: 271..276, name: \"tests\", kind: Module, description: \"mod tests\" })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 283..290, name: \"foo_test\", kind: Function })", - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 293..301, name: \"tests2\", kind: Module, description: \"mod tests2\" }, true)", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 293..301, name: \"foo_test2\", kind: Function }, true)", - "(Bin, NavigationTarget { file_id: FileId(0), full_range: 302..314, name: \"main\", kind: Function })", + "(TestMod, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 0..315, name: \"\", kind: Module })", + "(TestMod, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 267..292, focus_range: 271..276, name: \"tests\", kind: Module, description: \"mod tests\" })", ] "#]], ); @@ -1262,12 +1257,7 @@ macro_rules! foo { foo!(); "#, expect![[r#" - [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo_tests\", kind: Module, description: \"mod foo_tests\" }, true)", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo0\", kind: Function }, true)", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo1\", kind: Function }, true)", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 210..217, name: \"foo2\", kind: Function }, true)", - ] + [] "#]], ); } @@ -1306,7 +1296,7 @@ fn t1() {} "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 1..7, focus_range: 5..6, name: \"m\", kind: Module, description: \"mod m\" })", + "(TestMod, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1..7, focus_range: 5..6, name: \"m\", kind: Module, description: \"mod m\" })", ] "#]], ); @@ -1327,9 +1317,9 @@ fn t1() {} "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(1), full_range: 0..39, name: \"m\", kind: Module })", - "(Test, NavigationTarget { file_id: FileId(1), full_range: 1..19, focus_range: 12..14, name: \"t0\", kind: Function })", - "(Test, NavigationTarget { file_id: FileId(1), full_range: 20..38, focus_range: 31..33, name: \"t1\", kind: Function })", + "(TestMod, NavigationTarget { file_id: EditionedFileId(1, Edition2021), full_range: 0..39, name: \"m\", kind: Module })", + "(Test, NavigationTarget { file_id: EditionedFileId(1, Edition2021), full_range: 1..19, focus_range: 12..14, name: \"t0\", kind: Function })", + "(Test, NavigationTarget { file_id: EditionedFileId(1, Edition2021), full_range: 20..38, focus_range: 31..33, name: \"t1\", kind: Function })", ] "#]], ); @@ -1351,11 +1341,7 @@ mod module { } "#, expect![[r#" - [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 26..94, focus_range: 30..36, name: \"module\", kind: Module, description: \"mod module\" }, true)", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 43..65, focus_range: 58..60, name: \"t0\", kind: Function }, true)", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 70..92, focus_range: 85..87, name: \"t1\", kind: Function }, true)", - ] + [] "#]], ); } @@ -1390,8 +1376,9 @@ mod tests { expect![[r#" [ NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 31..85, focus_range: 46..54, @@ -1423,8 +1410,9 @@ mod tests { expect![[r#" [ NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 71..122, focus_range: 86..94, @@ -1463,8 +1451,9 @@ mod tests { expect![[r#" [ NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 133..183, focus_range: 148..156, @@ -1503,8 +1492,9 @@ mod tests { expect![[r#" [ NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 52..115, focus_range: 67..75, @@ -1512,8 +1502,9 @@ mod tests { kind: Function, }, NavigationTarget { - file_id: FileId( + file_id: EditionedFileId( 0, + Edition2021, ), full_range: 121..185, focus_range: 136..145, @@ -1542,8 +1533,8 @@ impl Data<'a, A, 12, C, D> { "#, expect![[r#" [ - "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 121..156, name: \"foo\" })", + "(Bin, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 121..156, name: \"foo\" })", ] "#]], ); @@ -1575,10 +1566,10 @@ impl Foo, ()> { "#, expect![[r#" [ - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 20..103, focus_range: 47..56, name: \"impl\", kind: Impl })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 63..101, name: \"t\" })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 105..188, focus_range: 126..146, name: \"impl\", kind: Impl })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 153..186, name: \"t\" })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 20..103, focus_range: 47..56, name: \"impl\", kind: Impl })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 63..101, name: \"t\" })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 105..188, focus_range: 126..146, name: \"impl\", kind: Impl })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 153..186, name: \"t\" })", ] "#]], ); @@ -1625,7 +1616,7 @@ macro_rules! foo { "#, expect![[r#" [ - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 1..94, name: \"foo\" })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1..94, name: \"foo\" })", ] "#]], ); @@ -1673,14 +1664,14 @@ mod r#mod { "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 1..461, focus_range: 5..10, name: \"r#mod\", kind: Module, description: \"mod r#mod\" })", - "(Test, NavigationTarget { file_id: FileId(0), full_range: 17..41, focus_range: 32..36, name: \"r#fn\", kind: Function })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 47..84, name: \"r#for\", container_name: \"r#mod\" })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 90..146, name: \"r#struct\", container_name: \"r#mod\" })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 152..266, focus_range: 189..205, name: \"impl\", kind: Impl })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 216..260, name: \"r#fn\" })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 323..367, name: \"r#fn\" })", - "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 401..459, focus_range: 445..456, name: \"impl\", kind: Impl })", + "(TestMod, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 1..461, focus_range: 5..10, name: \"r#mod\", kind: Module, description: \"mod r#mod\" })", + "(Test, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 17..41, focus_range: 32..36, name: \"r#fn\", kind: Function })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 47..84, name: \"r#for\", container_name: \"r#mod\" })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 90..146, name: \"r#struct\", container_name: \"r#mod\" })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 152..266, focus_range: 189..205, name: \"impl\", kind: Impl })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 216..260, name: \"r#fn\" })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 323..367, name: \"r#fn\" })", + "(DocTest, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 401..459, focus_range: 445..456, name: \"impl\", kind: Impl })", ] "#]], ) @@ -1713,9 +1704,9 @@ fn exp_main() {} "#, expect![[r#" [ - "(Bin, NavigationTarget { file_id: FileId(0), full_range: 36..80, focus_range: 67..75, name: \"exp_main\", kind: Function })", - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 83..168, focus_range: 100..115, name: \"test_mod_inline\", kind: Module, description: \"mod test_mod_inline\" }, Atom(Flag(\"test\")))", - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 192..218, focus_range: 209..217, name: \"test_mod\", kind: Module, description: \"mod test_mod\" }, Atom(Flag(\"test\")))", + "(Bin, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 36..80, focus_range: 67..75, name: \"exp_main\", kind: Function })", + "(TestMod, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 83..168, focus_range: 100..115, name: \"test_mod_inline\", kind: Module, description: \"mod test_mod_inline\" }, Atom(Flag(\"test\")))", + "(TestMod, NavigationTarget { file_id: EditionedFileId(0, Edition2021), full_range: 192..218, focus_range: 209..217, name: \"test_mod\", kind: Module, description: \"mod test_mod\" }, Atom(Flag(\"test\")))", ] "#]], ) diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 07553a87d28f..dcee0879fb3f 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -10,7 +10,7 @@ use ide_db::{ helpers::get_definition, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, }; -use span::Edition; +use span::{Edition, EditionedFileId}; use syntax::{AstNode, SyntaxKind::*, SyntaxNode, TextRange, T}; use crate::navigation_target::UpmappingResult; @@ -129,8 +129,14 @@ pub enum VendoredLibrariesConfig<'a> { impl StaticIndex<'_> { fn add_file(&mut self, file_id: FileId) { + let sema = hir::Semantics::new(self.db); + let root = sema.parse_guess_edition(file_id).syntax().clone(); + let editioned_file_id = sema + .attach_first_edition(file_id) + .unwrap_or_else(|| EditionedFileId::new(file_id, Edition::CURRENT)); + let edition = editioned_file_id.edition(); let current_crate = crates_for(self.db, file_id).pop().map(Into::into); - let folds = self.analysis.folding_ranges(file_id).unwrap(); + let folds = self.analysis.folding_ranges(editioned_file_id.into()).unwrap(); let inlay_hints = self .analysis .inlay_hints( @@ -164,15 +170,11 @@ impl StaticIndex<'_> { fields_to_resolve: InlayFieldsToResolve::empty(), range_exclusive_hints: false, }, - file_id, + editioned_file_id.into(), None, ) .unwrap(); // hovers - let sema = hir::Semantics::new(self.db); - let root = sema.parse_guess_edition(file_id).syntax().clone(); - let edition = - sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT); let tokens = root.descendants_with_tokens().filter_map(|it| match it { syntax::NodeOrToken::Node(_) => None, syntax::NodeOrToken::Token(it) => Some(it), @@ -204,14 +206,13 @@ impl StaticIndex<'_> { documentation: documentation_for_definition(&sema, def, scope_node), hover: Some(hover_for_definition( &sema, - file_id, + editioned_file_id.into(), def, None, scope_node, None, false, &hover_config, - edition, )), definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| { FileRange { file_id: it.file_id, range: it.focus_or_full_range() } @@ -238,7 +239,7 @@ impl StaticIndex<'_> { result.tokens.push((range, id)); }; - if let Some(module) = sema.file_to_module_def(file_id) { + if let Some(module) = sema.file_to_module_def(editioned_file_id) { let def = Definition::Module(module); let range = root.text_range(); add_token(def, range, &root); @@ -309,7 +310,7 @@ mod tests { ) { let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture); let s = StaticIndex::compute(&analysis, vendored_libs_config); - let mut range_set: FxHashSet<_> = ranges.iter().map(|it| it.0).collect(); + let mut range_set: FxHashSet = ranges.iter().map(|it| it.0.into()).collect(); for f in s.files { for (range, _) in f.tokens { if range.start() == TextSize::from(0) { @@ -335,7 +336,7 @@ mod tests { ) { let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture); let s = StaticIndex::compute(&analysis, vendored_libs_config); - let mut range_set: FxHashSet<_> = ranges.iter().map(|it| it.0).collect(); + let mut range_set: FxHashSet = ranges.iter().map(|it| it.0.into()).collect(); for (_, t) in s.tokens.iter() { if let Some(t) = t.definition { if t.range.start() == TextSize::from(0) { diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 1853e3a34074..98f3903d44aa 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs @@ -15,9 +15,8 @@ mod tests; use std::ops::ControlFlow; -use hir::{InRealFile, Name, Semantics}; +use hir::{HirFileId, HirFileIdExt, InFile, Name, Semantics}; use ide_db::{FxHashMap, Ranker, RootDatabase, SymbolKind}; -use span::EditionedFileId; use syntax::{ ast::{self, IsString}, AstNode, AstToken, NodeOrToken, @@ -33,7 +32,7 @@ use crate::{ macro_::MacroHighlighter, tags::Highlight, }, - FileId, HlMod, HlOperator, HlPunct, HlTag, + HlMod, HlOperator, HlPunct, HlTag, }; pub(crate) use html::highlight_as_html; @@ -191,19 +190,16 @@ pub struct HighlightConfig { pub(crate) fn highlight( db: &RootDatabase, config: HighlightConfig, - file_id: FileId, + file_id: HirFileId, range_to_highlight: Option, ) -> Vec { let _p = tracing::info_span!("highlight").entered(); let sema = Semantics::new(db); - let file_id = sema - .attach_first_edition(file_id) - .unwrap_or_else(|| EditionedFileId::current_edition(file_id)); // Determine the root based on the given range. let (root, range_to_highlight) = { - let file = sema.parse(file_id); - let source_file = file.syntax(); + let file_id = sema.adjust_edition(file_id); + let source_file = sema.parse_or_expand(file_id); match range_to_highlight { Some(range) => { let node = match source_file.covering_element(range) { @@ -229,12 +225,14 @@ fn traverse( hl: &mut Highlights, sema: &Semantics<'_, RootDatabase>, config: HighlightConfig, - file_id: EditionedFileId, + file_id: HirFileId, root: &SyntaxNode, krate: hir::Crate, range_to_highlight: TextRange, ) { - let is_unlinked = sema.file_to_module_def(file_id).is_none(); + let edition = file_id.edition(sema.db); + let is_unlinked = + file_id.file_id().is_some_and(|file_id| sema.file_to_module_def(file_id).is_none()); let mut bindings_shadow_count: FxHashMap = FxHashMap::default(); enum AttrOrDerive { @@ -412,7 +410,7 @@ fn traverse( let mut t = None; let mut r = 0; sema.descend_into_macros_breakable( - InRealFile::new(file_id, token.clone()), + InFile::new(file_id, token.clone()), |tok, _ctx| { // FIXME: Consider checking ctx transparency for being opaque? let tok = tok.value; @@ -490,7 +488,7 @@ fn traverse( &string, &expanded_string, range, - file_id.edition(), + file_id.edition(sema.db), ); if !string.is_raw() { @@ -539,11 +537,9 @@ fn traverse( &mut bindings_shadow_count, config.syntactic_name_ref_highlighting, name_like, - file_id.edition(), + edition, ), - NodeOrToken::Token(token) => { - highlight::token(sema, token, file_id.edition()).zip(Some(None)) - } + NodeOrToken::Token(token) => highlight::token(sema, token, edition).zip(Some(None)), }; if let Some((mut highlight, binding_hash)) = element { if is_unlinked && highlight.tag == HlTag::UnresolvedReference { diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs index 47ad54759a87..d21008dcf900 100644 --- a/crates/ide/src/syntax_highlighting/html.rs +++ b/crates/ide/src/syntax_highlighting/html.rs @@ -1,23 +1,18 @@ //! Renders a bit of code as HTML. -use hir::Semantics; +use hir::{HirFileId, Semantics}; use oorandom::Rand32; -use span::EditionedFileId; use stdx::format_to; -use syntax::AstNode; use crate::{ syntax_highlighting::{highlight, HighlightConfig}, - FileId, RootDatabase, + RootDatabase, }; -pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String { +pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: HirFileId, rainbow: bool) -> String { let sema = Semantics::new(db); - let file_id = sema - .attach_first_edition(file_id) - .unwrap_or_else(|| EditionedFileId::current_edition(file_id)); - let file = sema.parse(file_id); - let file = file.syntax(); + let file_id = sema.adjust_edition(file_id); + let file = sema.parse_or_expand(file_id); fn rainbowify(seed: u64) -> String { let mut rng = Rand32::new(seed); format!( @@ -40,7 +35,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo macro_bang: true, syntactic_name_ref_highlighting: false, }, - file_id.into(), + file_id, None, ); let text = file.to_string(); diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs index 1be90ad6a1eb..db6a8931294f 100644 --- a/crates/ide/src/syntax_highlighting/inject.rs +++ b/crates/ide/src/syntax_highlighting/inject.rs @@ -8,7 +8,6 @@ use ide_db::{ active_parameter::ActiveParameter, defs::Definition, documentation::docs_with_rangemap, rust_doc::is_rust_fence, SymbolKind, }; -use span::EditionedFileId; use syntax::{ ast::{self, AstNode, IsString, QuoteOffsets}, AstToken, NodeOrToken, SyntaxNode, TextRange, TextSize, @@ -88,7 +87,7 @@ pub(super) fn ra_fixture( inject_doc_comment: config.inject_doc_comment, macro_bang: config.macro_bang, }, - tmp_file_id, + tmp_file_id.into(), ) .unwrap() { @@ -116,14 +115,13 @@ pub(super) fn doc_comment( hl: &mut Highlights, sema: &Semantics<'_, RootDatabase>, config: HighlightConfig, - src_file_id: EditionedFileId, + src_file_id: HirFileId, node: &SyntaxNode, ) { let (attributes, def) = match doc_attributes(sema, node) { Some(it) => it, None => return, }; - let src_file_id: HirFileId = src_file_id.into(); // Extract intra-doc links and emit highlights for them. if let Some((docs, doc_mapping)) = docs_with_rangemap(sema.db, &attributes) { @@ -249,7 +247,7 @@ pub(super) fn doc_comment( inject_doc_comment: config.inject_doc_comment, macro_bang: config.macro_bang, }, - tmp_file_id, + tmp_file_id.into(), None, ) }) { diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 3775265f234d..5b3c7e444480 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -1,11 +1,12 @@ use std::time::Instant; use expect_test::{expect_file, ExpectFile}; +use hir::HirFileRange; use ide_db::SymbolKind; use span::Edition; use test_utils::{bench, bench_fixture, skip_slow_tests, AssertLinear}; -use crate::{fixture, FileRange, HighlightConfig, HlTag, TextRange}; +use crate::{fixture, HighlightConfig, HlTag, TextRange}; const HL_CONFIG: HighlightConfig = HighlightConfig { strings: true, @@ -1151,7 +1152,7 @@ struct Foo { let highlights = &analysis .highlight_range( HL_CONFIG, - FileRange { file_id, range: TextRange::at(45.into(), 1.into()) }, + HirFileRange { file_id: file_id.into(), range: TextRange::at(45.into(), 1.into()) }, ) .unwrap(); @@ -1167,7 +1168,7 @@ macro_rules! test {} }"# .trim(), ); - let _ = analysis.highlight(HL_CONFIG, file_id).unwrap(); + let _ = analysis.highlight(HL_CONFIG, file_id.into()).unwrap(); } #[test] @@ -1187,7 +1188,7 @@ trait Trait {} fn foo(x: &fn(&dyn Trait)) {} "#, ); - let _ = analysis.highlight(HL_CONFIG, file_id).unwrap(); + let _ = analysis.highlight(HL_CONFIG, file_id.into()).unwrap(); } /// Highlights the code given by the `ra_fixture` argument, renders the @@ -1199,7 +1200,7 @@ fn check_highlighting( rainbow: bool, ) { let (analysis, file_id) = fixture::file(ra_fixture.trim()); - let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap(); + let actual_html = &analysis.highlight_as_html(file_id.into(), rainbow).unwrap(); expect.assert_eq(actual_html) } @@ -1215,7 +1216,7 @@ fn benchmark_syntax_highlighting_long_struct() { let hash = { let _pt = bench("syntax highlighting long struct"); analysis - .highlight(HL_CONFIG, file_id) + .highlight(HL_CONFIG, file_id.into()) .unwrap() .iter() .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct)) @@ -1241,7 +1242,7 @@ fn syntax_highlighting_not_quadratic() { let time = Instant::now(); let hash = analysis - .highlight(HL_CONFIG, file_id) + .highlight(HL_CONFIG, file_id.into()) .unwrap() .iter() .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct)) @@ -1266,7 +1267,7 @@ fn benchmark_syntax_highlighting_parser() { let hash = { let _pt = bench("syntax highlighting parser"); analysis - .highlight(HL_CONFIG, file_id) + .highlight(HL_CONFIG, file_id.into()) .unwrap() .iter() .filter(|it| { @@ -1291,7 +1292,7 @@ fn f<'de, T: Deserialize<'de>>() { "# .trim(), ); - let _ = analysis.highlight(HL_CONFIG, file_id).unwrap(); + let _ = analysis.highlight(HL_CONFIG, file_id.into()).unwrap(); } #[test] diff --git a/crates/ide/src/test_explorer.rs b/crates/ide/src/test_explorer.rs index 30b1d4c39b30..ce66d8648f68 100644 --- a/crates/ide/src/test_explorer.rs +++ b/crates/ide/src/test_explorer.rs @@ -5,9 +5,10 @@ use ide_db::{ base_db::{CrateGraph, CrateId, SourceDatabase}, FileId, RootDatabase, }; +use span::EditionedFileId; use syntax::TextRange; -use crate::{runnables::runnable_fn, NavigationTarget, Runnable, TryToNav}; +use crate::{navigation_target::HirNavigationTarget, runnables::runnable_fn, Runnable, TryToNav}; #[derive(Debug)] pub enum TestItemKind { @@ -74,7 +75,7 @@ fn discover_tests_in_module( let module_id = format!("{prefix_id}::{module_name}"); let module_children = discover_tests_in_module(db, c, module_id.clone(), only_in_this_file); if !module_children.is_empty() { - let nav = NavigationTarget::from_module_to_decl(sema.db, c).call_site; + let nav = HirNavigationTarget::from_module_to_decl(sema.db, c).upmap(sema.db).call_site; r.push(TestItem { id: module_id, kind: TestItemKind::Module, @@ -96,15 +97,15 @@ fn discover_tests_in_module( if !f.is_test(db) { continue; } - let nav = f.try_to_nav(db).map(|r| r.call_site); + let nav = f.try_to_nav(db); let fn_name = f.name(db).as_str().to_owned(); r.push(TestItem { id: format!("{prefix_id}::{fn_name}"), kind: TestItemKind::Function, label: fn_name, parent: Some(prefix_id.clone()), - file: nav.as_ref().map(|n| n.file_id), - text_range: nav.as_ref().map(|n| n.focus_or_full_range()), + file: nav.as_ref().map(|n| n.call_site.file_id), + text_range: nav.as_ref().map(|n| n.call_site.focus_or_full_range()), runnable: runnable_fn(&sema, f), }); } @@ -125,7 +126,9 @@ pub(crate) fn discover_tests_in_crate_by_test_id( pub(crate) fn discover_tests_in_file(db: &RootDatabase, file_id: FileId) -> Vec { let sema = Semantics::new(db); - let Some(module) = sema.file_to_module_def(file_id) else { return vec![] }; + let Some(module) = sema.file_to_module_def(EditionedFileId::current_edition(file_id)) else { + return vec![]; + }; let Some((mut tests, id)) = find_module_id_and_test_parents(&sema, module) else { return vec![]; }; @@ -158,7 +161,7 @@ fn find_module_id_and_test_parents( let module_name = &module.name(sema.db); let module_name = module_name.as_ref().map(|n| n.as_str()).unwrap_or("[mod without name]"); id += module_name; - let nav = NavigationTarget::from_module_to_decl(sema.db, module).call_site; + let nav = HirNavigationTarget::from_module_to_decl(sema.db, module).upmap(sema.db).call_site; r.push(TestItem { id: id.clone(), kind: TestItemKind::Module, diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs index c6d1c283f4ec..9ab88cd5f00d 100644 --- a/crates/ide/src/typing/on_enter.rs +++ b/crates/ide/src/typing/on_enter.rs @@ -199,9 +199,9 @@ mod tests { fn apply_on_enter(before: &str) -> Option { let (analysis, position) = fixture::position(before); - let result = analysis.on_enter(position).unwrap()?; + let result = analysis.on_enter(position.into()).unwrap()?; - let mut actual = analysis.file_text(position.file_id).unwrap().to_string(); + let mut actual = analysis.file_text(position.file_id.into()).unwrap().to_string(); result.apply(&mut actual); Some(actual) } diff --git a/crates/ide/src/view_memory_layout.rs b/crates/ide/src/view_memory_layout.rs index edb83bc4eac4..0c393cb9edd7 100644 --- a/crates/ide/src/view_memory_layout.rs +++ b/crates/ide/src/view_memory_layout.rs @@ -223,7 +223,7 @@ mod tests { ) -> Option { let (analysis, position, _) = fixture::annotations(ra_fixture); - view_memory_layout(&analysis.db, position) + view_memory_layout(&analysis.db, position.into()) } #[test] diff --git a/crates/ide/src/view_syntax_tree.rs b/crates/ide/src/view_syntax_tree.rs index 407720864bfd..8c3560cf91c8 100644 --- a/crates/ide/src/view_syntax_tree.rs +++ b/crates/ide/src/view_syntax_tree.rs @@ -179,7 +179,7 @@ mod tests { fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: expect_test::Expect) { let (analysis, file_id) = fixture::file(ra_fixture); - let syn = analysis.view_syntax_tree(file_id).unwrap(); + let syn = analysis.view_syntax_tree(file_id.into()).unwrap(); expect.assert_eq(&syn) } diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs index fb68d35a4c84..071d85417fd9 100644 --- a/crates/mbe/src/tests.rs +++ b/crates/mbe/src/tests.rs @@ -74,7 +74,8 @@ fn check_( "{}", syntax_bridge::prettify_macro_expansion::prettify_macro_expansion( node.syntax_node(), - &mut |it| it.clone() + &mut |_| None, + |_| () ) ); expect.assert_eq(&expect_res); diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index b8ce2b7430b9..bcbe8aab1a7c 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml @@ -67,7 +67,9 @@ load-cargo.workspace = true proc-macro-api.workspace = true profile.workspace = true project-model.workspace = true +span = { workspace = true , features = ["ra-salsa"]} stdx.workspace = true +syntax-bridge.workspace = true syntax.workspace = true parser.workspace = true toolchain.workspace = true @@ -90,7 +92,6 @@ xshell.workspace = true test-utils.workspace = true test-fixture.workspace = true -syntax-bridge.workspace = true [features] jemalloc = ["jemallocator", "profile/jemalloc"] diff --git a/crates/rust-analyzer/src/cli/highlight.rs b/crates/rust-analyzer/src/cli/highlight.rs index 84607b9fd5d5..238ce2a32861 100644 --- a/crates/rust-analyzer/src/cli/highlight.rs +++ b/crates/rust-analyzer/src/cli/highlight.rs @@ -7,7 +7,7 @@ use crate::cli::{flags, read_stdin}; impl flags::Highlight { pub fn run(self) -> anyhow::Result<()> { let (analysis, file_id) = Analysis::from_single_file(read_stdin()?); - let html = analysis.highlight_as_html(file_id, self.rainbow).unwrap(); + let html = analysis.highlight_as_html(file_id.into(), self.rainbow).unwrap(); println!("{html}"); Ok(()) } diff --git a/crates/rust-analyzer/src/cli/lsif.rs b/crates/rust-analyzer/src/cli/lsif.rs index eb5c44418b72..83df0d7d145c 100644 --- a/crates/rust-analyzer/src/cli/lsif.rs +++ b/crates/rust-analyzer/src/cli/lsif.rs @@ -125,6 +125,7 @@ impl LsifManager<'_, '_> { index: line_index, encoding: PositionEncoding::Wide(WideEncoding::Utf16), endings: LineEndings::Unix, + transform: Default::default(), }; let range_id = self.add_vertex(lsif::Vertex::Range { range: to_proto::range(&line_index, id.range), @@ -246,6 +247,7 @@ impl LsifManager<'_, '_> { index: line_index, encoding: PositionEncoding::Wide(WideEncoding::Utf16), endings: LineEndings::Unix, + transform: Default::default(), }; let result = folds .into_iter() diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs index fe75872105ae..a513df610303 100644 --- a/crates/rust-analyzer/src/cli/scip.rs +++ b/crates/rust-analyzer/src/cli/scip.rs @@ -342,6 +342,7 @@ fn get_line_index(db: &RootDatabase, file_id: FileId) -> LineIndex { index: db.line_index(file_id), encoding: PositionEncoding::Utf8, endings: LineEndings::Unix, + transform: Default::default(), } } diff --git a/crates/rust-analyzer/src/cli/symbols.rs b/crates/rust-analyzer/src/cli/symbols.rs index 9fad6723afcd..a40ea894be86 100644 --- a/crates/rust-analyzer/src/cli/symbols.rs +++ b/crates/rust-analyzer/src/cli/symbols.rs @@ -7,7 +7,7 @@ impl flags::Symbols { pub fn run(self) -> anyhow::Result<()> { let text = read_stdin()?; let (analysis, file_id) = Analysis::from_single_file(text); - let structure = analysis.file_structure(file_id).unwrap(); + let structure = analysis.file_structure(file_id.into()).unwrap(); for s in structure { println!("{s:?}"); } diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 70105cda006b..32fd69ed83bf 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -5,10 +5,14 @@ use std::{ops::Not as _, time::Instant}; +use ::span::HirFileIdRepr; use crossbeam_channel::{unbounded, Receiver, Sender}; -use hir::ChangeWithProcMacros; -use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId}; -use ide_db::base_db::{CrateId, ProcMacroPaths, SourceDatabase, SourceRootDatabase}; +use hir::{db::ExpandDatabase, ChangeWithProcMacros, HirFileId}; +use ide::{Analysis, AnalysisHost, Cancellable, Edition, FileId, SourceRootId}; +use ide_db::{ + base_db::{CrateId, ProcMacroPaths, SourceDatabase, SourceRootDatabase}, + EditionedFileId, +}; use itertools::Itertools; use load_cargo::SourceRootConfig; use lsp_types::{SemanticTokens, Url}; @@ -20,6 +24,8 @@ use parking_lot::{ use proc_macro_api::ProcMacroClient; use project_model::{ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, WorkspaceBuildScripts}; use rustc_hash::{FxHashMap, FxHashSet}; +#[allow(deprecated)] +use syntax_bridge::prettify_macro_expansion::prettify_macro_expansion; use tracing::{span, trace, Level}; use triomphe::Arc; use vfs::{AbsPathBuf, AnchoredPathBuf, ChangeKind, Vfs, VfsPath}; @@ -29,7 +35,7 @@ use crate::{ diagnostics::{CheckFixes, DiagnosticCollection}, discover, flycheck::{FlycheckHandle, FlycheckMessage}, - line_index::{LineEndings, LineIndex}, + line_index::{LineEndings, LineIndex, PositionTransform}, lsp::{from_proto, to_proto::url_from_abs_path}, lsp_ext, main_loop::Task, @@ -655,10 +661,19 @@ impl GlobalStateSnapshot { url_to_file_id(&self.vfs_read(), url) } + /// Returns `None` if the file was excluded. + pub(crate) fn url_to_hir_file_id(&self, url: &Url) -> anyhow::Result> { + url_to_hir_file_id(&self.vfs_read(), url) + } + pub(crate) fn file_id_to_url(&self, id: FileId) -> Url { file_id_to_url(&self.vfs_read(), id) } + pub(crate) fn hir_file_id_to_url(&self, id: HirFileId) -> Url { + hir_file_id_to_url(&self.vfs_read(), id) + } + /// Returns `None` if the file was excluded. pub(crate) fn vfs_path_to_file_id(&self, vfs_path: &VfsPath) -> anyhow::Result> { vfs_path_to_file_id(&self.vfs_read(), vfs_path) @@ -667,16 +682,62 @@ impl GlobalStateSnapshot { pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancellable { let endings = self.vfs.read().1[&file_id]; let index = self.analysis.file_line_index(file_id)?; - let res = LineIndex { index, endings, encoding: self.config.caps().negotiated_encoding() }; + let res = LineIndex { + index, + endings, + encoding: self.config.caps().negotiated_encoding(), + transform: Default::default(), + }; Ok(res) } + pub(crate) fn hir_line_index(&self, file_id: HirFileId) -> Cancellable { + match file_id.repr() { + HirFileIdRepr::FileId(editioned_file_id) => { + self.file_line_index(editioned_file_id.file_id()) + } + HirFileIdRepr::MacroFile(macro_file_id) => { + // FIXME: Cache this + let s = self + .analysis + .with_db(|db| db.parse_macro_expansion(macro_file_id).value.0.syntax_node())?; + let mut transform = vec![]; + #[allow(deprecated)] + let s = prettify_macro_expansion(s, &mut |_| None, |mods| { + transform = mods + .iter() + .map(|(pos, kind)| (pos.offset(), *kind)) + .sorted_by(|&(a_off, a2), &(b_off, b2)| a_off.cmp(&b_off).then_with(|| { + // the prettify infra inserts these in reverse due to implementation + // reasons, but or our line assumptions we need to flip them so that + // then indent is not treated as part of the line + match (a2,b2) { + (syntax_bridge::prettify_macro_expansion::PrettifyWsKind::Indent(_) | syntax_bridge::prettify_macro_expansion::PrettifyWsKind::Space, syntax_bridge::prettify_macro_expansion::PrettifyWsKind::Newline) => std::cmp::Ordering::Greater, + (syntax_bridge::prettify_macro_expansion::PrettifyWsKind::Newline, syntax_bridge::prettify_macro_expansion::PrettifyWsKind::Indent(_) | syntax_bridge::prettify_macro_expansion::PrettifyWsKind::Space) => std::cmp::Ordering::Less, + (syntax_bridge::prettify_macro_expansion::PrettifyWsKind::Space,syntax_bridge::prettify_macro_expansion::PrettifyWsKind::Indent(_)) => std::cmp::Ordering::Greater, + (syntax_bridge::prettify_macro_expansion::PrettifyWsKind::Indent(_),syntax_bridge::prettify_macro_expansion::PrettifyWsKind::Space) => std::cmp::Ordering::Less, + _ => std::cmp::Ordering::Equal + } + })) + .collect(); + }); + let res = LineIndex { + index: Arc::new(ide_db::line_index::LineIndex::new(&s.to_string())), + endings: LineEndings::Unix, + encoding: self.config.caps().negotiated_encoding(), + transform: PositionTransform { insertions: transform }, + }; + Ok(res) + } + } + } + pub(crate) fn file_version(&self, file_id: FileId) -> Option { Some(self.mem_docs.get(self.vfs_read().file_path(file_id))?.version) } pub(crate) fn url_file_version(&self, url: &Url) -> Option { - let path = from_proto::vfs_path(url).ok()?; + let path = from_proto::url_to_vfs_path(url).ok()?.into_vfs()?; Some(self.mem_docs.get(&path)?.version) } @@ -752,10 +813,36 @@ pub(crate) fn file_id_to_url(vfs: &vfs::Vfs, id: FileId) -> Url { url_from_abs_path(path) } +pub(crate) fn hir_file_id_to_url(vfs: &vfs::Vfs, id: HirFileId) -> Url { + match id.repr() { + HirFileIdRepr::FileId(editioned_file_id) => { + file_id_to_url(vfs, editioned_file_id.file_id()) + } + HirFileIdRepr::MacroFile(macro_file_id) => lsp_types::Url::parse(&format!( + "rust-macro-file:{}.macro-file.rs", + ::span::InternKey::as_intern_id(¯o_file_id.macro_call_id).as_u32() + )) + .unwrap(), + } +} + /// Returns `None` if the file was excluded. pub(crate) fn url_to_file_id(vfs: &vfs::Vfs, url: &Url) -> anyhow::Result> { - let path = from_proto::vfs_path(url)?; - vfs_path_to_file_id(vfs, &path) + let path = from_proto::url_to_vfs_path(url)?; + match path { + from_proto::VfsOrMacroPath::Vfs(path) => vfs_path_to_file_id(vfs, &path), + from_proto::VfsOrMacroPath::Macro(..) => anyhow::bail!("unexpected macro file"), + } +} + +/// Returns `None` if the file was excluded. +pub(crate) fn url_to_hir_file_id(vfs: &vfs::Vfs, url: &Url) -> anyhow::Result> { + let path = from_proto::url_to_vfs_path(url)?; + Ok(match path { + from_proto::VfsOrMacroPath::Vfs(path) => vfs_path_to_file_id(vfs, &path)? + .map(|file_id| EditionedFileId::new(file_id, Edition::CURRENT).into()), + from_proto::VfsOrMacroPath::Macro(call) => Some(call.into()), + }) } /// Returns `None` if the file was excluded. diff --git a/crates/rust-analyzer/src/handlers/notification.rs b/crates/rust-analyzer/src/handlers/notification.rs index 55344a4d6ac6..b36b110f18e6 100644 --- a/crates/rust-analyzer/src/handlers/notification.rs +++ b/crates/rust-analyzer/src/handlers/notification.rs @@ -17,7 +17,10 @@ use crate::{ config::{Config, ConfigChange}, flycheck::Target, global_state::{FetchWorkspaceRequest, GlobalState}, - lsp::{from_proto, utils::apply_document_changes}, + lsp::{ + from_proto::{self, VfsOrMacroPath}, + utils::apply_document_changes, + }, lsp_ext::{self, RunFlycheckParams}, mem_docs::DocumentData, reload, @@ -60,7 +63,7 @@ pub(crate) fn handle_did_open_text_document( ) -> anyhow::Result<()> { let _p = tracing::info_span!("handle_did_open_text_document").entered(); - if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { + if let Ok(VfsOrMacroPath::Vfs(path)) = from_proto::url_to_vfs_path(¶ms.text_document.uri) { let already_exists = state .mem_docs .insert( @@ -102,7 +105,7 @@ pub(crate) fn handle_did_change_text_document( ) -> anyhow::Result<()> { let _p = tracing::info_span!("handle_did_change_text_document").entered(); - if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { + if let Ok(VfsOrMacroPath::Vfs(path)) = from_proto::url_to_vfs_path(¶ms.text_document.uri) { let Some(DocumentData { version, data }) = state.mem_docs.get_mut(&path) else { tracing::error!(?path, "unexpected DidChangeTextDocument"); return Ok(()); @@ -131,7 +134,7 @@ pub(crate) fn handle_did_close_text_document( ) -> anyhow::Result<()> { let _p = tracing::info_span!("handle_did_close_text_document").entered(); - if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { + if let Ok(VfsOrMacroPath::Vfs(path)) = from_proto::url_to_vfs_path(¶ms.text_document.uri) { if state.mem_docs.remove(&path).is_err() { tracing::error!("orphan DidCloseTextDocument: {}", path); } @@ -154,9 +157,9 @@ pub(crate) fn handle_did_save_text_document( state: &mut GlobalState, params: DidSaveTextDocumentParams, ) -> anyhow::Result<()> { - if let Ok(vfs_path) = from_proto::vfs_path(¶ms.text_document.uri) { + if let Ok(VfsOrMacroPath::Vfs(path)) = from_proto::url_to_vfs_path(¶ms.text_document.uri) { let snap = state.snapshot(); - let file_id = try_default!(snap.vfs_path_to_file_id(&vfs_path)?); + let file_id = try_default!(snap.vfs_path_to_file_id(&path)?); let sr = snap.analysis.source_root_id(file_id)?; if state.config.script_rebuild_on_save(Some(sr)) && state.build_deps_changed { @@ -167,7 +170,7 @@ pub(crate) fn handle_did_save_text_document( } // Re-fetch workspaces if a workspace related file has changed - if let Some(path) = vfs_path.as_path() { + if let Some(path) = path.as_path() { let additional_files = &state .config .discover_workspace_config() @@ -195,7 +198,7 @@ pub(crate) fn handle_did_save_text_document( } } - if !state.config.check_on_save(Some(sr)) || run_flycheck(state, vfs_path) { + if !state.config.check_on_save(Some(sr)) || run_flycheck(state, path) { return Ok(()); } } else if state.config.check_on_save(None) && state.config.flycheck_workspace(None) { @@ -289,8 +292,10 @@ pub(crate) fn handle_did_change_watched_files( params: DidChangeWatchedFilesParams, ) -> anyhow::Result<()> { for change in params.changes.iter().unique_by(|&it| &it.uri) { - if let Ok(path) = from_proto::abs_path(&change.uri) { - state.loader.handle.invalidate(path); + if let Ok(VfsOrMacroPath::Vfs(path)) = from_proto::url_to_vfs_path(&change.uri) { + if let Some(path) = path.into_abs_path() { + state.loader.handle.invalidate(path); + } } } Ok(()) @@ -449,7 +454,7 @@ pub(crate) fn handle_run_flycheck( ) -> anyhow::Result<()> { let _p = tracing::info_span!("handle_run_flycheck").entered(); if let Some(text_document) = params.text_document { - if let Ok(vfs_path) = from_proto::vfs_path(&text_document.uri) { + if let Ok(VfsOrMacroPath::Vfs(vfs_path)) = from_proto::url_to_vfs_path(&text_document.uri) { if run_flycheck(state, vfs_path) { return Ok(()); } diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index 1b144d90732e..21e7896f4293 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -6,6 +6,7 @@ use std::{fs, io::Write as _, ops::Not, process::Stdio}; use anyhow::Context; use base64::{prelude::BASE64_STANDARD, Engine}; +use hir::{db::ExpandDatabase, HirFileId, HirFilePosition, HirFileRange}; use ide::{ AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve, FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, @@ -28,8 +29,10 @@ use project_model::{CargoWorkspace, ManifestPath, ProjectWorkspaceKind, TargetKi use serde_json::json; use stdx::{format_to, never}; use syntax::{TextRange, TextSize}; +#[allow(deprecated)] +use syntax_bridge::prettify_macro_expansion::prettify_macro_expansion; use triomphe::Arc; -use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath}; +use vfs::{AbsPath, AbsPathBuf, VfsPath}; use crate::{ completion_item_hash, @@ -83,7 +86,7 @@ pub(crate) fn handle_analyzer_status( let mut file_id = None; if let Some(tdi) = params.text_document { - match from_proto::file_id(&snap, &tdi.uri) { + match snap.url_to_file_id(&tdi.uri) { Ok(Some(it)) => file_id = Some(it), Ok(None) => {} Err(_) => format_to!(buf, "file {} not found in vfs", tdi.uri), @@ -143,7 +146,7 @@ pub(crate) fn handle_view_syntax_tree( params: lsp_ext::ViewSyntaxTreeParams, ) -> anyhow::Result { let _p = tracing::info_span!("handle_view_syntax_tree").entered(); - let id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); + let id = try_default!(snap.url_to_file_id(¶ms.text_document.uri)?); let res = snap.analysis.view_syntax_tree(id)?; Ok(res) } @@ -182,7 +185,7 @@ pub(crate) fn handle_view_file_text( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentIdentifier, ) -> anyhow::Result { - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.uri)?); + let file_id = try_default!(snap.url_to_file_id(¶ms.uri)?); Ok(snap.analysis.file_text(file_id)?.to_string()) } @@ -191,7 +194,7 @@ pub(crate) fn handle_view_item_tree( params: lsp_ext::ViewItemTreeParams, ) -> anyhow::Result { let _p = tracing::info_span!("handle_view_item_tree").entered(); - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); + let file_id = try_default!(snap.url_to_file_id(¶ms.text_document.uri)?); let res = snap.analysis.view_item_tree(file_id)?; Ok(res) } @@ -317,11 +320,11 @@ pub(crate) fn handle_expand_macro( params: lsp_ext::ExpandMacroParams, ) -> anyhow::Result> { let _p = tracing::info_span!("handle_expand_macro").entered(); - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); - let line_index = snap.file_line_index(file_id)?; + let file_id = try_default!(snap.url_to_hir_file_id(¶ms.text_document.uri)?); + let line_index = snap.hir_line_index(file_id)?; let offset = from_proto::offset(&line_index, params.position)?; - let res = snap.analysis.expand_macro(FilePosition { file_id, offset })?; + let res = snap.analysis.expand_macro(HirFilePosition { file_id, offset })?; Ok(res.map(|it| lsp_ext::ExpandedMacro { name: it.name, expansion: it.expansion })) } @@ -330,7 +333,7 @@ pub(crate) fn handle_selection_range( params: lsp_types::SelectionRangeParams, ) -> anyhow::Result>> { let _p = tracing::info_span!("handle_selection_range").entered(); - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); + let file_id = try_default!(snap.url_to_file_id(¶ms.text_document.uri)?); let line_index = snap.file_line_index(file_id)?; let res: anyhow::Result> = params .positions @@ -373,7 +376,7 @@ pub(crate) fn handle_matching_brace( params: lsp_ext::MatchingBraceParams, ) -> anyhow::Result> { let _p = tracing::info_span!("handle_matching_brace").entered(); - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); + let file_id = try_default!(snap.url_to_file_id(¶ms.text_document.uri)?); let line_index = snap.file_line_index(file_id)?; params .positions @@ -397,7 +400,7 @@ pub(crate) fn handle_join_lines( ) -> anyhow::Result> { let _p = tracing::info_span!("handle_join_lines").entered(); - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); + let file_id = try_default!(snap.url_to_file_id(¶ms.text_document.uri)?); let config = snap.config.join_lines(); let line_index = snap.file_line_index(file_id)?; @@ -484,10 +487,15 @@ pub(crate) fn handle_document_diagnostics( snap: GlobalStateSnapshot, params: lsp_types::DocumentDiagnosticParams, ) -> anyhow::Result { - let file_id = match from_proto::file_id(&snap, ¶ms.text_document.uri)? { + let file_id = match snap.url_to_hir_file_id(¶ms.text_document.uri)? { Some(it) => it, None => return Ok(empty_diagnostic_report()), }; + + let Some(file_id) = file_id.file_id() else { + return Ok(empty_diagnostic_report()); + }; + let file_id = file_id.file_id(); let source_root = snap.analysis.source_root_id(file_id)?; if !snap.analysis.is_local_source_root(source_root)? { return Ok(empty_diagnostic_report()); @@ -550,8 +558,8 @@ pub(crate) fn handle_document_symbol( params: lsp_types::DocumentSymbolParams, ) -> anyhow::Result> { let _p = tracing::info_span!("handle_document_symbol").entered(); - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); - let line_index = snap.file_line_index(file_id)?; + let file_id = try_default!(snap.url_to_hir_file_id(¶ms.text_document.uri)?); + let line_index = snap.hir_line_index(file_id)?; let mut parents: Vec<(lsp_types::DocumentSymbol, Option)> = Vec::new(); @@ -596,7 +604,7 @@ pub(crate) fn handle_document_symbol( let res = if snap.config.hierarchical_symbols() { document_symbols.into() } else { - let url = to_proto::url(&snap, file_id); + let url = to_proto::url_hir(&snap, file_id); let mut symbol_information = Vec::::new(); for symbol in document_symbols { flatten_document_symbol(&symbol, None, &url, &mut symbol_information); @@ -787,12 +795,12 @@ pub(crate) fn handle_goto_definition( ) -> anyhow::Result> { let _p = tracing::info_span!("handle_goto_definition").entered(); let position = - try_default!(from_proto::file_position(&snap, params.text_document_position_params)?); + try_default!(from_proto::hir_file_position(&snap, params.text_document_position_params)?); let nav_info = match snap.analysis.goto_definition(position)? { None => return Ok(None), Some(it) => it, }; - let src = FileRange { file_id: position.file_id, range: nav_info.range }; + let src = HirFileRange { file_id: position.file_id, range: nav_info.range }; let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; Ok(Some(res)) } @@ -802,7 +810,7 @@ pub(crate) fn handle_goto_declaration( params: lsp_types::request::GotoDeclarationParams, ) -> anyhow::Result> { let _p = tracing::info_span!("handle_goto_declaration").entered(); - let position = try_default!(from_proto::file_position( + let position = try_default!(from_proto::hir_file_position( &snap, params.text_document_position_params.clone() )?); @@ -810,7 +818,7 @@ pub(crate) fn handle_goto_declaration( None => return handle_goto_definition(snap, params), Some(it) => it, }; - let src = FileRange { file_id: position.file_id, range: nav_info.range }; + let src = HirFileRange { file_id: position.file_id, range: nav_info.range }; let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; Ok(Some(res)) } @@ -821,12 +829,12 @@ pub(crate) fn handle_goto_implementation( ) -> anyhow::Result> { let _p = tracing::info_span!("handle_goto_implementation").entered(); let position = - try_default!(from_proto::file_position(&snap, params.text_document_position_params)?); + try_default!(from_proto::hir_file_position(&snap, params.text_document_position_params)?); let nav_info = match snap.analysis.goto_implementation(position)? { None => return Ok(None), Some(it) => it, }; - let src = FileRange { file_id: position.file_id, range: nav_info.range }; + let src = HirFileRange { file_id: position.file_id, range: nav_info.range }; let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; Ok(Some(res)) } @@ -837,12 +845,12 @@ pub(crate) fn handle_goto_type_definition( ) -> anyhow::Result> { let _p = tracing::info_span!("handle_goto_type_definition").entered(); let position = - try_default!(from_proto::file_position(&snap, params.text_document_position_params)?); + try_default!(from_proto::hir_file_position(&snap, params.text_document_position_params)?); let nav_info = match snap.analysis.goto_type_definition(position)? { None => return Ok(None), Some(it) => it, }; - let src = FileRange { file_id: position.file_id, range: nav_info.range }; + let src = HirFileRange { file_id: position.file_id, range: nav_info.range }; let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?; Ok(Some(res)) } @@ -890,7 +898,7 @@ pub(crate) fn handle_parent_module( } // check if invoked at the crate root - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); + let file_id = try_default!(snap.url_to_file_id(¶ms.text_document.uri)?); let crate_id = match snap.analysis.crates_for(file_id)?.first() { Some(&crate_id) => crate_id, None => return Ok(None), @@ -914,7 +922,7 @@ pub(crate) fn handle_parent_module( } // locate parent module by semantics - let position = try_default!(from_proto::file_position(&snap, params)?); + let position = try_default!(from_proto::hir_file_position(&snap, params)?); let navs = snap.analysis.parent_module(position)?; let res = to_proto::goto_definition_response(&snap, None, navs)?; Ok(Some(res)) @@ -925,11 +933,14 @@ pub(crate) fn handle_runnables( params: lsp_ext::RunnablesParams, ) -> anyhow::Result> { let _p = tracing::info_span!("handle_runnables").entered(); - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); - let source_root = snap.analysis.source_root_id(file_id).ok(); - let line_index = snap.file_line_index(file_id)?; + let file_id = try_default!(snap.url_to_hir_file_id(¶ms.text_document.uri)?); + // let source_root = snap.analysis.source_root_id(file_id).ok(); + // FIXME + let source_root = None; + + let line_index = snap.hir_line_index(file_id)?; let offset = params.position.and_then(|it| from_proto::offset(&line_index, it).ok()); - let target_spec = TargetSpec::for_file(&snap, file_id)?; + let target_spec = TargetSpec::for_hir_file(&snap, file_id)?; let mut res = Vec::new(); for runnable in snap.analysis.runnables(file_id)? { @@ -1009,23 +1020,24 @@ pub(crate) fn handle_runnables( Some(TargetSpec::ProjectJson(_)) => {} None => { if !snap.config.linked_or_discovered_projects().is_empty() { - if let Some(path) = snap.file_id_to_file_path(file_id).parent() { - let mut cargo_args = vec!["check".to_owned(), "--workspace".to_owned()]; - cargo_args.extend(config.cargo_extra_args.iter().cloned()); - res.push(lsp_ext::Runnable { - label: "cargo check --workspace".to_owned(), - location: None, - kind: lsp_ext::RunnableKind::Cargo, - args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs { - workspace_root: None, - cwd: path.as_path().unwrap().to_path_buf().into(), - override_cargo: config.override_cargo, - cargo_args, - executable_args: Vec::new(), - environment: Default::default(), - }), - }); - }; + // FIXME + // if let Some(path) = snap.file_id_to_file_path(file_id).parent() { + // let mut cargo_args = vec!["check".to_owned(), "--workspace".to_owned()]; + // cargo_args.extend(config.cargo_extra_args.iter().cloned()); + // res.push(lsp_ext::Runnable { + // label: "cargo check --workspace".to_owned(), + // location: None, + // kind: lsp_ext::RunnableKind::Cargo, + // args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs { + // workspace_root: None, + // cwd: path.as_path().unwrap().to_path_buf().into(), + // override_cargo: config.override_cargo, + // cargo_args, + // executable_args: Vec::new(), + // environment: Default::default(), + // }), + // }); + // }; } } } @@ -1113,8 +1125,10 @@ pub(crate) fn handle_completion_resolve( let resolve_data: lsp_ext::CompletionResolveData = serde_json::from_value(data)?; - let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)? + let file_id = snap + .url_to_file_id(&resolve_data.position.text_document.uri)? .expect("we never provide completions for excluded files"); + let line_index = snap.file_line_index(file_id)?; // FIXME: We should fix up the position when retrying the cancelled request instead let Ok(offset) = from_proto::offset(&line_index, resolve_data.position.position) else { @@ -1197,11 +1211,15 @@ pub(crate) fn handle_folding_range( params: FoldingRangeParams, ) -> anyhow::Result>> { let _p = tracing::info_span!("handle_folding_range").entered(); - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); + let file_id = try_default!(snap.url_to_hir_file_id(¶ms.text_document.uri)?); let folds = snap.analysis.folding_ranges(file_id)?; - let text = snap.analysis.file_text(file_id)?; - let line_index = snap.file_line_index(file_id)?; - let line_folding_only = snap.config.line_folding_only(); + let (text, line_folding_only) = match file_id.repr() { + span::HirFileIdRepr::FileId(editioned_file_id) => { + (snap.analysis.file_text(editioned_file_id.file_id())?, snap.config.line_folding_only()) + } + span::HirFileIdRepr::MacroFile(_) => (Arc::from(String::new()) as Arc, false), + }; + let line_index = snap.hir_line_index(file_id)?; let res = folds .into_iter() .map(|it| to_proto::folding_range(&text, &line_index, line_folding_only, it)) @@ -1234,7 +1252,7 @@ pub(crate) fn handle_hover( PositionOrRange::Position(position) => Range::new(position, position), PositionOrRange::Range(range) => range, }; - let file_range = try_default!(from_proto::file_range(&snap, ¶ms.text_document, range)?); + let file_range = try_default!(from_proto::hir_file_range(&snap, ¶ms.text_document, range)?); let hover = snap.config.hover(); let info = match snap.analysis.hover(&hover, file_range)? { @@ -1242,7 +1260,7 @@ pub(crate) fn handle_hover( Some(info) => info, }; - let line_index = snap.file_line_index(file_range.file_id)?; + let line_index = snap.hir_line_index(file_range.file_id)?; let range = to_proto::range(&line_index, info.range); let markup_kind = hover.format; let hover = lsp_ext::Hover { @@ -1317,7 +1335,8 @@ pub(crate) fn handle_references( params: lsp_types::ReferenceParams, ) -> anyhow::Result>> { let _p = tracing::info_span!("handle_references").entered(); - let position = try_default!(from_proto::file_position(&snap, params.text_document_position)?); + let position = + try_default!(from_proto::hir_file_position(&snap, params.text_document_position)?); let exclude_imports = snap.config.find_all_refs_exclude_imports(); let exclude_tests = snap.config.find_all_refs_exclude_tests(); @@ -1331,7 +1350,7 @@ pub(crate) fn handle_references( .into_iter() .flat_map(|refs| { let decl = if include_declaration { - refs.declaration.map(|decl| FileRange { + refs.declaration.map(|decl| HirFileRange { file_id: decl.nav.file_id, range: decl.nav.focus_or_full_range(), }) @@ -1346,7 +1365,7 @@ pub(crate) fn handle_references( (!exclude_imports || !category.contains(ReferenceCategory::IMPORT)) && (!exclude_tests || !category.contains(ReferenceCategory::TEST)) }) - .map(move |(range, _)| FileRange { file_id, range }) + .map(move |(range, _)| HirFileRange { file_id, range }) }) .chain(decl) }) @@ -1388,7 +1407,7 @@ pub(crate) fn handle_code_action( return Ok(None); } - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); + let file_id = try_default!(snap.url_to_file_id(¶ms.text_document.uri)?); let line_index = snap.file_line_index(file_id)?; let frange = try_default!(from_proto::file_range(&snap, ¶ms.text_document, params.range)?); let source_root = snap.analysis.source_root_id(file_id)?; @@ -1468,8 +1487,10 @@ pub(crate) fn handle_code_action_resolve( return Err(invalid_params_error("code action without data".to_owned()).into()); }; - let file_id = from_proto::file_id(&snap, ¶ms.code_action_params.text_document.uri)? + let file_id = snap + .url_to_file_id(¶ms.code_action_params.text_document.uri)? .expect("we never provide code actions for excluded files"); + if snap.file_version(file_id) != params.version { return Err(invalid_params_error("stale code action".to_owned()).into()); } @@ -1565,8 +1586,8 @@ pub(crate) fn handle_code_lens( return Ok(Some(Vec::default())); } - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); - let target_spec = TargetSpec::for_file(&snap, file_id)?; + let file_id = try_default!(snap.url_to_hir_file_id(¶ms.text_document.uri)?); + let target_spec = TargetSpec::for_hir_file(&snap, file_id)?; let annotations = snap.analysis.annotations( &AnnotationConfig { @@ -1628,17 +1649,16 @@ pub(crate) fn handle_document_highlight( ) -> anyhow::Result>> { let _p = tracing::info_span!("handle_document_highlight").entered(); let position = - try_default!(from_proto::file_position(&snap, params.text_document_position_params)?); - let line_index = snap.file_line_index(position.file_id)?; - let source_root = snap.analysis.source_root_id(position.file_id)?; + try_default!(from_proto::hir_file_position(&snap, params.text_document_position_params)?); + let line_index = snap.hir_line_index(position.file_id)?; + // FIXME + // let source_root = snap.analysis.source_root_id(position.file_id)?; - let refs = match snap - .analysis - .highlight_related(snap.config.highlight_related(Some(source_root)), position)? - { - None => return Ok(None), - Some(refs) => refs, - }; + let refs = + match snap.analysis.highlight_related(snap.config.highlight_related(None), position)? { + None => return Ok(None), + Some(refs) => refs, + }; let res = refs .into_iter() .map(|ide::HighlightedRange { range, category }| lsp_types::DocumentHighlight { @@ -1675,12 +1695,12 @@ pub(crate) fn handle_inlay_hints( ) -> anyhow::Result>> { let _p = tracing::info_span!("handle_inlay_hints").entered(); let document_uri = ¶ms.text_document.uri; - let FileRange { file_id, range } = try_default!(from_proto::file_range( + let HirFileRange { file_id, range } = try_default!(from_proto::hir_file_range( &snap, &TextDocumentIdentifier::new(document_uri.to_owned()), params.range, )?); - let line_index = snap.file_line_index(file_id)?; + let line_index = snap.hir_line_index(file_id)?; let range = TextRange::new( range.start().min(line_index.index.len()), range.end().min(line_index.index.len()), @@ -1712,15 +1732,21 @@ pub(crate) fn handle_inlay_hints_resolve( let Some(data) = original_hint.data.take() else { return Ok(original_hint) }; let resolve_data: lsp_ext::InlayHintResolveData = serde_json::from_value(data)?; - let file_id = FileId::from_raw(resolve_data.file_id); - if resolve_data.version != snap.file_version(file_id) { + let file_id = HirFileId::from_raw(resolve_data.file_id); + if file_id + .file_id() + .is_some_and(|file_id| resolve_data.version != snap.file_version(file_id.file_id())) + { tracing::warn!("Inlay hint resolve data is outdated"); return Ok(original_hint); } let Some(hash) = resolve_data.hash.parse().ok() else { return Ok(original_hint) }; - anyhow::ensure!(snap.file_exists(file_id), "Invalid LSP resolve data"); + anyhow::ensure!( + file_id.file_id().is_none_or(|file_id| snap.file_exists(file_id.file_id())), + "Invalid LSP resolve data" + ); - let line_index = snap.file_line_index(file_id)?; + let line_index = snap.hir_line_index(file_id)?; let range = from_proto::text_range(&line_index, resolve_data.resolve_range)?; let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints(); @@ -1760,7 +1786,7 @@ pub(crate) fn handle_call_hierarchy_prepare( ) -> anyhow::Result>> { let _p = tracing::info_span!("handle_call_hierarchy_prepare").entered(); let position = - try_default!(from_proto::file_position(&snap, params.text_document_position_params)?); + try_default!(from_proto::hir_file_position(&snap, params.text_document_position_params)?); let nav_info = match snap.analysis.call_hierarchy(position)? { None => return Ok(None), @@ -1785,8 +1811,8 @@ pub(crate) fn handle_call_hierarchy_incoming( let item = params.item; let doc = TextDocumentIdentifier::new(item.uri); - let frange = try_default!(from_proto::file_range(&snap, &doc, item.selection_range)?); - let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; + let frange = try_default!(from_proto::hir_file_range(&snap, &doc, item.selection_range)?); + let fpos = HirFilePosition { file_id: frange.file_id, offset: frange.range.start() }; let config = snap.config.call_hierarchy(); let call_items = match snap.analysis.incoming_calls(config, fpos)? { @@ -1798,7 +1824,7 @@ pub(crate) fn handle_call_hierarchy_incoming( for call_item in call_items.into_iter() { let file_id = call_item.target.file_id; - let line_index = snap.file_line_index(file_id)?; + let line_index = snap.hir_line_index(file_id)?; let item = to_proto::call_hierarchy_item(&snap, call_item.target)?; res.push(CallHierarchyIncomingCall { from: item, @@ -1823,9 +1849,9 @@ pub(crate) fn handle_call_hierarchy_outgoing( let item = params.item; let doc = TextDocumentIdentifier::new(item.uri); - let frange = try_default!(from_proto::file_range(&snap, &doc, item.selection_range)?); - let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; - let line_index = snap.file_line_index(fpos.file_id)?; + let frange = try_default!(from_proto::hir_file_range(&snap, &doc, item.selection_range)?); + let fpos = HirFilePosition { file_id: frange.file_id, offset: frange.range.start() }; + let line_index = snap.hir_line_index(fpos.file_id)?; let config = snap.config.call_hierarchy(); let call_items = match snap.analysis.outgoing_calls(config, fpos)? { @@ -1858,9 +1884,8 @@ pub(crate) fn handle_semantic_tokens_full( ) -> anyhow::Result> { let _p = tracing::info_span!("handle_semantic_tokens_full").entered(); - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); - let text = snap.analysis.file_text(file_id)?; - let line_index = snap.file_line_index(file_id)?; + let file_id = try_default!(snap.url_to_hir_file_id(¶ms.text_document.uri)?); + let line_index = snap.hir_line_index(file_id)?; let mut highlight_config = snap.config.highlighting_config(); // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet. @@ -1869,7 +1894,7 @@ pub(crate) fn handle_semantic_tokens_full( let highlights = snap.analysis.highlight(highlight_config, file_id)?; let semantic_tokens = to_proto::semantic_tokens( - &text, + // &text, &line_index, highlights, snap.config.semantics_tokens_augments_syntax_tokens(), @@ -1888,9 +1913,8 @@ pub(crate) fn handle_semantic_tokens_full_delta( ) -> anyhow::Result> { let _p = tracing::info_span!("handle_semantic_tokens_full_delta").entered(); - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); - let text = snap.analysis.file_text(file_id)?; - let line_index = snap.file_line_index(file_id)?; + let file_id = try_default!(snap.url_to_hir_file_id(¶ms.text_document.uri)?); + let line_index = snap.hir_line_index(file_id)?; let mut highlight_config = snap.config.highlighting_config(); // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet. @@ -1899,7 +1923,7 @@ pub(crate) fn handle_semantic_tokens_full_delta( let highlights = snap.analysis.highlight(highlight_config, file_id)?; let semantic_tokens = to_proto::semantic_tokens( - &text, + // &text, &line_index, highlights, snap.config.semantics_tokens_augments_syntax_tokens(), @@ -1931,9 +1955,9 @@ pub(crate) fn handle_semantic_tokens_range( ) -> anyhow::Result> { let _p = tracing::info_span!("handle_semantic_tokens_range").entered(); - let frange = try_default!(from_proto::file_range(&snap, ¶ms.text_document, params.range)?); - let text = snap.analysis.file_text(frange.file_id)?; - let line_index = snap.file_line_index(frange.file_id)?; + let frange = + try_default!(from_proto::hir_file_range(&snap, ¶ms.text_document, params.range)?); + let line_index = snap.hir_line_index(frange.file_id)?; let mut highlight_config = snap.config.highlighting_config(); // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet. @@ -1942,7 +1966,7 @@ pub(crate) fn handle_semantic_tokens_range( let highlights = snap.analysis.highlight_range(highlight_config, frange)?; let semantic_tokens = to_proto::semantic_tokens( - &text, + // &text, &line_index, highlights, snap.config.semantics_tokens_augments_syntax_tokens(), @@ -1998,7 +2022,7 @@ pub(crate) fn handle_open_cargo_toml( params: lsp_ext::OpenCargoTomlParams, ) -> anyhow::Result> { let _p = tracing::info_span!("handle_open_cargo_toml").entered(); - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); + let file_id = try_default!(snap.url_to_file_id(¶ms.text_document.uri)?); let cargo_spec = match TargetSpec::for_file(&snap, file_id)? { Some(TargetSpec::Cargo(it)) => it, @@ -2011,12 +2035,30 @@ pub(crate) fn handle_open_cargo_toml( Ok(Some(res)) } +pub(crate) fn macro_file_content( + snap: GlobalStateSnapshot, + url: lsp_types::TextDocumentIdentifier, +) -> anyhow::Result { + let file_id = snap.url_to_hir_file_id(&url.uri)?.expect("expected macro file"); + snap.analysis + .with_db(|db| { + #[allow(deprecated)] + prettify_macro_expansion( + db.parse_macro_expansion(file_id.macro_file().unwrap()).value.0.syntax_node(), + &mut |_| None, + |_| (), + ) + .to_string() + }) + .map_err(Into::into) +} + pub(crate) fn handle_move_item( snap: GlobalStateSnapshot, params: lsp_ext::MoveItemParams, ) -> anyhow::Result> { let _p = tracing::info_span!("handle_move_item").entered(); - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); + let file_id = try_default!(snap.url_to_file_id(¶ms.text_document.uri)?); let range = try_default!(from_proto::file_range(&snap, ¶ms.text_document, params.range)?); let direction = match params.direction { @@ -2038,7 +2080,7 @@ pub(crate) fn handle_view_recursive_memory_layout( params: lsp_types::TextDocumentPositionParams, ) -> anyhow::Result> { let _p = tracing::info_span!("handle_view_recursive_memory_layout").entered(); - let file_id = try_default!(from_proto::file_id(&snap, ¶ms.text_document.uri)?); + let file_id = try_default!(snap.url_to_file_id(¶ms.text_document.uri)?); let line_index = snap.file_line_index(file_id)?; let offset = from_proto::offset(&line_index, params.position)?; @@ -2067,12 +2109,12 @@ fn to_command_link(command: lsp_types::Command, tooltip: String) -> lsp_ext::Com fn show_impl_command_link( snap: &GlobalStateSnapshot, - position: &FilePosition, + position: &HirFilePosition, ) -> Option { if snap.config.hover_actions().implementations && snap.config.client_commands().show_reference { if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) { - let uri = to_proto::url(snap, position.file_id); - let line_index = snap.file_line_index(position.file_id).ok()?; + let uri = to_proto::url_hir(snap, position.file_id); + let line_index = snap.hir_line_index(position.file_id).ok()?; let position = to_proto::position(&line_index, position.offset); let locations: Vec<_> = nav_data .info @@ -2093,18 +2135,18 @@ fn show_impl_command_link( fn show_ref_command_link( snap: &GlobalStateSnapshot, - position: &FilePosition, + position: &HirFilePosition, ) -> Option { if snap.config.hover_actions().references && snap.config.client_commands().show_reference { if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) { - let uri = to_proto::url(snap, position.file_id); - let line_index = snap.file_line_index(position.file_id).ok()?; + let uri = to_proto::url_hir(snap, position.file_id); + let line_index = snap.hir_line_index(position.file_id).ok()?; let position = to_proto::position(&line_index, position.offset); let locations: Vec<_> = ref_search_res .into_iter() .flat_map(|res| res.references) .flat_map(|(file_id, ranges)| { - ranges.into_iter().map(move |(range, _)| FileRange { file_id, range }) + ranges.into_iter().map(move |(range, _)| HirFileRange { file_id, range }) }) .unique() .filter_map(|range| to_proto::location(snap, range).ok()) @@ -2130,7 +2172,7 @@ fn runnable_action_links( return None; } - let target_spec = TargetSpec::for_file(snap, runnable.nav.file_id).ok()?; + let target_spec = TargetSpec::for_hir_file(snap, runnable.nav.file_id).ok()?; if should_skip_target(&runnable, target_spec.as_ref()) { return None; } @@ -2226,7 +2268,7 @@ fn run_rustfmt( text_document: TextDocumentIdentifier, range: Option, ) -> anyhow::Result>> { - let file_id = try_default!(from_proto::file_id(snap, &text_document.uri)?); + let file_id = try_default!(snap.url_to_file_id(&text_document.uri)?); let file = snap.analysis.file_text(file_id)?; // Determine the edition of the crate the file belongs to (if there's multiple, we pick the @@ -2437,7 +2479,7 @@ pub(crate) fn internal_testing_fetch_config( Some(it) => Some( state .analysis - .source_root_id(try_default!(from_proto::file_id(&state, &it.uri)?)) + .source_root_id(try_default!(state.url_to_file_id(&it.uri)?)) .map_err(anyhow::Error::from)?, ), None => None, diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs index c6aa8ba17077..23ca72312236 100644 --- a/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -13,13 +13,14 @@ use hir::ChangeWithProcMacros; use ide::{ AnalysisHost, CallableSnippets, CompletionConfig, CompletionFieldsToResolve, DiagnosticsConfig, - FilePosition, TextSize, + Edition, FilePosition, TextSize, }; use ide_db::{ imports::insert_use::{ImportGranularity, InsertUseConfig}, SnippetCap, }; use project_model::CargoConfig; +use span::EditionedFileId; use test_utils::project_root; use vfs::{AbsPathBuf, VfsPath}; @@ -76,7 +77,9 @@ fn integrated_highlighting_benchmark() { { let _it = stdx::timeit("initial"); let analysis = host.analysis(); - analysis.highlight_as_html(file_id, false).unwrap(); + analysis + .highlight_as_html(EditionedFileId::new(file_id, Edition::CURRENT).into(), false) + .unwrap(); } { @@ -97,7 +100,9 @@ fn integrated_highlighting_benchmark() { let _it = stdx::timeit("after change"); let _span = profile::cpu_span(); let analysis = host.analysis(); - analysis.highlight_as_html(file_id, false).unwrap(); + analysis + .highlight_as_html(EditionedFileId::new(file_id, Edition::CURRENT).into(), false) + .unwrap(); } } diff --git a/crates/rust-analyzer/src/line_index.rs b/crates/rust-analyzer/src/line_index.rs index 951762074073..c4b4e652c9c8 100644 --- a/crates/rust-analyzer/src/line_index.rs +++ b/crates/rust-analyzer/src/line_index.rs @@ -5,8 +5,11 @@ //! This module does line ending conversion and detection (so that we can //! convert back to `\r\n` on the way out). +use ide::{TextRange, TextSize}; use ide_db::line_index::WideEncoding; +use itertools::Itertools; use memchr::memmem; +use syntax_bridge::prettify_macro_expansion::PrettifyWsKind; use triomphe::Arc; #[derive(Clone, Copy)] @@ -19,6 +22,111 @@ pub(crate) struct LineIndex { pub(crate) index: Arc, pub(crate) endings: LineEndings, pub(crate) encoding: PositionEncoding, + pub(crate) transform: PositionTransform, +} + +impl LineIndex { + pub(crate) fn line_col(&self, mut offset: TextSize) -> ide::LineCol { + if !self.transform.insertions.is_empty() { + offset += TextSize::new( + self.transform + .insertions + .iter() + .copied() + .take_while(|&(off, _)| off < offset) + .map(|(_, len)| ws_kind_width(len)) + .sum::(), + ); + } + self.index.line_col(offset) + } + pub(crate) fn offset(&self, line_col: ide::LineCol) -> Option { + let mut offset = self.index.offset(line_col)?; + if !self.transform.insertions.is_empty() { + let mut iter = self.transform.insertions.iter(); + let overall_sub = TextSize::new(if line_col.line == 0 { + 0 + } else { + // collect all ws insertions until the line `line` starts + // we need to offset our range by this value + let mut nl_seen = 0; + let res = iter + .peeking_take_while(|&&(_p, ws)| { + let m = nl_seen != line_col.line; + if ws == PrettifyWsKind::Newline { + nl_seen += 1; + } + m + }) + .copied() + .map(|(_, len)| ws_kind_width(len)) + .sum::(); + + res + }); + offset -= overall_sub; + + for (pos, ws) in iter.copied().take_while(|&(_, ws)| ws != PrettifyWsKind::Newline) { + if offset < pos { + break; + } + offset -= TextSize::new(ws_kind_width(ws)); + } + } + Some(offset) + } + + pub(crate) fn line(&self, line: u32) -> Option { + let mut range = self.index.line(line)?; + if !self.transform.insertions.is_empty() { + let mut iter = self.transform.insertions.iter(); + let overall_sub = TextSize::new(if line == 0 { + 0 + } else { + // collect all ws insertions until the line `line` starts + // we need to offset our range by this value + let mut nl_seen = 0; + let res = iter + .peeking_take_while(|&&(_p, ws)| { + let m = nl_seen != line; + if ws == PrettifyWsKind::Newline { + nl_seen += 1; + } + m + }) + .copied() + .map(|(_, len)| ws_kind_width(len)) + .sum::(); + + res + }); + + // collect all ws insertions within the line `line` + // we need to deduct this from range end by this value + let end_sub = TextSize::new( + iter.copied() + .take_while(|&(_, ws)| ws != PrettifyWsKind::Newline) + .map(|(_, len)| ws_kind_width(len)) + .sum::(), + ); + range = + TextRange::new(range.start() - overall_sub, range.end() - overall_sub - end_sub); + } + Some(range) + } +} + +#[derive(Default)] +pub(crate) struct PositionTransform { + pub insertions: Vec<(TextSize, PrettifyWsKind)>, +} + +fn ws_kind_width(ws: PrettifyWsKind) -> u32 { + match ws { + PrettifyWsKind::Space => 1, + PrettifyWsKind::Indent(indent) => 4 * (indent as u32), + PrettifyWsKind::Newline => 1, + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/crates/rust-analyzer/src/lsp/capabilities.rs b/crates/rust-analyzer/src/lsp/capabilities.rs index b1136dbbdac3..8b1e9d08e491 100644 --- a/crates/rust-analyzer/src/lsp/capabilities.rs +++ b/crates/rust-analyzer/src/lsp/capabilities.rs @@ -415,6 +415,10 @@ impl ClientCapabilities { == Some(true) } + pub fn virtual_macro_files(&self) -> bool { + self.experimental_bool("virtualMacroFiles") + } + pub fn code_action_group(&self) -> bool { self.experimental_bool("codeActionGroup") } diff --git a/crates/rust-analyzer/src/lsp/ext.rs b/crates/rust-analyzer/src/lsp/ext.rs index ca4372aa83f8..a3df765006d2 100644 --- a/crates/rust-analyzer/src/lsp/ext.rs +++ b/crates/rust-analyzer/src/lsp/ext.rs @@ -18,6 +18,14 @@ use paths::Utf8PathBuf; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; +pub enum MacroFileContent {} + +impl Request for MacroFileContent { + type Params = lsp_types::TextDocumentIdentifier; + type Result = String; + const METHOD: &'static str = "rust-analyzer/macroFileContent"; +} + pub enum InternalTestingFetchConfig {} #[derive(Deserialize, Serialize, Debug)] diff --git a/crates/rust-analyzer/src/lsp/from_proto.rs b/crates/rust-analyzer/src/lsp/from_proto.rs index 6375a1a054b7..9c392e40630b 100644 --- a/crates/rust-analyzer/src/lsp/from_proto.rs +++ b/crates/rust-analyzer/src/lsp/from_proto.rs @@ -1,8 +1,14 @@ //! Conversion lsp_types types to rust-analyzer specific ones. use anyhow::format_err; +use hir::{HirFilePosition, HirFileRange}; use ide::{Annotation, AnnotationKind, AssistKind, LineCol}; -use ide_db::{line_index::WideLineCol, FileId, FilePosition, FileRange}; +use ide_db::{ + base_db::ra_salsa::{InternId, InternKey}, + line_index::WideLineCol, + FilePosition, FileRange, +}; use paths::Utf8PathBuf; +use span::MacroCallId; use syntax::{TextRange, TextSize}; use vfs::AbsPathBuf; @@ -12,13 +18,37 @@ use crate::{ lsp_ext, try_default, }; -pub(crate) fn abs_path(url: &lsp_types::Url) -> anyhow::Result { - let path = url.to_file_path().map_err(|()| anyhow::format_err!("url is not a file"))?; - Ok(AbsPathBuf::try_from(Utf8PathBuf::from_path_buf(path).unwrap()).unwrap()) +#[derive(Clone)] +pub(crate) enum VfsOrMacroPath { + Vfs(vfs::VfsPath), + Macro(MacroCallId), } -pub(crate) fn vfs_path(url: &lsp_types::Url) -> anyhow::Result { - abs_path(url).map(vfs::VfsPath::from) +impl VfsOrMacroPath { + pub(crate) fn into_vfs(self) -> Option { + if let Self::Vfs(v) = self { + Some(v) + } else { + None + } + } +} + +pub(crate) fn url_to_vfs_path(url: &lsp_types::Url) -> anyhow::Result { + if url.scheme() == "rust-macro-file" { + // rust-macro-file:/id.macro-file.rs + let macro_call = url + .path() + .strip_suffix(".macro-file.rs") + .unwrap() + .parse::() + .unwrap_or_else(|_| panic!("{url:?}")); + + return Ok(VfsOrMacroPath::Macro(MacroCallId::from_intern_id(InternId::from(macro_call)))); + } + let path = url.to_file_path().map_err(|()| anyhow::format_err!("url is not a file"))?; + let path = AbsPathBuf::try_from(Utf8PathBuf::from_path_buf(path).unwrap()).unwrap(); + Ok(VfsOrMacroPath::Vfs(vfs::VfsPath::from(path))) } pub(crate) fn offset( @@ -35,18 +65,9 @@ pub(crate) fn offset( .ok_or_else(|| format_err!("Invalid wide col offset"))? } }; - let line_range = line_index.index.line(line_col.line).ok_or_else(|| { + line_index.offset(line_col).ok_or_else(|| { format_err!("Invalid offset {line_col:?} (line index length: {:?})", line_index.index.len()) - })?; - let col = TextSize::from(line_col.col); - let clamped_len = col.min(line_range.len()); - if clamped_len < col { - tracing::error!( - "Position {line_col:?} column exceeds line length {}, clamping it", - u32::from(line_range.len()), - ); - } - Ok(line_range.start() + clamped_len) + }) } pub(crate) fn text_range( @@ -61,25 +82,28 @@ pub(crate) fn text_range( } } -/// Returns `None` if the file was excluded. -pub(crate) fn file_id( - snap: &GlobalStateSnapshot, - url: &lsp_types::Url, -) -> anyhow::Result> { - snap.url_to_file_id(url) -} - /// Returns `None` if the file was excluded. pub(crate) fn file_position( snap: &GlobalStateSnapshot, tdpp: lsp_types::TextDocumentPositionParams, ) -> anyhow::Result> { - let file_id = try_default!(file_id(snap, &tdpp.text_document.uri)?); + let file_id = try_default!(snap.url_to_file_id(&tdpp.text_document.uri)?); let line_index = snap.file_line_index(file_id)?; let offset = offset(&line_index, tdpp.position)?; Ok(Some(FilePosition { file_id, offset })) } +/// Returns `None` if the file was excluded. +pub(crate) fn hir_file_position( + snap: &GlobalStateSnapshot, + tdpp: lsp_types::TextDocumentPositionParams, +) -> anyhow::Result> { + let file_id = try_default!(snap.url_to_hir_file_id(&tdpp.text_document.uri)?); + let line_index = snap.hir_line_index(file_id)?; + let offset = offset(&line_index, tdpp.position)?; + Ok(Some(HirFilePosition { file_id, offset })) +} + /// Returns `None` if the file was excluded. pub(crate) fn file_range( snap: &GlobalStateSnapshot, @@ -90,12 +114,23 @@ pub(crate) fn file_range( } /// Returns `None` if the file was excluded. +pub(crate) fn hir_file_range( + snap: &GlobalStateSnapshot, + text_document_identifier: &lsp_types::TextDocumentIdentifier, + range: lsp_types::Range, +) -> anyhow::Result> { + let file_id = try_default!(snap.url_to_hir_file_id(&text_document_identifier.uri)?); + let line_index = snap.hir_line_index(file_id)?; + let range = text_range(&line_index, range)?; + Ok(Some(HirFileRange { file_id, range })) +} + pub(crate) fn file_range_uri( snap: &GlobalStateSnapshot, document: &lsp_types::Url, range: lsp_types::Range, ) -> anyhow::Result> { - let file_id = try_default!(file_id(snap, document)?); + let file_id = try_default!(snap.url_to_file_id(document)?); let line_index = snap.file_line_index(file_id)?; let range = text_range(&line_index, range)?; Ok(Some(FileRange { file_id, range })) @@ -128,9 +163,9 @@ pub(crate) fn annotation( { return Ok(None); } - let pos @ FilePosition { file_id, .. } = - try_default!(file_position(snap, params.text_document_position_params)?); - let line_index = snap.file_line_index(file_id)?; + let pos @ HirFilePosition { file_id, .. } = + try_default!(hir_file_position(snap, params.text_document_position_params)?); + let line_index = snap.hir_line_index(file_id)?; Ok(Annotation { range: text_range(&line_index, range)?, @@ -141,8 +176,9 @@ pub(crate) fn annotation( if snap.url_file_version(¶ms.text_document.uri) != Some(data.version) { return Ok(None); } - let pos @ FilePosition { file_id, .. } = try_default!(file_position(snap, params)?); - let line_index = snap.file_line_index(file_id)?; + let pos @ HirFilePosition { file_id, .. } = + try_default!(hir_file_position(snap, params)?); + let line_index = snap.hir_line_index(file_id)?; Ok(Annotation { range: text_range(&line_index, range)?, diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs index bff53cf98b7b..f339bb293f8a 100644 --- a/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/crates/rust-analyzer/src/lsp/to_proto.rs @@ -7,15 +7,16 @@ use std::{ }; use base64::{prelude::BASE64_STANDARD, Engine}; +use hir::{HirFileId, HirFileIdExt, HirFileRange}; use ide::{ Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionFieldsToResolve, - CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, - FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, - InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, LazyProperty, - Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp, + CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileSystemEdit, + Fold, FoldKind, Highlight, HirNavigationTarget, HlMod, HlOperator, HlPunct, HlRange, HlTag, + Indel, InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, + LazyProperty, Markup, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp, SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize, }; -use ide_db::{assists, rust_doc::format_docs, FxHasher}; +use ide_db::{assists, base_db::SourceRootDatabase, rust_doc::format_docs, FxHasher}; use itertools::Itertools; use paths::{Utf8Component, Utf8Prefix}; use semver::VersionReq; @@ -39,7 +40,7 @@ use crate::{ }; pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position { - let line_col = line_index.index.line_col(offset); + let line_col = line_index.line_col(offset); match line_index.encoding { PositionEncoding::Utf8 => lsp_types::Position::new(line_col.line, line_col.col), PositionEncoding::Wide(enc) => { @@ -541,7 +542,7 @@ pub(crate) fn inlay_hint( snap: &GlobalStateSnapshot, fields_to_resolve: &InlayFieldsToResolve, line_index: &LineIndex, - file_id: FileId, + file_id: HirFileId, mut inlay_hint: InlayHint, ) -> Cancellable { let hint_needs_resolve = |hint: &InlayHint| -> Option { @@ -591,9 +592,9 @@ pub(crate) fn inlay_hint( let data = match resolve_range_and_hash { Some((resolve_range, hash)) if something_to_resolve => Some( to_value(lsp_ext::InlayHintResolveData { - file_id: file_id.index(), + file_id: file_id.into_raw(), hash: hash.to_string(), - version: snap.file_version(file_id), + version: file_id.file_id().and_then(|file_id| snap.file_version(file_id.file_id())), resolve_range: range(line_index, resolve_range), }) .unwrap(), @@ -706,7 +707,6 @@ fn inlay_hint_label( static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1); pub(crate) fn semantic_tokens( - text: &str, line_index: &LineIndex, highlights: Vec, semantics_tokens_augments_syntax_tokens: bool, @@ -752,11 +752,7 @@ pub(crate) fn semantic_tokens( let token_index = semantic_tokens::type_index(ty); let modifier_bitset = mods.0; - for mut text_range in line_index.index.lines(highlight_range.range) { - if text[text_range].ends_with('\n') { - text_range = - TextRange::new(text_range.start(), text_range.end() - TextSize::of('\n')); - } + for text_range in line_index.index.lines(highlight_range.range) { let range = range(line_index, text_range); builder.push(range, token_index, modifier_bitset); } @@ -941,6 +937,10 @@ pub(crate) fn url(snap: &GlobalStateSnapshot, file_id: FileId) -> lsp_types::Url snap.file_id_to_url(file_id) } +pub(crate) fn url_hir(snap: &GlobalStateSnapshot, file_id: HirFileId) -> lsp_types::Url { + snap.hir_file_id_to_url(file_id) +} + /// Returns a `Url` object from a given path, will lowercase drive letters if present. /// This will only happen when processing windows paths. /// @@ -984,10 +984,10 @@ pub(crate) fn optional_versioned_text_document_identifier( pub(crate) fn location( snap: &GlobalStateSnapshot, - frange: FileRange, + frange: HirFileRange, ) -> Cancellable { - let url = url(snap, frange.file_id); - let line_index = snap.file_line_index(frange.file_id)?; + let url = url_hir(snap, frange.file_id); + let line_index = snap.hir_line_index(frange.file_id)?; let range = range(&line_index, frange.range); let loc = lsp_types::Location::new(url, range); Ok(loc) @@ -996,10 +996,10 @@ pub(crate) fn location( /// Prefer using `location_link`, if the client has the cap. pub(crate) fn location_from_nav( snap: &GlobalStateSnapshot, - nav: NavigationTarget, + nav: HirNavigationTarget, ) -> Cancellable { - let url = url(snap, nav.file_id); - let line_index = snap.file_line_index(nav.file_id)?; + let url = url_hir(snap, nav.file_id); + let line_index = snap.hir_line_index(nav.file_id)?; let range = range(&line_index, nav.focus_or_full_range()); let loc = lsp_types::Location::new(url, range); Ok(loc) @@ -1007,12 +1007,12 @@ pub(crate) fn location_from_nav( pub(crate) fn location_link( snap: &GlobalStateSnapshot, - src: Option, - target: NavigationTarget, + src: Option, + target: HirNavigationTarget, ) -> Cancellable { let origin_selection_range = match src { Some(src) => { - let line_index = snap.file_line_index(src.file_id)?; + let line_index = snap.hir_line_index(src.file_id)?; let range = range(&line_index, src.range); Some(range) } @@ -1030,11 +1030,11 @@ pub(crate) fn location_link( fn location_info( snap: &GlobalStateSnapshot, - target: NavigationTarget, + target: HirNavigationTarget, ) -> Cancellable<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> { - let line_index = snap.file_line_index(target.file_id)?; + let line_index = snap.hir_line_index(target.file_id)?; - let target_uri = url(snap, target.file_id); + let target_uri = url_hir(snap, target.file_id); let target_range = range(&line_index, target.full_range); let target_selection_range = target.focus_range.map(|it| range(&line_index, it)).unwrap_or(target_range); @@ -1043,8 +1043,8 @@ fn location_info( pub(crate) fn goto_definition_response( snap: &GlobalStateSnapshot, - src: Option, - targets: Vec, + src: Option, + targets: Vec, ) -> Cancellable { if snap.config.location_link() { let links = targets @@ -1056,7 +1056,7 @@ pub(crate) fn goto_definition_response( } else { let locations = targets .into_iter() - .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) + .map(|nav| HirFileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }) .unique() .map(|range| location(snap, range)) .collect::>>()?; @@ -1409,7 +1409,7 @@ impl From pub(crate) fn call_hierarchy_item( snap: &GlobalStateSnapshot, - target: NavigationTarget, + target: HirNavigationTarget, ) -> Cancellable { let name = target.name.to_string(); let detail = target.description.clone(); @@ -1482,9 +1482,7 @@ pub(crate) fn runnable( snap: &GlobalStateSnapshot, runnable: Runnable, ) -> Cancellable> { - let target_spec = TargetSpec::for_file(snap, runnable.nav.file_id)?; - let source_root = snap.analysis.source_root_id(runnable.nav.file_id).ok(); - let config = snap.config.runnables(source_root); + let target_spec = TargetSpec::for_hir_file(snap, runnable.nav.file_id)?; match target_spec { Some(TargetSpec::Cargo(spec)) => { @@ -1505,7 +1503,13 @@ pub(crate) fn runnable( }; let label = runnable.label(Some(&target)); + let source_root = snap.analysis.with_db(|db| { + db.file_source_root( + runnable.nav.file_id.original_file_respecting_includes(db).into(), + ) + })?; let location = location_link(snap, None, runnable.nav)?; + let config = snap.config.runnables(Some(source_root)); Ok(Some(lsp_ext::Runnable { label, @@ -1548,13 +1552,24 @@ pub(crate) fn runnable( } } None => { - let Some(path) = snap.file_id_to_file_path(runnable.nav.file_id).parent() else { + let Some(path) = runnable + .nav + .file_id + .file_id() + .and_then(|file_id| snap.file_id_to_file_path(file_id.into()).parent()) + else { return Ok(None); }; let (cargo_args, executable_args) = CargoTargetSpec::runnable_args(snap, None, &runnable.kind, &runnable.cfg); let label = runnable.label(None); + let source_root = snap.analysis.with_db(|db| { + db.file_source_root( + runnable.nav.file_id.original_file_respecting_includes(db).into(), + ) + })?; + let config = snap.config.runnables(Some(source_root)); let location = location_link(snap, None, runnable.nav)?; Ok(Some(lsp_ext::Runnable { @@ -1582,7 +1597,7 @@ pub(crate) fn code_lens( let client_commands_config = snap.config.client_commands(); match annotation.kind { AnnotationKind::Runnable(run) => { - let line_index = snap.file_line_index(run.nav.file_id)?; + let line_index = snap.hir_line_index(run.nav.file_id)?; let annotation_range = range(&line_index, annotation.range); let update_test = run.update_test; @@ -1649,9 +1664,9 @@ pub(crate) fn code_lens( if !client_commands_config.show_reference { return Ok(()); } - let line_index = snap.file_line_index(pos.file_id)?; + let line_index = snap.hir_line_index(pos.file_id)?; let annotation_range = range(&line_index, annotation.range); - let url = url(snap, pos.file_id); + let url = url_hir(snap, pos.file_id); let pos = position(&line_index, pos.offset); let id = lsp_types::TextDocumentIdentifier { uri: url.clone() }; @@ -1670,7 +1685,7 @@ pub(crate) fn code_lens( .filter_map(|target| { location( snap, - FileRange { file_id: target.file_id, range: target.full_range }, + HirFileRange { file_id: target.file_id, range: target.full_range }, ) .ok() }) @@ -1703,9 +1718,9 @@ pub(crate) fn code_lens( if !client_commands_config.show_reference { return Ok(()); } - let line_index = snap.file_line_index(pos.file_id)?; + let line_index = snap.hir_line_index(pos.file_id)?; let annotation_range = range(&line_index, annotation.range); - let url = url(snap, pos.file_id); + let url = url_hir(snap, pos.file_id); let pos = position(&line_index, pos.offset); let id = lsp_types::TextDocumentIdentifier { uri: url.clone() }; @@ -1777,7 +1792,8 @@ pub(crate) fn test_item( } pub(crate) mod command { - use ide::{FileRange, NavigationTarget}; + use hir::HirFileRange; + use ide::HirNavigationTarget; use serde_json::to_value; use crate::{ @@ -1834,13 +1850,13 @@ pub(crate) mod command { pub(crate) fn goto_location( snap: &GlobalStateSnapshot, - nav: &NavigationTarget, + nav: &HirNavigationTarget, ) -> Option { let value = if snap.config.location_link() { let link = location_link(snap, None, nav.clone()).ok()?; to_value(link).ok()? } else { - let range = FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }; + let range = HirFileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }; let location = location(snap, range).ok()?; to_value(location).ok()? }; @@ -1950,13 +1966,14 @@ fn main() { }"#; let (analysis, file_id) = Analysis::from_single_file(text.to_owned()); - let folds = analysis.folding_ranges(file_id).unwrap(); + let folds = analysis.folding_ranges(file_id.into()).unwrap(); assert_eq!(folds.len(), 4); let line_index = LineIndex { index: Arc::new(ide::LineIndex::new(text)), endings: LineEndings::Unix, encoding: PositionEncoding::Utf8, + transform: Default::default(), }; let converted: Vec = folds.into_iter().map(|it| folding_range(text, &line_index, true, it)).collect(); @@ -1987,7 +2004,10 @@ fn bar(_: usize) {} let (offset, text) = extract_offset(text); let (analysis, file_id) = Analysis::from_single_file(text); let help = signature_help( - analysis.signature_help(FilePosition { file_id, offset }).unwrap().unwrap(), + analysis + .signature_help(FilePosition { file_id: file_id.into(), offset }) + .unwrap() + .unwrap(), CallInfoConfig { params_only: false, docs: true }, false, ); @@ -2022,6 +2042,7 @@ fn bar(_: usize) {} index: Arc::new(ide::LineIndex::new(&source)), endings, encoding: PositionEncoding::Utf8, + transform: Default::default(), }; let res = merge_text_and_snippet_edits(&line_index, edit, snippets); diff --git a/crates/rust-analyzer/src/lsp/utils.rs b/crates/rust-analyzer/src/lsp/utils.rs index 9a9e66be51ce..7f8fbfacc1ce 100644 --- a/crates/rust-analyzer/src/lsp/utils.rs +++ b/crates/rust-analyzer/src/lsp/utils.rs @@ -191,6 +191,7 @@ pub(crate) fn apply_document_changes( // We don't care about line endings here. endings: LineEndings::Unix, encoding, + transform: Default::default(), }; // The changes we got must be applied sequentially, but can cross lines so we diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index f5d9469f2622..2b1ab05b2117 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -32,7 +32,8 @@ use crate::{ request::empty_diagnostic_report, }, lsp::{ - from_proto, to_proto, + from_proto::{self, VfsOrMacroPath}, + to_proto, utils::{notification_is, Progress}, }, lsp_ext, @@ -481,9 +482,11 @@ impl GlobalState { if let Some(diagnostic_changes) = self.diagnostics.take_changes() { for file_id in diagnostic_changes { let uri = file_id_to_url(&self.vfs.read().0, file_id); - let version = from_proto::vfs_path(&uri) - .ok() - .and_then(|path| self.mem_docs.get(&path).map(|it| it.version)); + let version = from_proto::url_to_vfs_path(&uri).ok().and_then(|path| match path { + VfsOrMacroPath::Vfs(path) => self.mem_docs.get(&path).map(|it| it.version), + // FIXME MACRO DIAGNOSTICS SHOULD WORK! + VfsOrMacroPath::Macro(..) => None, + }); let diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect::>(); @@ -888,17 +891,20 @@ impl GlobalState { self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| { let _p = tracing::info_span!("GlobalState::check_if_indexed").entered(); tracing::debug!(?uri, "handling uri"); - let Some(id) = from_proto::file_id(&snap, &uri).expect("unable to get FileId") - else { + let Some(id) = snap.url_to_file_id(&uri).expect("unable to get FileId") else { return; }; if let Ok(crates) = &snap.analysis.crates_for(id) { if crates.is_empty() { if snap.config.discover_workspace_config().is_some() { - let path = - from_proto::abs_path(&uri).expect("Unable to get AbsPath"); - let arg = DiscoverProjectParam::Path(path); - sender.send(Task::DiscoverLinkedProjects(arg)).unwrap(); + if let VfsOrMacroPath::Vfs(path) = from_proto::url_to_vfs_path(&uri) + .expect("Unable to get AbsPath") + { + if let Some(path) = path.into_abs_path() { + let arg = DiscoverProjectParam::Path(path); + sender.send(Task::DiscoverLinkedProjects(arg)).unwrap(); + } + } } } else { tracing::debug!(?uri, "is indexed"); @@ -1178,6 +1184,7 @@ impl GlobalState { .on::(handlers::handle_open_docs) .on::(handlers::handle_open_cargo_toml) .on::(handlers::handle_move_item) + .on::(handlers::macro_file_content) // .on::(handlers::internal_testing_fetch_config) .finish(); diff --git a/crates/rust-analyzer/src/target_spec.rs b/crates/rust-analyzer/src/target_spec.rs index b28567fe09b5..1655c461fb0a 100644 --- a/crates/rust-analyzer/src/target_spec.rs +++ b/crates/rust-analyzer/src/target_spec.rs @@ -3,7 +3,8 @@ use std::mem; use cfg::{CfgAtom, CfgExpr}; -use hir::sym; +use hir::db::ExpandDatabase; +use hir::{sym, HirFileId}; use ide::{Cancellable, CrateId, FileId, RunnableKind, TestId}; use project_model::project_json::Runnable; use project_model::{CargoFeatures, ManifestPath, TargetKind}; @@ -35,6 +36,25 @@ impl TargetSpec { Ok(global_state_snapshot.target_spec_for_crate(crate_id)) } + pub(crate) fn for_hir_file( + global_state_snapshot: &GlobalStateSnapshot, + file_id: HirFileId, + ) -> Cancellable> { + let crate_id = match file_id.repr() { + span::HirFileIdRepr::FileId(editioned_file_id) => { + match &*global_state_snapshot.analysis.crates_for(editioned_file_id.into())? { + &[crate_id, ..] => crate_id, + _ => return Ok(None), + } + } + span::HirFileIdRepr::MacroFile(macro_file_id) => global_state_snapshot + .analysis + .with_db(|db| db.lookup_intern_macro_call(macro_file_id.macro_call_id).krate)?, + }; + + Ok(global_state_snapshot.target_spec_for_crate(crate_id)) + } + pub(crate) fn target_kind(&self) -> TargetKind { match self { TargetSpec::Cargo(cargo) => cargo.target_kind, diff --git a/crates/span/src/lib.rs b/crates/span/src/lib.rs index 8dc957350381..05a91a488030 100644 --- a/crates/span/src/lib.rs +++ b/crates/span/src/lib.rs @@ -115,7 +115,10 @@ pub struct EditionedFileId(u32); impl fmt::Debug for EditionedFileId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("EditionedFileId").field(&self.file_id()).field(&self.edition()).finish() + f.debug_tuple("EditionedFileId") + .field(&self.file_id().index()) + .field(&self.edition()) + .finish() } } @@ -264,6 +267,8 @@ pub struct MacroFileId { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MacroCallId(InternId); +#[cfg(feature = "ra-salsa")] +pub use ra_salsa::InternKey; #[cfg(feature = "ra-salsa")] impl ra_salsa::InternKey for MacroCallId { fn from_intern_id(v: ra_salsa::InternId) -> Self { @@ -324,6 +329,16 @@ impl HirFileId { const MAX_HIR_FILE_ID: u32 = u32::MAX ^ Self::MACRO_FILE_TAG_MASK; const MACRO_FILE_TAG_MASK: u32 = 1 << 31; + #[inline] + pub fn from_raw(raw: u32) -> Self { + HirFileId(raw) + } + + #[inline] + pub fn into_raw(self) -> u32 { + self.0 + } + #[inline] pub fn is_macro(self) -> bool { self.0 & Self::MACRO_FILE_TAG_MASK != 0 diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 04c2153abf41..ffd31c246627 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs @@ -75,6 +75,17 @@ impl TupleExt for (T, U, V) { } } +impl<'a, T, U> TupleExt for &'a (T, U) { + type Head = &'a T; + type Tail = &'a U; + fn head(self) -> Self::Head { + &self.0 + } + fn tail(self) -> Self::Tail { + &self.1 + } +} + pub fn to_lower_snake_case(s: &str) -> String { to_snake_case(s, char::to_lowercase) } diff --git a/crates/syntax-bridge/src/prettify_macro_expansion.rs b/crates/syntax-bridge/src/prettify_macro_expansion.rs index fc7caaa98865..84586e4c5ba8 100644 --- a/crates/syntax-bridge/src/prettify_macro_expansion.rs +++ b/crates/syntax-bridge/src/prettify_macro_expansion.rs @@ -7,6 +7,13 @@ use syntax::{ SyntaxNode, SyntaxToken, WalkEvent, T, }; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PrettifyWsKind { + Space, + Indent(usize), + Newline, +} + /// Renders a [`SyntaxNode`] with whitespace inserted between tokens that require them. /// /// This is an internal API that is only exported because `mbe` needs it for tests and cannot depend @@ -15,7 +22,8 @@ use syntax::{ #[deprecated = "use `hir_expand::prettify_macro_expansion()` instead"] pub fn prettify_macro_expansion( syn: SyntaxNode, - dollar_crate_replacement: &mut dyn FnMut(&SyntaxToken) -> SyntaxToken, + dollar_crate_replacement: &mut dyn FnMut(&SyntaxToken) -> Option, + inspect_mods: impl FnOnce(&[(Position, PrettifyWsKind)]), ) -> SyntaxNode { let mut indent = 0; let mut last: Option = None; @@ -27,14 +35,12 @@ pub fn prettify_macro_expansion( let after = Position::after; let do_indent = |pos: fn(_) -> Position, token: &SyntaxToken, indent| { - (pos(token.clone()), make::tokens::whitespace(&" ".repeat(4 * indent))) - }; - let do_ws = |pos: fn(_) -> Position, token: &SyntaxToken| { - (pos(token.clone()), make::tokens::single_space()) - }; - let do_nl = |pos: fn(_) -> Position, token: &SyntaxToken| { - (pos(token.clone()), make::tokens::single_newline()) + (pos(token.clone()), PrettifyWsKind::Indent(indent)) }; + let do_ws = + |pos: fn(_) -> Position, token: &SyntaxToken| (pos(token.clone()), PrettifyWsKind::Space); + let do_nl = + |pos: fn(_) -> Position, token: &SyntaxToken| (pos(token.clone()), PrettifyWsKind::Newline); for event in syn.preorder_with_tokens() { let token = match event { @@ -46,20 +52,19 @@ pub fn prettify_macro_expansion( ) => { if indent > 0 { - mods.push(( - Position::after(node.clone()), - make::tokens::whitespace(&" ".repeat(4 * indent)), - )); + mods.push((Position::after(node.clone()), PrettifyWsKind::Indent(indent))); } if node.parent().is_some() { - mods.push((Position::after(node), make::tokens::single_newline())); + mods.push((Position::after(node), PrettifyWsKind::Newline)); } continue; } _ => continue, }; if token.kind() == SyntaxKind::IDENT && token.text() == "$crate" { - dollar_crate_replacements.push((token.clone(), dollar_crate_replacement(&token))); + if let Some(replacement) = dollar_crate_replacement(&token) { + dollar_crate_replacements.push((token.clone(), replacement)); + } } let tok = &token; @@ -129,8 +134,16 @@ pub fn prettify_macro_expansion( last = Some(tok.kind()); } + inspect_mods(&mods); for (pos, insert) in mods { - ted::insert(pos, insert); + ted::insert_raw( + pos, + match insert { + PrettifyWsKind::Space => make::tokens::single_space(), + PrettifyWsKind::Indent(indent) => make::tokens::whitespace(&" ".repeat(4 * indent)), + PrettifyWsKind::Newline => make::tokens::single_newline(), + }, + ); } for (old, new) in dollar_crate_replacements { ted::replace(old, new); diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs index 8592df159755..f6927c0b3d6a 100644 --- a/crates/syntax/src/ted.rs +++ b/crates/syntax/src/ted.rs @@ -5,6 +5,7 @@ use std::{mem, ops::RangeInclusive}; use parser::T; +use rowan::TextSize; use crate::{ ast::{self, edit::IndentLevel, make, AstNode}, @@ -74,6 +75,13 @@ impl Position { }; Position { repr } } + + pub fn offset(&self) -> TextSize { + match &self.repr { + PositionRepr::FirstChild(node) => node.text_range().start(), + PositionRepr::After(elem) => elem.text_range().end(), + } + } } pub fn insert(position: Position, elem: impl Element) { diff --git a/crates/vfs/src/vfs_path.rs b/crates/vfs/src/vfs_path.rs index 3c8e37413f68..fa50f7944d29 100644 --- a/crates/vfs/src/vfs_path.rs +++ b/crates/vfs/src/vfs_path.rs @@ -39,6 +39,13 @@ impl VfsPath { } } + pub fn into_abs_path(self) -> Option { + match self.0 { + VfsPathRepr::PathBuf(it) => Some(it), + VfsPathRepr::VirtualPath(_) => None, + } + } + /// Creates a new `VfsPath` with `path` adjoined to `self`. pub fn join(&self, path: &str) -> Option { match &self.0 { diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index eac7b849fdb9..bcb9325046ee 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -19,7 +19,7 @@ export async function createClient( unlinkedFiles: vscode.Uri[], ): Promise { const clientOptions: lc.LanguageClientOptions = { - documentSelector: [{ scheme: "file", language: "rust" }], + documentSelector: [{ scheme: "file", language: "rust" }, { scheme: "rust-macro-file" }], initializationOptions, diagnosticCollectionName: "rustc", traceOutputChannel, @@ -332,6 +332,7 @@ class ExperimentalFeatures implements lc.StaticFeature { openServerLogs: true, localDocs: true, testExplorer: this.testExplorer, + virtualMacroFiles: true, commands: { commands: [ "rust-analyzer.runSingle", diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index af86d9efd142..1dec9e26da5b 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts @@ -26,6 +26,9 @@ export type CommandLinkGroup = { // rust-analyzer extensions +export const macroFile = new lc.RequestType( + "rust-analyzer/macroFileContent", +); export const analyzerStatus = new lc.RequestType( "rust-analyzer/analyzerStatus", ); diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index c84b69b66cd2..8503f56ba41d 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -7,6 +7,7 @@ import * as diagnostics from "./diagnostics"; import { activateTaskProvider } from "./tasks"; import { setContextValue } from "./util"; import { initializeDebugSessionTrackingAndRebuild } from "./debug"; +import * as ra from "./lsp_ext"; const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; @@ -37,11 +38,32 @@ export async function activate( return api; } +class MacroFileProvider implements vscode.TextDocumentContentProvider { + constructor(private readonly ctx: Ctx) {} + onDidChange?: vscode.Event | undefined; + provideTextDocumentContent( + uri: vscode.Uri, + token: vscode.CancellationToken, + ): vscode.ProviderResult { + if (!this.ctx.client) { + throw new Error("rust-analyzer is not running"); + } + return this.ctx.client.sendRequest(ra.macroFile, { uri: uri.toString() }, token); + } +} + async function activateServer(ctx: Ctx): Promise { if (ctx.workspace.kind === "Workspace Folder") { ctx.pushExtCleanup(activateTaskProvider(ctx.config)); } + ctx.pushExtCleanup( + vscode.workspace.registerTextDocumentContentProvider( + "rust-macro-file", + new MacroFileProvider(ctx), + ), + ); + const diagnosticProvider = new diagnostics.TextDocumentProvider(ctx); ctx.pushExtCleanup( vscode.workspace.registerTextDocumentContentProvider(