Skip to content

Commit 410da90

Browse files
Provide an option to not show derives near the ADT for "Goto Implementations" or "Implementations" codelens
I don't do it by default, for three reasons: (1) it's more expensive, (2) I actually quite like seeing the derives, and they may expand to no impl/more than one impl, (3) if #19130 will ever be merged this will become even more useful. Even a config might be too much, but it was fun and easy to code so I did that.
1 parent 3816d0a commit 410da90

File tree

9 files changed

+164
-25
lines changed

9 files changed

+164
-25
lines changed

crates/hir/src/semantics.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,22 @@ impl<'db> SemanticsImpl<'db> {
20832083
parent = parent_;
20842084
}
20852085
}
2086+
2087+
pub fn impl_generated_from_derive(&self, impl_: Impl) -> Option<Adt> {
2088+
let source = hir_def::src::HasSource::ast_ptr(&impl_.id.loc(self.db), self.db);
2089+
let mut file_id = source.file_id;
2090+
let adt_ast_id = loop {
2091+
let macro_call = file_id.macro_file()?;
2092+
match macro_call.loc(self.db).kind {
2093+
hir_expand::MacroCallKind::Derive { ast_id, .. } => break ast_id,
2094+
hir_expand::MacroCallKind::FnLike { ast_id, .. } => file_id = ast_id.file_id,
2095+
hir_expand::MacroCallKind::Attr { ast_id, .. } => file_id = ast_id.file_id,
2096+
}
2097+
};
2098+
let adt_source = adt_ast_id.to_in_file_node(self.db);
2099+
self.cache(adt_source.value.syntax().ancestors().last().unwrap(), adt_source.file_id);
2100+
ToDef::to_def(self, adt_source.as_ref())
2101+
}
20862102
}
20872103

20882104
// FIXME This can't be the best way to do this

