about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-02-19 11:38:14 +0000
committerbors <bors@rust-lang.org>2024-02-19 11:38:14 +0000
commitd8c8ccc38005c0583d0188a112f88233b151eff0 (patch)
tree09dc56becee428e94a193be9cf988034d1a2ff31
parent60982dc8fc2e7862d68bb2b3e3d5d4fff8052de9 (diff)
parent91a8f34aeed075427ad4f6c0c6f58f247ac7de42 (diff)
downloadrust-d8c8ccc38005c0583d0188a112f88233b151eff0.tar.gz
rust-d8c8ccc38005c0583d0188a112f88233b151eff0.zip
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 6a06f6f72 (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
-rw-r--r--crates/rust-analyzer/src/handlers/request.rs13
-rw-r--r--crates/rust-analyzer/src/lsp/to_proto.rs7
-rw-r--r--crates/stdx/src/lib.rs16
3 files changed, 27 insertions, 9 deletions
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index eb9d4bf0f02..04a04395429 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -16,6 +16,7 @@ use ide::{
     ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
 };
 use ide_db::SymbolKind;
+use itertools::Itertools;
 use lsp_server::ErrorCode;
 use lsp_types::{
     CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem,
@@ -1055,9 +1056,8 @@ pub(crate) fn handle_references(
     let exclude_imports = snap.config.find_all_refs_exclude_imports();
     let exclude_tests = snap.config.find_all_refs_exclude_tests();
 
-    let refs = match snap.analysis.find_all_refs(position, None)? {
-        None => return Ok(None),
-        Some(refs) => refs,
+    let Some(refs) = snap.analysis.find_all_refs(position, None)? else {
+        return Ok(None);
     };
 
     let include_declaration = params.context.include_declaration;
@@ -1084,6 +1084,7 @@ pub(crate) fn handle_references(
                 })
                 .chain(decl)
         })
+        .unique()
         .filter_map(|frange| to_proto::location(&snap, frange).ok())
         .collect();
 
@@ -1802,10 +1803,10 @@ fn show_ref_command_link(
                 .into_iter()
                 .flat_map(|res| res.references)
                 .flat_map(|(file_id, ranges)| {
-                    ranges.into_iter().filter_map(move |(range, _)| {
-                        to_proto::location(snap, FileRange { file_id, range }).ok()
-                    })
+                    ranges.into_iter().map(move |(range, _)| FileRange { file_id, range })
                 })
+                .unique()
+                .filter_map(|range| to_proto::location(snap, range).ok())
                 .collect();
             let title = to_proto::reference_title(locations.len());
             let command = to_proto::command::show_references(title, &uri, position, locations);
diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs
index 727007bba08..4101d476cd3 100644
--- a/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -904,15 +904,16 @@ pub(crate) fn goto_definition_response(
     if snap.config.location_link() {
         let links = targets
             .into_iter()
+            .unique_by(|nav| (nav.file_id, nav.full_range, nav.focus_range))
             .map(|nav| location_link(snap, src, nav))
             .collect::<Cancellable<Vec<_>>>()?;
         Ok(links.into())
     } else {
         let locations = targets
             .into_iter()
-            .map(|nav| {
-                location(snap, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
-            })
+            .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
+            .unique()
+            .map(|range| location(snap, range))
             .collect::<Cancellable<Vec<_>>>()?;
         Ok(locations.into())
     }
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index 9a9ebae74e8..0504ca50b88 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -302,6 +302,22 @@ pub fn slice_tails<T>(this: &[T]) -> impl Iterator<Item = &[T]> {
     (0..this.len()).map(|i| &this[i..])
 }
 
+pub trait IsNoneOr {
+    type Type;
+    #[allow(clippy::wrong_self_convention)]
+    fn is_none_or(self, s: impl FnOnce(Self::Type) -> bool) -> bool;
+}
+#[allow(unstable_name_collisions)]
+impl<T> IsNoneOr for Option<T> {
+    type Type = T;
+    fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool {
+        match self {
+            Some(v) => f(v),
+            None => true,
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;