6331: correct hover text for items with doc attribute with raw strings r=matklad a=JoshMcguigan

Fixes #6300 by improving the handling of raw string literals in attribute style doc comments.

This still has a bug where it could consume too many `"` at the start or end of the comment text, just as the original code had. Not sure if we want to fix that as part of this PR or not? If so, I think I'd prefer to add a unit test for either the `as_simple_key_value` function (I'm not exactly sure where this would belong / how to set this up) or create a `fn(&SmolStr) -> &SmolStr` to unit test by factoring out the `trim` operations from `as_simple_key_value`. Thoughts on this? 

6342: Shorter dependency chain r=matklad a=popzxc

Continuing implementing suggestions from the `Completion refactoring` zulip thread.

This PR does the following:

- Removes dependency of `completions` on `assists` by moving required functionality into `ide_db`.
- Moves completely `call_info` crate into `ide_db` as it looks like it fits perfect there.
- Adds a bunch of new tests and docs.
- Adds the re-export of `base_db` to the `ide_db` and removes direct dependency on `base_db` from other crates.

The last point is controversial, I guess, but I noticed that in places where `ide_db` is used, `base_db` is also *always* used. Thus I think the dependency on the `base_db` is implied by the fact of `ide_db` interfaces, and thus it makes sense to just provide `base_db` out of the box.


Co-authored-by: Josh Mcguigan <joshmcg88@gmail.com>
Co-authored-by: Igor Aleksanov <popzxc@yandex.ru>
This commit is contained in:
bors[bot] 2020-10-24 19:08:12 +00:00 committed by GitHub
commit bf84e4958e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 421 additions and 259 deletions

22
Cargo.lock generated
View File

