From: Lukas Wirth Date: Thu, 10 Mar 2022 20:56:19 +0000 (+0100) Subject: Enable qualifier completions for derives X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=b1ab5770c9df12504bc09ab912a8b6a8bd15c6c7;p=rust.git Enable qualifier completions for derives --- diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs index 90070a2cdb9..1edc92d5d62 100644 --- a/crates/ide_completion/src/completions/attribute/derive.rs +++ b/crates/ide_completion/src/completions/attribute/derive.rs @@ -1,77 +1,111 @@ //! Completion for derives -use hir::{HasAttrs, Macro}; +use hir::{HasAttrs, ScopeDef}; use ide_db::SymbolKind; use itertools::Itertools; use syntax::SmolStr; use crate::{ - context::{CompletionContext, PathCompletionCtx, PathKind}, + context::{CompletionContext, PathCompletionCtx, PathKind, PathQualifierCtx}, item::CompletionItem, Completions, }; pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) { - match ctx.path_context { - // FIXME: Enable qualified completions - Some(PathCompletionCtx { kind: Some(PathKind::Derive), qualifier: None, .. }) => (), + let (qualifier, is_absolute_path) = match ctx.path_context { + Some(PathCompletionCtx { + kind: Some(PathKind::Derive), + ref qualifier, + is_absolute_path, + .. + }) => (qualifier, is_absolute_path), _ => return, - } + }; let core = ctx.famous_defs().core(); - for (name, mac) in get_derives_in_scope(ctx) { - if ctx.existing_derives.contains(&mac) { - continue; - } + match qualifier { + Some(PathQualifierCtx { resolution, is_super_chain, .. }) => { + if *is_super_chain { + acc.add_keyword(ctx, "super::"); + } - let name = name.to_smol_str(); - let (label, lookup) = match (core, mac.module(ctx.db).krate()) { - // show derive dependencies for `core`/`std` derives - (Some(core), mac_krate) if core == mac_krate => { - if let Some(derive_completion) = DEFAULT_DERIVE_DEPENDENCIES - .iter() - .find(|derive_completion| derive_completion.label == name) - { - let mut components = vec![derive_completion.label]; - components.extend(derive_completion.dependencies.iter().filter( - |&&dependency| { - !ctx.existing_derives - .iter() - .map(|it| it.name(ctx.db)) - .any(|it| it.to_smol_str() == dependency) - }, - )); - let lookup = components.join(", "); - let label = Itertools::intersperse(components.into_iter().rev(), ", "); - (SmolStr::from_iter(label), Some(lookup)) - } else { - (name, None) + let module = match resolution { + Some(hir::PathResolution::Def(hir::ModuleDef::Module(it))) => it, + _ => return, + }; + + for (name, def) in module.scope(ctx.db, ctx.module) { + let add_def = match def { + ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => { + !ctx.existing_derives.contains(&mac) && mac.is_derive(ctx.db) + } + ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true, + _ => false, + }; + if add_def { + acc.add_resolution(ctx, name, def); } } - _ => (name, None), - }; - - let mut item = CompletionItem::new(SymbolKind::Derive, ctx.source_range(), label); - if let Some(docs) = mac.docs(ctx.db) { - item.documentation(docs); + return; } - if let Some(lookup) = lookup { - item.lookup_by(lookup); - } - item.add_to(acc); - } -} + None if is_absolute_path => acc.add_crate_roots(ctx), + // only show modules in a fresh UseTree + None => { + ctx.process_all_names(&mut |name, def| { + let mac = match def { + ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) + if !ctx.existing_derives.contains(&mac) && mac.is_derive(ctx.db) => + { + mac + } + ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => { + return acc.add_resolution(ctx, name, def); + } + _ => return, + }; -fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, Macro)> { - let mut result = Vec::default(); - ctx.process_all_names(&mut |name, scope_def| { - if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) = scope_def { - if mac.kind(ctx.db) == hir::MacroKind::Derive { - result.push((name, mac)); - } + match (core, mac.module(ctx.db).krate()) { + // show derive dependencies for `core`/`std` derives + (Some(core), mac_krate) if core == mac_krate && qualifier.is_none() => {} + _ => return acc.add_resolution(ctx, name, def), + }; + + let name_ = name.to_smol_str(); + let find = DEFAULT_DERIVE_DEPENDENCIES + .iter() + .find(|derive_completion| derive_completion.label == name_); + + match find { + Some(derive_completion) => { + let mut components = vec![derive_completion.label]; + components.extend(derive_completion.dependencies.iter().filter( + |&&dependency| { + !ctx.existing_derives + .iter() + .map(|it| it.name(ctx.db)) + .any(|it| it.to_smol_str() == dependency) + }, + )); + let lookup = components.join(", "); + let label = Itertools::intersperse(components.into_iter().rev(), ", "); + + let mut item = CompletionItem::new( + SymbolKind::Derive, + ctx.source_range(), + SmolStr::from_iter(label), + ); + if let Some(docs) = mac.docs(ctx.db) { + item.documentation(docs); + } + item.lookup_by(lookup); + item.add_to(acc); + } + None => acc.add_resolution(ctx, name, def), + } + }); + acc.add_nameref_keywords(ctx); } - }); - result + } } struct DeriveDependencies { diff --git a/crates/ide_completion/src/tests/attribute.rs b/crates/ide_completion/src/tests/attribute.rs index 3bc25259239..647fd742e63 100644 --- a/crates/ide_completion/src/tests/attribute.rs +++ b/crates/ide_completion/src/tests/attribute.rs @@ -688,13 +688,17 @@ fn empty_derive() { #[derive($0)] struct Test; "#, expect![[r#" - de Default + md core + de Default pub macro Default de Clone, Copy - de PartialEq + de PartialEq pub macro PartialEq de PartialEq, Eq de PartialEq, Eq, PartialOrd, Ord - de Clone + de Clone pub macro Clone de PartialEq, PartialOrd + kw self:: + kw super:: + kw crate:: "#]], ); } @@ -707,12 +711,16 @@ fn derive_with_input_before() { #[derive(serde::Serialize, PartialEq, $0)] struct Test; "#, expect![[r#" - de Default + md core + de Default pub macro Default de Clone, Copy de Eq de Eq, PartialOrd, Ord - de Clone + de Clone pub macro Clone de PartialOrd + kw self:: + kw super:: + kw crate:: "#]], ) } @@ -725,36 +733,20 @@ fn derive_with_input_after() { #[derive($0 serde::Serialize, PartialEq)] struct Test; "#, expect![[r#" - de Default + md core + de Default pub macro Default de Clone, Copy de Eq de Eq, PartialOrd, Ord - de Clone + de Clone pub macro Clone de PartialOrd + kw self:: + kw super:: + kw crate:: "#]], ) } - #[test] - fn derive_no_attrs() { - check_derive( - r#" -//- proc_macros: identity -//- minicore: derive -#[derive($0)] struct Test; -"#, - expect![[r#""#]], - ); - check_derive( - r#" -//- proc_macros: identity -//- minicore: derive -#[derive(i$0)] struct Test; -"#, - expect![[r#""#]], - ); - } - #[test] fn derive_flyimport() { check_derive( @@ -764,6 +756,11 @@ fn derive_flyimport() { #[derive(der$0)] struct Test; "#, expect![[r#" + md proc_macros + md core + kw self:: + kw super:: + kw crate:: de DeriveIdentity (use proc_macros::DeriveIdentity) pub macro derive_identity "#]], ); @@ -775,7 +772,12 @@ fn derive_flyimport() { #[derive(der$0)] struct Test; "#, expect![[r#" - de DeriveIdentity + de DeriveIdentity pub macro derive_identity + md proc_macros + md core + kw self:: + kw super:: + kw crate:: "#]], ); } @@ -805,7 +807,9 @@ fn qualified() { //- minicore: derive, copy, clone #[derive(proc_macros::$0)] struct Test; "#, - expect![[r#""#]], + expect![[r#" + de DeriveIdentity pub macro derive_identity + "#]], ); check_derive( r#" @@ -813,7 +817,9 @@ fn qualified() { //- minicore: derive, copy, clone #[derive(proc_macros::C$0)] struct Test; "#, - expect![[r#""#]], + expect![[r#" + de DeriveIdentity pub macro derive_identity + "#]], ); } }