Cleanup Completions api a bit

This commit is contained in:
Lukas Wirth 2022-02-02 12:05:21 +01:00
parent 70650897d8
commit 7267749f6b
9 changed files with 70 additions and 77 deletions

View file

@ -18,7 +18,7 @@ pub(crate) mod format_string;
use std::iter; use std::iter;
use hir::known; use hir::{known, ScopeDef};
use ide_db::SymbolKind; use ide_db::SymbolKind;
use crate::{ use crate::{
@ -28,7 +28,6 @@ use crate::{
const_::render_const, const_::render_const,
enum_variant::render_variant, enum_variant::render_variant,
function::{render_fn, render_method}, function::{render_fn, render_method},
macro_::render_macro,
pattern::{render_struct_pat, render_variant_pat}, pattern::{render_struct_pat, render_variant_pat},
render_field, render_resolution, render_tuple_field, render_field, render_resolution, render_tuple_field,
struct_literal::render_struct_literal, struct_literal::render_struct_literal,
@ -38,6 +37,22 @@ use crate::{
CompletionContext, CompletionItem, CompletionItemKind, CompletionContext, CompletionItem, CompletionItemKind,
}; };
fn module_or_attr(def: ScopeDef) -> Option<ScopeDef> {
match def {
ScopeDef::MacroDef(mac) if mac.is_attr() => Some(def),
ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => Some(def),
_ => None,
}
}
fn module_or_fn_macro(def: ScopeDef) -> Option<ScopeDef> {
match def {
ScopeDef::MacroDef(mac) if mac.is_fn_like() => Some(def),
ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => Some(def),
_ => None,
}
}
/// Represents an in-progress set of completions being built. /// Represents an in-progress set of completions being built.
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Completions { pub struct Completions {
@ -95,19 +110,6 @@ impl Completions {
self.add(render_resolution(RenderContext::new(ctx, false), local_name, resolution)); self.add(render_resolution(RenderContext::new(ctx, false), local_name, resolution));
} }
pub(crate) fn add_macro(
&mut self,
ctx: &CompletionContext,
name: Option<hir::Name>,
macro_: hir::MacroDef,
) {
let name = match name {
Some(it) => it,
None => return,
};
self.add(render_macro(RenderContext::new(ctx, false), None, name, macro_));
}
pub(crate) fn add_function( pub(crate) fn add_function(
&mut self, &mut self,
ctx: &CompletionContext, ctx: &CompletionContext,
@ -227,9 +229,13 @@ impl Completions {
self.add(item); self.add(item);
} }
pub(crate) fn add_static_lifetime(&mut self, ctx: &CompletionContext) { pub(crate) fn add_lifetime(&mut self, ctx: &CompletionContext, name: hir::Name) {
let item = CompletionItem::new(SymbolKind::LifetimeParam, ctx.source_range(), "'static"); CompletionItem::new(SymbolKind::LifetimeParam, ctx.source_range(), name.to_smol_str())
self.add(item.build()); .add_to(self)
}
pub(crate) fn add_label(&mut self, ctx: &CompletionContext, name: hir::Name) {
CompletionItem::new(SymbolKind::Label, ctx.source_range(), name.to_smol_str()).add_to(self)
} }
pub(crate) fn add_variant_pat( pub(crate) fn add_variant_pat(

View file

@ -7,7 +7,7 @@
//! there is no value in lifting these out into the outline module test since they will either not //! there is no value in lifting these out into the outline module test since they will either not
//! show up for normal completions, or they won't show completions other than lifetimes depending //! show up for normal completions, or they won't show completions other than lifetimes depending
//! on the fixture input. //! on the fixture input.
use hir::ScopeDef; use hir::{known, ScopeDef};
use syntax::ast; use syntax::ast;
use crate::{ use crate::{
@ -35,12 +35,12 @@ pub(crate) fn complete_lifetime(acc: &mut Completions, ctx: &CompletionContext)
ctx.scope.process_all_names(&mut |name, res| { ctx.scope.process_all_names(&mut |name, res| {
if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
if param_lifetime != Some(&*name.to_smol_str()) { if param_lifetime != Some(&*name.to_smol_str()) {
acc.add_resolution(ctx, name, res); acc.add_lifetime(ctx, name);
} }
} }
}); });
if param_lifetime.is_none() { if param_lifetime.is_none() {
acc.add_static_lifetime(ctx); acc.add_lifetime(ctx, known::STATIC_LIFETIME);
} }
} }
@ -51,7 +51,7 @@ pub(crate) fn complete_label(acc: &mut Completions, ctx: &CompletionContext) {
} }
ctx.scope.process_all_names(&mut |name, res| { ctx.scope.process_all_names(&mut |name, res| {
if let ScopeDef::Label(_) = res { if let ScopeDef::Label(_) = res {
acc.add_resolution(ctx, name, res); acc.add_label(ctx, name);
} }
}); });
} }

View file

@ -7,6 +7,7 @@ use rustc_hash::FxHashSet;
use syntax::{ast, AstNode}; use syntax::{ast, AstNode};
use crate::{ use crate::{
completions::{module_or_attr, module_or_fn_macro},
context::{PathCompletionContext, PathKind}, context::{PathCompletionContext, PathKind},
patterns::ImmediateLocation, patterns::ImmediateLocation,
CompletionContext, Completions, CompletionContext, Completions,
@ -57,12 +58,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => { Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution { if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
for (name, def) in module.scope(ctx.db, context_module) { for (name, def) in module.scope(ctx.db, context_module) {
if let ScopeDef::MacroDef(macro_def) = def { if let Some(def) = module_or_fn_macro(def) {
if macro_def.is_fn_like() {
acc.add_macro(ctx, Some(name.clone()), macro_def);
}
}
if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def {
acc.add_resolution(ctx, name, def); acc.add_resolution(ctx, name, def);
} }
} }
@ -73,16 +69,18 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
} }
match kind { match kind {
// Complete next child module that comes after the qualified module which is still our parent
Some(PathKind::Vis { .. }) => { Some(PathKind::Vis { .. }) => {
if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution { if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
if let Some(current_module) = ctx.module { if let Some(current_module) = ctx.module {
if let Some(next) = current_module let next_towards_current = current_module
.path_to_root(ctx.db) .path_to_root(ctx.db)
.into_iter() .into_iter()
.take_while(|&it| it != module) .take_while(|&it| it != module)
.next() .next();
{ if let Some(next) = next_towards_current {
if let Some(name) = next.name(ctx.db) { if let Some(name) = next.name(ctx.db) {
cov_mark::hit!(visibility_qualified);
acc.add_resolution(ctx, name, ScopeDef::ModuleDef(next.into())); acc.add_resolution(ctx, name, ScopeDef::ModuleDef(next.into()));
} }
} }
@ -93,12 +91,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
Some(PathKind::Attr) => { Some(PathKind::Attr) => {
if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution { if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
for (name, def) in module.scope(ctx.db, context_module) { for (name, def) in module.scope(ctx.db, context_module) {
let add_resolution = match def { if let Some(def) = module_or_attr(def) {
ScopeDef::MacroDef(mac) => mac.is_attr(),
ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
_ => false,
};
if add_resolution {
acc.add_resolution(ctx, name, def); acc.add_resolution(ctx, name, def);
} }
} }
@ -263,7 +256,6 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
); );
} }
} }
hir::PathResolution::Macro(mac) => acc.add_macro(ctx, None, mac),
_ => {} _ => {}
} }
} }

View file

@ -3,7 +3,8 @@ use ide_db::SymbolKind;
use syntax::{ast::Expr, T}; use syntax::{ast::Expr, T};
use crate::{ use crate::{
patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind, Completions, patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind,
CompletionRelevance, Completions,
}; };
pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
@ -25,7 +26,10 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text); CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
let completion_text = let completion_text =
completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text); completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
item.insert_text(completion_text); item.insert_text(completion_text).set_relevance(CompletionRelevance {
exact_postfix_snippet_match: true,
..Default::default()
});
item.add_to(acc); item.add_to(acc);
} }
if ctx.previous_token_is(T![.]) { if ctx.previous_token_is(T![.]) {

View file

@ -42,7 +42,7 @@ use text_edit::TextEdit;
use crate::{CompletionContext, CompletionItem, CompletionItemKind, Completions}; use crate::{CompletionContext, CompletionItem, CompletionItemKind, Completions};
#[derive(Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum ImplCompletionKind { enum ImplCompletionKind {
All, All,
Fn, Fn,
@ -53,23 +53,22 @@ enum ImplCompletionKind {
pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
if let Some((kind, trigger, impl_def)) = completion_match(ctx.token.clone()) { if let Some((kind, trigger, impl_def)) = completion_match(ctx.token.clone()) {
if let Some(hir_impl) = ctx.sema.to_def(&impl_def) { if let Some(hir_impl) = ctx.sema.to_def(&impl_def) {
get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item { get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| {
hir::AssocItem::Function(fn_item) match (item, kind) {
if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => (
{ hir::AssocItem::Function(fn_item),
add_function_impl(&trigger, acc, ctx, fn_item, hir_impl) ImplCompletionKind::All | ImplCompletionKind::Fn,
} ) => add_function_impl(&trigger, acc, ctx, fn_item, hir_impl),
hir::AssocItem::TypeAlias(type_item) (
if kind == ImplCompletionKind::All || kind == ImplCompletionKind::TypeAlias => hir::AssocItem::TypeAlias(type_item),
{ ImplCompletionKind::All | ImplCompletionKind::TypeAlias,
add_type_alias_impl(&trigger, acc, ctx, type_item) ) => add_type_alias_impl(&trigger, acc, ctx, type_item),
} (
hir::AssocItem::Const(const_item) hir::AssocItem::Const(const_item),
if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Const => ImplCompletionKind::All | ImplCompletionKind::Const,
{ ) => add_const_impl(&trigger, acc, ctx, const_item, hir_impl),
add_const_impl(&trigger, acc, ctx, const_item, hir_impl)
}
_ => {} _ => {}
}
}); });
} }
} }
@ -194,7 +193,7 @@ fn get_transformed_assoc_item(
transform.apply(assoc_item.syntax()); transform.apply(assoc_item.syntax());
if let ast::AssocItem::Fn(func) = &assoc_item { if let ast::AssocItem::Fn(func) = &assoc_item {
func.remove_attrs_and_docs() func.remove_attrs_and_docs();
} }
Some(assoc_item) Some(assoc_item)
} }

View file

@ -4,6 +4,7 @@ use hir::ScopeDef;
use syntax::{ast, AstNode}; use syntax::{ast, AstNode};
use crate::{ use crate::{
completions::{module_or_attr, module_or_fn_macro},
context::{PathCompletionContext, PathKind}, context::{PathCompletionContext, PathKind},
patterns::ImmediateLocation, patterns::ImmediateLocation,
CompletionContext, Completions, CompletionContext, Completions,
@ -36,14 +37,9 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
match kind { match kind {
Some(PathKind::Vis { .. }) => return, Some(PathKind::Vis { .. }) => return,
Some(PathKind::Attr) => { Some(PathKind::Attr) => {
ctx.process_all_names(&mut |name, res| { ctx.process_all_names(&mut |name, def| {
let add_resolution = match res { if let Some(def) = module_or_attr(def) {
ScopeDef::MacroDef(mac) => mac.is_attr(), acc.add_resolution(ctx, name, def);
ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
_ => false,
};
if add_resolution {
acc.add_resolution(ctx, name, res);
} }
}); });
return; return;
@ -54,14 +50,9 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
match &ctx.completion_location { match &ctx.completion_location {
Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => { Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
// only show macros in {Assoc}ItemList // only show macros in {Assoc}ItemList
ctx.process_all_names(&mut |name, res| { ctx.process_all_names(&mut |name, def| {
if let hir::ScopeDef::MacroDef(mac) = res { if let Some(def) = module_or_fn_macro(def) {
if mac.is_fn_like() { acc.add_resolution(ctx, name, def);
acc.add_macro(ctx, Some(name.clone()), mac);
}
}
if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
acc.add_resolution(ctx, name, res);
} }
}); });
return; return;

View file

@ -34,7 +34,7 @@ pub(crate) enum PatternRefutability {
Refutable, Refutable,
Irrefutable, Irrefutable,
} }
pub enum Visible { pub(crate) enum Visible {
Yes, Yes,
Editable, Editable,
No, No,
@ -108,7 +108,7 @@ pub(crate) struct CompletionContext<'a> {
pub(super) token: SyntaxToken, pub(super) token: SyntaxToken,
/// The crate of the current file. /// The crate of the current file.
pub(super) krate: Option<hir::Crate>, pub(super) krate: Option<hir::Crate>,
/// The crate of the `scope`. /// The module of the `scope`.
pub(super) module: Option<hir::Module>, pub(super) module: Option<hir::Module>,
pub(super) expected_name: Option<NameOrNameRef>, pub(super) expected_name: Option<NameOrNameRef>,
pub(super) expected_type: Option<Type>, pub(super) expected_type: Option<Type>,

View file

@ -40,6 +40,7 @@ pub(in $0)
#[test] #[test]
fn qualified() { fn qualified() {
cov_mark::check!(visibility_qualified);
check( check(
r#" r#"
mod foo { mod foo {