Skip to content

feat: Provide an option to not show derives near the ADT for "Goto Implementations" or "Implementations" codelens #20186

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions crates/hir/src/semantics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2083,6 +2083,22 @@ impl<'db> SemanticsImpl<'db> {
parent = parent_;
}
}

pub fn impl_generated_from_derive(&self, impl_: Impl) -> Option<Adt> {
let source = hir_def::src::HasSource::ast_ptr(&impl_.id.loc(self.db), self.db);
let mut file_id = source.file_id;
let adt_ast_id = loop {
let macro_call = file_id.macro_file()?;
match macro_call.loc(self.db).kind {
hir_expand::MacroCallKind::Derive { ast_id, .. } => break ast_id,
hir_expand::MacroCallKind::FnLike { ast_id, .. } => file_id = ast_id.file_id,
hir_expand::MacroCallKind::Attr { ast_id, .. } => file_id = ast_id.file_id,
}
};
let adt_source = adt_ast_id.to_in_file_node(self.db);
self.cache(adt_source.value.syntax().ancestors().last().unwrap(), adt_source.file_id);
ToDef::to_def(self, adt_source.as_ref())
}
}

// FIXME This can't be the best way to do this
Expand Down
30 changes: 25 additions & 5 deletions crates/ide/src/annotations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use syntax::{AstNode, TextRange, ast::HasName};
use crate::{
NavigationTarget, RunnableKind,
annotations::fn_references::find_all_methods,
goto_implementation::goto_implementation,
goto_implementation::{GotoImplementationConfig, goto_implementation},
navigation_target,
references::find_all_refs,
runnables::{Runnable, runnables},
Expand Down Expand Up @@ -44,6 +44,11 @@ pub struct AnnotationConfig {
pub annotate_method_references: bool,
pub annotate_enum_variant_references: bool,
pub location: AnnotationLocation,
pub filter_adjacent_derive_implementations: bool,
}

pub struct ResolveAnnotationConfig {
pub filter_adjacent_derive_implementations: bool,
}

pub enum AnnotationLocation {
Expand Down Expand Up @@ -196,10 +201,19 @@ pub(crate) fn annotations(
.collect()
}

pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation {
pub(crate) fn resolve_annotation(
db: &RootDatabase,
config: &ResolveAnnotationConfig,
mut annotation: Annotation,
) -> Annotation {
match annotation.kind {
AnnotationKind::HasImpls { pos, ref mut data } => {
*data = goto_implementation(db, pos).map(|range| range.info);
let goto_implementation_config = GotoImplementationConfig {
filter_adjacent_derive_implementations: config
.filter_adjacent_derive_implementations,
};
*data =
goto_implementation(db, &goto_implementation_config, pos).map(|range| range.info);
}
AnnotationKind::HasReferences { pos, ref mut data } => {
*data = find_all_refs(&Semantics::new(db), pos, None).map(|result| {
Expand Down Expand Up @@ -229,7 +243,7 @@ fn should_skip_runnable(kind: &RunnableKind, binary_target: bool) -> bool {
mod tests {
use expect_test::{Expect, expect};

use crate::{Annotation, AnnotationConfig, fixture};
use crate::{Annotation, AnnotationConfig, ResolveAnnotationConfig, fixture};

use super::AnnotationLocation;

Expand All @@ -241,8 +255,12 @@ mod tests {
annotate_method_references: true,
annotate_enum_variant_references: true,
location: AnnotationLocation::AboveName,
filter_adjacent_derive_implementations: false,
};

const DEFAULT_RESOLVE_CONFIG: ResolveAnnotationConfig =
ResolveAnnotationConfig { filter_adjacent_derive_implementations: false };

fn check_with_config(
#[rust_analyzer::rust_fixture] ra_fixture: &str,
expect: Expect,
Expand All @@ -254,7 +272,9 @@ mod tests {
.annotations(config, file_id)
.unwrap()
.into_iter()
.map(|annotation| analysis.resolve_annotation(annotation).unwrap())
.map(|annotation| {
analysis.resolve_annotation(&DEFAULT_RESOLVE_CONFIG, annotation).unwrap()
})
.collect();

expect.assert_debug_eq(&annotations);
Expand Down
53 changes: 50 additions & 3 deletions crates/ide/src/goto_implementation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ use syntax::{AstNode, SyntaxKind::*, T, ast};

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

pub struct GotoImplementationConfig {
pub filter_adjacent_derive_implementations: bool,
}

// Feature: Go to Implementation
//
// Navigates to the impl items of types.
Expand All @@ -19,6 +23,7 @@ use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav};
// ![Go to Implementation](https://user-images.githubusercontent.com/48062697/113065566-02f85480-91b1-11eb-9288-aaad8abd8841.gif)
pub(crate) fn goto_implementation(
db: &RootDatabase,
config: &GotoImplementationConfig,
FilePosition { file_id, offset }: FilePosition,
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
let sema = Semantics::new(db);
Expand Down Expand Up @@ -55,7 +60,19 @@ pub(crate) fn goto_implementation(
.and_then(|def| {
let navs = match def {
Definition::Trait(trait_) => impls_for_trait(&sema, trait_),
Definition::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)),
Definition::Adt(adt) => {
let mut impls = Impl::all_for_type(db, adt.ty(sema.db));
if config.filter_adjacent_derive_implementations {
impls.retain(|impl_| {
sema.impl_generated_from_derive(*impl_) != Some(adt)
});
}
impls
.into_iter()
.filter_map(|imp| imp.try_to_nav(sema.db))
.flatten()
.collect()
}
Definition::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)),
Definition::BuiltinType(builtin) => {
impls_for_ty(&sema, builtin.ty(sema.db))
Expand Down Expand Up @@ -125,12 +142,24 @@ mod tests {
use ide_db::FileRange;
use itertools::Itertools;

use crate::fixture;
use crate::{GotoImplementationConfig, fixture};

const TEST_CONFIG: &GotoImplementationConfig =
&GotoImplementationConfig { filter_adjacent_derive_implementations: false };

#[track_caller]
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
check_with_config(TEST_CONFIG, ra_fixture);
}

#[track_caller]
fn check_with_config(
config: &GotoImplementationConfig,
#[rust_analyzer::rust_fixture] ra_fixture: &str,
) {
let (analysis, position, expected) = fixture::annotations(ra_fixture);

let navs = analysis.goto_implementation(position).unwrap().unwrap().info;
let navs = analysis.goto_implementation(config, position).unwrap().unwrap().info;

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

Expand Down Expand Up @@ -416,4 +445,22 @@ fn test() {
"#,
);
}

#[test]
fn filter_adjacent_derives() {
check_with_config(
&GotoImplementationConfig { filter_adjacent_derive_implementations: true },
r#"
//- minicore: clone, copy, derive

#[derive(Clone, Copy)]
struct Foo$0;

trait Bar {}

impl Bar for Foo {}
// ^^^
"#,
);
}
}
16 changes: 12 additions & 4 deletions crates/ide/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,14 @@ use view_memory_layout::{RecursiveMemoryLayout, view_memory_layout};
use crate::navigation_target::ToNav;

pub use crate::{
annotations::{Annotation, AnnotationConfig, AnnotationKind, AnnotationLocation},
annotations::{
Annotation, AnnotationConfig, AnnotationKind, AnnotationLocation, ResolveAnnotationConfig,
},
call_hierarchy::{CallHierarchyConfig, CallItem},
expand_macro::ExpandedMacro,
file_structure::{StructureNode, StructureNodeKind},
folding_ranges::{Fold, FoldKind},
goto_implementation::GotoImplementationConfig,
highlight_related::{HighlightRelatedConfig, HighlightedRange},
hover::{
HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult,
Expand Down Expand Up @@ -501,9 +504,10 @@ impl Analysis {
/// Returns the impls from the symbol at `position`.
pub fn goto_implementation(
&self,
config: &GotoImplementationConfig,
position: FilePosition,
) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
self.with_db(|db| goto_implementation::goto_implementation(db, position))
self.with_db(|db| goto_implementation::goto_implementation(db, config, position))
}

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

pub fn resolve_annotation(&self, annotation: Annotation) -> Cancellable<Annotation> {
self.with_db(|db| annotations::resolve_annotation(db, annotation))
pub fn resolve_annotation(
&self,
config: &ResolveAnnotationConfig,
annotation: Annotation,
) -> Cancellable<Annotation> {
self.with_db(|db| annotations::resolve_annotation(db, config, annotation))
}

pub fn move_item(
Expand Down
8 changes: 6 additions & 2 deletions crates/rust-analyzer/src/cli/analysis_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use hir_def::{
use hir_ty::{Interner, Substitution, TyExt, TypeFlags};
use ide::{
Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, Edition, InlayFieldsToResolve,
InlayHintsConfig, LineCol, RootDatabase,
InlayHintsConfig, LineCol, ResolveAnnotationConfig, RootDatabase,
};
use ide_db::{
EditionedFileId, LineIndexDatabase, SnippetCap,
Expand Down Expand Up @@ -1192,13 +1192,17 @@ impl flags::AnalysisStats {
annotate_method_references: false,
annotate_enum_variant_references: false,
location: ide::AnnotationLocation::AboveName,
filter_adjacent_derive_implementations: false,
},
analysis.editioned_file_id_to_vfs(file_id),
)
.unwrap()
.into_iter()
.for_each(|annotation| {
_ = analysis.resolve_annotation(annotation);
_ = analysis.resolve_annotation(
&ResolveAnnotationConfig { filter_adjacent_derive_implementations: false },
annotation,
);
});
}
let ide_time = sw.elapsed();
Expand Down
20 changes: 16 additions & 4 deletions crates/rust-analyzer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use cfg::{CfgAtom, CfgDiff};
use hir::Symbol;
use ide::{
AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig,
CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, HighlightConfig,
HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve, InlayHintsConfig,
JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope,
SourceRootId,
CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, GotoImplementationConfig,
HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
Snippet, SnippetScope, SourceRootId,
};
use ide_db::{
SnippetCap,
Expand Down Expand Up @@ -93,6 +93,8 @@ config_data! {
files_exclude | files_excludeDirs: Vec<Utf8PathBuf> = vec![],


/// 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.
gotoImplementations_filterAdjacentDerives: bool = false,

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

// annotations
pub location: AnnotationLocation,
pub filter_adjacent_derive_implementations: bool,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
Expand Down Expand Up @@ -2289,6 +2292,15 @@ impl Config {
refs_trait: *self.lens_enable() && *self.lens_references_trait_enable(),
enum_variant_refs: *self.lens_enable() && *self.lens_references_enumVariant_enable(),
location: *self.lens_location(),
filter_adjacent_derive_implementations: *self
.gotoImplementations_filterAdjacentDerives(),
}
}

pub fn goto_implementation(&self) -> GotoImplementationConfig {
GotoImplementationConfig {
filter_adjacent_derive_implementations: *self
.gotoImplementations_filterAdjacentDerives(),
}
}

Expand Down
29 changes: 22 additions & 7 deletions crates/rust-analyzer/src/handlers/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use base64::{Engine, prelude::BASE64_STANDARD};
use ide::{
AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve,
FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query,
RangeInfo, ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
RangeInfo, ReferenceCategory, ResolveAnnotationConfig, Runnable, RunnableKind, SingleResolve,
SourceChange, TextEdit,
};
use ide_db::{FxHashMap, SymbolKind};
use itertools::Itertools;
Expand Down Expand Up @@ -838,10 +839,11 @@ pub(crate) fn handle_goto_implementation(
let _p = tracing::info_span!("handle_goto_implementation").entered();
let position =
try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
let nav_info = match snap.analysis.goto_implementation(position)? {
None => return Ok(None),
Some(it) => it,
};
let nav_info =
match snap.analysis.goto_implementation(&snap.config.goto_implementation(), position)? {
None => return Ok(None),
Some(it) => it,
};
let src = FileRange { file_id: position.file_id, range: nav_info.range };
let res = to_proto::goto_definition_response(&snap, Some(src), nav_info.info)?;
Ok(Some(res))
Expand Down Expand Up @@ -1624,6 +1626,8 @@ pub(crate) fn handle_code_lens(
annotate_method_references: lens_config.method_refs,
annotate_enum_variant_references: lens_config.enum_variant_refs,
location: lens_config.location.into(),
filter_adjacent_derive_implementations: lens_config
.filter_adjacent_derive_implementations,
},
file_id,
)?;
Expand All @@ -1647,7 +1651,14 @@ pub(crate) fn handle_code_lens_resolve(
let Some(annotation) = from_proto::annotation(&snap, code_lens.range, resolve)? else {
return Ok(code_lens);
};
let annotation = snap.analysis.resolve_annotation(annotation)?;
let lens_config = snap.config.lens();
let annotation = snap.analysis.resolve_annotation(
&ResolveAnnotationConfig {
filter_adjacent_derive_implementations: lens_config
.filter_adjacent_derive_implementations,
},
annotation,
)?;

let mut acc = Vec::new();
to_proto::code_lens(&mut acc, &snap, annotation)?;
Expand Down Expand Up @@ -2123,7 +2134,11 @@ fn show_impl_command_link(
position: &FilePosition,
) -> Option<lsp_ext::CommandLinkGroup> {
if snap.config.hover_actions().implementations && snap.config.client_commands().show_reference {
if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) {
if let Some(nav_data) = snap
.analysis
.goto_implementation(&snap.config.goto_implementation(), *position)
.unwrap_or(None)
{
let uri = to_proto::url(snap, position.file_id);
let line_index = snap.file_line_index(position.file_id).ok()?;
let position = to_proto::position(&line_index, position.offset);
Expand Down
7 changes: 7 additions & 0 deletions docs/book/src/configuration_generated.md
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,13 @@ Default: `"client"`
Controls file watching implementation.


## rust-analyzer.gotoImplementations.filterAdjacentDerives {#gotoImplementations.filterAdjacentDerives}

Default: `false`

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.


## rust-analyzer.highlightRelated.branchExitPoints.enable {#highlightRelated.branchExitPoints.enable}

Default: `true`
Expand Down
Loading