6276: Extract call_info and completion into separate crates r=matklad a=popzxc

As it was discussed in [zulip](https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0/topic/Completion.20refactoring), we need to move `completions` into a separate crate.

Unfortunately, the dependency on `call_info::ActiveParameter` doesn't look easy to get rid of, and it seems to be a topic for a separate PR, thus I also extracted `call_info` into a separate crate (on which both `ide` and `completion` crates depend).

Additionally, a few `FIXME`s in doc-comments were resolved in order to make `tidy` happy.


Co-authored-by: Igor Aleksanov <popzxc@yandex.ru>
This commit is contained in:
bors[bot] 2020-10-18 10:41:46 +00:00 committed by GitHub
commit 886cfd6821
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 336 additions and 226 deletions

36
Cargo.lock generated
View file

@ -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",

View 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"

View file

@ -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 {

View 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" }

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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,
};

View file

@ -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);

View file

@ -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) {

View file

@ -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);

View file

@ -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},
},
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,
};

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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);

View file

@ -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);

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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,8 +14,6 @@ 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,
@ -23,8 +22,6 @@ use crate::{
unsafe_is_prev,
},
CompletionConfig,
},
FilePosition,
};
/// `CompletionContext` is created early during completion to figure out, where

View file

@ -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>,

View file

@ -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,
};
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()
});

View file

@ -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)

View file

@ -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;

View file

@ -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 (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)));
})
.unwrap();
}
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 (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)));
})
.unwrap();
}
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()
}

View file

@ -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`.

View file

@ -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)]

View file

@ -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};

View file

@ -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,

View file

@ -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;

View 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)
}

View file

@ -32,6 +32,7 @@ mod ptr;
#[cfg(test)]
mod tests;
pub mod display;
pub mod algo;
pub mod ast;
#[doc(hidden)]

View file

@ -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;