crates/ide/src/annotations.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use syntax::{AstNode, TextRange, ast::HasName};
99
use crate::{
1010
NavigationTarget, RunnableKind,
1111
annotations::fn_references::find_all_methods,
12-
goto_implementation::goto_implementation,
12+
goto_implementation::{GotoImplementationConfig, goto_implementation},
1313
navigation_target,
1414
references::find_all_refs,
1515
runnables::{Runnable, runnables},
@@ -44,6 +44,11 @@ pub struct AnnotationConfig {
4444
pub annotate_method_references: bool,
4545
pub annotate_enum_variant_references: bool,
4646
pub location: AnnotationLocation,
47+
pub filter_adjacent_derive_implementations: bool,
48+
}
49+
50+
pub struct ResolveAnnotationConfig {
51+
pub filter_adjacent_derive_implementations: bool,
4752
}
4853

4954
pub enum AnnotationLocation {
@@ -196,10 +201,19 @@ pub(crate) fn annotations(
196201
.collect()
197202
}
198203

199-
pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation {
204+
pub(crate) fn resolve_annotation(
205+
db: &RootDatabase,
206+
config: &ResolveAnnotationConfig,
207+
mut annotation: Annotation,
208+
) -> Annotation {
200209
match annotation.kind {
201210
AnnotationKind::HasImpls { pos, ref mut data } => {
202-
*data = goto_implementation(db, pos).map(|range| range.info);
211+
let goto_implementation_config = GotoImplementationConfig {
212+
filter_adjacent_derive_implementations: config
213+
.filter_adjacent_derive_implementations,
214+
};
215+
*data =
216+
goto_implementation(db, &goto_implementation_config, pos).map(|range| range.info);
203217
}
204218
AnnotationKind::HasReferences { pos, ref mut data } => {
205219
*data = find_all_refs(&Semantics::new(db), pos, None).map(|result| {
@@ -229,7 +243,7 @@ fn should_skip_runnable(kind: &RunnableKind, binary_target: bool) -> bool {
229243
mod tests {
230244
use expect_test::{Expect, expect};
231245

232-
use crate::{Annotation, AnnotationConfig, fixture};
246+
use crate::{Annotation, AnnotationConfig, ResolveAnnotationConfig, fixture};
233247

234248
use super::AnnotationLocation;
235249

@@ -241,8 +255,12 @@ mod tests {
241255
annotate_method_references: true,
242256
annotate_enum_variant_references: true,
243257
location: AnnotationLocation::AboveName,
258+
filter_adjacent_derive_implementations: false,
244259
};
245260

261+
const DEFAULT_RESOLVE_CONFIG: ResolveAnnotationConfig =
262+
ResolveAnnotationConfig { filter_adjacent_derive_implementations: false };
263+
246264
fn check_with_config(
247265
#[rust_analyzer::rust_fixture] ra_fixture: &str,
248266
expect: Expect,
@@ -254,7 +272,9 @@ mod tests {
254272
.annotations(config, file_id)
255273
.unwrap()
256274
.into_iter()
257-
.map(|annotation| analysis.resolve_annotation(annotation).unwrap())
275+
.map(|annotation| {
276+
analysis.resolve_annotation(&DEFAULT_RESOLVE_CONFIG, annotation).unwrap()
277+
})
258278
.collect();
259279

260280
expect.assert_debug_eq(&annotations);

crates/ide/src/goto_implementation.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ use syntax::{AstNode, SyntaxKind::*, T, ast};
88

99
use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav};
1010

11+
pub struct GotoImplementationConfig {
12+
pub filter_adjacent_derive_implementations: bool,
13+
}
14+
1115
// Feature: Go to Implementation
1216
//
1317
// Navigates to the impl items of types.
@@ -19,6 +23,7 @@ use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav};
1923
// ![Go to Implementation](https://user-images.githubusercontent.com/48062697/113065566-02f85480-91b1-11eb-9288-aaad8abd8841.gif)
2024
pub(crate) fn goto_implementation(
2125
db: &RootDatabase,
26+
config: &GotoImplementationConfig,
2227
FilePosition { file_id, offset }: FilePosition,
2328
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
2429
let sema = Semantics::new(db);
@@ -55,7 +60,19 @@ pub(crate) fn goto_implementation(
5560
.and_then(|def| {
5661
let navs = match def {
5762
Definition::Trait(trait_) => impls_for_trait(&sema, trait_),
58-
Definition::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)),
63+
Definition::Adt(adt) => {
64+
let mut impls = Impl::all_for_type(db, adt.ty(sema.db));
65+
if config.filter_adjacent_derive_implementations {
66+
impls.retain(|impl_| {
67+
sema.impl_generated_from_derive(*impl_) != Some(adt)
68+
});
69+
}
70+
impls
71+
.into_iter()
72+
.filter_map(|imp| imp.try_to_nav(sema.db))
73+
.flatten()
74+
.collect()
75+
}
5976
Definition::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)),
6077
Definition::BuiltinType(builtin) => {
6178
impls_for_ty(&sema, builtin.ty(sema.db))
@@ -125,12 +142,24 @@ mod tests {
125142
use ide_db::FileRange;
126143
use itertools::Itertools;
127144

128-
use crate::fixture;
145+
use crate::{GotoImplementationConfig, fixture};
129146

147+
const TEST_CONFIG: &GotoImplementationConfig =
148+
&GotoImplementationConfig { filter_adjacent_derive_implementations: false };
149+
150+
#[track_caller]
130151
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
152+
check_with_config(TEST_CONFIG, ra_fixture);
153+
}
154+
155+
#[track_caller]
156+
fn check_with_config(
157+
config: &GotoImplementationConfig,
158+
#[rust_analyzer::rust_fixture] ra_fixture: &str,
159+
) {
131160
let (analysis, position, expected) = fixture::annotations(ra_fixture);
132161

133-
let navs = analysis.goto_implementation(position).unwrap().unwrap().info;
162+
let navs = analysis.goto_implementation(config, position).unwrap().unwrap().info;
134163

135164
let cmp = |frange: &FileRange| (frange.file_id, frange.range.start());
136165

@@ -416,4 +445,22 @@ fn test() {
416445
"#,
417446
);
418447
}
448+
449+
#[test]
450+
fn filter_adjacent_derives() {
451+
check_with_config(
452+
&GotoImplementationConfig { filter_adjacent_derive_implementations: true },
453+
r#"
454+
//- minicore: clone, copy, derive
455+
456+
#[derive(Clone, Copy)]
457+
struct Foo$0;
458+
459+
trait Bar {}
460+
461+
impl Bar for Foo {}
462+
// ^^^
463+
"#,
464+
);
465+
}
419466
}

crates/ide/src/lib.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,14 @@ use view_memory_layout::{RecursiveMemoryLayout, view_memory_layout};
7878
use crate::navigation_target::ToNav;
7979

8080
pub use crate::{
81-
annotations::{Annotation, AnnotationConfig, AnnotationKind, AnnotationLocation},
81+
annotations::{
82+
Annotation, AnnotationConfig, AnnotationKind, AnnotationLocation, ResolveAnnotationConfig,
83+
},
8284
call_hierarchy::{CallHierarchyConfig, CallItem},
8385
expand_macro::ExpandedMacro,
8486
file_structure::{StructureNode, StructureNodeKind},
8587
folding_ranges::{Fold, FoldKind},
88+
goto_implementation::GotoImplementationConfig,
8689
highlight_related::{HighlightRelatedConfig, HighlightedRange},
8790
hover::{
8891
HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult,
@@ -501,9 +504,10 @@ impl Analysis {
501504
/// Returns the impls from the symbol at `position`.
502505
pub fn goto_implementation(
503506
&self,
507+
config: &GotoImplementationConfig,
504508
position: FilePosition,
505509
) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
506-
self.with_db(|db| goto_implementation::goto_implementation(db, position))
510+
self.with_db(|db| goto_implementation::goto_implementation(db, config, position))
507511
}
508512

509513
/// Returns the type definitions for the symbol at `position`.
@@ -823,8 +827,12 @@ impl Analysis {
823827
self.with_db(|db| annotations::annotations(db, config, file_id))
824828
}
825829

826-
pub fn resolve_annotation(&self, annotation: Annotation) -> Cancellable<Annotation> {
827-
self.with_db(|db| annotations::resolve_annotation(db, annotation))
830+
pub fn resolve_annotation(
831+
&self,
832+
config: &ResolveAnnotationConfig,
833+
annotation: Annotation,
834+
) -> Cancellable<Annotation> {
835+
self.with_db(|db| annotations::resolve_annotation(db, config, annotation))
828836
}
829837

830838
pub fn move_item(

crates/rust-analyzer/src/cli/analysis_stats.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use hir_def::{
2121
use hir_ty::{Interner, Substitution, TyExt, TypeFlags};
2222
use ide::{
2323
Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, Edition, InlayFieldsToResolve,
24-
InlayHintsConfig, LineCol, RootDatabase,
24+
InlayHintsConfig, LineCol, ResolveAnnotationConfig, RootDatabase,
2525
};
2626
use ide_db::{
2727
EditionedFileId, LineIndexDatabase, SnippetCap,
@@ -1192,13 +1192,17 @@ impl flags::AnalysisStats {
11921192
annotate_method_references: false,
11931193
annotate_enum_variant_references: false,
11941194
location: ide::AnnotationLocation::AboveName,
1195+
filter_adjacent_derive_implementations: false,
11951196
},
11961197
analysis.editioned_file_id_to_vfs(file_id),
11971198
)
11981199
.unwrap()
11991200
.into_iter()
12001201
.for_each(|annotation| {
1201-
_ = analysis.resolve_annotation(annotation);
1202+
_ = analysis.resolve_annotation(
1203+
&ResolveAnnotationConfig { filter_adjacent_derive_implementations: false },
1204+
annotation,
1205+
);
12021206
});
12031207
}
12041208
let ide_time = sw.elapsed();

crates/rust-analyzer/src/config.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ use cfg::{CfgAtom, CfgDiff};
99
use hir::Symbol;
1010
use ide::{
1111
AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig,
12-
CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, HighlightConfig,
13-
HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve, InlayHintsConfig,
14-
JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope,
15-
SourceRootId,
12+
CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, GotoImplementationConfig,
13+
HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
14+
InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
15+
Snippet, SnippetScope, SourceRootId,
1616
};
1717
use ide_db::{
1818
SnippetCap,
@@ -93,6 +93,8 @@ config_data! {
9393
files_exclude | files_excludeDirs: Vec<Utf8PathBuf> = vec![],
9494

9595

96+
/// If this is `true`, when "Goto Implementations" and in "Implementations" lens, are triggered on a `struct` or `enum` or `union`, we filter out trait implementations that originate from `derive`s above the type.
97+
gotoImplementations_filterAdjacentDerives: bool = false,
9698

9799
/// Enables highlighting of related return values while the cursor is on any `match`, `if`, or match arm arrow (`=>`).
98100
highlightRelated_branchExitPoints_enable: bool = true,
@@ -1249,6 +1251,7 @@ pub struct LensConfig {
12491251

12501252
// annotations
12511253
pub location: AnnotationLocation,
1254+
pub filter_adjacent_derive_implementations: bool,
12521255
}
12531256

12541257
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
@@ -2289,6 +2292,15 @@ impl Config {
22892292
refs_trait: *self.lens_enable() && *self.lens_references_trait_enable(),
22902293
enum_variant_refs: *self.lens_enable() && *self.lens_references_enumVariant_enable(),
22912294
location: *self.lens_location(),
2295+
filter_adjacent_derive_implementations: *self
2296+
.gotoImplementations_filterAdjacentDerives(),
2297+
}
2298+
}
2299+
2300+
pub fn goto_implementation(&self) -> GotoImplementationConfig {
2301+
GotoImplementationConfig {
2302+
filter_adjacent_derive_implementations: *self
2303+
.gotoImplementations_filterAdjacentDerives(),
22922304
}
22932305
}
22942306

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

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use base64::{Engine, prelude::BASE64_STANDARD};
99
use ide::{
1010
AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve,
1111
FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query,
12-
RangeInfo, ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
12+
RangeInfo, ReferenceCategory, ResolveAnnotationConfig, Runnable, RunnableKind, SingleResolve,
13+
SourceChange, TextEdit,
1314
};
1415
use ide_db::{FxHashMap, SymbolKind};
1516
use itertools::Itertools;
@@ -838,10 +839,11 @@ pub(crate) fn handle_goto_implementation(
838839
let _p = tracing::info_span!("handle_goto_implementation").entered();
839840
let position =
840841
try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
841-
let nav_info = match snap.analysis.goto_implementation(position)? {
842-
None => return Ok(None),
843-
Some(it) => it,
844-
};
842+
let nav_info =
843+
match snap.analysis.goto_implementation(&snap.config.goto_implementation(), position)? {
844+
None => return Ok(None),
845+
Some(it) => it,
846+
};
845847
let src = FileRange { file_id: position.file_id, range: nav_info.range };
846848
let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
847849
Ok(Some(res))
@@ -1624,6 +1626,8 @@ pub(crate) fn handle_code_lens(
16241626
annotate_method_references: lens_config.method_refs,
16251627
annotate_enum_variant_references: lens_config.enum_variant_refs,
16261628
location: lens_config.location.into(),
1629+
filter_adjacent_derive_implementations: lens_config
1630+
.filter_adjacent_derive_implementations,
16271631
},
16281632
file_id,
16291633
)?;
@@ -1647,7 +1651,14 @@ pub(crate) fn handle_code_lens_resolve(
16471651
let Some(annotation) = from_proto::annotation(&snap, code_lens.range, resolve)? else {
16481652
return Ok(code_lens);
16491653
};
1650-
let annotation = snap.analysis.resolve_annotation(annotation)?;
1654+
let lens_config = snap.config.lens();
1655+
let annotation = snap.analysis.resolve_annotation(
1656+
&ResolveAnnotationConfig {
1657+
filter_adjacent_derive_implementations: lens_config
1658+
.filter_adjacent_derive_implementations,
1659+
},
1660+
annotation,
1661+
)?;
16511662

16521663
let mut acc = Vec::new();
16531664
to_proto::code_lens(&mut acc, &snap, annotation)?;
@@ -2123,7 +2134,11 @@ fn show_impl_command_link(
21232134
position: &FilePosition,
21242135
) -> Option<lsp_ext::CommandLinkGroup> {
21252136
if snap.config.hover_actions().implementations && snap.config.client_commands().show_reference {
2126-
if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) {
2137+
if let Some(nav_data) = snap
2138+
.analysis
2139+
.goto_implementation(&snap.config.goto_implementation(), *position)
2140+
.unwrap_or(None)
2141+
{
21272142
let uri = to_proto::url(snap, position.file_id);
21282143
let line_index = snap.file_line_index(position.file_id).ok()?;
21292144
let position = to_proto::position(&line_index, position.offset);

docs/book/src/configuration_generated.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,13 @@ Default: `"client"`
612612
Controls file watching implementation.
613613

614614

615+
## rust-analyzer.gotoImplementations.filterAdjacentDerives {#gotoImplementations.filterAdjacentDerives}
616+
617+
Default: `false`
618+
619+
If this is `true`, when "Goto Implementations" and in "Implementations" lens, are triggered on a `struct` or `enum` or `union`, we filter out trait implementations that originate from `derive`s above the type.
620+
621+
615622
## rust-analyzer.highlightRelated.branchExitPoints.enable {#highlightRelated.branchExitPoints.enable}
616623

617624
Default: `true`

0 commit comments

Comments
 (0)