Skip to content

Commit d8c8ccc

Browse files
committed
Auto merge of #16358 - krobelus:fix-redundant-references-with-macros, r=Veykril
Deduplicate references when some of them are in macro expansions EDIT: I wonder if this is a regression, I'll try to investigate. Commit 6a06f6f (Deduplicate reference search results, 2022-11-07) deduplicates references within each definition. Apparently our descend_into_macros() stanza returns one definition for each time a name is used in a macro. Each of those definitions has the same set of references. We return them all, leading to many redundant references. Work around this by deduplicating definitions as well. Perhaps there is a better fix to not produce duplicate definitions in the first place. I discovered this working with the "bitflags" macro from the crate of the same name. Fixes #16357
2 parents 60982dc + 91a8f34 commit d8c8ccc

File tree

3 files changed

+27
-9
lines changed

3 files changed

+27
-9
lines changed

crates/rust-analyzer/src/handlers/request.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use ide::{
1616
ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
1717
};
1818
use ide_db::SymbolKind;
19+
use itertools::Itertools;
1920
use lsp_server::ErrorCode;
2021
use lsp_types::{
2122
CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem,
@@ -1055,9 +1056,8 @@ pub(crate) fn handle_references(
10551056
let exclude_imports = snap.config.find_all_refs_exclude_imports();
10561057
let exclude_tests = snap.config.find_all_refs_exclude_tests();
10571058

1058-
let refs = match snap.analysis.find_all_refs(position, None)? {
1059-
None => return Ok(None),
1060-
Some(refs) => refs,
1059+
let Some(refs) = snap.analysis.find_all_refs(position, None)? else {
1060+
return Ok(None);
10611061
};
10621062

10631063
let include_declaration = params.context.include_declaration;
@@ -1084,6 +1084,7 @@ pub(crate) fn handle_references(
10841084
})
10851085
.chain(decl)
10861086
})
1087+
.unique()
10871088
.filter_map(|frange| to_proto::location(&snap, frange).ok())
10881089
.collect();
10891090

@@ -1802,10 +1803,10 @@ fn show_ref_command_link(
18021803
.into_iter()
18031804
.flat_map(|res| res.references)
18041805
.flat_map(|(file_id, ranges)| {
1805-
ranges.into_iter().filter_map(move |(range, _)| {
1806-
to_proto::location(snap, FileRange { file_id, range }).ok()
1807-
})
1806+
ranges.into_iter().map(move |(range, _)| FileRange { file_id, range })
18081807
})
1808+
.unique()
1809+
.filter_map(|range| to_proto::location(snap, range).ok())
18091810
.collect();
18101811
let title = to_proto::reference_title(locations.len());
18111812
let command = to_proto::command::show_references(title, &uri, position, locations);

crates/rust-analyzer/src/lsp/to_proto.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -904,15 +904,16 @@ pub(crate) fn goto_definition_response(
904904
if snap.config.location_link() {
905905
let links = targets
906906
.into_iter()
907+
.unique_by(|nav| (nav.file_id, nav.full_range, nav.focus_range))
907908
.map(|nav| location_link(snap, src, nav))
908909
.collect::<Cancellable<Vec<_>>>()?;
909910
Ok(links.into())
910911
} else {
911912
let locations = targets
912913
.into_iter()
913-
.map(|nav| {
914-
location(snap, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
915-
})
914+
.map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
915+
.unique()
916+
.map(|range| location(snap, range))
916917
.collect::<Cancellable<Vec<_>>>()?;
917918
Ok(locations.into())
918919
}

crates/stdx/src/lib.rs

+16
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,22 @@ pub fn slice_tails<T>(this: &[T]) -> impl Iterator<Item = &[T]> {
302302
(0..this.len()).map(|i| &this[i..])
303303
}
304304

305+
pub trait IsNoneOr {
306+
type Type;
307+
#[allow(clippy::wrong_self_convention)]
308+
fn is_none_or(self, s: impl FnOnce(Self::Type) -> bool) -> bool;
309+
}
310+
#[allow(unstable_name_collisions)]
311+
impl<T> IsNoneOr for Option<T> {
312+
type Type = T;
313+
fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool {
314+
match self {
315+
Some(v) => f(v),
316+
None => true,
317+
}
318+
}
319+
}
320+
305321
#[cfg(test)]
306322
mod tests {
307323
use super::*;

0 commit comments

Comments
 (0)