@ -50,7 +50,6 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
name = "assists"
version = "0.0.0"
dependencies = [
"base_db",
"either",
"hir",
"ide_db",
@ -127,20 +126,6 @@ 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.12.0"
@ -268,9 +253,7 @@ dependencies = [
name = "completion"
version = "0.0.0"
dependencies = [
"assists",
"base_db",
"call_info",
"expect-test",
"hir",
"ide_db",
@ -655,8 +638,6 @@ name = "ide"
version = "0.0.0"
dependencies = [
"assists",
"base_db",
"call_info",
"cfg",
"completion",
"either",
@ -685,6 +666,7 @@ version = "0.0.0"
dependencies = [
"base_db",
"either",
"expect-test",
"fst",
"hir",
"log",
@ -1356,7 +1338,6 @@ name = "rust-analyzer"
version = "0.0.0"
dependencies = [
"anyhow",
"base_db",
"cfg",
"crossbeam-channel 0.5.0",
"env_logger",
@ -1614,7 +1595,6 @@ dependencies = [
name = "ssr"
version = "0.0.0"
dependencies = [
"base_db",
"expect-test",
"hir",
"ide_db",

View File

@ -18,7 +18,6 @@ stdx = { path = "../stdx", version = "0.0.0" }
syntax = { path = "../syntax", version = "0.0.0" }
text_edit = { path = "../text_edit", version = "0.0.0" }
profile = { path = "../profile", version = "0.0.0" }
base_db = { path = "../base_db", version = "0.0.0" }
ide_db = { path = "../ide_db", version = "0.0.0" }
hir = { path = "../hir", version = "0.0.0" }
test_utils = { path = "../test_utils", version = "0.0.0" }

View File

@ -3,8 +3,8 @@
use std::mem;
use algo::find_covering_element;
use base_db::{FileId, FileRange};
use hir::Semantics;
use ide_db::base_db::{FileId, FileRange};
use ide_db::{
label::Label,
source_change::{SourceChange, SourceFileEdit},

View File

@ -1,4 +1,5 @@
use hir::HasSource;
use ide_db::traits::{get_missing_assoc_items, resolve_target_trait};
use syntax::{
ast::{
self,
@ -11,7 +12,7 @@
use crate::{
assist_context::{AssistContext, Assists},
ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor},
utils::{render_snippet, Cursor},
AssistId, AssistKind,
};

View File

@ -1,5 +1,5 @@
use base_db::FileId;
use hir::{EnumVariant, Module, ModuleDef, Name};
use ide_db::base_db::FileId;
use ide_db::{defs::Definition, search::Reference, RootDatabase};
use itertools::Itertools;
use rustc_hash::FxHashSet;

View File

@ -1,5 +1,5 @@
use base_db::FileId;
use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
use ide_db::base_db::FileId;
use syntax::{
ast::{self, VisibilityOwner},
AstNode, TextRange, TextSize,

View File

@ -1,5 +1,5 @@
use base_db::FileId;
use hir::HirDisplay;
use ide_db::base_db::FileId;
use rustc_hash::{FxHashMap, FxHashSet};
use syntax::{
ast::{

View File

@ -7,10 +7,8 @@
AstNode,
};
use crate::{
utils::{unwrap_trivial_block, TryEnum},
AssistContext, AssistId, AssistKind, Assists,
};
use crate::{utils::unwrap_trivial_block, AssistContext, AssistId, AssistKind, Assists};
use ide_db::ty_filter::TryEnum;
// Assist: replace_if_let_with_match
//

View File

@ -9,7 +9,8 @@
AstNode, T,
};
use crate::{utils::TryEnum, AssistContext, AssistId, AssistKind, Assists};
use crate::{AssistContext, AssistId, AssistKind, Assists};
use ide_db::ty_filter::TryEnum;
// Assist: replace_let_with_if_let
//

View File

@ -10,9 +10,10 @@
};
use crate::{
utils::{render_snippet, Cursor, TryEnum},
utils::{render_snippet, Cursor},
AssistContext, AssistId, AssistKind, Assists,
};
use ide_db::ty_filter::TryEnum;
// Assist: replace_unwrap_with_match
//

View File

@ -17,8 +17,8 @@ macro_rules! eprintln {
pub mod utils;
pub mod ast_transform;
use base_db::FileRange;
use hir::Semantics;
use ide_db::base_db::FileRange;
use ide_db::{label::Label, source_change::SourceChange, RootDatabase};
use syntax::TextRange;

View File

@ -1,7 +1,7 @@
mod generated;
use base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
use hir::Semantics;
use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
use ide_db::RootDatabase;
use syntax::TextRange;
use test_utils::{assert_eq_text, extract_offset, extract_range};

View File

@ -2,14 +2,13 @@
pub(crate) mod insert_use;
pub(crate) mod import_assets;
use std::{iter, ops};
use std::ops;
use hir::{Adt, Crate, Enum, Module, ScopeDef, Semantics, Trait, Type};
use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait};
use ide_db::RootDatabase;
use itertools::Itertools;
use rustc_hash::FxHashSet;
use syntax::{
ast::{self, make, ArgListOwner, NameOwner},
ast::{self, make, ArgListOwner},
AstNode, Direction,
SyntaxKind::*,
SyntaxNode, TextSize, T,
@ -115,72 +114,6 @@ fn escape(buf: &mut String) {
}
}
pub fn get_missing_assoc_items(
sema: &Semantics<RootDatabase>,
impl_def: &ast::Impl,
) -> Vec<hir::AssocItem> {
// Names must be unique between constants and functions. However, type aliases
// may share the same name as a function or constant.
let mut impl_fns_consts = FxHashSet::default();
let mut impl_type = FxHashSet::default();
if let Some(item_list) = impl_def.assoc_item_list() {
for item in item_list.assoc_items() {
match item {
ast::AssocItem::Fn(f) => {
if let Some(n) = f.name() {
impl_fns_consts.insert(n.syntax().to_string());
}
}
ast::AssocItem::TypeAlias(t) => {
if let Some(n) = t.name() {
impl_type.insert(n.syntax().to_string());
}
}
ast::AssocItem::Const(c) => {
if let Some(n) = c.name() {
impl_fns_consts.insert(n.syntax().to_string());
}
}
ast::AssocItem::MacroCall(_) => (),
}
}
}
resolve_target_trait(sema, impl_def).map_or(vec![], |target_trait| {
target_trait
.items(sema.db)
.iter()
.filter(|i| match i {
hir::AssocItem::Function(f) => {
!impl_fns_consts.contains(&f.name(sema.db).to_string())
}
hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db).to_string()),
hir::AssocItem::Const(c) => c
.name(sema.db)
.map(|n| !impl_fns_consts.contains(&n.to_string()))
.unwrap_or_default(),
})
.cloned()
.collect()
})
}
pub(crate) fn resolve_target_trait(
sema: &Semantics<RootDatabase>,
impl_def: &ast::Impl,
) -> Option<hir::Trait> {
let ast_path =
impl_def.trait_().map(|it| it.syntax().clone()).and_then(ast::PathType::cast)?.path()?;
match sema.resolve_path(&ast_path) {
Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def),
_ => None,
}
}
pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
node.children_with_tokens()
.find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
@ -223,54 +156,6 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
}
}
#[derive(Clone, Copy)]
pub enum TryEnum {
Result,
Option,
}
impl TryEnum {
const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> {
let enum_ = match ty.as_adt() {
Some(Adt::Enum(it)) => it,
_ => return None,
};
TryEnum::ALL.iter().find_map(|&var| {
if &enum_.name(sema.db).to_string() == var.type_name() {
return Some(var);
}
None
})
}
pub(crate) fn happy_case(self) -> &'static str {
match self {
TryEnum::Result => "Ok",
TryEnum::Option => "Some",
}
}
pub(crate) fn sad_pattern(self) -> ast::Pat {
match self {
TryEnum::Result => make::tuple_struct_pat(
make::path_unqualified(make::path_segment(make::name_ref("Err"))),
iter::once(make::wildcard_pat().into()),
)
.into(),
TryEnum::Option => make::ident_pat(make::name("None")).into(),
}
}
fn type_name(self) -> &'static str {
match self {
TryEnum::Result => "Result",
TryEnum::Option => "Option",
}
}
}
/// Helps with finding well-know things inside the standard library. This is
/// somewhat similar to the known paths infra inside hir, but it different; We
/// want to make sure that IDE specific paths don't become interesting inside

View File

@ -1,26 +0,0 @@
[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

@ -21,8 +21,6 @@ base_db = { path = "../base_db", version = "0.0.0" }
ide_db = { path = "../ide_db", version = "0.0.0" }
profile = { path = "../profile", version = "0.0.0" }
test_utils = { path = "../test_utils", version = "0.0.0" }
assists = { path = "../assists", version = "0.0.0" }
call_info = { path = "../call_info", version = "0.0.0" }
# completions crate should depend only on the top-level `hir` package. if you need
# something from some `hir_xxx` subpackage, reexport the API via `hir`.

View File

@ -1,7 +1,7 @@
//! Completes mod declarations.
use base_db::{SourceDatabaseExt, VfsPath};
use hir::{Module, ModuleSource};
use ide_db::base_db::{SourceDatabaseExt, VfsPath};
use ide_db::RootDatabase;
use rustc_hash::FxHashSet;

View File

@ -2,7 +2,7 @@
mod format_like;
use assists::utils::TryEnum;
use ide_db::ty_filter::TryEnum;
use syntax::{
ast::{self, AstNode, AstToken},
TextRange, TextSize,

View File

@ -31,8 +31,8 @@
//! }
//! ```
use assists::utils::get_missing_assoc_items;
use hir::{self, HasAttrs, HasSource};
use ide_db::traits::get_missing_assoc_items;
use syntax::{
ast::{self, edit, Impl},
display::function_declaration,

View File

@ -1,9 +1,8 @@
//! See `CompletionContext` structure.
use base_db::{FilePosition, SourceDatabase};
use call_info::ActiveParameter;
use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type};
use ide_db::RootDatabase;
use ide_db::base_db::{FilePosition, SourceDatabase};
use ide_db::{call_info::ActiveParameter, RootDatabase};
use syntax::{
algo::{find_covering_element, find_node_at_offset},
ast, match_ast, AstNode, NodeOrToken,

View File

@ -23,7 +23,7 @@
mod complete_trait_impl;
mod complete_mod;
use base_db::FilePosition;
use ide_db::base_db::FilePosition;
use ide_db::RootDatabase;
use crate::{

View File

@ -1,7 +1,7 @@
//! Runs completion for testing purposes.
use base_db::{fixture::ChangeFixture, FileLoader, FilePosition};
use hir::Semantics;
use ide_db::base_db::{fixture::ChangeFixture, FileLoader, FilePosition};
use ide_db::RootDatabase;
use itertools::Itertools;
use stdx::{format_to, trim_indent};

View File

@ -23,14 +23,12 @@ url = "2.1.1"
stdx = { path = "../stdx", version = "0.0.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" }
cfg = { path = "../cfg", 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" }
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

View File

@ -2,8 +2,8 @@
use indexmap::IndexMap;
use call_info::FnCallNode;
use hir::Semantics;
use ide_db::call_info::FnCallNode;
use ide_db::RootDatabase;
use syntax::{ast, match_ast, AstNode, TextRange};
@ -137,7 +137,7 @@ fn into_items(self) -> Vec<CallItem> {
#[cfg(test)]
mod tests {
use base_db::FilePosition;
use ide_db::base_db::FilePosition;
use crate::fixture;

View File

@ -9,11 +9,11 @@
use std::cell::RefCell;
use base_db::SourceDatabase;
use hir::{
diagnostics::{Diagnostic as _, DiagnosticSinkBuilder},
Semantics,
};
use ide_db::base_db::SourceDatabase;
use ide_db::RootDatabase;
use itertools::Itertools;
use rustc_hash::FxHashSet;

View File

@ -1,7 +1,7 @@
//! Suggests shortening `Foo { field: field }` to `Foo { field }` in both
//! expressions and patterns.
use base_db::FileId;
use ide_db::base_db::FileId;
use ide_db::source_change::SourceFileEdit;
use syntax::{ast, match_ast, AstNode, SyntaxNode};
use text_edit::TextEdit;

View File

@ -1,6 +1,5 @@
//! Provides a way to attach fixes to the diagnostics.
//! The same module also has all curret custom fixes for the diagnostics implemented.
use base_db::FileId;
use hir::{
db::AstDatabase,
diagnostics::{
@ -9,6 +8,7 @@
},
HasSource, HirDisplay, Semantics, VariantDef,
};
use ide_db::base_db::FileId;
use ide_db::{
source_change::{FileSystemEdit, SourceFileEdit},
RootDatabase,

View File

@ -1,8 +1,8 @@
//! FIXME: write short doc here
use base_db::{FileId, SourceDatabase};
use either::Either;
use hir::{original_range, AssocItem, FieldSource, HasSource, InFile, ModuleSource};
use ide_db::base_db::{FileId, SourceDatabase};
use ide_db::{defs::Definition, RootDatabase};
use syntax::{
ast::{self, DocCommentsOwner, NameOwner},

View File

@ -1,5 +1,5 @@
//! Utilities for creating `Analysis` instances for tests.
use base_db::fixture::ChangeFixture;
use ide_db::base_db::fixture::ChangeFixture;
use test_utils::{extract_annotations, RangeOrOffset};
use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange};

View File

@ -100,7 +100,7 @@ pub(crate) fn reference_definition(
#[cfg(test)]
mod tests {
use base_db::FileRange;
use ide_db::base_db::FileRange;
use syntax::{TextRange, TextSize};
use crate::fixture;

View File

@ -74,7 +74,7 @@ fn impls_for_trait(
#[cfg(test)]
mod tests {
use base_db::FileRange;
use ide_db::base_db::FileRange;
use crate::fixture;

View File

@ -54,7 +54,7 @@ fn priority(n: &SyntaxToken) -> usize {
#[cfg(test)]
mod tests {
use base_db::FileRange;
use ide_db::base_db::FileRange;
use crate::fixture;

View File

@ -1,8 +1,8 @@
use base_db::SourceDatabase;
use hir::{
Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay,
Module, ModuleDef, ModuleSource, Semantics,
};
use ide_db::base_db::SourceDatabase;
use ide_db::{
defs::{Definition, NameClass, NameRefClass},
RootDatabase,
@ -385,8 +385,8 @@ fn priority(n: &SyntaxToken) -> usize {
#[cfg(test)]
mod tests {
use base_db::FileLoader;
use expect_test::{expect, Expect};
use ide_db::base_db::FileLoader;
use crate::fixture;
@ -637,6 +637,33 @@ pub fn foo(_: &Path)
);
}
#[test]
fn hover_shows_fn_doc_attr_raw_string() {
check(
r##"
#[doc = r#"Raw string doc attr"#]
pub fn foo<|>(_: &Path) {}
fn main() { }
"##,
expect![[r##"
*foo*
```rust
test
```
```rust
pub fn foo(_: &Path)
```
---
Raw string doc attr
"##]],
);
}
#[test]
fn hover_shows_struct_field_info() {
// Hovering over the field when instantiating

View File

@ -48,11 +48,11 @@ macro_rules! eprintln {
use std::sync::Arc;
use base_db::{
use cfg::CfgOptions;
use ide_db::base_db::{
salsa::{self, ParallelDatabase},
CheckCanceled, Env, FileLoader, FileSet, SourceDatabase, VfsPath,
};
use cfg::CfgOptions;
use ide_db::{
symbol_index::{self, FileSymbol},
LineIndexDatabase,
@ -80,19 +80,19 @@ macro_rules! eprintln {
Highlight, HighlightModifier, HighlightModifiers, HighlightTag, HighlightedRange,
},
};
pub use call_info::CallInfo;
pub use completion::{
CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
};
pub use ide_db::call_info::CallInfo;
pub use assists::{
utils::MergeBehaviour, Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist,
};
pub use base_db::{
pub use hir::{Documentation, Semantics};
pub use ide_db::base_db::{
Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot,
SourceRootId,
};
pub use hir::{Documentation, Semantics};
pub use ide_db::{
label::Label,
line_index::{LineCol, LineIndex},
@ -396,7 +396,7 @@ pub fn external_docs(
/// Computes parameter information for the given call expression.
pub fn call_info(&self, position: FilePosition) -> Cancelable<Option<CallInfo>> {
self.with_db(|db| call_info::call_info(db, position))
self.with_db(|db| ide_db::call_info::call_info(db, position))
}
/// Computes call hierarchy candidates for the given file position.

View File

@ -1,5 +1,5 @@
use base_db::{CrateId, FileId, FilePosition};
use hir::Semantics;
use ide_db::base_db::{CrateId, FileId, FilePosition};
use ide_db::RootDatabase;
use syntax::{
algo::find_node_at_offset,

View File

@ -3,8 +3,8 @@
//! request takes longer to compute. This modules implemented prepopulating of
//! various caches, it's not really advanced at the moment.
use base_db::SourceDatabase;
use hir::db::DefDatabase;
use ide_db::base_db::SourceDatabase;
use crate::RootDatabase;

View File

@ -191,8 +191,8 @@ fn get_struct_def_name_for_struct_literal_search(
#[cfg(test)]
mod tests {
use base_db::FileId;
use expect_test::{expect, Expect};
use ide_db::base_db::FileId;
use stdx::format_to;
use crate::{fixture, SearchScope};

View File

@ -1,7 +1,7 @@
//! FIXME: write short doc here
use base_db::SourceDatabaseExt;
use hir::{Module, ModuleDef, ModuleSource, Semantics};
use ide_db::base_db::SourceDatabaseExt;
use ide_db::{
defs::{Definition, NameClass, NameRefClass},
RootDatabase,

View File

@ -1,10 +1,10 @@
use std::{fmt, iter::FromIterator, sync::Arc};
use base_db::{
use hir::MacroFile;
use ide_db::base_db::{
salsa::debug::{DebugQueryTable, TableEntry},
CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId,
};
use hir::MacroFile;
use ide_db::{
symbol_index::{LibrarySymbolsQuery, SymbolIndex},
RootDatabase,
@ -16,7 +16,7 @@
use syntax::{ast, Parse, SyntaxNode};
fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>()
ide_db::base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>()
}
fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
hir::db::ParseMacroQuery.in_db(db).entries::<SyntaxTreeStats>()

View File

@ -1,6 +1,6 @@
//! Renders a bit of code as HTML.
use base_db::SourceDatabase;
use ide_db::base_db::SourceDatabase;
use oorandom::Rand32;
use stdx::format_to;
use syntax::{AstNode, TextRange, TextSize};

View File

@ -3,8 +3,8 @@
use std::{collections::BTreeMap, convert::TryFrom};
use ast::{HasQuotes, HasStringValue};
use call_info::ActiveParameter;
use hir::Semantics;
use ide_db::call_info::ActiveParameter;
use itertools::Itertools;
use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize};

View File

@ -1,4 +1,4 @@
use base_db::{FileId, SourceDatabase};
use ide_db::base_db::{FileId, SourceDatabase};
use ide_db::RootDatabase;
use syntax::{
algo, AstNode, NodeOrToken, SourceFile,

View File

@ -15,7 +15,7 @@
mod on_enter;
use base_db::{FilePosition, SourceDatabase};
use ide_db::base_db::{FilePosition, SourceDatabase};
use ide_db::{source_change::SourceFileEdit, RootDatabase};
use syntax::{
algo::find_node_at_offset,

View File

@ -1,7 +1,7 @@
//! Handles the `Enter` key press. At the momently, this only continues
//! comments, but should handle indent some time in the future as well.
use base_db::{FilePosition, SourceDatabase};
use ide_db::base_db::{FilePosition, SourceDatabase};
use ide_db::RootDatabase;
use syntax::{
ast::{self, AstToken},

View File

@ -29,3 +29,6 @@ test_utils = { path = "../test_utils", 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`.
hir = { path = "../hir", version = "0.0.0" }
[dev-dependencies]
expect-test = "1.0"

View File

@ -2,7 +2,6 @@
use base_db::FilePosition;
use either::Either;
use hir::{HasAttrs, HirDisplay, Semantics, Type};
use ide_db::RootDatabase;
use stdx::format_to;
use syntax::{
ast::{self, ArgListOwner},
@ -10,6 +9,8 @@
};
use test_utils::mark;
use crate::RootDatabase;
/// Contains information about a call site. Specifically the
/// `FunctionSignature`and current parameter.
#[derive(Debug)]
@ -228,9 +229,9 @@ fn arg_list(&self) -> Option<ast::ArgList> {
#[cfg(test)]
mod tests {
use crate::RootDatabase;
use base_db::{fixture::ChangeFixture, FilePosition};
use expect_test::{expect, Expect};
use ide_db::RootDatabase;
use test_utils::{mark, RangeOrOffset};
/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
@ -249,7 +250,7 @@ pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
fn check(ra_fixture: &str, expect: Expect) {
let (db, position) = position(ra_fixture);
let call_info = crate::call_info(&db, position);
let call_info = crate::call_info::call_info(&db, position);
let actual = match call_info {
Some(call_info) => {
let docs = match &call_info.doc {

View File

@ -10,6 +10,9 @@
pub mod search;
pub mod imports_locator;
pub mod source_change;
pub mod ty_filter;
pub mod traits;
pub mod call_info;
use std::{fmt, sync::Arc};
@ -23,6 +26,9 @@
use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
/// `base_db` is normally also needed in places where `ide_db` is used, so this re-export is for convenience.
pub use base_db;
#[salsa::database(
base_db::SourceDatabaseStorage,
base_db::SourceDatabaseExtStorage,

227
crates/ide_db/src/traits.rs Normal file
View File

@ -0,0 +1,227 @@
//! Functionality for obtaining data related to traits from the DB.
use crate::RootDatabase;
use hir::Semantics;
use rustc_hash::FxHashSet;
use syntax::{
ast::{self, NameOwner},
AstNode,
};
/// Given the `impl` block, attempts to find the trait this `impl` corresponds to.
pub fn resolve_target_trait(
sema: &Semantics<RootDatabase>,
impl_def: &ast::Impl,
) -> Option<hir::Trait> {
let ast_path =
impl_def.trait_().map(|it| it.syntax().clone()).and_then(ast::PathType::cast)?.path()?;
match sema.resolve_path(&ast_path) {
Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def),
_ => None,
}
}
/// Given the `impl` block, returns the list of associated items (e.g. functions or types) that are
/// missing in this `impl` block.
pub fn get_missing_assoc_items(
sema: &Semantics<RootDatabase>,
impl_def: &ast::Impl,
) -> Vec<hir::AssocItem> {
// Names must be unique between constants and functions. However, type aliases
// may share the same name as a function or constant.
let mut impl_fns_consts = FxHashSet::default();
let mut impl_type = FxHashSet::default();
if let Some(item_list) = impl_def.assoc_item_list() {
for item in item_list.assoc_items() {
match item {
ast::AssocItem::Fn(f) => {
if let Some(n) = f.name() {
impl_fns_consts.insert(n.syntax().to_string());
}
}
ast::AssocItem::TypeAlias(t) => {
if let Some(n) = t.name() {
impl_type.insert(n.syntax().to_string());
}
}
ast::AssocItem::Const(c) => {
if let Some(n) = c.name() {
impl_fns_consts.insert(n.syntax().to_string());
}
}
ast::AssocItem::MacroCall(_) => (),
}
}
}
resolve_target_trait(sema, impl_def).map_or(vec![], |target_trait| {
target_trait
.items(sema.db)
.iter()
.filter(|i| match i {
hir::AssocItem::Function(f) => {
!impl_fns_consts.contains(&f.name(sema.db).to_string())
}
hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db).to_string()),
hir::AssocItem::Const(c) => c
.name(sema.db)
.map(|n| !impl_fns_consts.contains(&n.to_string()))
.unwrap_or_default(),
})
.cloned()
.collect()
})
}
#[cfg(test)]
mod tests {
use crate::RootDatabase;
use base_db::{fixture::ChangeFixture, FilePosition};
use expect_test::{expect, Expect};
use hir::Semantics;
use syntax::ast::{self, AstNode};
use test_utils::RangeOrOffset;
/// 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_trait(ra_fixture: &str, expect: Expect) {
let (db, position) = position(ra_fixture);
let sema = Semantics::new(&db);
let file = sema.parse(position.file_id);
let impl_block: ast::Impl =
sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block);
let actual = match trait_ {
Some(trait_) => trait_.name(&db).to_string(),
None => String::new(),
};
expect.assert_eq(&actual);
}
fn check_missing_assoc(ra_fixture: &str, expect: Expect) {
let (db, position) = position(ra_fixture);
let sema = Semantics::new(&db);
let file = sema.parse(position.file_id);
let impl_block: ast::Impl =
sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
let items = crate::traits::get_missing_assoc_items(&sema, &impl_block);
let actual = items
.into_iter()
.map(|item| item.name(&db).unwrap().to_string())
.collect::<Vec<_>>()
.join("\n");
expect.assert_eq(&actual);
}
#[test]
fn resolve_trait() {
check_trait(
r#"
pub trait Foo {
fn bar();
}
impl Foo for u8 {
<|>
}
"#,
expect![["Foo"]],
);
check_trait(
r#"
pub trait Foo {
fn bar();
}
impl Foo for u8 {
fn bar() {
fn baz() {
<|>
}
baz();
}
}
"#,
expect![["Foo"]],
);
check_trait(
r#"
pub trait Foo {
fn bar();
}
pub struct Bar;
impl Bar {
<|>
}
"#,
expect![[""]],
);
}
#[test]
fn missing_assoc_items() {
check_missing_assoc(
r#"
pub trait Foo {
const FOO: u8;
fn bar();
}
impl Foo for u8 {
<|>
}"#,
expect![[r#"
FOO
bar"#]],
);
check_missing_assoc(
r#"
pub trait Foo {
const FOO: u8;
fn bar();
}
impl Foo for u8 {
const FOO: u8 = 10;
<|>
}"#,
expect![[r#"
bar"#]],
);
check_missing_assoc(
r#"
pub trait Foo {
const FOO: u8;
fn bar();
}
impl Foo for u8 {
const FOO: u8 = 10;
fn bar() {<|>}
}"#,
expect![[r#""#]],
);
check_missing_assoc(
r#"
pub struct Foo;
impl Foo {
fn bar() {<|>}
}"#,
expect![[r#""#]],
);
}
}

View File

@ -0,0 +1,58 @@
//! This module contains structures for filtering the expected types.
//! Use case for structures in this module is, for example, situation when you need to process
//! only certain `Enum`s.
use crate::RootDatabase;
use hir::{Adt, Semantics, Type};
use std::iter;
use syntax::ast::{self, make};
/// Enum types that implement `std::ops::Try` trait.
#[derive(Clone, Copy)]
pub enum TryEnum {
Result,
Option,
}
impl TryEnum {
const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
/// Returns `Some(..)` if the provided type is an enum that implements `std::ops::Try`.
pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> {
let enum_ = match ty.as_adt() {
Some(Adt::Enum(it)) => it,
_ => return None,
};
TryEnum::ALL.iter().find_map(|&var| {
if &enum_.name(sema.db).to_string() == var.type_name() {
return Some(var);
}
None
})
}
pub fn happy_case(self) -> &'static str {
match self {
TryEnum::Result => "Ok",
TryEnum::Option => "Some",
}
}
pub fn sad_pattern(self) -> ast::Pat {
match self {
TryEnum::Result => make::tuple_struct_pat(
make::path_unqualified(make::path_segment(make::name_ref("Err"))),
iter::once(make::wildcard_pat().into()),
)
.into(),
TryEnum::Option => make::ident_pat(make::name("None")).into(),
}
}
fn type_name(self) -> &'static str {
match self {
TryEnum::Result => "Result",
TryEnum::Option => "Option",
}
}
}

View File

@ -46,7 +46,6 @@ cfg = { path = "../cfg", version = "0.0.0" }
toolchain = { path = "../toolchain", version = "0.0.0" }
# This should only be used in CLI
base_db = { path = "../base_db", version = "0.0.0" }
ide_db = { path = "../ide_db", version = "0.0.0" }
ssr = { path = "../ssr", version = "0.0.0" }
hir = { path = "../hir", version = "0.0.0" }

View File

@ -3,13 +3,13 @@
use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant};
use anyhow::{bail, format_err, Result};
use base_db::{
salsa::{Database, Durability},
FileId,
};
use ide::{
Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol,
};
use ide_db::base_db::{
salsa::{Database, Durability},
FileId,
};
use vfs::AbsPathBuf;
use crate::{

View File

@ -6,16 +6,16 @@
time::{SystemTime, UNIX_EPOCH},
};
use base_db::{
salsa::{self, ParallelDatabase},
SourceDatabaseExt,
};
use hir::{
db::{AstDatabase, DefDatabase, HirDatabase},
original_range, AssocItem, Crate, HasSource, HirDisplay, ModuleDef,
};
use hir_def::FunctionId;
use hir_ty::{Ty, TypeWalk};
use ide_db::base_db::{
salsa::{self, ParallelDatabase},
SourceDatabaseExt,
};
use itertools::Itertools;
use oorandom::Rand32;
use rayon::prelude::*;

View File

@ -6,9 +6,9 @@
use anyhow::anyhow;
use rustc_hash::FxHashSet;
use base_db::SourceDatabaseExt;
use hir::Crate;
use ide::{DiagnosticsConfig, Severity};
use ide_db::base_db::SourceDatabaseExt;
use crate::cli::{load_cargo::load_cargo, Result};

View File

@ -3,9 +3,9 @@
use std::{path::Path, sync::Arc};
use anyhow::Result;
use base_db::CrateGraph;
use crossbeam_channel::{unbounded, Receiver};
use ide::{AnalysisHost, Change};
use ide_db::base_db::CrateGraph;
use project_model::{CargoConfig, ProcMacroClient, ProjectManifest, ProjectWorkspace};
use vfs::{loader::Handle, AbsPath, AbsPathBuf};

View File

@ -4,7 +4,7 @@
use ssr::{MatchFinder, SsrPattern, SsrRule};
pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> {
use base_db::SourceDatabaseExt;
use ide_db::base_db::SourceDatabaseExt;
let (host, vfs) = load_cargo(&std::env::current_dir()?, true, true)?;
let db = host.raw_database();
let mut match_finder = MatchFinder::at_first_file(db)?;
@ -26,7 +26,7 @@ pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> {
/// `debug_snippet`. This is intended for debugging and probably isn't in it's current form useful
/// for much else.
pub fn search_for_patterns(patterns: Vec<SsrPattern>, debug_snippet: Option<String>) -> Result<()> {
use base_db::SourceDatabaseExt;
use ide_db::base_db::SourceDatabaseExt;
use ide_db::symbol_index::SymbolsDatabase;
let (host, _vfs) = load_cargo(&std::env::current_dir()?, true, true)?;
let db = host.raw_database();

View File

@ -1,8 +1,8 @@
//! Conversion lsp_types types to rust-analyzer specific ones.
use std::convert::TryFrom;
use base_db::{FileId, FilePosition, FileRange};
use ide::{AssistKind, LineCol, LineIndex};
use ide_db::base_db::{FileId, FilePosition, FileRange};
use syntax::{TextRange, TextSize};
use vfs::AbsPathBuf;

View File

@ -5,10 +5,10 @@
use std::{sync::Arc, time::Instant};
use base_db::{CrateId, VfsPath};
use crossbeam_channel::{unbounded, Receiver, Sender};
use flycheck::FlycheckHandle;
use ide::{Analysis, AnalysisHost, Change, FileId};
use ide_db::base_db::{CrateId, VfsPath};
use lsp_types::{SemanticTokens, Url};
use parking_lot::{Mutex, RwLock};
use project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};

View File

@ -1,8 +1,8 @@
//! Utilities for LSP-related boilerplate code.
use std::{error::Error, ops::Range};
use base_db::Canceled;
use ide::LineIndex;
use ide_db::base_db::Canceled;
use lsp_server::Notification;
use crate::{from_proto, global_state::GlobalState};

View File

@ -5,10 +5,10 @@
time::{Duration, Instant},
};
use base_db::VfsPath;
use crossbeam_channel::{select, Receiver};
use ide::PrimeCachesProgress;
use ide::{Canceled, FileId};
use ide_db::base_db::VfsPath;
use lsp_server::{Connection, Notification, Request, Response};
use lsp_types::notification::Notification as _;
use project_model::ProjectWorkspace;

View File

@ -1,9 +1,9 @@
//! Project loading & configuration updates
use std::{mem, sync::Arc};
use base_db::{CrateGraph, SourceRoot, VfsPath};
use flycheck::{FlycheckConfig, FlycheckHandle};
use ide::Change;
use ide_db::base_db::{CrateGraph, SourceRoot, VfsPath};
use project_model::{ProcMacroClient, ProjectWorkspace};
use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};

View File

@ -4,13 +4,13 @@
sync::atomic::{AtomicU32, Ordering},
};
use base_db::{FileId, FileRange};
use ide::{
Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation,
FileSystemEdit, Fold, FoldKind, Highlight, HighlightModifier, HighlightTag, HighlightedRange,
Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget,
ReferenceAccess, ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit,
};
use ide_db::base_db::{FileId, FileRange};
use itertools::Itertools;
use syntax::{SyntaxKind, TextRange, TextSize};
@ -809,7 +809,7 @@ fn main() {
let completions: Vec<(String, Option<String>)> = analysis
.completions(
&ide::CompletionConfig::default(),
base_db::FilePosition { file_id, offset },
ide_db::base_db::FilePosition { file_id, offset },
)
.unwrap()
.unwrap()

View File

@ -16,7 +16,6 @@ itertools = "0.9.0"
text_edit = { path = "../text_edit", 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" }
hir = { path = "../hir", version = "0.0.0" }
test_utils = { path = "../test_utils", version = "0.0.0" }

View File

@ -73,8 +73,8 @@
pub use crate::errors::SsrError;
pub use crate::matching::Match;
use crate::matching::MatchFailureReason;
use base_db::{FileId, FilePosition, FileRange};
use hir::Semantics;
use ide_db::base_db::{FileId, FilePosition, FileRange};
use ide_db::source_change::SourceFileEdit;
use resolving::ResolvedRule;
use rustc_hash::FxHashMap;
@ -126,7 +126,7 @@ pub fn in_context(
/// Constructs an instance using the start of the first file in `db` as the lookup context.
pub fn at_first_file(db: &'db ide_db::RootDatabase) -> Result<MatchFinder<'db>, SsrError> {
use base_db::SourceDatabaseExt;
use ide_db::base_db::SourceDatabaseExt;
use ide_db::symbol_index::SymbolsDatabase;
if let Some(first_file_id) = db
.local_roots()
@ -160,7 +160,7 @@ pub fn add_rule(&mut self, rule: SsrRule) -> Result<(), SsrError> {
/// Finds matches for all added rules and returns edits for all found matches.
pub fn edits(&self) -> Vec<SourceFileEdit> {
use base_db::SourceDatabaseExt;
use ide_db::base_db::SourceDatabaseExt;
let mut matches_by_file = FxHashMap::default();
for m in self.matches().matches {
matches_by_file
@ -205,7 +205,7 @@ pub fn matches(&self) -> SsrMatches {
/// them, while recording reasons why they don't match. This API is useful for command
/// line-based debugging where providing a range is difficult.
pub fn debug_where_text_equal(&self, file_id: FileId, snippet: &str) -> Vec<MatchDebugInfo> {
use base_db::SourceDatabaseExt;
use ide_db::base_db::SourceDatabaseExt;
let file = self.sema.parse(file_id);
let mut res = Vec::new();
let file_text = self.sema.db.file_text(file_id);

View File

@ -6,8 +6,8 @@
resolving::{ResolvedPattern, ResolvedRule, UfcsCallInfo},
SsrMatches,
};
use base_db::FileRange;
use hir::Semantics;
use ide_db::base_db::FileRange;
use rustc_hash::FxHashMap;
use std::{cell::Cell, iter::Peekable};
use syntax::ast::{AstNode, AstToken};

View File

@ -2,7 +2,7 @@
use crate::errors::error;
use crate::{parsing, SsrError};
use base_db::FilePosition;
use ide_db::base_db::FilePosition;
use parsing::Placeholder;
use rustc_hash::FxHashMap;
use syntax::{ast, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken};

View File

@ -5,7 +5,7 @@
resolving::{ResolvedPath, ResolvedPattern, ResolvedRule},
Match, MatchFinder,
};
use base_db::{FileId, FileRange};
use ide_db::base_db::{FileId, FileRange};
use ide_db::{
defs::Definition,
search::{Reference, SearchScope},
@ -145,7 +145,7 @@ fn slow_scan(&self, rule: &ResolvedRule, matches_out: &mut Vec<Match>) {
fn search_files_do(&self, mut callback: impl FnMut(FileId)) {
if self.restrict_ranges.is_empty() {
// Unrestricted search.
use base_db::SourceDatabaseExt;
use ide_db::base_db::SourceDatabaseExt;
use ide_db::symbol_index::SymbolsDatabase;
for &root in self.sema.db.local_roots().iter() {
let sr = self.sema.db.source_root(root);

View File

@ -1,6 +1,6 @@
use crate::{MatchFinder, SsrRule};
use base_db::{salsa::Durability, FileId, FilePosition, FileRange, SourceDatabaseExt};
use expect_test::{expect, Expect};
use ide_db::base_db::{salsa::Durability, FileId, FilePosition, FileRange, SourceDatabaseExt};
use rustc_hash::FxHashSet;
use std::sync::Arc;
use test_utils::{mark, RangeOrOffset};
@ -62,7 +62,7 @@ fn parser_undefined_placeholder_in_replacement() {
/// `code` may optionally contain a cursor marker `<|>`. If it doesn't, then the position will be
/// the start of the file. If there's a second cursor marker, then we'll return a single range.
pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Vec<FileRange>) {
use base_db::fixture::WithFixture;
use ide_db::base_db::fixture::WithFixture;
use ide_db::symbol_index::SymbolsDatabase;
let (mut db, file_id, range_or_offset) = if code.contains(test_utils::CURSOR_MARKER) {
ide_db::RootDatabase::with_range_or_offset(code)
@ -83,7 +83,7 @@ pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Ve
}
}
let mut local_roots = FxHashSet::default();
local_roots.insert(base_db::fixture::WORKSPACE);
local_roots.insert(ide_db::base_db::fixture::WORKSPACE);
db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
(db, position, selections)
}

View File

@ -7,7 +7,7 @@
use parser::SyntaxKind;
use crate::{
ast::{self, support, AstNode, NameOwner, SyntaxNode},
ast::{self, support, token_ext::HasStringValue, AstNode, AstToken, NameOwner, SyntaxNode},
SmolStr, SyntaxElement, SyntaxToken, T,
};
@ -53,8 +53,16 @@ pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> {
pub fn as_simple_key_value(&self) -> Option<(SmolStr, SmolStr)> {
let lit = self.literal()?;
let key = self.simple_name()?;
// FIXME: escape? raw string?
let value = lit.syntax().first_token()?.text().trim_matches('"').into();
let value_token = lit.syntax().first_token()?;
let value: SmolStr = if let Some(s) = ast::String::cast(value_token.clone()) {
s.value()?.into()
} else if let Some(s) = ast::RawString::cast(value_token) {
s.value()?.into()
} else {
return None;
};
Some((key, value))
}