mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 07:04:22 +00:00
Extract call_info and completion into separate crates
This commit is contained in:
parent
2067a410f3
commit
9e7c952bbd
34 changed files with 336 additions and 226 deletions
36
Cargo.lock
generated
36
Cargo.lock
generated
|
@ -127,6 +127,20 @@ version = "1.3.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
|
||||
[[package]]
|
||||
name = "call_info"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"base_db",
|
||||
"either",
|
||||
"expect-test",
|
||||
"hir",
|
||||
"ide_db",
|
||||
"stdx",
|
||||
"syntax",
|
||||
"test_utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.11.4"
|
||||
|
@ -249,6 +263,26 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "completion"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"assists",
|
||||
"base_db",
|
||||
"call_info",
|
||||
"expect-test",
|
||||
"hir",
|
||||
"ide_db",
|
||||
"itertools",
|
||||
"log",
|
||||
"profile",
|
||||
"rustc-hash",
|
||||
"stdx",
|
||||
"syntax",
|
||||
"test_utils",
|
||||
"text_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const_fn"
|
||||
version = "0.4.2"
|
||||
|
@ -609,7 +643,9 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"assists",
|
||||
"base_db",
|
||||
"call_info",
|
||||
"cfg",
|
||||
"completion",
|
||||
"either",
|
||||
"expect-test",
|
||||
"hir",
|
||||
|
|
26
crates/call_info/Cargo.toml
Normal file
26
crates/call_info/Cargo.toml
Normal file
|
@ -0,0 +1,26 @@
|
|||
[package]
|
||||
name = "call_info"
|
||||
version = "0.0.0"
|
||||
description = "TBD"
|
||||
license = "MIT OR Apache-2.0"
|
||||
authors = ["rust-analyzer developers"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
either = "1.5.3"
|
||||
|
||||
stdx = { path = "../stdx", version = "0.0.0" }
|
||||
syntax = { path = "../syntax", version = "0.0.0" }
|
||||
base_db = { path = "../base_db", version = "0.0.0" }
|
||||
ide_db = { path = "../ide_db", version = "0.0.0" }
|
||||
test_utils = { path = "../test_utils", version = "0.0.0" }
|
||||
|
||||
# call_info crate should depend only on the top-level `hir` package. if you need
|
||||
# something from some `hir_xxx` subpackage, reexport the API via `hir`.
|
||||
hir = { path = "../hir", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
expect-test = "1.0"
|
|
@ -1,4 +1,5 @@
|
|||
//! FIXME: write short doc here
|
||||
//! This crate provides primitives for tracking the information about a call site.
|
||||
use base_db::FilePosition;
|
||||
use either::Either;
|
||||
use hir::{HasAttrs, HirDisplay, Semantics, Type};
|
||||
use ide_db::RootDatabase;
|
||||
|
@ -9,8 +10,6 @@ use syntax::{
|
|||
};
|
||||
use test_utils::mark;
|
||||
|
||||
use crate::FilePosition;
|
||||
|
||||
/// Contains information about a call site. Specifically the
|
||||
/// `FunctionSignature`and current parameter.
|
||||
#[derive(Debug)]
|
||||
|
@ -40,7 +39,7 @@ impl CallInfo {
|
|||
}
|
||||
|
||||
/// Computes parameter information for the given call expression.
|
||||
pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
|
||||
pub fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
|
||||
let sema = Semantics::new(db);
|
||||
let file = sema.parse(position.file_id);
|
||||
let file = file.syntax();
|
||||
|
@ -141,13 +140,13 @@ fn call_info_impl(
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ActiveParameter {
|
||||
pub(crate) ty: Type,
|
||||
pub(crate) name: String,
|
||||
pub struct ActiveParameter {
|
||||
pub ty: Type,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl ActiveParameter {
|
||||
pub(crate) fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> {
|
||||
pub fn at(db: &RootDatabase, position: FilePosition) -> Option<Self> {
|
||||
let sema = Semantics::new(db);
|
||||
let file = sema.parse(position.file_id);
|
||||
let file = file.syntax();
|
||||
|
@ -156,7 +155,7 @@ impl ActiveParameter {
|
|||
Self::at_token(&sema, token)
|
||||
}
|
||||
|
||||
pub(crate) fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> {
|
||||
pub fn at_token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Option<Self> {
|
||||
let (signature, active_parameter) = call_info_impl(&sema, token)?;
|
||||
|
||||
let idx = active_parameter?;
|
||||
|
@ -172,7 +171,7 @@ impl ActiveParameter {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum FnCallNode {
|
||||
pub enum FnCallNode {
|
||||
CallExpr(ast::CallExpr),
|
||||
MethodCallExpr(ast::MethodCallExpr),
|
||||
}
|
||||
|
@ -196,7 +195,7 @@ impl FnCallNode {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn with_node_exact(node: &SyntaxNode) -> Option<FnCallNode> {
|
||||
pub fn with_node_exact(node: &SyntaxNode) -> Option<FnCallNode> {
|
||||
match_ast! {
|
||||
match node {
|
||||
ast::CallExpr(it) => Some(FnCallNode::CallExpr(it)),
|
||||
|
@ -206,7 +205,7 @@ impl FnCallNode {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn name_ref(&self) -> Option<ast::NameRef> {
|
||||
pub fn name_ref(&self) -> Option<ast::NameRef> {
|
||||
match self {
|
||||
FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()? {
|
||||
ast::Expr::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?,
|
||||
|
@ -229,14 +228,28 @@ impl FnCallNode {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use base_db::{fixture::ChangeFixture, FilePosition};
|
||||
use expect_test::{expect, Expect};
|
||||
use test_utils::mark;
|
||||
use ide_db::RootDatabase;
|
||||
use test_utils::{mark, RangeOrOffset};
|
||||
|
||||
use crate::fixture;
|
||||
/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
|
||||
pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
|
||||
let change_fixture = ChangeFixture::parse(ra_fixture);
|
||||
let mut database = RootDatabase::default();
|
||||
database.apply_change(change_fixture.change);
|
||||
let (file_id, range_or_offset) =
|
||||
change_fixture.file_position.expect("expected a marker (<|>)");
|
||||
let offset = match range_or_offset {
|
||||
RangeOrOffset::Range(_) => panic!(),
|
||||
RangeOrOffset::Offset(it) => it,
|
||||
};
|
||||
(database, FilePosition { file_id, offset })
|
||||
}
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
||||
let (analysis, position) = fixture::position(ra_fixture);
|
||||
let call_info = analysis.call_info(position).unwrap();
|
||||
let (db, position) = position(ra_fixture);
|
||||
let call_info = crate::call_info(&db, position);
|
||||
let actual = match call_info {
|
||||
Some(call_info) => {
|
||||
let docs = match &call_info.doc {
|
32
crates/completion/Cargo.toml
Normal file
32
crates/completion/Cargo.toml
Normal file
|
@ -0,0 +1,32 @@
|
|||
[package]
|
||||
name = "completion"
|
||||
version = "0.0.0"
|
||||
description = "TBD"
|
||||
license = "MIT OR Apache-2.0"
|
||||
authors = ["rust-analyzer developers"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
itertools = "0.9.0"
|
||||
log = "0.4.8"
|
||||
rustc-hash = "1.1.0"
|
||||
|
||||
syntax = { path = "../syntax", version = "0.0.0" }
|
||||
text_edit = { path = "../text_edit", version = "0.0.0" }
|
||||
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
|
||||
# something from some `hir_xxx` subpackage, reexport the API via `hir`.
|
||||
hir = { path = "../hir", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
expect-test = "1.0"
|
||||
stdx = { path = "../stdx", version = "0.0.0" }
|
|
@ -6,7 +6,7 @@
|
|||
use rustc_hash::FxHashSet;
|
||||
use syntax::{ast, AstNode, SyntaxKind};
|
||||
|
||||
use crate::completion::{
|
||||
use crate::{
|
||||
completion_context::CompletionContext,
|
||||
completion_item::{CompletionItem, CompletionItemKind, CompletionKind, Completions},
|
||||
generated_features::FEATURES,
|
||||
|
@ -389,7 +389,7 @@ const DEFAULT_LINT_COMPLETIONS: &[LintCompletion] = &[
|
|||
mod tests {
|
||||
use expect_test::{expect, Expect};
|
||||
|
||||
use crate::completion::{test_utils::completion_list, CompletionKind};
|
||||
use crate::{test_utils::completion_list, CompletionKind};
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
||||
let actual = completion_list(ra_fixture, CompletionKind::Attribute);
|
|
@ -4,7 +4,7 @@ use hir::{HasVisibility, Type};
|
|||
use rustc_hash::FxHashSet;
|
||||
use test_utils::mark;
|
||||
|
||||
use crate::completion::{completion_context::CompletionContext, completion_item::Completions};
|
||||
use crate::{completion_context::CompletionContext, completion_item::Completions};
|
||||
|
||||
/// Complete dot accesses, i.e. fields or methods.
|
||||
pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
|
@ -64,7 +64,7 @@ mod tests {
|
|||
use expect_test::{expect, Expect};
|
||||
use test_utils::mark;
|
||||
|
||||
use crate::completion::{test_utils::completion_list, CompletionKind};
|
||||
use crate::{test_utils::completion_list, CompletionKind};
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
||||
let actual = completion_list(ra_fixture, CompletionKind::Reference);
|
|
@ -6,7 +6,7 @@ use syntax::{
|
|||
match_ast, AstNode,
|
||||
};
|
||||
|
||||
use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions};
|
||||
use crate::{CompletionContext, CompletionItem, CompletionKind, Completions};
|
||||
|
||||
/// Complete repeated parameters, both name and type. For example, if all
|
||||
/// functions in a file have a `spam: &mut Spam` parameter, a completion with
|
||||
|
@ -68,7 +68,7 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
|
|||
mod tests {
|
||||
use expect_test::{expect, Expect};
|
||||
|
||||
use crate::completion::{test_utils::completion_list, CompletionKind};
|
||||
use crate::{test_utils::completion_list, CompletionKind};
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
||||
let actual = completion_list(ra_fixture, CompletionKind::Magic);
|
|
@ -1,11 +1,9 @@
|
|||
//! FIXME: write short doc here
|
||||
//! Completes keywords.
|
||||
|
||||
use syntax::{ast, SyntaxKind};
|
||||
use test_utils::mark;
|
||||
|
||||
use crate::completion::{
|
||||
CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
|
||||
};
|
||||
use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
|
||||
|
||||
pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
// complete keyword "crate" in use stmt
|
||||
|
@ -177,7 +175,7 @@ fn complete_return(
|
|||
mod tests {
|
||||
use expect_test::{expect, Expect};
|
||||
|
||||
use crate::completion::{
|
||||
use crate::{
|
||||
test_utils::{check_edit, completion_list},
|
||||
CompletionKind,
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
//! FIXME: write short doc here
|
||||
//! Completes macro invocations used in item position.
|
||||
|
||||
use crate::completion::{CompletionContext, Completions};
|
||||
use crate::{CompletionContext, Completions};
|
||||
|
||||
pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
// Show only macros in top level.
|
||||
|
@ -17,7 +17,7 @@ pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &Compl
|
|||
mod tests {
|
||||
use expect_test::{expect, Expect};
|
||||
|
||||
use crate::completion::{test_utils::completion_list, CompletionKind};
|
||||
use crate::{test_utils::completion_list, CompletionKind};
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
||||
let actual = completion_list(ra_fixture, CompletionKind::Reference);
|
|
@ -150,7 +150,7 @@ fn module_chain_to_containing_module_file(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::completion::{test_utils::completion_list, CompletionKind};
|
||||
use crate::{test_utils::completion_list, CompletionKind};
|
||||
use expect_test::{expect, Expect};
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
|
@ -1,6 +1,6 @@
|
|||
//! FIXME: write short doc here
|
||||
//! Completes constats and paths in patterns.
|
||||
|
||||
use crate::completion::{CompletionContext, Completions};
|
||||
use crate::{CompletionContext, Completions};
|
||||
|
||||
/// Completes constats and paths in patterns.
|
||||
pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
|
@ -35,7 +35,7 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
|
|||
mod tests {
|
||||
use expect_test::{expect, Expect};
|
||||
|
||||
use crate::completion::{test_utils::completion_list, CompletionKind};
|
||||
use crate::{test_utils::completion_list, CompletionKind};
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
||||
let actual = completion_list(ra_fixture, CompletionKind::Reference);
|
|
@ -1,4 +1,4 @@
|
|||
//! FIXME: write short doc here
|
||||
//! Postfix completions, like `Ok(10).ifl<|>` => `if let Ok() = Ok(10) { <|> }`.
|
||||
|
||||
mod format_like;
|
||||
|
||||
|
@ -11,11 +11,9 @@ use text_edit::TextEdit;
|
|||
|
||||
use self::format_like::add_format_like_completions;
|
||||
use crate::{
|
||||
completion::{
|
||||
completion_config::SnippetCap,
|
||||
completion_context::CompletionContext,
|
||||
completion_item::{Builder, CompletionKind, Completions},
|
||||
},
|
||||
completion_config::SnippetCap,
|
||||
completion_context::CompletionContext,
|
||||
completion_item::{Builder, CompletionKind, Completions},
|
||||
CompletionItem, CompletionItemKind,
|
||||
};
|
||||
|
||||
|
@ -263,7 +261,7 @@ fn postfix_snippet(
|
|||
mod tests {
|
||||
use expect_test::{expect, Expect};
|
||||
|
||||
use crate::completion::{
|
||||
use crate::{
|
||||
test_utils::{check_edit, completion_list},
|
||||
CompletionKind,
|
||||
};
|
|
@ -14,7 +14,7 @@
|
|||
// + `logw` -> `log::warn!(...)`
|
||||
// + `loge` -> `log::error!(...)`
|
||||
|
||||
use crate::completion::{
|
||||
use crate::{
|
||||
complete_postfix::postfix_snippet, completion_config::SnippetCap,
|
||||
completion_context::CompletionContext, completion_item::Completions,
|
||||
};
|
|
@ -5,7 +5,7 @@ use rustc_hash::FxHashSet;
|
|||
use syntax::AstNode;
|
||||
use test_utils::mark;
|
||||
|
||||
use crate::completion::{CompletionContext, Completions};
|
||||
use crate::{CompletionContext, Completions};
|
||||
|
||||
pub(super) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
let path = match &ctx.path_qual {
|
||||
|
@ -149,7 +149,7 @@ mod tests {
|
|||
use expect_test::{expect, Expect};
|
||||
use test_utils::mark;
|
||||
|
||||
use crate::completion::{
|
||||
use crate::{
|
||||
test_utils::{check_edit, completion_list},
|
||||
CompletionKind,
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
//! Complete fields in record literals and patterns.
|
||||
use crate::completion::{CompletionContext, Completions};
|
||||
use crate::{CompletionContext, Completions};
|
||||
|
||||
pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
|
||||
let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) {
|
||||
|
@ -20,7 +20,7 @@ pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
|
|||
mod tests {
|
||||
use expect_test::{expect, Expect};
|
||||
|
||||
use crate::completion::{test_utils::completion_list, CompletionKind};
|
||||
use crate::{test_utils::completion_list, CompletionKind};
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
||||
let actual = completion_list(ra_fixture, CompletionKind::Reference);
|
|
@ -1,6 +1,6 @@
|
|||
//! FIXME: write short doc here
|
||||
//! This file provides snippet completions, like `pd` => `eprintln!(...)`.
|
||||
|
||||
use crate::completion::{
|
||||
use crate::{
|
||||
completion_config::SnippetCap, completion_item::Builder, CompletionContext, CompletionItem,
|
||||
CompletionItemKind, CompletionKind, Completions,
|
||||
};
|
||||
|
@ -71,7 +71,7 @@ fn ${1:feature}() {
|
|||
mod tests {
|
||||
use expect_test::{expect, Expect};
|
||||
|
||||
use crate::completion::{test_utils::completion_list, CompletionKind};
|
||||
use crate::{test_utils::completion_list, CompletionKind};
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
||||
let actual = completion_list(ra_fixture, CompletionKind::Snippet);
|
|
@ -35,15 +35,18 @@ use assists::utils::get_missing_assoc_items;
|
|||
use hir::{self, HasAttrs, HasSource};
|
||||
use syntax::{
|
||||
ast::{self, edit, Impl},
|
||||
display::function_declaration,
|
||||
AstNode, SyntaxKind, SyntaxNode, TextRange, T,
|
||||
};
|
||||
use text_edit::TextEdit;
|
||||
|
||||
use crate::{
|
||||
completion::{
|
||||
CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
|
||||
},
|
||||
display::function_declaration,
|
||||
CompletionContext,
|
||||
CompletionItem,
|
||||
CompletionItemKind,
|
||||
CompletionKind,
|
||||
Completions,
|
||||
// display::function_declaration,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
|
@ -237,7 +240,7 @@ fn make_const_compl_syntax(const_: &ast::Const) -> String {
|
|||
mod tests {
|
||||
use expect_test::{expect, Expect};
|
||||
|
||||
use crate::completion::{
|
||||
use crate::{
|
||||
test_utils::{check_edit, completion_list},
|
||||
CompletionKind,
|
||||
};
|
|
@ -4,7 +4,7 @@ use hir::{Adt, ModuleDef, ScopeDef, Type};
|
|||
use syntax::AstNode;
|
||||
use test_utils::mark;
|
||||
|
||||
use crate::completion::{CompletionContext, Completions};
|
||||
use crate::{CompletionContext, Completions};
|
||||
|
||||
pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
|
||||
|
@ -68,7 +68,7 @@ mod tests {
|
|||
use expect_test::{expect, Expect};
|
||||
use test_utils::mark;
|
||||
|
||||
use crate::completion::{
|
||||
use crate::{
|
||||
test_utils::{check_edit, completion_list},
|
||||
CompletionKind,
|
||||
};
|
|
@ -1,6 +1,7 @@
|
|||
//! FIXME: write short doc here
|
||||
//! See `CompletionContext` structure.
|
||||
|
||||
use base_db::SourceDatabase;
|
||||
use base_db::{FilePosition, SourceDatabase};
|
||||
use call_info::ActiveParameter;
|
||||
use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type};
|
||||
use ide_db::RootDatabase;
|
||||
use syntax::{
|
||||
|
@ -13,18 +14,14 @@ use test_utils::mark;
|
|||
use text_edit::Indel;
|
||||
|
||||
use crate::{
|
||||
call_info::ActiveParameter,
|
||||
completion::{
|
||||
patterns::{
|
||||
fn_is_prev, for_is_prev2, has_bind_pat_parent, has_block_expr_parent,
|
||||
has_field_list_parent, has_impl_as_prev_sibling, has_impl_parent,
|
||||
has_item_list_or_source_file_parent, has_ref_parent, has_trait_as_prev_sibling,
|
||||
has_trait_parent, if_is_prev, inside_impl_trait_block, is_in_loop_body, is_match_arm,
|
||||
unsafe_is_prev,
|
||||
},
|
||||
CompletionConfig,
|
||||
patterns::{
|
||||
fn_is_prev, for_is_prev2, has_bind_pat_parent, has_block_expr_parent,
|
||||
has_field_list_parent, has_impl_as_prev_sibling, has_impl_parent,
|
||||
has_item_list_or_source_file_parent, has_ref_parent, has_trait_as_prev_sibling,
|
||||
has_trait_parent, if_is_prev, inside_impl_trait_block, is_in_loop_body, is_match_arm,
|
||||
unsafe_is_prev,
|
||||
},
|
||||
FilePosition,
|
||||
CompletionConfig,
|
||||
};
|
||||
|
||||
/// `CompletionContext` is created early during completion to figure out, where
|
|
@ -1,4 +1,4 @@
|
|||
//! FIXME: write short doc here
|
||||
//! See `CompletionItem` structure.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
|
@ -6,7 +6,7 @@ use hir::Documentation;
|
|||
use syntax::TextRange;
|
||||
use text_edit::TextEdit;
|
||||
|
||||
use crate::completion::completion_config::SnippetCap;
|
||||
use crate::completion_config::SnippetCap;
|
||||
|
||||
/// `CompletionItem` describes a single completion variant in the editor pop-up.
|
||||
/// It is basically a POD with various properties. To construct a
|
||||
|
@ -360,15 +360,15 @@ impl<'a> Into<CompletionItem> for Builder {
|
|||
|
||||
/// Represents an in-progress set of completions being built.
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct Completions {
|
||||
pub struct Completions {
|
||||
buf: Vec<CompletionItem>,
|
||||
}
|
||||
|
||||
impl Completions {
|
||||
pub(crate) fn add(&mut self, item: impl Into<CompletionItem>) {
|
||||
pub fn add(&mut self, item: impl Into<CompletionItem>) {
|
||||
self.buf.push(item.into())
|
||||
}
|
||||
pub(crate) fn add_all<I>(&mut self, items: I)
|
||||
pub fn add_all<I>(&mut self, items: I)
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: Into<CompletionItem>,
|
File diff suppressed because one or more lines are too long
|
@ -1,3 +1,5 @@
|
|||
//! `completions` crate provides utilities for generating completions of user input.
|
||||
|
||||
mod completion_config;
|
||||
mod completion_item;
|
||||
mod completion_context;
|
||||
|
@ -21,17 +23,15 @@ mod complete_macro_in_item_position;
|
|||
mod complete_trait_impl;
|
||||
mod complete_mod;
|
||||
|
||||
use base_db::FilePosition;
|
||||
use ide_db::RootDatabase;
|
||||
|
||||
use crate::{
|
||||
completion::{
|
||||
completion_context::CompletionContext,
|
||||
completion_item::{CompletionKind, Completions},
|
||||
},
|
||||
FilePosition,
|
||||
completion_context::CompletionContext,
|
||||
completion_item::{CompletionKind, Completions},
|
||||
};
|
||||
|
||||
pub use crate::completion::{
|
||||
pub use crate::{
|
||||
completion_config::CompletionConfig,
|
||||
completion_item::{CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat},
|
||||
};
|
||||
|
@ -105,7 +105,7 @@ pub use crate::completion::{
|
|||
/// `foo` *should* be present among the completion variants. Filtering by
|
||||
/// identifier prefix/fuzzy match should be done higher in the stack, together
|
||||
/// with ordering of completions (currently this is done by the client).
|
||||
pub(crate) fn completions(
|
||||
pub fn completions(
|
||||
db: &RootDatabase,
|
||||
config: &CompletionConfig,
|
||||
position: FilePosition,
|
||||
|
@ -139,8 +139,8 @@ pub(crate) fn completions(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::completion::completion_config::CompletionConfig;
|
||||
use crate::fixture;
|
||||
use crate::completion_config::CompletionConfig;
|
||||
use crate::test_utils;
|
||||
|
||||
struct DetailAndDocumentation<'a> {
|
||||
detail: &'a str,
|
||||
|
@ -148,9 +148,9 @@ mod tests {
|
|||
}
|
||||
|
||||
fn check_detail_and_documentation(ra_fixture: &str, expected: DetailAndDocumentation) {
|
||||
let (analysis, position) = fixture::position(ra_fixture);
|
||||
let (db, position) = test_utils::position(ra_fixture);
|
||||
let config = CompletionConfig::default();
|
||||
let completions = analysis.completions(&config, position).unwrap().unwrap();
|
||||
let completions: Vec<_> = crate::completions(&db, &config, position).unwrap().into();
|
||||
for item in completions {
|
||||
if item.detail() == Some(expected.detail) {
|
||||
let opt = item.documentation();
|
||||
|
@ -163,14 +163,18 @@ mod tests {
|
|||
}
|
||||
|
||||
fn check_no_completion(ra_fixture: &str) {
|
||||
let (analysis, position) = fixture::position(ra_fixture);
|
||||
let (db, position) = test_utils::position(ra_fixture);
|
||||
let config = CompletionConfig::default();
|
||||
analysis.completions(&config, position).unwrap();
|
||||
|
||||
let completions: Option<Vec<String>> = analysis
|
||||
.completions(&config, position)
|
||||
.unwrap()
|
||||
.and_then(|completions| if completions.is_empty() { None } else { Some(completions) })
|
||||
let completions: Option<Vec<String>> = crate::completions(&db, &config, position)
|
||||
.and_then(|completions| {
|
||||
let completions: Vec<_> = completions.into();
|
||||
if completions.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(completions)
|
||||
}
|
||||
})
|
||||
.map(|completions| {
|
||||
completions.into_iter().map(|completion| format!("{:?}", completion)).collect()
|
||||
});
|
|
@ -9,7 +9,7 @@ use syntax::{
|
|||
};
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::completion::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable};
|
||||
use crate::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable};
|
||||
|
||||
pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool {
|
||||
not_same_range_ancestor(element)
|
|
@ -3,16 +3,17 @@
|
|||
|
||||
use hir::{HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type};
|
||||
use itertools::Itertools;
|
||||
use syntax::ast::NameOwner;
|
||||
use syntax::{ast::NameOwner, display::*};
|
||||
use test_utils::mark;
|
||||
|
||||
use crate::{
|
||||
completion::{
|
||||
// display::{const_label, function_declaration, macro_label, type_label},
|
||||
CompletionScore,
|
||||
RootDatabase,
|
||||
{
|
||||
completion_item::Builder, CompletionContext, CompletionItem, CompletionItemKind,
|
||||
CompletionKind, Completions,
|
||||
},
|
||||
display::{const_label, function_declaration, macro_label, type_label},
|
||||
CompletionScore, RootDatabase,
|
||||
};
|
||||
|
||||
impl Completions {
|
||||
|
@ -487,13 +488,8 @@ mod tests {
|
|||
use test_utils::mark;
|
||||
|
||||
use crate::{
|
||||
completion::{
|
||||
test_utils::{
|
||||
check_edit, check_edit_with_config, do_completion, get_all_completion_items,
|
||||
},
|
||||
CompletionConfig, CompletionKind,
|
||||
},
|
||||
CompletionScore,
|
||||
test_utils::{check_edit, check_edit_with_config, do_completion, get_all_completion_items},
|
||||
CompletionConfig, CompletionKind, CompletionScore,
|
||||
};
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
||||
|
@ -1277,7 +1273,6 @@ fn go(world: &WorldSnapshot) { go(w<|>) }
|
|||
|
||||
#[test]
|
||||
fn too_many_arguments() {
|
||||
mark::check!(too_many_arguments);
|
||||
check_scores(
|
||||
r#"
|
||||
struct Foo;
|
|
@ -1,15 +1,27 @@
|
|||
//! Runs completion for testing purposes.
|
||||
|
||||
use base_db::{fixture::ChangeFixture, FileLoader, FilePosition};
|
||||
use hir::Semantics;
|
||||
use ide_db::RootDatabase;
|
||||
use itertools::Itertools;
|
||||
use stdx::{format_to, trim_indent};
|
||||
use syntax::{AstNode, NodeOrToken, SyntaxElement};
|
||||
use test_utils::assert_eq_text;
|
||||
use test_utils::{assert_eq_text, RangeOrOffset};
|
||||
|
||||
use crate::{
|
||||
completion::{completion_item::CompletionKind, CompletionConfig},
|
||||
fixture, CompletionItem,
|
||||
};
|
||||
use crate::{completion_item::CompletionKind, CompletionConfig, CompletionItem};
|
||||
|
||||
/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
|
||||
pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
|
||||
let change_fixture = ChangeFixture::parse(ra_fixture);
|
||||
let mut database = RootDatabase::default();
|
||||
database.apply_change(change_fixture.change);
|
||||
let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker (<|>)");
|
||||
let offset = match range_or_offset {
|
||||
RangeOrOffset::Range(_) => panic!(),
|
||||
RangeOrOffset::Offset(it) => it,
|
||||
};
|
||||
(database, FilePosition { file_id, offset })
|
||||
}
|
||||
|
||||
pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
|
||||
do_completion_with_config(CompletionConfig::default(), code, kind)
|
||||
|
@ -79,47 +91,40 @@ pub(crate) fn check_edit_with_config(
|
|||
ra_fixture_after: &str,
|
||||
) {
|
||||
let ra_fixture_after = trim_indent(ra_fixture_after);
|
||||
let (analysis, position) = fixture::position(ra_fixture_before);
|
||||
let (db, position) = position(ra_fixture_before);
|
||||
let completions: Vec<CompletionItem> =
|
||||
analysis.completions(&config, position).unwrap().unwrap().into();
|
||||
crate::completions(&db, &config, position).unwrap().into();
|
||||
let (completion,) = completions
|
||||
.iter()
|
||||
.filter(|it| it.lookup() == what)
|
||||
.collect_tuple()
|
||||
.unwrap_or_else(|| panic!("can't find {:?} completion in {:#?}", what, completions));
|
||||
let mut actual = analysis.file_text(position.file_id).unwrap().to_string();
|
||||
let mut actual = db.file_text(position.file_id).to_string();
|
||||
completion.text_edit().apply(&mut actual);
|
||||
assert_eq_text!(&ra_fixture_after, &actual)
|
||||
}
|
||||
|
||||
pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -> bool) {
|
||||
let (analysis, pos) = fixture::position(code);
|
||||
analysis
|
||||
.with_db(|db| {
|
||||
let sema = Semantics::new(db);
|
||||
let original_file = sema.parse(pos.file_id);
|
||||
let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap();
|
||||
assert!(check(NodeOrToken::Token(token)));
|
||||
})
|
||||
.unwrap();
|
||||
let (db, pos) = position(code);
|
||||
|
||||
let sema = Semantics::new(&db);
|
||||
let original_file = sema.parse(pos.file_id);
|
||||
let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap();
|
||||
assert!(check(NodeOrToken::Token(token)));
|
||||
}
|
||||
|
||||
pub(crate) fn check_pattern_is_not_applicable(code: &str, check: fn(SyntaxElement) -> bool) {
|
||||
let (analysis, pos) = fixture::position(code);
|
||||
analysis
|
||||
.with_db(|db| {
|
||||
let sema = Semantics::new(db);
|
||||
let original_file = sema.parse(pos.file_id);
|
||||
let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap();
|
||||
assert!(!check(NodeOrToken::Token(token)));
|
||||
})
|
||||
.unwrap();
|
||||
let (db, pos) = position(code);
|
||||
let sema = Semantics::new(&db);
|
||||
let original_file = sema.parse(pos.file_id);
|
||||
let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap();
|
||||
assert!(!check(NodeOrToken::Token(token)));
|
||||
}
|
||||
|
||||
pub(crate) fn get_all_completion_items(
|
||||
config: CompletionConfig,
|
||||
code: &str,
|
||||
) -> Vec<CompletionItem> {
|
||||
let (analysis, position) = fixture::position(code);
|
||||
analysis.completions(&config, position).unwrap().unwrap().into()
|
||||
let (db, position) = position(code);
|
||||
crate::completions(&db, &config, position).unwrap().into()
|
||||
}
|
|
@ -30,6 +30,8 @@ profile = { path = "../profile", version = "0.0.0" }
|
|||
test_utils = { path = "../test_utils", version = "0.0.0" }
|
||||
assists = { path = "../assists", version = "0.0.0" }
|
||||
ssr = { path = "../ssr", version = "0.0.0" }
|
||||
call_info = { path = "../call_info", version = "0.0.0" }
|
||||
completion = { path = "../completion", version = "0.0.0" }
|
||||
|
||||
# ide should depend only on the top-level `hir` package. if you need
|
||||
# something from some `hir_xxx` subpackage, reexport the API via `hir`.
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use call_info::FnCallNode;
|
||||
use hir::Semantics;
|
||||
use ide_db::RootDatabase;
|
||||
use syntax::{ast, match_ast, AstNode, TextRange};
|
||||
|
||||
use crate::{
|
||||
call_info::FnCallNode, display::ToNav, goto_definition, references, FilePosition,
|
||||
NavigationTarget, RangeInfo,
|
||||
display::ToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -4,87 +4,8 @@
|
|||
mod navigation_target;
|
||||
mod short_label;
|
||||
|
||||
use syntax::{
|
||||
ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner},
|
||||
SyntaxKind::{ATTR, COMMENT},
|
||||
};
|
||||
|
||||
use ast::VisibilityOwner;
|
||||
use stdx::format_to;
|
||||
|
||||
pub use navigation_target::NavigationTarget;
|
||||
pub(crate) use navigation_target::{ToNav, TryToNav};
|
||||
pub(crate) use short_label::ShortLabel;
|
||||
|
||||
pub(crate) fn function_declaration(node: &ast::Fn) -> String {
|
||||
let mut buf = String::new();
|
||||
if let Some(vis) = node.visibility() {
|
||||
format_to!(buf, "{} ", vis);
|
||||
}
|
||||
if node.async_token().is_some() {
|
||||
format_to!(buf, "async ");
|
||||
}
|
||||
if node.const_token().is_some() {
|
||||
format_to!(buf, "const ");
|
||||
}
|
||||
if node.unsafe_token().is_some() {
|
||||
format_to!(buf, "unsafe ");
|
||||
}
|
||||
if let Some(abi) = node.abi() {
|
||||
// Keyword `extern` is included in the string.
|
||||
format_to!(buf, "{} ", abi);
|
||||
}
|
||||
if let Some(name) = node.name() {
|
||||
format_to!(buf, "fn {}", name)
|
||||
}
|
||||
if let Some(type_params) = node.generic_param_list() {
|
||||
format_to!(buf, "{}", type_params);
|
||||
}
|
||||
if let Some(param_list) = node.param_list() {
|
||||
let params: Vec<String> = param_list
|
||||
.self_param()
|
||||
.into_iter()
|
||||
.map(|self_param| self_param.to_string())
|
||||
.chain(param_list.params().map(|param| param.to_string()))
|
||||
.collect();
|
||||
// Useful to inline parameters
|
||||
format_to!(buf, "({})", params.join(", "));
|
||||
}
|
||||
if let Some(ret_type) = node.ret_type() {
|
||||
if ret_type.ty().is_some() {
|
||||
format_to!(buf, " {}", ret_type);
|
||||
}
|
||||
}
|
||||
if let Some(where_clause) = node.where_clause() {
|
||||
format_to!(buf, "\n{}", where_clause);
|
||||
}
|
||||
buf
|
||||
}
|
||||
|
||||
pub(crate) fn const_label(node: &ast::Const) -> String {
|
||||
let label: String = node
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
.filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR))
|
||||
.map(|node| node.to_string())
|
||||
.collect();
|
||||
|
||||
label.trim().to_owned()
|
||||
}
|
||||
|
||||
pub(crate) fn type_label(node: &ast::TypeAlias) -> String {
|
||||
let label: String = node
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
.filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR))
|
||||
.map(|node| node.to_string())
|
||||
.collect();
|
||||
|
||||
label.trim().to_owned()
|
||||
}
|
||||
|
||||
pub(crate) fn macro_label(node: &ast::MacroCall) -> String {
|
||||
let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
|
||||
let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" };
|
||||
format!("{}macro_rules! {}", vis, name)
|
||||
}
|
||||
pub(crate) use syntax::display::{function_declaration, macro_label};
|
||||
|
|
|
@ -23,8 +23,6 @@ mod prime_caches;
|
|||
mod display;
|
||||
|
||||
mod call_hierarchy;
|
||||
mod call_info;
|
||||
mod completion;
|
||||
mod diagnostics;
|
||||
mod expand_macro;
|
||||
mod extend_selection;
|
||||
|
@ -65,10 +63,6 @@ use crate::display::ToNav;
|
|||
|
||||
pub use crate::{
|
||||
call_hierarchy::CallItem,
|
||||
call_info::CallInfo,
|
||||
completion::{
|
||||
CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
|
||||
},
|
||||
diagnostics::{Diagnostic, DiagnosticsConfig, Fix, Severity},
|
||||
display::NavigationTarget,
|
||||
expand_macro::ExpandedMacro,
|
||||
|
@ -86,6 +80,10 @@ pub use crate::{
|
|||
Highlight, HighlightModifier, HighlightModifiers, HighlightTag, HighlightedRange,
|
||||
},
|
||||
};
|
||||
pub use call_info::CallInfo;
|
||||
pub use completion::{
|
||||
CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
|
||||
};
|
||||
|
||||
pub use assists::{
|
||||
utils::MergeBehaviour, Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist,
|
||||
|
|
|
@ -3,14 +3,12 @@
|
|||
use std::{collections::BTreeMap, convert::TryFrom};
|
||||
|
||||
use ast::{HasQuotes, HasStringValue};
|
||||
use call_info::ActiveParameter;
|
||||
use hir::Semantics;
|
||||
use itertools::Itertools;
|
||||
use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize};
|
||||
|
||||
use crate::{
|
||||
call_info::ActiveParameter, Analysis, Highlight, HighlightModifier, HighlightTag,
|
||||
HighlightedRange, RootDatabase,
|
||||
};
|
||||
use crate::{Analysis, Highlight, HighlightModifier, HighlightTag, HighlightedRange, RootDatabase};
|
||||
|
||||
use super::HighlightedRangeStack;
|
||||
|
||||
|
|
83
crates/syntax/src/display.rs
Normal file
83
crates/syntax/src/display.rs
Normal file
|
@ -0,0 +1,83 @@
|
|||
//! This module contains utilities for turning SyntaxNodes and HIR types
|
||||
//! into types that may be used to render in a UI.
|
||||
|
||||
use crate::{
|
||||
ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner},
|
||||
SyntaxKind::{ATTR, COMMENT},
|
||||
};
|
||||
|
||||
use ast::VisibilityOwner;
|
||||
use stdx::format_to;
|
||||
|
||||
pub fn function_declaration(node: &ast::Fn) -> String {
|
||||
let mut buf = String::new();
|
||||
if let Some(vis) = node.visibility() {
|
||||
format_to!(buf, "{} ", vis);
|
||||
}
|
||||
if node.async_token().is_some() {
|
||||
format_to!(buf, "async ");
|
||||
}
|
||||
if node.const_token().is_some() {
|
||||
format_to!(buf, "const ");
|
||||
}
|
||||
if node.unsafe_token().is_some() {
|
||||
format_to!(buf, "unsafe ");
|
||||
}
|
||||
if let Some(abi) = node.abi() {
|
||||
// Keyword `extern` is included in the string.
|
||||
format_to!(buf, "{} ", abi);
|
||||
}
|
||||
if let Some(name) = node.name() {
|
||||
format_to!(buf, "fn {}", name)
|
||||
}
|
||||
if let Some(type_params) = node.generic_param_list() {
|
||||
format_to!(buf, "{}", type_params);
|
||||
}
|
||||
if let Some(param_list) = node.param_list() {
|
||||
let params: Vec<String> = param_list
|
||||
.self_param()
|
||||
.into_iter()
|
||||
.map(|self_param| self_param.to_string())
|
||||
.chain(param_list.params().map(|param| param.to_string()))
|
||||
.collect();
|
||||
// Useful to inline parameters
|
||||
format_to!(buf, "({})", params.join(", "));
|
||||
}
|
||||
if let Some(ret_type) = node.ret_type() {
|
||||
if ret_type.ty().is_some() {
|
||||
format_to!(buf, " {}", ret_type);
|
||||
}
|
||||
}
|
||||
if let Some(where_clause) = node.where_clause() {
|
||||
format_to!(buf, "\n{}", where_clause);
|
||||
}
|
||||
buf
|
||||
}
|
||||
|
||||
pub fn const_label(node: &ast::Const) -> String {
|
||||
let label: String = node
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
.filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR))
|
||||
.map(|node| node.to_string())
|
||||
.collect();
|
||||
|
||||
label.trim().to_owned()
|
||||
}
|
||||
|
||||
pub fn type_label(node: &ast::TypeAlias) -> String {
|
||||
let label: String = node
|
||||
.syntax()
|
||||
.children_with_tokens()
|
||||
.filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR))
|
||||
.map(|node| node.to_string())
|
||||
.collect();
|
||||
|
||||
label.trim().to_owned()
|
||||
}
|
||||
|
||||
pub fn macro_label(node: &ast::MacroCall) -> String {
|
||||
let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
|
||||
let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" };
|
||||
format!("{}macro_rules! {}", vis, name)
|
||||
}
|
|
@ -32,6 +32,7 @@ mod ptr;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub mod display;
|
||||
pub mod algo;
|
||||
pub mod ast;
|
||||
#[doc(hidden)]
|
||||
|
|
|
@ -213,7 +213,7 @@ fn check_todo(path: &Path, text: &str) {
|
|||
// `ast::make`.
|
||||
"ast/make.rs",
|
||||
// The documentation in string literals may contain anything for its own purposes
|
||||
"completion/generated_features.rs",
|
||||
"completion/src/generated_features.rs",
|
||||
];
|
||||
if need_todo.iter().any(|p| path.ends_with(p)) {
|
||||
return;
|
||||
|
|
Loading…
Reference in a new issue