fix: Deduplicate annotations

This commit is contained in:
Lukas Wirth 2023-12-19 08:30:48 +01:00
parent ae2c3223b0
commit 002e611d09
7 changed files with 179 additions and 182 deletions

View file

@ -342,7 +342,7 @@ impl InFile<TextRange> {
} }
impl<N: AstNode> InFile<N> { impl<N: AstNode> InFile<N> {
pub fn original_ast_node(self, db: &dyn db::ExpandDatabase) -> Option<InRealFile<N>> { pub fn original_ast_node_rooted(self, db: &dyn db::ExpandDatabase) -> Option<InRealFile<N>> {
// This kind of upmapping can only be achieved in attribute expanded files, // This kind of upmapping can only be achieved in attribute expanded files,
// as we don't have node inputs otherwise and therefore can't find an `N` node in the input // as we don't have node inputs otherwise and therefore can't find an `N` node in the input
let file_id = match self.file_id.repr() { let file_id = match self.file_id.repr() {

View file

@ -512,8 +512,7 @@ impl<'db> SemanticsImpl<'db> {
} }
/// Descend the token into its macro call if it is part of one, returning the tokens in the /// Descend the token into its macro call if it is part of one, returning the tokens in the
/// expansion that it is associated with. If `offset` points into the token's range, it will /// expansion that it is associated with.
/// be considered for the mapping in case of inline format args.
pub fn descend_into_macros( pub fn descend_into_macros(
&self, &self,
mode: DescendPreference, mode: DescendPreference,
@ -850,7 +849,7 @@ impl<'db> SemanticsImpl<'db> {
/// Attempts to map the node out of macro expanded files. /// Attempts to map the node out of macro expanded files.
/// This only work for attribute expansions, as other ones do not have nodes as input. /// This only work for attribute expansions, as other ones do not have nodes as input.
pub fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> { pub fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map( self.wrap_node_infile(node).original_ast_node_rooted(self.db.upcast()).map(
|InRealFile { file_id, value }| { |InRealFile { file_id, value }| {
self.cache(find_root(value.syntax()), file_id.into()); self.cache(find_root(value.syntax()), file_id.into());
value value

View file

@ -114,7 +114,7 @@ fn add_variant_to_accumulator(
parent: PathParent, parent: PathParent,
) -> Option<()> { ) -> Option<()> {
let db = ctx.db(); let db = ctx.db();
let InRealFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node(db)?; let InRealFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node_rooted(db)?;
acc.add( acc.add(
AssistId("generate_enum_variant", AssistKind::Generate), AssistId("generate_enum_variant", AssistKind::Generate),

View file

@ -516,7 +516,7 @@ fn source_edit_from_def(
if let Definition::Local(local) = def { if let Definition::Local(local) = def {
let mut file_id = None; let mut file_id = None;
for source in local.sources(sema.db) { for source in local.sources(sema.db) {
let source = match source.source.clone().original_ast_node(sema.db) { let source = match source.source.clone().original_ast_node_rooted(sema.db) {
Some(source) => source, Some(source) => source,
None => match source None => match source
.source .source
@ -560,7 +560,7 @@ fn source_edit_from_def(
} }
} else { } else {
// Foo { ref mut field } -> Foo { field: ref mut new_name } // Foo { ref mut field } -> Foo { field: ref mut new_name }
// ^ insert `field: ` // original_ast_node_rootedd: `
// ^^^^^ replace this with `new_name` // ^^^^^ replace this with `new_name`
edit.insert( edit.insert(
pat.syntax().text_range().start(), pat.syntax().text_range().start(),

View file

@ -3,8 +3,9 @@ use ide_db::{
base_db::{FileId, FilePosition, FileRange}, base_db::{FileId, FilePosition, FileRange},
defs::Definition, defs::Definition,
helpers::visit_file_defs, helpers::visit_file_defs,
RootDatabase, FxHashSet, RootDatabase,
}; };
use itertools::Itertools;
use syntax::{ast::HasName, AstNode, TextRange}; use syntax::{ast::HasName, AstNode, TextRange};
use crate::{ use crate::{
@ -23,13 +24,13 @@ mod fn_references;
// and running/debugging binaries. // and running/debugging binaries.
// //
// image::https://user-images.githubusercontent.com/48062697/113020672-b7c34f00-917a-11eb-8f6e-858735660a0e.png[] // image::https://user-images.githubusercontent.com/48062697/113020672-b7c34f00-917a-11eb-8f6e-858735660a0e.png[]
#[derive(Debug)] #[derive(Debug, Hash, PartialEq, Eq)]
pub struct Annotation { pub struct Annotation {
pub range: TextRange, pub range: TextRange,
pub kind: AnnotationKind, pub kind: AnnotationKind,
} }
#[derive(Debug)] #[derive(Debug, Hash, PartialEq, Eq)]
pub enum AnnotationKind { pub enum AnnotationKind {
Runnable(Runnable), Runnable(Runnable),
HasImpls { pos: FilePosition, data: Option<Vec<NavigationTarget>> }, HasImpls { pos: FilePosition, data: Option<Vec<NavigationTarget>> },
@ -56,7 +57,7 @@ pub(crate) fn annotations(
config: &AnnotationConfig, config: &AnnotationConfig,
file_id: FileId, file_id: FileId,
) -> Vec<Annotation> { ) -> Vec<Annotation> {
let mut annotations = Vec::default(); let mut annotations = FxHashSet::default();
if config.annotate_runnables { if config.annotate_runnables {
for runnable in runnables(db, file_id) { for runnable in runnables(db, file_id) {
@ -66,7 +67,7 @@ pub(crate) fn annotations(
let range = runnable.nav.focus_or_full_range(); let range = runnable.nav.focus_or_full_range();
annotations.push(Annotation { range, kind: AnnotationKind::Runnable(runnable) }); annotations.insert(Annotation { range, kind: AnnotationKind::Runnable(runnable) });
} }
} }
@ -99,13 +100,13 @@ pub(crate) fn annotations(
}) })
.for_each(|range| { .for_each(|range| {
let (annotation_range, target_position) = mk_ranges(range); let (annotation_range, target_position) = mk_ranges(range);
annotations.push(Annotation { annotations.insert(Annotation {
range: annotation_range, range: annotation_range,
kind: AnnotationKind::HasReferences { kind: AnnotationKind::HasReferences {
pos: target_position, pos: target_position,
data: None, data: None,
}, },
}) });
}) })
} }
if config.annotate_references || config.annotate_impls { if config.annotate_references || config.annotate_impls {
@ -131,14 +132,14 @@ pub(crate) fn annotations(
}; };
let (annotation_range, target_pos) = mk_ranges(range); let (annotation_range, target_pos) = mk_ranges(range);
if config.annotate_impls && !matches!(def, Definition::Const(_)) { if config.annotate_impls && !matches!(def, Definition::Const(_)) {
annotations.push(Annotation { annotations.insert(Annotation {
range: annotation_range, range: annotation_range,
kind: AnnotationKind::HasImpls { pos: target_pos, data: None }, kind: AnnotationKind::HasImpls { pos: target_pos, data: None },
}); });
} }
if config.annotate_references { if config.annotate_references {
annotations.push(Annotation { annotations.insert(Annotation {
range: annotation_range, range: annotation_range,
kind: AnnotationKind::HasReferences { pos: target_pos, data: None }, kind: AnnotationKind::HasReferences { pos: target_pos, data: None },
}); });
@ -149,7 +150,7 @@ pub(crate) fn annotations(
node: InFile<T>, node: InFile<T>,
source_file_id: FileId, source_file_id: FileId,
) -> Option<(TextRange, Option<TextRange>)> { ) -> Option<(TextRange, Option<TextRange>)> {
if let Some(InRealFile { file_id, value }) = node.original_ast_node(db) { if let Some(InRealFile { file_id, value }) = node.original_ast_node_rooted(db) {
if file_id == source_file_id { if file_id == source_file_id {
return Some(( return Some((
value.syntax().text_range(), value.syntax().text_range(),
@ -171,7 +172,7 @@ pub(crate) fn annotations(
})); }));
} }
annotations annotations.into_iter().sorted_by_key(|a| (a.range.start(), a.range.end())).collect()
} }
pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation { pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation {
@ -252,25 +253,6 @@ fn main() {
"#, "#,
expect![[r#" expect![[r#"
[ [
Annotation {
range: 53..57,
kind: Runnable(
Runnable {
use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
),
full_range: 50..85,
focus_range: 53..57,
name: "main",
kind: Function,
},
kind: Bin,
cfg: None,
},
),
},
Annotation { Annotation {
range: 6..10, range: 6..10,
kind: HasReferences { kind: HasReferences {
@ -306,6 +288,25 @@ fn main() {
), ),
}, },
}, },
Annotation {
range: 53..57,
kind: Runnable(
Runnable {
use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
),
full_range: 50..85,
focus_range: 53..57,
name: "main",
kind: Function,
},
kind: Bin,
cfg: None,
},
),
},
Annotation { Annotation {
range: 53..57, range: 53..57,
kind: HasReferences { kind: HasReferences {
@ -337,39 +338,6 @@ fn main() {
"#, "#,
expect![[r#" expect![[r#"
[ [
Annotation {
range: 17..21,
kind: Runnable(
Runnable {
use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
),
full_range: 14..48,
focus_range: 17..21,
name: "main",
kind: Function,
},
kind: Bin,
cfg: None,
},
),
},
Annotation {
range: 7..11,
kind: HasImpls {
pos: FilePosition {
file_id: FileId(
0,
),
offset: 7,
},
data: Some(
[],
),
},
},
Annotation { Annotation {
range: 7..11, range: 7..11,
kind: HasReferences { kind: HasReferences {
@ -391,6 +359,39 @@ fn main() {
), ),
}, },
}, },
Annotation {
range: 7..11,
kind: HasImpls {
pos: FilePosition {
file_id: FileId(
0,
),
offset: 7,
},
data: Some(
[],
),
},
},
Annotation {
range: 17..21,
kind: Runnable(
Runnable {
use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
),
full_range: 14..48,
focus_range: 17..21,
name: "main",
kind: Function,
},
kind: Bin,
cfg: None,
},
),
},
Annotation { Annotation {
range: 17..21, range: 17..21,
kind: HasReferences { kind: HasReferences {
@ -426,49 +427,6 @@ fn main() {
"#, "#,
expect![[r#" expect![[r#"
[ [
Annotation {
range: 69..73,
kind: Runnable(
Runnable {
use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
),
full_range: 66..100,
focus_range: 69..73,
name: "main",
kind: Function,
},
kind: Bin,
cfg: None,
},
),
},
Annotation {
range: 7..11,
kind: HasImpls {
pos: FilePosition {
file_id: FileId(
0,
),
offset: 7,
},
data: Some(
[
NavigationTarget {
file_id: FileId(
0,
),
full_range: 36..64,
focus_range: 57..61,
name: "impl",
kind: Impl,
},
],
),
},
},
Annotation { Annotation {
range: 7..11, range: 7..11,
kind: HasReferences { kind: HasReferences {
@ -496,6 +454,30 @@ fn main() {
), ),
}, },
}, },
Annotation {
range: 7..11,
kind: HasImpls {
pos: FilePosition {
file_id: FileId(
0,
),
offset: 7,
},
data: Some(
[
NavigationTarget {
file_id: FileId(
0,
),
full_range: 36..64,
focus_range: 57..61,
name: "impl",
kind: Impl,
},
],
),
},
},
Annotation { Annotation {
range: 20..31, range: 20..31,
kind: HasImpls { kind: HasImpls {
@ -555,6 +537,25 @@ fn main() {
), ),
}, },
}, },
Annotation {
range: 69..73,
kind: Runnable(
Runnable {
use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
),
full_range: 66..100,
focus_range: 69..73,
name: "main",
kind: Function,
},
kind: Bin,
cfg: None,
},
),
},
] ]
"#]], "#]],
); );
@ -622,49 +623,6 @@ fn main() {
"#, "#,
expect![[r#" expect![[r#"
[ [
Annotation {
range: 61..65,
kind: Runnable(
Runnable {
use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
),
full_range: 58..95,
focus_range: 61..65,
name: "main",
kind: Function,
},
kind: Bin,
cfg: None,
},
),
},
Annotation {
range: 7..11,
kind: HasImpls {
pos: FilePosition {
file_id: FileId(
0,
),
offset: 7,
},
data: Some(
[
NavigationTarget {
file_id: FileId(
0,
),
full_range: 14..56,
focus_range: 19..23,
name: "impl",
kind: Impl,
},
],
),
},
},
Annotation { Annotation {
range: 7..11, range: 7..11,
kind: HasReferences { kind: HasReferences {
@ -692,6 +650,30 @@ fn main() {
), ),
}, },
}, },
Annotation {
range: 7..11,
kind: HasImpls {
pos: FilePosition {
file_id: FileId(
0,
),
offset: 7,
},
data: Some(
[
NavigationTarget {
file_id: FileId(
0,
),
full_range: 14..56,
focus_range: 19..23,
name: "impl",
kind: Impl,
},
],
),
},
},
Annotation { Annotation {
range: 33..44, range: 33..44,
kind: HasReferences { kind: HasReferences {
@ -727,6 +709,25 @@ fn main() {
), ),
}, },
}, },
Annotation {
range: 61..65,
kind: Runnable(
Runnable {
use_name_in_title: false,
nav: NavigationTarget {
file_id: FileId(
0,
),
full_range: 58..95,
focus_range: 61..65,
name: "main",
kind: Function,
},
kind: Bin,
cfg: None,
},
),
},
] ]
"#]], "#]],
); );
@ -745,6 +746,20 @@ mod tests {
"#, "#,
expect![[r#" expect![[r#"
[ [
Annotation {
range: 3..7,
kind: HasReferences {
pos: FilePosition {
file_id: FileId(
0,
),
offset: 3,
},
data: Some(
[],
),
},
},
Annotation { Annotation {
range: 3..7, range: 3..7,
kind: Runnable( kind: Runnable(
@ -812,20 +827,6 @@ mod tests {
}, },
), ),
}, },
Annotation {
range: 3..7,
kind: HasReferences {
pos: FilePosition {
file_id: FileId(
0,
),
offset: 3,
},
data: Some(
[],
),
},
},
] ]
"#]], "#]],
); );
@ -877,7 +878,7 @@ struct Foo;
[ [
Annotation { Annotation {
range: 0..71, range: 0..71,
kind: HasImpls { kind: HasReferences {
pos: FilePosition { pos: FilePosition {
file_id: FileId( file_id: FileId(
0, 0,
@ -891,7 +892,7 @@ struct Foo;
}, },
Annotation { Annotation {
range: 0..71, range: 0..71,
kind: HasReferences { kind: HasImpls {
pos: FilePosition { pos: FilePosition {
file_id: FileId( file_id: FileId(
0, 0,

View file

@ -4,7 +4,6 @@ use ide_db::{
helpers::pick_best_token, helpers::pick_best_token,
RootDatabase, RootDatabase,
}; };
use itertools::Itertools;
use syntax::{ast, AstNode, SyntaxKind::*, T}; use syntax::{ast, AstNode, SyntaxKind::*, T};
use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav}; use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav};
@ -34,10 +33,10 @@ pub(crate) fn goto_implementation(
})?; })?;
let range = original_token.text_range(); let range = original_token.text_range();
let navs = let navs =
sema.descend_into_macros(DescendPreference::None, original_token) sema.descend_into_macros_single(DescendPreference::SameText, original_token)
.into_iter() .parent()
.filter_map(|token| token.parent().and_then(ast::NameLike::cast)) .and_then(ast::NameLike::cast)
.filter_map(|node| match &node { .and_then(|node| match &node {
ast::NameLike::Name(name) => { ast::NameLike::Name(name) => {
NameClass::classify(&sema, name).and_then(|class| match class { NameClass::classify(&sema, name).and_then(|class| match class {
NameClass::Definition(it) | NameClass::ConstReference(it) => Some(it), NameClass::Definition(it) | NameClass::ConstReference(it) => Some(it),
@ -52,8 +51,7 @@ pub(crate) fn goto_implementation(
}), }),
ast::NameLike::Lifetime(_) => None, ast::NameLike::Lifetime(_) => None,
}) })
.unique() .and_then(|def| {
.filter_map(|def| {
let navs = match def { let navs = match def {
Definition::Trait(trait_) => impls_for_trait(&sema, trait_), Definition::Trait(trait_) => impls_for_trait(&sema, trait_),
Definition::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)), Definition::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)),
@ -75,8 +73,7 @@ pub(crate) fn goto_implementation(
}; };
Some(navs) Some(navs)
}) })
.flatten() .unwrap_or_default();
.collect();
Some(RangeInfo { range, info: navs }) Some(RangeInfo { range, info: navs })
} }

View file

@ -12,7 +12,7 @@ pub use crate::map::{RealSpanMap, SpanMap};
pub use syntax::{TextRange, TextSize}; pub use syntax::{TextRange, TextSize};
pub use vfs::FileId; pub use vfs::FileId;
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FilePosition { pub struct FilePosition {
pub file_id: FileId, pub file_id: FileId,
pub offset: TextSize, pub offset: TextSize,