Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/navigation_target.rs')
-rw-r--r--crates/ide/src/navigation_target.rs48
1 files changed, 31 insertions, 17 deletions
diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs
index 32f211c6b2..df0c4a6ade 100644
--- a/crates/ide/src/navigation_target.rs
+++ b/crates/ide/src/navigation_target.rs
@@ -4,8 +4,8 @@ use std::fmt;
use either::Either;
use hir::{
- symbols::FileSymbol, AssocItem, FieldSource, HasContainer, HasSource, HirDisplay, HirFileId,
- InFile, LocalSource, ModuleSource,
+ db::ExpandDatabase, symbols::FileSymbol, AssocItem, FieldSource, HasContainer, HasSource,
+ HirDisplay, HirFileId, InFile, LocalSource, ModuleSource,
};
use ide_db::{
base_db::{FileId, FileRange},
@@ -40,6 +40,8 @@ pub struct NavigationTarget {
/// comments, and `focus_range` is the range of the identifier.
///
/// Clients should place the cursor on this range when navigating to this target.
+ ///
+ /// This range must be contained within [`Self::full_range`].
pub focus_range: Option<TextRange>,
pub name: SmolStr,
pub kind: Option<SymbolKind>,
@@ -166,13 +168,14 @@ impl NavigationTarget {
impl TryToNav for FileSymbol {
fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
let full_range = self.loc.original_range(db);
- let focus_range = self.loc.original_name_range(db).and_then(|it| {
- if it.file_id == full_range.file_id {
- Some(it.range)
- } else {
- None
- }
- });
+ let focus_range = self.loc.original_name_range(db);
+ let focus_range = if focus_range.file_id == full_range.file_id
+ && full_range.range.contains_range(focus_range.range)
+ {
+ Some(focus_range.range)
+ } else {
+ None
+ };
Some(NavigationTarget {
file_id: full_range.file_id,
@@ -363,11 +366,11 @@ impl ToNav for hir::Module {
impl TryToNav for hir::Impl {
fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
let InFile { file_id, value } = self.source(db)?;
- let derive_attr = self.as_builtin_derive(db);
+ let derive_path = self.as_builtin_derive_path(db);
- let (focus, syntax) = match &derive_attr {
- Some(attr) => (None, attr.value.syntax()),
- None => (value.self_ty(), value.syntax()),
+ let (file_id, focus, syntax) = match &derive_path {
+ Some(attr) => (attr.file_id.into(), None, attr.value.syntax()),
+ None => (file_id, value.self_ty(), value.syntax()),
};
let (file_id, full_range, focus_range) = orig_range_with_focus(db, file_id, syntax, focus);
@@ -628,19 +631,30 @@ impl TryToNav for hir::ConstParam {
}
}
+/// Returns the original range of the syntax node, and the range of the name mapped out of macro expansions
+/// Additionally verifies that the name span is in bounds and related to the original range.
fn orig_range_with_focus(
db: &RootDatabase,
hir_file: HirFileId,
value: &SyntaxNode,
name: Option<impl AstNode>,
) -> (FileId, TextRange, Option<TextRange>) {
- let FileRange { file_id, range: full_range } =
- InFile::new(hir_file, value).original_file_range(db);
+ let FileRange { file_id, range } =
+ match InFile::new(hir_file, value).original_file_range_opt(db) {
+ Some((range, ctxt)) if ctxt.is_root() => range,
+ _ => db
+ .lookup_intern_macro_call(hir_file.macro_file().unwrap().macro_call_id)
+ .kind
+ .original_call_range(db),
+ };
let focus_range = name
.and_then(|it| InFile::new(hir_file, it.syntax()).original_file_range_opt(db))
- .and_then(|range| if range.file_id == file_id { Some(range.range) } else { None });
+ .filter(|(frange, ctxt)| {
+ ctxt.is_root() && frange.file_id == file_id && frange.range.contains_range(frange.range)
+ })
+ .map(|(frange, _ctxt)| frange.range);
- (file_id, full_range, focus_range)
+ (file_id, range, focus_range)
}
#[cfg(test)]