mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 05:15:04 +00:00
Remove dependency on 'assists' from 'completion' crate
This commit is contained in:
parent
4105378dc7
commit
8d3d509af7
12 changed files with 151 additions and 129 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -268,7 +268,6 @@ dependencies = [
|
|||
name = "completion"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"assists",
|
||||
"base_db",
|
||||
"call_info",
|
||||
"expect-test",
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
78
crates/ide_db/src/traits.rs
Normal file
78
crates/ide_db/src/traits.rs
Normal 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()
|
||||
})
|
||||
}
|
58
crates/ide_db/src/ty_filter.rs
Normal file
58
crates/ide_db/src/ty_filter.rs
Normal 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",
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue