mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +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"
|
name = "completion"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assists",
|
|
||||||
"base_db",
|
"base_db",
|
||||||
"call_info",
|
"call_info",
|
||||||
"expect-test",
|
"expect-test",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use hir::HasSource;
|
use hir::HasSource;
|
||||||
|
use ide_db::traits::{get_missing_assoc_items, resolve_target_trait};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{
|
ast::{
|
||||||
self,
|
self,
|
||||||
|
@ -11,7 +12,7 @@ use syntax::{
|
||||||
use crate::{
|
use crate::{
|
||||||
assist_context::{AssistContext, Assists},
|
assist_context::{AssistContext, Assists},
|
||||||
ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
|
ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
|
||||||
utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor},
|
utils::{render_snippet, Cursor},
|
||||||
AssistId, AssistKind,
|
AssistId, AssistKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,8 @@ use syntax::{
|
||||||
AstNode,
|
AstNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{utils::unwrap_trivial_block, AssistContext, AssistId, AssistKind, Assists};
|
||||||
utils::{unwrap_trivial_block, TryEnum},
|
use ide_db::ty_filter::TryEnum;
|
||||||
AssistContext, AssistId, AssistKind, Assists,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Assist: replace_if_let_with_match
|
// Assist: replace_if_let_with_match
|
||||||
//
|
//
|
||||||
|
|
|
@ -9,7 +9,8 @@ use syntax::{
|
||||||
AstNode, T,
|
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
|
// Assist: replace_let_with_if_let
|
||||||
//
|
//
|
||||||
|
|
|
@ -10,9 +10,10 @@ use syntax::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
utils::{render_snippet, Cursor, TryEnum},
|
utils::{render_snippet, Cursor},
|
||||||
AssistContext, AssistId, AssistKind, Assists,
|
AssistContext, AssistId, AssistKind, Assists,
|
||||||
};
|
};
|
||||||
|
use ide_db::ty_filter::TryEnum;
|
||||||
|
|
||||||
// Assist: replace_unwrap_with_match
|
// Assist: replace_unwrap_with_match
|
||||||
//
|
//
|
||||||
|
|
|
@ -2,14 +2,13 @@
|
||||||
pub(crate) mod insert_use;
|
pub(crate) mod insert_use;
|
||||||
pub(crate) mod import_assets;
|
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 ide_db::RootDatabase;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_hash::FxHashSet;
|
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, make, ArgListOwner, NameOwner},
|
ast::{self, make, ArgListOwner},
|
||||||
AstNode, Direction,
|
AstNode, Direction,
|
||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
SyntaxNode, TextSize, T,
|
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 {
|
pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
|
||||||
node.children_with_tokens()
|
node.children_with_tokens()
|
||||||
.find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
|
.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
|
/// 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
|
/// 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
|
/// 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" }
|
ide_db = { path = "../ide_db", version = "0.0.0" }
|
||||||
profile = { path = "../profile", version = "0.0.0" }
|
profile = { path = "../profile", version = "0.0.0" }
|
||||||
test_utils = { path = "../test_utils", 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" }
|
call_info = { path = "../call_info", version = "0.0.0" }
|
||||||
|
|
||||||
# completions crate should depend only on the top-level `hir` package. if you need
|
# completions crate should depend only on the top-level `hir` package. if you need
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
mod format_like;
|
mod format_like;
|
||||||
|
|
||||||
use assists::utils::TryEnum;
|
use ide_db::ty_filter::TryEnum;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode, AstToken},
|
ast::{self, AstNode, AstToken},
|
||||||
TextRange, TextSize,
|
TextRange, TextSize,
|
||||||
|
|
|
@ -31,8 +31,8 @@
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use assists::utils::get_missing_assoc_items;
|
|
||||||
use hir::{self, HasAttrs, HasSource};
|
use hir::{self, HasAttrs, HasSource};
|
||||||
|
use ide_db::traits::get_missing_assoc_items;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, edit, Impl},
|
ast::{self, edit, Impl},
|
||||||
display::function_declaration,
|
display::function_declaration,
|
||||||
|
|
|
@ -10,6 +10,8 @@ pub mod defs;
|
||||||
pub mod search;
|
pub mod search;
|
||||||
pub mod imports_locator;
|
pub mod imports_locator;
|
||||||
pub mod source_change;
|
pub mod source_change;
|
||||||
|
pub mod ty_filter;
|
||||||
|
pub mod traits;
|
||||||
|
|
||||||
use std::{fmt, sync::Arc};
|
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