mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 22:24:14 +00:00
Merge #6650
6650: Make completion and assists module independent r=matklad a=SomeoneToIgnore A follow-up of https://github.com/rust-analyzer/rust-analyzer/pull/6553#discussion_r524402907 Move the common code for both assists and completion modules into a separate crate. Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
This commit is contained in:
commit
b7ece77af4
30 changed files with 305 additions and 303 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -253,7 +253,6 @@ dependencies = [
|
||||||
name = "completion"
|
name = "completion"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assists",
|
|
||||||
"base_db",
|
"base_db",
|
||||||
"either",
|
"either",
|
||||||
"expect-test",
|
"expect-test",
|
||||||
|
@ -682,6 +681,7 @@ dependencies = [
|
||||||
"expect-test",
|
"expect-test",
|
||||||
"fst",
|
"fst",
|
||||||
"hir",
|
"hir",
|
||||||
|
"itertools",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"profile",
|
"profile",
|
||||||
|
|
|
@ -12,7 +12,7 @@ doctest = false
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
itertools = "0.9.0"
|
itertools = "0.9.0"
|
||||||
either = "1.5.3"
|
either = "1.6.1"
|
||||||
|
|
||||||
stdx = { path = "../stdx", version = "0.0.0" }
|
stdx = { path = "../stdx", version = "0.0.0" }
|
||||||
syntax = { path = "../syntax", version = "0.0.0" }
|
syntax = { path = "../syntax", version = "0.0.0" }
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
//! assists if we are allowed to.
|
//! assists if we are allowed to.
|
||||||
|
|
||||||
use hir::PrefixKind;
|
use hir::PrefixKind;
|
||||||
|
use ide_db::helpers::insert_use::MergeBehaviour;
|
||||||
|
|
||||||
use crate::{utils::MergeBehaviour, AssistKind};
|
use crate::AssistKind;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct AssistConfig {
|
pub struct AssistConfig {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! `AstTransformer`s are functions that replace nodes in an AST and can be easily combined.
|
//! `AstTransformer`s are functions that replace nodes in an AST and can be easily combined.
|
||||||
use hir::{HirDisplay, PathResolution, SemanticsScope};
|
use hir::{HirDisplay, PathResolution, SemanticsScope};
|
||||||
|
use ide_db::helpers::mod_path_to_ast;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo::SyntaxRewriter,
|
algo::SyntaxRewriter,
|
||||||
|
@ -7,8 +8,6 @@ use syntax::{
|
||||||
SyntaxNode,
|
SyntaxNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::utils::mod_path_to_ast;
|
|
||||||
|
|
||||||
pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: N) -> N {
|
pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: N) -> N {
|
||||||
SyntaxRewriter::from_fn(|element| match element {
|
SyntaxRewriter::from_fn(|element| match element {
|
||||||
syntax::SyntaxElement::Node(n) => {
|
syntax::SyntaxElement::Node(n) => {
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
use ide_db::helpers::{
|
||||||
|
insert_use::{insert_use, ImportScope},
|
||||||
|
mod_path_to_ast,
|
||||||
|
};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
utils::import_assets::{ImportAssets, ImportCandidate},
|
utils::import_assets::{ImportAssets, ImportCandidate},
|
||||||
utils::{insert_use, mod_path_to_ast, ImportScope},
|
|
||||||
AssistContext, AssistId, AssistKind, Assists, GroupLabel,
|
AssistContext, AssistId, AssistKind, Assists, GroupLabel,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,10 @@ use std::iter;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{AsName, EnumVariant, Module, ModuleDef, Name};
|
use hir::{AsName, EnumVariant, Module, ModuleDef, Name};
|
||||||
|
use ide_db::helpers::{
|
||||||
|
insert_use::{insert_use, ImportScope},
|
||||||
|
mod_path_to_ast,
|
||||||
|
};
|
||||||
use ide_db::{defs::Definition, search::Reference, RootDatabase};
|
use ide_db::{defs::Definition, search::Reference, RootDatabase};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
|
@ -10,10 +14,7 @@ use syntax::{
|
||||||
SourceFile, SyntaxElement, SyntaxNode, T,
|
SourceFile, SyntaxElement, SyntaxNode, T,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{AssistContext, AssistId, AssistKind, Assists};
|
||||||
utils::{insert_use, mod_path_to_ast, ImportScope},
|
|
||||||
AssistContext, AssistId, AssistKind, Assists,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Assist: extract_struct_from_enum_variant
|
// Assist: extract_struct_from_enum_variant
|
||||||
//
|
//
|
||||||
|
@ -236,10 +237,9 @@ fn update_reference(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use ide_db::helpers::FamousDefs;
|
||||||
tests::{check_assist, check_assist_not_applicable},
|
|
||||||
utils::FamousDefs,
|
use crate::tests::{check_assist, check_assist_not_applicable};
|
||||||
};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use hir::{Adt, HasSource, ModuleDef, Semantics};
|
use hir::{Adt, HasSource, ModuleDef, Semantics};
|
||||||
|
use ide_db::helpers::{mod_path_to_ast, FamousDefs};
|
||||||
use ide_db::RootDatabase;
|
use ide_db::RootDatabase;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat};
|
use syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat};
|
||||||
use test_utils::mark;
|
use test_utils::mark;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
utils::{mod_path_to_ast, render_snippet, Cursor, FamousDefs},
|
utils::{render_snippet, Cursor},
|
||||||
AssistContext, AssistId, AssistKind, Assists,
|
AssistContext, AssistId, AssistKind, Assists,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -212,12 +213,10 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> O
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use ide_db::helpers::FamousDefs;
|
||||||
use test_utils::mark;
|
use test_utils::mark;
|
||||||
|
|
||||||
use crate::{
|
use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
|
||||||
tests::{check_assist, check_assist_not_applicable, check_assist_target},
|
|
||||||
utils::FamousDefs,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::fill_match_arms;
|
use super::fill_match_arms;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
use ide_db::helpers::FamousDefs;
|
||||||
use ide_db::RootDatabase;
|
use ide_db::RootDatabase;
|
||||||
use syntax::ast::{self, AstNode, NameOwner};
|
use syntax::ast::{self, AstNode, NameOwner};
|
||||||
use test_utils::mark;
|
use test_utils::mark;
|
||||||
|
|
||||||
use crate::{utils::FamousDefs, AssistContext, AssistId, AssistKind, Assists};
|
use crate::{AssistContext, AssistId, AssistKind, Assists};
|
||||||
|
|
||||||
// Assist: generate_from_impl_for_enum
|
// Assist: generate_from_impl_for_enum
|
||||||
//
|
//
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use ide_db::helpers::insert_use::{try_merge_imports, try_merge_trees, MergeBehaviour};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo::{neighbor, SyntaxRewriter},
|
algo::{neighbor, SyntaxRewriter},
|
||||||
ast, AstNode,
|
ast, AstNode,
|
||||||
|
@ -5,10 +6,7 @@ use syntax::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
assist_context::{AssistContext, Assists},
|
assist_context::{AssistContext, Assists},
|
||||||
utils::{
|
utils::next_prev,
|
||||||
insert_use::{try_merge_imports, try_merge_trees},
|
|
||||||
next_prev, MergeBehaviour,
|
|
||||||
},
|
|
||||||
AssistId, AssistKind,
|
AssistId, AssistKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use hir::AsName;
|
use hir::AsName;
|
||||||
|
use ide_db::helpers::mod_path_to_ast;
|
||||||
use ide_db::RootDatabase;
|
use ide_db::RootDatabase;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast,
|
ast,
|
||||||
|
@ -12,7 +13,6 @@ use test_utils::mark;
|
||||||
use crate::{
|
use crate::{
|
||||||
assist_context::{AssistContext, Assists},
|
assist_context::{AssistContext, Assists},
|
||||||
utils::import_assets::{ImportAssets, ImportCandidate},
|
utils::import_assets::{ImportAssets, ImportCandidate},
|
||||||
utils::mod_path_to_ast,
|
|
||||||
AssistId, AssistKind, GroupLabel,
|
AssistId, AssistKind, GroupLabel,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use ide_db::helpers::mod_path_to_ast;
|
||||||
use ide_db::imports_locator;
|
use ide_db::imports_locator;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
|
@ -10,8 +11,7 @@ use syntax::{
|
||||||
use crate::{
|
use crate::{
|
||||||
assist_context::{AssistBuilder, AssistContext, Assists},
|
assist_context::{AssistBuilder, AssistContext, Assists},
|
||||||
utils::{
|
utils::{
|
||||||
add_trait_assoc_items_to_impl, filter_assoc_items, mod_path_to_ast, render_snippet, Cursor,
|
add_trait_assoc_items_to_impl, filter_assoc_items, render_snippet, Cursor, DefaultMethods,
|
||||||
DefaultMethods,
|
|
||||||
},
|
},
|
||||||
AssistId, AssistKind,
|
AssistId, AssistKind,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
|
use ide_db::helpers::insert_use::{insert_use, ImportScope};
|
||||||
use syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SyntaxNode};
|
use syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SyntaxNode};
|
||||||
use test_utils::mark;
|
use test_utils::mark;
|
||||||
|
|
||||||
use crate::{
|
use crate::{AssistContext, AssistId, AssistKind, Assists};
|
||||||
utils::{insert_use, ImportScope},
|
|
||||||
AssistContext, AssistId, AssistKind, Assists,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Assist: replace_qualified_name_with_use
|
// Assist: replace_qualified_name_with_use
|
||||||
//
|
//
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
//! Assorted functions shared by several assists.
|
//! Assorted functions shared by several assists.
|
||||||
pub(crate) mod insert_use;
|
|
||||||
pub(crate) mod import_assets;
|
pub(crate) mod import_assets;
|
||||||
|
|
||||||
use std::ops;
|
use std::ops;
|
||||||
|
|
||||||
use hir::{Crate, Enum, HasSource, Module, ScopeDef, Semantics, Trait};
|
use hir::HasSource;
|
||||||
use ide_db::RootDatabase;
|
use ide_db::RootDatabase;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
|
@ -22,30 +21,6 @@ use crate::{
|
||||||
ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
|
ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use insert_use::{insert_use, ImportScope, MergeBehaviour};
|
|
||||||
|
|
||||||
pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
|
|
||||||
let _p = profile::span("mod_path_to_ast");
|
|
||||||
let mut segments = Vec::new();
|
|
||||||
let mut is_abs = false;
|
|
||||||
match path.kind {
|
|
||||||
hir::PathKind::Plain => {}
|
|
||||||
hir::PathKind::Super(0) => segments.push(make::path_segment_self()),
|
|
||||||
hir::PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())),
|
|
||||||
hir::PathKind::DollarCrate(_) | hir::PathKind::Crate => {
|
|
||||||
segments.push(make::path_segment_crate())
|
|
||||||
}
|
|
||||||
hir::PathKind::Abs => is_abs = true,
|
|
||||||
}
|
|
||||||
|
|
||||||
segments.extend(
|
|
||||||
path.segments
|
|
||||||
.iter()
|
|
||||||
.map(|segment| make::path_segment(make::name_ref(&segment.to_string()))),
|
|
||||||
);
|
|
||||||
make::path_from_segments(segments, is_abs)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr {
|
pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr {
|
||||||
extract_trivial_expression(&block)
|
extract_trivial_expression(&block)
|
||||||
.filter(|expr| !expr.syntax().text().contains_char('\n'))
|
.filter(|expr| !expr.syntax().text().contains_char('\n'))
|
||||||
|
@ -260,179 +235,6 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
|
||||||
/// the compiler itself as well.
|
|
||||||
pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>);
|
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
impl FamousDefs<'_, '_> {
|
|
||||||
pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
|
|
||||||
pub mod convert {
|
|
||||||
pub trait From<T> {
|
|
||||||
fn from(t: T) -> Self;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod default {
|
|
||||||
pub trait Default {
|
|
||||||
fn default() -> Self;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod iter {
|
|
||||||
pub use self::traits::{collect::IntoIterator, iterator::Iterator};
|
|
||||||
mod traits {
|
|
||||||
pub(crate) mod iterator {
|
|
||||||
use crate::option::Option;
|
|
||||||
pub trait Iterator {
|
|
||||||
type Item;
|
|
||||||
fn next(&mut self) -> Option<Self::Item>;
|
|
||||||
fn by_ref(&mut self) -> &mut Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
fn take(self, n: usize) -> crate::iter::Take<Self> {
|
|
||||||
crate::iter::Take { inner: self }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Iterator> Iterator for &mut I {
|
|
||||||
type Item = I::Item;
|
|
||||||
fn next(&mut self) -> Option<I::Item> {
|
|
||||||
(**self).next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub(crate) mod collect {
|
|
||||||
pub trait IntoIterator {
|
|
||||||
type Item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use self::sources::*;
|
|
||||||
pub(crate) mod sources {
|
|
||||||
use super::Iterator;
|
|
||||||
use crate::option::Option::{self, *};
|
|
||||||
pub struct Repeat<A> {
|
|
||||||
element: A,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn repeat<T>(elt: T) -> Repeat<T> {
|
|
||||||
Repeat { element: elt }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A> Iterator for Repeat<A> {
|
|
||||||
type Item = A;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<A> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use self::adapters::*;
|
|
||||||
pub(crate) mod adapters {
|
|
||||||
use super::Iterator;
|
|
||||||
use crate::option::Option::{self, *};
|
|
||||||
pub struct Take<I> { pub(crate) inner: I }
|
|
||||||
impl<I> Iterator for Take<I> where I: Iterator {
|
|
||||||
type Item = <I as Iterator>::Item;
|
|
||||||
fn next(&mut self) -> Option<<I as Iterator>::Item> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod option {
|
|
||||||
pub enum Option<T> { None, Some(T)}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod prelude {
|
|
||||||
pub use crate::{convert::From, iter::{IntoIterator, Iterator}, option::Option::{self, *}, default::Default};
|
|
||||||
}
|
|
||||||
#[prelude_import]
|
|
||||||
pub use prelude::*;
|
|
||||||
"#;
|
|
||||||
|
|
||||||
pub fn core(&self) -> Option<Crate> {
|
|
||||||
self.find_crate("core")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn core_convert_From(&self) -> Option<Trait> {
|
|
||||||
self.find_trait("core:convert:From")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn core_option_Option(&self) -> Option<Enum> {
|
|
||||||
self.find_enum("core:option:Option")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn core_default_Default(&self) -> Option<Trait> {
|
|
||||||
self.find_trait("core:default:Default")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn core_iter_Iterator(&self) -> Option<Trait> {
|
|
||||||
self.find_trait("core:iter:traits:iterator:Iterator")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn core_iter(&self) -> Option<Module> {
|
|
||||||
self.find_module("core:iter")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_trait(&self, path: &str) -> Option<Trait> {
|
|
||||||
match self.find_def(path)? {
|
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_enum(&self, path: &str) -> Option<Enum> {
|
|
||||||
match self.find_def(path)? {
|
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(it))) => Some(it),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_module(&self, path: &str) -> Option<Module> {
|
|
||||||
match self.find_def(path)? {
|
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(it)) => Some(it),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_crate(&self, name: &str) -> Option<Crate> {
|
|
||||||
let krate = self.1?;
|
|
||||||
let db = self.0.db;
|
|
||||||
let res =
|
|
||||||
krate.dependencies(db).into_iter().find(|dep| dep.name.to_string() == name)?.krate;
|
|
||||||
Some(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_def(&self, path: &str) -> Option<ScopeDef> {
|
|
||||||
let db = self.0.db;
|
|
||||||
let mut path = path.split(':');
|
|
||||||
let trait_ = path.next_back()?;
|
|
||||||
let std_crate = path.next()?;
|
|
||||||
let std_crate = self.find_crate(std_crate)?;
|
|
||||||
let mut module = std_crate.root_module(db);
|
|
||||||
for segment in path {
|
|
||||||
module = module.children(db).find_map(|child| {
|
|
||||||
let name = child.name(db)?;
|
|
||||||
if name.to_string() == segment {
|
|
||||||
Some(child)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
let def =
|
|
||||||
module.scope(db, None).into_iter().find(|(name, _def)| name.to_string() == trait_)?.1;
|
|
||||||
Some(def)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn next_prev() -> impl Iterator<Item = Direction> {
|
pub(crate) fn next_prev() -> impl Iterator<Item = Direction> {
|
||||||
[Direction::Next, Direction::Prev].iter().copied()
|
[Direction::Next, Direction::Prev].iter().copied()
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ log = "0.4.8"
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
either = "1.6.1"
|
either = "1.6.1"
|
||||||
|
|
||||||
assists = { path = "../assists", version = "0.0.0" }
|
|
||||||
stdx = { path = "../stdx", version = "0.0.0" }
|
stdx = { path = "../stdx", version = "0.0.0" }
|
||||||
syntax = { path = "../syntax", version = "0.0.0" }
|
syntax = { path = "../syntax", version = "0.0.0" }
|
||||||
text_edit = { path = "../text_edit", version = "0.0.0" }
|
text_edit = { path = "../text_edit", version = "0.0.0" }
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//! Complete fields in record literals and patterns.
|
//! Complete fields in record literals and patterns.
|
||||||
use assists::utils::FamousDefs;
|
use ide_db::helpers::FamousDefs;
|
||||||
use syntax::ast::Expr;
|
use syntax::ast::Expr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -45,8 +45,8 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use assists::utils::FamousDefs;
|
|
||||||
use expect_test::{expect, Expect};
|
use expect_test::{expect, Expect};
|
||||||
|
use ide_db::helpers::FamousDefs;
|
||||||
|
|
||||||
use crate::{test_utils::completion_list, CompletionKind};
|
use crate::{test_utils::completion_list, CompletionKind};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//! Completion of names from the current scope, e.g. locals and imported items.
|
//! Completion of names from the current scope, e.g. locals and imported items.
|
||||||
|
|
||||||
use assists::utils::ImportScope;
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{Adt, ModuleDef, ScopeDef, Type};
|
use hir::{Adt, ModuleDef, ScopeDef, Type};
|
||||||
|
use ide_db::helpers::insert_use::ImportScope;
|
||||||
use ide_db::imports_locator;
|
use ide_db::imports_locator;
|
||||||
use syntax::AstNode;
|
use syntax::AstNode;
|
||||||
use test_utils::mark;
|
use test_utils::mark;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
//! module, and we use to statically check that we only produce snippet
|
//! module, and we use to statically check that we only produce snippet
|
||||||
//! completions if we are allowed to.
|
//! completions if we are allowed to.
|
||||||
|
|
||||||
use assists::utils::MergeBehaviour;
|
use ide_db::helpers::insert_use::MergeBehaviour;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct CompletionConfig {
|
pub struct CompletionConfig {
|
||||||
|
|
|
@ -2,8 +2,11 @@
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use assists::utils::{insert_use, mod_path_to_ast, ImportScope, MergeBehaviour};
|
|
||||||
use hir::{Documentation, ModPath, Mutability};
|
use hir::{Documentation, ModPath, Mutability};
|
||||||
|
use ide_db::helpers::{
|
||||||
|
insert_use::{self, ImportScope, MergeBehaviour},
|
||||||
|
mod_path_to_ast,
|
||||||
|
};
|
||||||
use syntax::{algo, TextRange};
|
use syntax::{algo, TextRange};
|
||||||
use text_edit::TextEdit;
|
use text_edit::TextEdit;
|
||||||
|
|
||||||
|
@ -201,7 +204,7 @@ impl CompletionItem {
|
||||||
trigger_call_info: None,
|
trigger_call_info: None,
|
||||||
score: None,
|
score: None,
|
||||||
ref_match: None,
|
ref_match: None,
|
||||||
import_data: None,
|
import_to_add: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,13 +258,21 @@ impl CompletionItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An extra import to add after the completion is applied.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct ImportToAdd {
|
||||||
|
pub(crate) import_path: ModPath,
|
||||||
|
pub(crate) import_scope: ImportScope,
|
||||||
|
pub(crate) merge_behaviour: Option<MergeBehaviour>,
|
||||||
|
}
|
||||||
|
|
||||||
/// A helper to make `CompletionItem`s.
|
/// A helper to make `CompletionItem`s.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct Builder {
|
pub(crate) struct Builder {
|
||||||
source_range: TextRange,
|
source_range: TextRange,
|
||||||
completion_kind: CompletionKind,
|
completion_kind: CompletionKind,
|
||||||
import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
|
import_to_add: Option<ImportToAdd>,
|
||||||
label: String,
|
label: String,
|
||||||
insert_text: Option<String>,
|
insert_text: Option<String>,
|
||||||
insert_text_format: InsertTextFormat,
|
insert_text_format: InsertTextFormat,
|
||||||
|
@ -285,9 +296,9 @@ impl Builder {
|
||||||
let mut insert_text = self.insert_text;
|
let mut insert_text = self.insert_text;
|
||||||
let mut text_edits = TextEdit::builder();
|
let mut text_edits = TextEdit::builder();
|
||||||
|
|
||||||
if let Some((import_path, import_scope, merge_behaviour)) = self.import_data {
|
if let Some(import_data) = self.import_to_add {
|
||||||
let import = mod_path_to_ast(&import_path);
|
let import = mod_path_to_ast(&import_data.import_path);
|
||||||
let mut import_path_without_last_segment = import_path;
|
let mut import_path_without_last_segment = import_data.import_path;
|
||||||
let _ = import_path_without_last_segment.segments.pop();
|
let _ = import_path_without_last_segment.segments.pop();
|
||||||
|
|
||||||
if !import_path_without_last_segment.segments.is_empty() {
|
if !import_path_without_last_segment.segments.is_empty() {
|
||||||
|
@ -300,7 +311,11 @@ impl Builder {
|
||||||
label = format!("{}::{}", import_path_without_last_segment, label);
|
label = format!("{}::{}", import_path_without_last_segment, label);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rewriter = insert_use(&import_scope, import, merge_behaviour);
|
let rewriter = insert_use::insert_use(
|
||||||
|
&import_data.import_scope,
|
||||||
|
import,
|
||||||
|
import_data.merge_behaviour,
|
||||||
|
);
|
||||||
if let Some(old_ast) = rewriter.rewrite_root() {
|
if let Some(old_ast) = rewriter.rewrite_root() {
|
||||||
algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits);
|
algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits);
|
||||||
}
|
}
|
||||||
|
@ -392,11 +407,8 @@ impl Builder {
|
||||||
self.trigger_call_info = Some(true);
|
self.trigger_call_info = Some(true);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
pub(crate) fn import_data(
|
pub(crate) fn add_import(mut self, import_to_add: Option<ImportToAdd>) -> Builder {
|
||||||
mut self,
|
self.import_to_add = import_to_add;
|
||||||
import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
|
|
||||||
) -> Builder {
|
|
||||||
self.import_data = import_data;
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
pub(crate) fn set_ref_match(
|
pub(crate) fn set_ref_match(
|
||||||
|
|
|
@ -9,15 +9,15 @@ pub(crate) mod type_alias;
|
||||||
|
|
||||||
mod builder_ext;
|
mod builder_ext;
|
||||||
|
|
||||||
use assists::utils::{ImportScope, MergeBehaviour};
|
|
||||||
use hir::{Documentation, HasAttrs, HirDisplay, ModPath, Mutability, ScopeDef, Type};
|
use hir::{Documentation, HasAttrs, HirDisplay, ModPath, Mutability, ScopeDef, Type};
|
||||||
|
use ide_db::helpers::insert_use::{ImportScope, MergeBehaviour};
|
||||||
use ide_db::RootDatabase;
|
use ide_db::RootDatabase;
|
||||||
use syntax::TextRange;
|
use syntax::TextRange;
|
||||||
use test_utils::mark;
|
use test_utils::mark;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::SnippetCap, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind,
|
config::SnippetCap, item::ImportToAdd, CompletionContext, CompletionItem, CompletionItemKind,
|
||||||
CompletionScore,
|
CompletionKind, CompletionScore,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::render::{enum_variant::render_enum_variant, function::render_fn, macro_::render_macro};
|
use crate::render::{enum_variant::render_enum_variant, function::render_fn, macro_::render_macro};
|
||||||
|
@ -48,15 +48,15 @@ pub(crate) fn render_resolution<'a>(
|
||||||
|
|
||||||
pub(crate) fn render_resolution_with_import<'a>(
|
pub(crate) fn render_resolution_with_import<'a>(
|
||||||
ctx: RenderContext<'a>,
|
ctx: RenderContext<'a>,
|
||||||
import: ModPath,
|
import_path: ModPath,
|
||||||
import_scope: ImportScope,
|
import_scope: ImportScope,
|
||||||
merge_behaviour: Option<MergeBehaviour>,
|
merge_behaviour: Option<MergeBehaviour>,
|
||||||
resolution: &ScopeDef,
|
resolution: &ScopeDef,
|
||||||
) -> Option<CompletionItem> {
|
) -> Option<CompletionItem> {
|
||||||
let local_name = import.segments.last()?.to_string();
|
let local_name = import_path.segments.last()?.to_string();
|
||||||
Render::new(ctx).render_resolution(
|
Render::new(ctx).render_resolution(
|
||||||
local_name,
|
local_name,
|
||||||
Some((import, import_scope, merge_behaviour)),
|
Some(ImportToAdd { import_path, import_scope, merge_behaviour }),
|
||||||
resolution,
|
resolution,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ impl<'a> Render<'a> {
|
||||||
fn render_resolution(
|
fn render_resolution(
|
||||||
self,
|
self,
|
||||||
local_name: String,
|
local_name: String,
|
||||||
import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
|
import_to_add: Option<ImportToAdd>,
|
||||||
resolution: &ScopeDef,
|
resolution: &ScopeDef,
|
||||||
) -> Option<CompletionItem> {
|
) -> Option<CompletionItem> {
|
||||||
let _p = profile::span("render_resolution");
|
let _p = profile::span("render_resolution");
|
||||||
|
@ -160,15 +160,16 @@ impl<'a> Render<'a> {
|
||||||
|
|
||||||
let kind = match resolution {
|
let kind = match resolution {
|
||||||
ScopeDef::ModuleDef(Function(func)) => {
|
ScopeDef::ModuleDef(Function(func)) => {
|
||||||
let item = render_fn(self.ctx, import_data, Some(local_name), *func);
|
let item = render_fn(self.ctx, import_to_add, Some(local_name), *func);
|
||||||
return Some(item);
|
return Some(item);
|
||||||
}
|
}
|
||||||
ScopeDef::ModuleDef(EnumVariant(var)) => {
|
ScopeDef::ModuleDef(EnumVariant(var)) => {
|
||||||
let item = render_enum_variant(self.ctx, import_data, Some(local_name), *var, None);
|
let item =
|
||||||
|
render_enum_variant(self.ctx, import_to_add, Some(local_name), *var, None);
|
||||||
return Some(item);
|
return Some(item);
|
||||||
}
|
}
|
||||||
ScopeDef::MacroDef(mac) => {
|
ScopeDef::MacroDef(mac) => {
|
||||||
let item = render_macro(self.ctx, import_data, local_name, *mac);
|
let item = render_macro(self.ctx, import_to_add, local_name, *mac);
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +194,7 @@ impl<'a> Render<'a> {
|
||||||
local_name,
|
local_name,
|
||||||
)
|
)
|
||||||
.kind(CompletionItemKind::UnresolvedReference)
|
.kind(CompletionItemKind::UnresolvedReference)
|
||||||
.import_data(import_data)
|
.add_import(import_to_add)
|
||||||
.build();
|
.build();
|
||||||
return Some(item);
|
return Some(item);
|
||||||
}
|
}
|
||||||
|
@ -248,7 +249,7 @@ impl<'a> Render<'a> {
|
||||||
|
|
||||||
let item = item
|
let item = item
|
||||||
.kind(kind)
|
.kind(kind)
|
||||||
.import_data(import_data)
|
.add_import(import_to_add)
|
||||||
.set_documentation(docs)
|
.set_documentation(docs)
|
||||||
.set_ref_match(ref_match)
|
.set_ref_match(ref_match)
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
//! Renderer for `enum` variants.
|
//! Renderer for `enum` variants.
|
||||||
|
|
||||||
use assists::utils::{ImportScope, MergeBehaviour};
|
|
||||||
use hir::{HasAttrs, HirDisplay, ModPath, StructKind};
|
use hir::{HasAttrs, HirDisplay, ModPath, StructKind};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use test_utils::mark;
|
use test_utils::mark;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
item::{CompletionItem, CompletionItemKind, CompletionKind},
|
item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd},
|
||||||
render::{builder_ext::Params, RenderContext},
|
render::{builder_ext::Params, RenderContext},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn render_enum_variant<'a>(
|
pub(crate) fn render_enum_variant<'a>(
|
||||||
ctx: RenderContext<'a>,
|
ctx: RenderContext<'a>,
|
||||||
import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
|
import_to_add: Option<ImportToAdd>,
|
||||||
local_name: Option<String>,
|
local_name: Option<String>,
|
||||||
variant: hir::EnumVariant,
|
variant: hir::EnumVariant,
|
||||||
path: Option<ModPath>,
|
path: Option<ModPath>,
|
||||||
) -> CompletionItem {
|
) -> CompletionItem {
|
||||||
let _p = profile::span("render_enum_variant");
|
let _p = profile::span("render_enum_variant");
|
||||||
EnumVariantRender::new(ctx, local_name, variant, path).render(import_data)
|
EnumVariantRender::new(ctx, local_name, variant, path).render(import_to_add)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -63,10 +62,7 @@ impl<'a> EnumVariantRender<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(
|
fn render(self, import_to_add: Option<ImportToAdd>) -> CompletionItem {
|
||||||
self,
|
|
||||||
import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
|
|
||||||
) -> CompletionItem {
|
|
||||||
let mut builder = CompletionItem::new(
|
let mut builder = CompletionItem::new(
|
||||||
CompletionKind::Reference,
|
CompletionKind::Reference,
|
||||||
self.ctx.source_range(),
|
self.ctx.source_range(),
|
||||||
|
@ -75,7 +71,7 @@ impl<'a> EnumVariantRender<'a> {
|
||||||
.kind(CompletionItemKind::EnumVariant)
|
.kind(CompletionItemKind::EnumVariant)
|
||||||
.set_documentation(self.variant.docs(self.ctx.db()))
|
.set_documentation(self.variant.docs(self.ctx.db()))
|
||||||
.set_deprecated(self.ctx.is_deprecated(self.variant))
|
.set_deprecated(self.ctx.is_deprecated(self.variant))
|
||||||
.import_data(import_data)
|
.add_import(import_to_add)
|
||||||
.detail(self.detail());
|
.detail(self.detail());
|
||||||
|
|
||||||
if self.variant_kind == StructKind::Tuple {
|
if self.variant_kind == StructKind::Tuple {
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
//! Renderer for function calls.
|
//! Renderer for function calls.
|
||||||
|
|
||||||
use assists::utils::{ImportScope, MergeBehaviour};
|
use hir::{HasSource, Type};
|
||||||
use hir::{HasSource, ModPath, Type};
|
|
||||||
use syntax::{ast::Fn, display::function_declaration};
|
use syntax::{ast::Fn, display::function_declaration};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
item::{CompletionItem, CompletionItemKind, CompletionKind},
|
item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd},
|
||||||
render::{builder_ext::Params, RenderContext},
|
render::{builder_ext::Params, RenderContext},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn render_fn<'a>(
|
pub(crate) fn render_fn<'a>(
|
||||||
ctx: RenderContext<'a>,
|
ctx: RenderContext<'a>,
|
||||||
import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
|
import_to_add: Option<ImportToAdd>,
|
||||||
local_name: Option<String>,
|
local_name: Option<String>,
|
||||||
fn_: hir::Function,
|
fn_: hir::Function,
|
||||||
) -> CompletionItem {
|
) -> CompletionItem {
|
||||||
let _p = profile::span("render_fn");
|
let _p = profile::span("render_fn");
|
||||||
FunctionRender::new(ctx, local_name, fn_).render(import_data)
|
FunctionRender::new(ctx, local_name, fn_).render(import_to_add)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -39,10 +38,7 @@ impl<'a> FunctionRender<'a> {
|
||||||
FunctionRender { ctx, name, fn_, ast_node }
|
FunctionRender { ctx, name, fn_, ast_node }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(
|
fn render(self, import_to_add: Option<ImportToAdd>) -> CompletionItem {
|
||||||
self,
|
|
||||||
import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
|
|
||||||
) -> CompletionItem {
|
|
||||||
let params = self.params();
|
let params = self.params();
|
||||||
CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone())
|
CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone())
|
||||||
.kind(self.kind())
|
.kind(self.kind())
|
||||||
|
@ -50,7 +46,7 @@ impl<'a> FunctionRender<'a> {
|
||||||
.set_deprecated(self.ctx.is_deprecated(self.fn_))
|
.set_deprecated(self.ctx.is_deprecated(self.fn_))
|
||||||
.detail(self.detail())
|
.detail(self.detail())
|
||||||
.add_call_parens(self.ctx.completion, self.name, params)
|
.add_call_parens(self.ctx.completion, self.name, params)
|
||||||
.import_data(import_data)
|
.add_import(import_to_add)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,22 @@
|
||||||
//! Renderer for macro invocations.
|
//! Renderer for macro invocations.
|
||||||
|
|
||||||
use assists::utils::{ImportScope, MergeBehaviour};
|
use hir::{Documentation, HasSource};
|
||||||
use hir::{Documentation, HasSource, ModPath};
|
|
||||||
use syntax::display::macro_label;
|
use syntax::display::macro_label;
|
||||||
use test_utils::mark;
|
use test_utils::mark;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
item::{CompletionItem, CompletionItemKind, CompletionKind},
|
item::{CompletionItem, CompletionItemKind, CompletionKind, ImportToAdd},
|
||||||
render::RenderContext,
|
render::RenderContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn render_macro<'a>(
|
pub(crate) fn render_macro<'a>(
|
||||||
ctx: RenderContext<'a>,
|
ctx: RenderContext<'a>,
|
||||||
import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
|
import_to_add: Option<ImportToAdd>,
|
||||||
name: String,
|
name: String,
|
||||||
macro_: hir::MacroDef,
|
macro_: hir::MacroDef,
|
||||||
) -> Option<CompletionItem> {
|
) -> Option<CompletionItem> {
|
||||||
let _p = profile::span("render_macro");
|
let _p = profile::span("render_macro");
|
||||||
MacroRender::new(ctx, name, macro_).render(import_data)
|
MacroRender::new(ctx, name, macro_).render(import_to_add)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -39,10 +38,7 @@ impl<'a> MacroRender<'a> {
|
||||||
MacroRender { ctx, name, macro_, docs, bra, ket }
|
MacroRender { ctx, name, macro_, docs, bra, ket }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(
|
fn render(&self, import_to_add: Option<ImportToAdd>) -> Option<CompletionItem> {
|
||||||
&self,
|
|
||||||
import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
|
|
||||||
) -> Option<CompletionItem> {
|
|
||||||
// FIXME: Currently proc-macro do not have ast-node,
|
// FIXME: Currently proc-macro do not have ast-node,
|
||||||
// such that it does not have source
|
// such that it does not have source
|
||||||
if self.macro_.is_proc_macro() {
|
if self.macro_.is_proc_macro() {
|
||||||
|
@ -54,7 +50,7 @@ impl<'a> MacroRender<'a> {
|
||||||
.kind(CompletionItemKind::Macro)
|
.kind(CompletionItemKind::Macro)
|
||||||
.set_documentation(self.docs.clone())
|
.set_documentation(self.docs.clone())
|
||||||
.set_deprecated(self.ctx.is_deprecated(self.macro_))
|
.set_deprecated(self.ctx.is_deprecated(self.macro_))
|
||||||
.import_data(import_data)
|
.add_import(import_to_add)
|
||||||
.detail(self.detail());
|
.detail(self.detail());
|
||||||
|
|
||||||
let needs_bang = self.needs_bang();
|
let needs_bang = self.needs_bang();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use assists::utils::FamousDefs;
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{known, Callable, HirDisplay, Semantics};
|
use hir::{known, Callable, HirDisplay, Semantics};
|
||||||
|
use ide_db::helpers::FamousDefs;
|
||||||
use ide_db::RootDatabase;
|
use ide_db::RootDatabase;
|
||||||
use stdx::to_lower_snake_case;
|
use stdx::to_lower_snake_case;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
|
@ -427,8 +427,8 @@ fn get_callable(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<hir:
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use assists::utils::FamousDefs;
|
|
||||||
use expect_test::{expect, Expect};
|
use expect_test::{expect, Expect};
|
||||||
|
use ide_db::helpers::FamousDefs;
|
||||||
use test_utils::extract_annotations;
|
use test_utils::extract_annotations;
|
||||||
|
|
||||||
use crate::{fixture, inlay_hints::InlayHintsConfig};
|
use crate::{fixture, inlay_hints::InlayHintsConfig};
|
||||||
|
|
|
@ -87,9 +87,7 @@ pub use ide_db::{
|
||||||
search::{Reference, ReferenceAccess, ReferenceKind},
|
search::{Reference, ReferenceAccess, ReferenceKind},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use assists::{
|
pub use assists::{Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist};
|
||||||
utils::MergeBehaviour, Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist,
|
|
||||||
};
|
|
||||||
pub use hir::{Documentation, Semantics};
|
pub use hir::{Documentation, Semantics};
|
||||||
pub use ide_db::base_db::{
|
pub use ide_db::base_db::{
|
||||||
Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot,
|
Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot,
|
||||||
|
|
|
@ -18,7 +18,8 @@ rayon = "1.5.0"
|
||||||
fst = { version = "0.4", default-features = false }
|
fst = { version = "0.4", default-features = false }
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
once_cell = "1.3.1"
|
once_cell = "1.3.1"
|
||||||
either = "1.5.3"
|
either = "1.6.1"
|
||||||
|
itertools = "0.9.0"
|
||||||
|
|
||||||
stdx = { path = "../stdx", version = "0.0.0" }
|
stdx = { path = "../stdx", version = "0.0.0" }
|
||||||
syntax = { path = "../syntax", version = "0.0.0" }
|
syntax = { path = "../syntax", version = "0.0.0" }
|
||||||
|
|
203
crates/ide_db/src/helpers.rs
Normal file
203
crates/ide_db/src/helpers.rs
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
//! A module with ide helpers for high-level ide features.
|
||||||
|
use crate::RootDatabase;
|
||||||
|
use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait};
|
||||||
|
use syntax::ast::{self, make};
|
||||||
|
|
||||||
|
pub mod insert_use;
|
||||||
|
|
||||||
|
/// Converts the mod path struct into its ast representation.
|
||||||
|
pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
|
||||||
|
let _p = profile::span("mod_path_to_ast");
|
||||||
|
|
||||||
|
let mut segments = Vec::new();
|
||||||
|
let mut is_abs = false;
|
||||||
|
match path.kind {
|
||||||
|
hir::PathKind::Plain => {}
|
||||||
|
hir::PathKind::Super(0) => segments.push(make::path_segment_self()),
|
||||||
|
hir::PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())),
|
||||||
|
hir::PathKind::DollarCrate(_) | hir::PathKind::Crate => {
|
||||||
|
segments.push(make::path_segment_crate())
|
||||||
|
}
|
||||||
|
hir::PathKind::Abs => is_abs = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
segments.extend(
|
||||||
|
path.segments
|
||||||
|
.iter()
|
||||||
|
.map(|segment| make::path_segment(make::name_ref(&segment.to_string()))),
|
||||||
|
);
|
||||||
|
make::path_from_segments(segments, is_abs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
/// the compiler itself as well.
|
||||||
|
pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>);
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
impl FamousDefs<'_, '_> {
|
||||||
|
pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
|
||||||
|
pub mod convert {
|
||||||
|
pub trait From<T> {
|
||||||
|
fn from(t: T) -> Self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod default {
|
||||||
|
pub trait Default {
|
||||||
|
fn default() -> Self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod iter {
|
||||||
|
pub use self::traits::{collect::IntoIterator, iterator::Iterator};
|
||||||
|
mod traits {
|
||||||
|
pub(crate) mod iterator {
|
||||||
|
use crate::option::Option;
|
||||||
|
pub trait Iterator {
|
||||||
|
type Item;
|
||||||
|
fn next(&mut self) -> Option<Self::Item>;
|
||||||
|
fn by_ref(&mut self) -> &mut Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn take(self, n: usize) -> crate::iter::Take<Self> {
|
||||||
|
crate::iter::Take { inner: self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator> Iterator for &mut I {
|
||||||
|
type Item = I::Item;
|
||||||
|
fn next(&mut self) -> Option<I::Item> {
|
||||||
|
(**self).next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub(crate) mod collect {
|
||||||
|
pub trait IntoIterator {
|
||||||
|
type Item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use self::sources::*;
|
||||||
|
pub(crate) mod sources {
|
||||||
|
use super::Iterator;
|
||||||
|
use crate::option::Option::{self, *};
|
||||||
|
pub struct Repeat<A> {
|
||||||
|
element: A,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn repeat<T>(elt: T) -> Repeat<T> {
|
||||||
|
Repeat { element: elt }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> Iterator for Repeat<A> {
|
||||||
|
type Item = A;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<A> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use self::adapters::*;
|
||||||
|
pub(crate) mod adapters {
|
||||||
|
use super::Iterator;
|
||||||
|
use crate::option::Option::{self, *};
|
||||||
|
pub struct Take<I> { pub(crate) inner: I }
|
||||||
|
impl<I> Iterator for Take<I> where I: Iterator {
|
||||||
|
type Item = <I as Iterator>::Item;
|
||||||
|
fn next(&mut self) -> Option<<I as Iterator>::Item> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod option {
|
||||||
|
pub enum Option<T> { None, Some(T)}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod prelude {
|
||||||
|
pub use crate::{convert::From, iter::{IntoIterator, Iterator}, option::Option::{self, *}, default::Default};
|
||||||
|
}
|
||||||
|
#[prelude_import]
|
||||||
|
pub use prelude::*;
|
||||||
|
"#;
|
||||||
|
|
||||||
|
pub fn core(&self) -> Option<Crate> {
|
||||||
|
self.find_crate("core")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn core_convert_From(&self) -> Option<Trait> {
|
||||||
|
self.find_trait("core:convert:From")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn core_option_Option(&self) -> Option<Enum> {
|
||||||
|
self.find_enum("core:option:Option")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn core_default_Default(&self) -> Option<Trait> {
|
||||||
|
self.find_trait("core:default:Default")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn core_iter_Iterator(&self) -> Option<Trait> {
|
||||||
|
self.find_trait("core:iter:traits:iterator:Iterator")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn core_iter(&self) -> Option<Module> {
|
||||||
|
self.find_module("core:iter")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_trait(&self, path: &str) -> Option<Trait> {
|
||||||
|
match self.find_def(path)? {
|
||||||
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_enum(&self, path: &str) -> Option<Enum> {
|
||||||
|
match self.find_def(path)? {
|
||||||
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(it))) => Some(it),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_module(&self, path: &str) -> Option<Module> {
|
||||||
|
match self.find_def(path)? {
|
||||||
|
hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(it)) => Some(it),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_crate(&self, name: &str) -> Option<Crate> {
|
||||||
|
let krate = self.1?;
|
||||||
|
let db = self.0.db;
|
||||||
|
let res =
|
||||||
|
krate.dependencies(db).into_iter().find(|dep| dep.name.to_string() == name)?.krate;
|
||||||
|
Some(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_def(&self, path: &str) -> Option<ScopeDef> {
|
||||||
|
let db = self.0.db;
|
||||||
|
let mut path = path.split(':');
|
||||||
|
let trait_ = path.next_back()?;
|
||||||
|
let std_crate = path.next()?;
|
||||||
|
let std_crate = self.find_crate(std_crate)?;
|
||||||
|
let mut module = std_crate.root_module(db);
|
||||||
|
for segment in path {
|
||||||
|
module = module.children(db).find_map(|child| {
|
||||||
|
let name = child.name(db)?;
|
||||||
|
if name.to_string() == segment {
|
||||||
|
Some(child)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
let def =
|
||||||
|
module.scope(db, None).into_iter().find(|(name, _def)| name.to_string() == trait_)?.1;
|
||||||
|
Some(def)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
//! Handle syntactic aspects of inserting a new `use`.
|
//! Handle syntactic aspects of inserting a new `use`.
|
||||||
use std::{cmp::Ordering, iter::successors};
|
use std::{cmp::Ordering, iter::successors};
|
||||||
|
|
||||||
|
use crate::RootDatabase;
|
||||||
use hir::Semantics;
|
use hir::Semantics;
|
||||||
use ide_db::RootDatabase;
|
|
||||||
use itertools::{EitherOrBoth, Itertools};
|
use itertools::{EitherOrBoth, Itertools};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo::SyntaxRewriter,
|
algo::SyntaxRewriter,
|
||||||
|
@ -22,7 +22,7 @@ pub enum ImportScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImportScope {
|
impl ImportScope {
|
||||||
pub(crate) fn from(syntax: SyntaxNode) -> Option<Self> {
|
pub fn from(syntax: SyntaxNode) -> Option<Self> {
|
||||||
if let Some(module) = ast::Module::cast(syntax.clone()) {
|
if let Some(module) = ast::Module::cast(syntax.clone()) {
|
||||||
module.item_list().map(ImportScope::Module)
|
module.item_list().map(ImportScope::Module)
|
||||||
} else if let this @ Some(_) = ast::SourceFile::cast(syntax.clone()) {
|
} else if let this @ Some(_) = ast::SourceFile::cast(syntax.clone()) {
|
||||||
|
@ -180,7 +180,7 @@ fn eq_visibility(vis0: Option<ast::Visibility>, vis1: Option<ast::Visibility>) -
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn try_merge_imports(
|
pub fn try_merge_imports(
|
||||||
lhs: &ast::Use,
|
lhs: &ast::Use,
|
||||||
rhs: &ast::Use,
|
rhs: &ast::Use,
|
||||||
merge_behaviour: MergeBehaviour,
|
merge_behaviour: MergeBehaviour,
|
||||||
|
@ -195,7 +195,7 @@ pub(crate) fn try_merge_imports(
|
||||||
Some(lhs.with_use_tree(merged))
|
Some(lhs.with_use_tree(merged))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn try_merge_trees(
|
pub fn try_merge_trees(
|
||||||
lhs: &ast::UseTree,
|
lhs: &ast::UseTree,
|
||||||
rhs: &ast::UseTree,
|
rhs: &ast::UseTree,
|
||||||
merge: MergeBehaviour,
|
merge: MergeBehaviour,
|
|
@ -13,6 +13,7 @@ pub mod source_change;
|
||||||
pub mod ty_filter;
|
pub mod ty_filter;
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
pub mod call_info;
|
pub mod call_info;
|
||||||
|
pub mod helpers;
|
||||||
|
|
||||||
use std::{fmt, sync::Arc};
|
use std::{fmt, sync::Arc};
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ tracing-tree = { version = "0.1.4" }
|
||||||
stdx = { path = "../stdx", version = "0.0.0" }
|
stdx = { path = "../stdx", version = "0.0.0" }
|
||||||
flycheck = { path = "../flycheck", version = "0.0.0" }
|
flycheck = { path = "../flycheck", version = "0.0.0" }
|
||||||
ide = { path = "../ide", version = "0.0.0" }
|
ide = { path = "../ide", 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" }
|
||||||
project_model = { path = "../project_model", version = "0.0.0" }
|
project_model = { path = "../project_model", version = "0.0.0" }
|
||||||
syntax = { path = "../syntax", version = "0.0.0" }
|
syntax = { path = "../syntax", version = "0.0.0" }
|
||||||
|
@ -49,7 +50,6 @@ cfg = { path = "../cfg", version = "0.0.0" }
|
||||||
toolchain = { path = "../toolchain", version = "0.0.0" }
|
toolchain = { path = "../toolchain", version = "0.0.0" }
|
||||||
|
|
||||||
# This should only be used in CLI
|
# This should only be used in CLI
|
||||||
ide_db = { path = "../ide_db", version = "0.0.0" }
|
|
||||||
ssr = { path = "../ssr", version = "0.0.0" }
|
ssr = { path = "../ssr", version = "0.0.0" }
|
||||||
hir = { path = "../hir", version = "0.0.0" }
|
hir = { path = "../hir", version = "0.0.0" }
|
||||||
hir_def = { path = "../hir_def", version = "0.0.0" }
|
hir_def = { path = "../hir_def", version = "0.0.0" }
|
||||||
|
|
|
@ -11,10 +11,8 @@ use std::{convert::TryFrom, ffi::OsString, path::PathBuf};
|
||||||
|
|
||||||
use flycheck::FlycheckConfig;
|
use flycheck::FlycheckConfig;
|
||||||
use hir::PrefixKind;
|
use hir::PrefixKind;
|
||||||
use ide::{
|
use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig};
|
||||||
AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig,
|
use ide_db::helpers::insert_use::MergeBehaviour;
|
||||||
MergeBehaviour,
|
|
||||||
};
|
|
||||||
use lsp_types::{ClientCapabilities, MarkupKind};
|
use lsp_types::{ClientCapabilities, MarkupKind};
|
||||||
use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest};
|
use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest};
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
|
Loading…
Reference in a new issue