mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-08-31 07:37:30 +00:00
Merge 4e9eef2ee5
into 6b4569dccd
This commit is contained in:
commit
fb735dfc42
9 changed files with 164 additions and 26 deletions
|
@ -2091,6 +2091,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
|
||||
|
|
|
@ -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},
|
||||
|
@ -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 {
|
||||
|
@ -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| {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
@ -19,6 +23,7 @@ use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav};
|
|||
// 
|
||||
pub(crate) fn goto_implementation(
|
||||
db: &RootDatabase,
|
||||
config: &GotoImplementationConfig,
|
||||
FilePosition { file_id, offset }: FilePosition,
|
||||
) -> Option<RangeInfo<Vec<NavigationTarget>>> {
|
||||
let sema = Semantics::new(db);
|
||||
|
@ -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))
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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 {}
|
||||
// ^^^
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::{FileStructureConfig, StructureNode, StructureNodeKind},
|
||||
folding_ranges::{Fold, FoldKind},
|
||||
goto_implementation::GotoImplementationConfig,
|
||||
highlight_related::{HighlightRelatedConfig, HighlightedRange},
|
||||
hover::{
|
||||
HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult,
|
||||
|
@ -510,9 +513,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`.
|
||||
|
@ -845,8 +849,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(
|
||||
|
|
|
@ -23,7 +23,7 @@ use hir_def::{
|
|||
use hir_ty::{Interner, TyExt, TypeFlags};
|
||||
use ide::{
|
||||
Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, Edition, InlayFieldsToResolve,
|
||||
InlayHintsConfig, LineCol, RootDatabase,
|
||||
InlayHintsConfig, LineCol, ResolveAnnotationConfig, RootDatabase,
|
||||
};
|
||||
use ide_db::{
|
||||
EditionedFileId, LineIndexDatabase, SnippetCap,
|
||||
|
@ -1170,13 +1170,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();
|
||||
|
|
|
@ -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,
|
||||
|
@ -98,6 +98,9 @@ config_data! {
|
|||
/// Code's `files.watcherExclude`.
|
||||
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,
|
||||
|
||||
/// Highlight related return values while the cursor is on any `match`, `if`, or match arm
|
||||
/// arrow (`=>`).
|
||||
highlightRelated_branchExitPoints_enable: bool = true,
|
||||
|
@ -1404,6 +1407,7 @@ pub struct LensConfig {
|
|||
|
||||
// annotations
|
||||
pub location: AnnotationLocation,
|
||||
pub filter_adjacent_derive_implementations: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
@ -2455,6 +2459,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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ use base64::{Engine, prelude::BASE64_STANDARD};
|
|||
use ide::{
|
||||
AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve,
|
||||
FilePosition, FileRange, FileStructureConfig, HoverAction, HoverGotoTypeData,
|
||||
InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind,
|
||||
SingleResolve, SourceChange, TextEdit,
|
||||
InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory, ResolveAnnotationConfig, Runnable,
|
||||
RunnableKind, SingleResolve, SourceChange, TextEdit,
|
||||
};
|
||||
use ide_db::{FxHashMap, SymbolKind};
|
||||
use itertools::Itertools;
|
||||
|
@ -845,10 +845,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))
|
||||
|
@ -1630,6 +1631,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,
|
||||
)?;
|
||||
|
@ -1653,7 +1656,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)?;
|
||||
|
@ -2129,7 +2139,10 @@ fn show_impl_command_link(
|
|||
) -> Option<lsp_ext::CommandLinkGroup> {
|
||||
if snap.config.hover_actions().implementations
|
||||
&& snap.config.client_commands().show_reference
|
||||
&& let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None)
|
||||
&& 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()?;
|
||||
|
|
|
@ -635,6 +635,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`
|
||||
|
|
|
@ -1626,6 +1626,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Goto Implementations",
|
||||
"properties": {
|
||||
"rust-analyzer.gotoImplementations.filterAdjacentDerives": {
|
||||
"markdownDescription": "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.",
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Highlight Related",
|
||||
"properties": {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue