Remove dependency on 'assists' from 'completion' crate

This commit is contained in:
Igor Aleksanov 2020-10-24 10:47:23 +03:00
parent 4105378dc7
commit 8d3d509af7
12 changed files with 151 additions and 129 deletions

1
Cargo.lock generated
View file

@ -268,7 +268,6 @@ dependencies = [
name = "completion"
version = "0.0.0"
dependencies = [
"assists",
"base_db",
"call_info",
"expect-test",

View file

@ -1,4 +1,5 @@
use hir::HasSource;
use ide_db::traits::{get_missing_assoc_items, resolve_target_trait};
use syntax::{
ast::{
self,
@ -11,7 +12,7 @@ use syntax::{
use crate::{
assist_context::{AssistContext, Assists},
ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor},
utils::{render_snippet, Cursor},
AssistId, AssistKind,
};

View file

@ -7,10 +7,8 @@ use syntax::{
AstNode,
};
use crate::{
utils::{unwrap_trivial_block, TryEnum},
AssistContext, AssistId, AssistKind, Assists,
};
use crate::{utils::unwrap_trivial_block, AssistContext, AssistId, AssistKind, Assists};
use ide_db::ty_filter::TryEnum;
// Assist: replace_if_let_with_match
//

View file

@ -9,7 +9,8 @@ use syntax::{
AstNode, T,
};
use crate::{utils::TryEnum, AssistContext, AssistId, AssistKind, Assists};
use crate::{AssistContext, AssistId, AssistKind, Assists};
use ide_db::ty_filter::TryEnum;
// Assist: replace_let_with_if_let
//

View file

@ -10,9 +10,10 @@ use syntax::{
};
use crate::{
utils::{render_snippet, Cursor, TryEnum},
utils::{render_snippet, Cursor},
AssistContext, AssistId, AssistKind, Assists,
};
use ide_db::ty_filter::TryEnum;
// Assist: replace_unwrap_with_match
//

View file

@ -2,14 +2,13 @@
pub(crate) mod insert_use;
pub(crate) mod import_assets;
use std::{iter, ops};
use std::ops;
use hir::{Adt, Crate, Enum, Module, ScopeDef, Semantics, Trait, Type};
use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait};
use ide_db::RootDatabase;
use itertools::Itertools;
use rustc_hash::FxHashSet;
use syntax::{
ast::{self, make, ArgListOwner, NameOwner},
ast::{self, make, ArgListOwner},
AstNode, Direction,
SyntaxKind::*,
SyntaxNode, TextSize, T,
@ -115,72 +114,6 @@ pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor
}
}
pub fn get_missing_assoc_items(
sema: &Semantics<RootDatabase>,
impl_def: &ast::Impl,
) -> Vec<hir::AssocItem> {
// Names must be unique between constants and functions. However, type aliases
// may share the same name as a function or constant.
let mut impl_fns_consts = FxHashSet::default();
let mut impl_type = FxHashSet::default();
if let Some(item_list) = impl_def.assoc_item_list() {
for item in item_list.assoc_items() {
match item {
ast::AssocItem::Fn(f) => {
if let Some(n) = f.name() {
impl_fns_consts.insert(n.syntax().to_string());
}
}
ast::AssocItem::TypeAlias(t) => {
if let Some(n) = t.name() {
impl_type.insert(n.syntax().to_string());
}
}
ast::AssocItem::Const(c) => {
if let Some(n) = c.name() {
impl_fns_consts.insert(n.syntax().to_string());
}
}
ast::AssocItem::MacroCall(_) => (),
}
}
}
resolve_target_trait(sema, impl_def).map_or(vec![], |target_trait| {
target_trait
.items(sema.db)
.iter()
.filter(|i| match i {
hir::AssocItem::Function(f) => {
!impl_fns_consts.contains(&f.name(sema.db).to_string())
}
hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db).to_string()),
hir::AssocItem::Const(c) => c
.name(sema.db)
.map(|n| !impl_fns_consts.contains(&n.to_string()))
.unwrap_or_default(),
})
.cloned()
.collect()
})
}
pub(crate) fn resolve_target_trait(
sema: &Semantics<RootDatabase>,
impl_def: &ast::Impl,
) -> Option<hir::Trait> {
let ast_path =
impl_def.trait_().map(|it| it.syntax().clone()).and_then(ast::PathType::cast)?.path()?;
match sema.resolve_path(&ast_path) {
Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def),
_ => None,
}
}
pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
node.children_with_tokens()
.find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
@ -223,54 +156,6 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
}
}
#[derive(Clone, Copy)]
pub enum TryEnum {
Result,
Option,
}
impl TryEnum {
const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> {
let enum_ = match ty.as_adt() {
Some(Adt::Enum(it)) => it,
_ => return None,
};
TryEnum::ALL.iter().find_map(|&var| {
if &enum_.name(sema.db).to_string() == var.type_name() {
return Some(var);
}
None
})
}
pub(crate) fn happy_case(self) -> &'static str {
match self {
TryEnum::Result => "Ok",
TryEnum::Option => "Some",
}
}
pub(crate) fn sad_pattern(self) -> ast::Pat {
match self {
TryEnum::Result => make::tuple_struct_pat(
make::path_unqualified(make::path_segment(make::name_ref("Err"))),
iter::once(make::wildcard_pat().into()),
)
.into(),
TryEnum::Option => make::ident_pat(make::name("None")).into(),
}
}
fn type_name(self) -> &'static str {
match self {
TryEnum::Result => "Result",
TryEnum::Option => "Option",
}
}
}
/// Helps with finding well-know things inside the standard library. This is
/// somewhat similar to the known paths infra inside hir, but it different; We
/// want to make sure that IDE specific paths don't become interesting inside

View file

@ -21,7 +21,6 @@ base_db = { path = "../base_db", version = "0.0.0" }
ide_db = { path = "../ide_db", version = "0.0.0" }
profile = { path = "../profile", version = "0.0.0" }
test_utils = { path = "../test_utils", version = "0.0.0" }
assists = { path = "../assists", version = "0.0.0" }
call_info = { path = "../call_info", version = "0.0.0" }
# completions crate should depend only on the top-level `hir` package. if you need

View file

@ -2,7 +2,7 @@
mod format_like;
use assists::utils::TryEnum;
use ide_db::ty_filter::TryEnum;
use syntax::{
ast::{self, AstNode, AstToken},
TextRange, TextSize,

View file

@ -31,8 +31,8 @@
//! }
//! ```
use assists::utils::get_missing_assoc_items;
use hir::{self, HasAttrs, HasSource};
use ide_db::traits::get_missing_assoc_items;
use syntax::{
ast::{self, edit, Impl},
display::function_declaration,

View file

@ -10,6 +10,8 @@ pub mod defs;
pub mod search;
pub mod imports_locator;
pub mod source_change;
pub mod ty_filter;
pub mod traits;
use std::{fmt, sync::Arc};

View file

@ -0,0 +1,78 @@
//! Functionality for obtaining data related to traits from the DB.
use crate::RootDatabase;
use hir::Semantics;
use rustc_hash::FxHashSet;
use syntax::{
ast::{self, NameOwner},
AstNode,
};
/// Given the `impl` block, attempts to find the trait this `impl` corresponds to.
pub fn resolve_target_trait(
sema: &Semantics<RootDatabase>,
impl_def: &ast::Impl,
) -> Option<hir::Trait> {
let ast_path =
impl_def.trait_().map(|it| it.syntax().clone()).and_then(ast::PathType::cast)?.path()?;
match sema.resolve_path(&ast_path) {
Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def),
_ => None,
}
}
/// Given the `impl` block, returns the list of associated items (e.g. functions or types) that are
/// missing in this `impl` block.
pub fn get_missing_assoc_items(
sema: &Semantics<RootDatabase>,
impl_def: &ast::Impl,
) -> Vec<hir::AssocItem> {
// Names must be unique between constants and functions. However, type aliases
// may share the same name as a function or constant.
let mut impl_fns_consts = FxHashSet::default();
let mut impl_type = FxHashSet::default();
if let Some(item_list) = impl_def.assoc_item_list() {
for item in item_list.assoc_items() {
match item {
ast::AssocItem::Fn(f) => {
if let Some(n) = f.name() {
impl_fns_consts.insert(n.syntax().to_string());
}
}
ast::AssocItem::TypeAlias(t) => {
if let Some(n) = t.name() {
impl_type.insert(n.syntax().to_string());
}
}
ast::AssocItem::Const(c) => {
if let Some(n) = c.name() {
impl_fns_consts.insert(n.syntax().to_string());
}
}
ast::AssocItem::MacroCall(_) => (),
}
}
}
resolve_target_trait(sema, impl_def).map_or(vec![], |target_trait| {
target_trait
.items(sema.db)
.iter()
.filter(|i| match i {
hir::AssocItem::Function(f) => {
!impl_fns_consts.contains(&f.name(sema.db).to_string())
}
hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db).to_string()),
hir::AssocItem::Const(c) => c
.name(sema.db)
.map(|n| !impl_fns_consts.contains(&n.to_string()))
.unwrap_or_default(),
})
.cloned()
.collect()
})
}

View file

@ -0,0 +1,58 @@
//! This module contains structures for filtering the expected types.
//! Use case for structures in this module is, for example, situation when you need to process
//! only certain `Enum`s.
use crate::RootDatabase;
use hir::{Adt, Semantics, Type};
use std::iter;
use syntax::ast::{self, make};
/// Enum types that implement `std::ops::Try` trait.
#[derive(Clone, Copy)]
pub enum TryEnum {
Result,
Option,
}
impl TryEnum {
const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
/// Returns `Some(..)` if the provided type is an enum that implements `std::ops::Try`.
pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> {
let enum_ = match ty.as_adt() {
Some(Adt::Enum(it)) => it,
_ => return None,
};
TryEnum::ALL.iter().find_map(|&var| {
if &enum_.name(sema.db).to_string() == var.type_name() {
return Some(var);
}
None
})
}
pub fn happy_case(self) -> &'static str {
match self {
TryEnum::Result => "Ok",
TryEnum::Option => "Some",
}
}
pub fn sad_pattern(self) -> ast::Pat {
match self {
TryEnum::Result => make::tuple_struct_pat(
make::path_unqualified(make::path_segment(make::name_ref("Err"))),
iter::once(make::wildcard_pat().into()),
)
.into(),
TryEnum::Option => make::ident_pat(make::name("None")).into(),
}
}
fn type_name(self) -> &'static str {
match self {
TryEnum::Result => "Result",
TryEnum::Option => "Option",
}
}
}