aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/Cargo.toml1
-rw-r--r--crates/assists/src/assist_context.rs2
-rw-r--r--crates/assists/src/handlers/add_missing_impl_members.rs3
-rw-r--r--crates/assists/src/handlers/extract_struct_from_enum_variant.rs2
-rw-r--r--crates/assists/src/handlers/fix_visibility.rs2
-rw-r--r--crates/assists/src/handlers/generate_function.rs2
-rw-r--r--crates/assists/src/handlers/remove_dbg.rs87
-rw-r--r--crates/assists/src/handlers/replace_if_let_with_match.rs6
-rw-r--r--crates/assists/src/handlers/replace_let_with_if_let.rs3
-rw-r--r--crates/assists/src/handlers/replace_unwrap_with_match.rs3
-rw-r--r--crates/assists/src/lib.rs2
-rw-r--r--crates/assists/src/tests.rs2
-rw-r--r--crates/assists/src/utils.rs121
-rw-r--r--crates/call_info/Cargo.toml26
-rw-r--r--crates/completion/Cargo.toml2
-rw-r--r--crates/completion/src/complete_mod.rs2
-rw-r--r--crates/completion/src/complete_postfix.rs2
-rw-r--r--crates/completion/src/complete_trait_impl.rs2
-rw-r--r--crates/completion/src/completion_context.rs5
-rw-r--r--crates/completion/src/lib.rs2
-rw-r--r--crates/completion/src/test_utils.rs2
-rw-r--r--crates/hir_ty/Cargo.toml6
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check/case_conv.rs249
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs17
-rw-r--r--crates/ide/Cargo.toml2
-rw-r--r--crates/ide/src/call_hierarchy.rs4
-rw-r--r--crates/ide/src/diagnostics.rs2
-rw-r--r--crates/ide/src/diagnostics/field_shorthand.rs2
-rw-r--r--crates/ide/src/diagnostics/fixes.rs2
-rw-r--r--crates/ide/src/display/navigation_target.rs2
-rw-r--r--crates/ide/src/fixture.rs2
-rw-r--r--crates/ide/src/goto_definition.rs2
-rw-r--r--crates/ide/src/goto_implementation.rs2
-rw-r--r--crates/ide/src/goto_type_definition.rs2
-rw-r--r--crates/ide/src/hover.rs31
-rw-r--r--crates/ide/src/lib.rs12
-rw-r--r--crates/ide/src/parent_module.rs2
-rw-r--r--crates/ide/src/prime_caches.rs2
-rw-r--r--crates/ide/src/references.rs2
-rw-r--r--crates/ide/src/references/rename.rs2
-rw-r--r--crates/ide/src/status.rs6
-rw-r--r--crates/ide/src/syntax_highlighting.rs9
-rw-r--r--crates/ide/src/syntax_highlighting/html.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/injection.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html3
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs3
-rw-r--r--crates/ide/src/syntax_tree.rs2
-rw-r--r--crates/ide/src/typing.rs2
-rw-r--r--crates/ide/src/typing/on_enter.rs2
-rw-r--r--crates/ide_db/Cargo.toml5
-rw-r--r--crates/ide_db/src/call_info.rs (renamed from crates/call_info/src/lib.rs)7
-rw-r--r--crates/ide_db/src/lib.rs6
-rw-r--r--crates/ide_db/src/traits.rs227
-rw-r--r--crates/ide_db/src/ty_filter.rs58
-rw-r--r--crates/rust-analyzer/Cargo.toml6
-rw-r--r--crates/rust-analyzer/src/bin/main.rs22
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs8
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs8
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs2
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs2
-rw-r--r--crates/rust-analyzer/src/cli/ssr.rs4
-rw-r--r--crates/rust-analyzer/src/from_proto.rs2
-rw-r--r--crates/rust-analyzer/src/global_state.rs2
-rw-r--r--crates/rust-analyzer/src/lsp_utils.rs2
-rw-r--r--crates/rust-analyzer/src/main_loop.rs2
-rw-r--r--crates/rust-analyzer/src/reload.rs2
-rw-r--r--crates/rust-analyzer/src/to_proto.rs4
-rw-r--r--crates/ssr/Cargo.toml1
-rw-r--r--crates/ssr/src/lib.rs8
-rw-r--r--crates/ssr/src/matching.rs2
-rw-r--r--crates/ssr/src/resolving.rs2
-rw-r--r--crates/ssr/src/search.rs4
-rw-r--r--crates/ssr/src/tests.rs6
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/ast/node_ext.rs14
75 files changed, 681 insertions, 382 deletions
diff --git a/crates/assists/Cargo.toml b/crates/assists/Cargo.toml
index 264125651..108f656e9 100644
--- a/crates/assists/Cargo.toml
+++ b/crates/assists/Cargo.toml
@@ -18,7 +18,6 @@ stdx = { path = "../stdx", version = "0.0.0" }
18syntax = { path = "../syntax", version = "0.0.0" } 18syntax = { path = "../syntax", version = "0.0.0" }
19text_edit = { path = "../text_edit", version = "0.0.0" } 19text_edit = { path = "../text_edit", version = "0.0.0" }
20profile = { path = "../profile", version = "0.0.0" } 20profile = { path = "../profile", version = "0.0.0" }
21base_db = { path = "../base_db", version = "0.0.0" }
22ide_db = { path = "../ide_db", version = "0.0.0" } 21ide_db = { path = "../ide_db", version = "0.0.0" }
23hir = { path = "../hir", version = "0.0.0" } 22hir = { path = "../hir", version = "0.0.0" }
24test_utils = { path = "../test_utils", version = "0.0.0" } 23test_utils = { path = "../test_utils", version = "0.0.0" }
diff --git a/crates/assists/src/assist_context.rs b/crates/assists/src/assist_context.rs
index bf520069e..d11fee196 100644
--- a/crates/assists/src/assist_context.rs
+++ b/crates/assists/src/assist_context.rs
@@ -3,8 +3,8 @@
3use std::mem; 3use std::mem;
4 4
5use algo::find_covering_element; 5use algo::find_covering_element;
6use base_db::{FileId, FileRange};
7use hir::Semantics; 6use hir::Semantics;
7use ide_db::base_db::{FileId, FileRange};
8use ide_db::{ 8use ide_db::{
9 label::Label, 9 label::Label,
10 source_change::{SourceChange, SourceFileEdit}, 10 source_change::{SourceChange, SourceFileEdit},
diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs
index 4c400f287..b82fb30ad 100644
--- a/crates/assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/assists/src/handlers/add_missing_impl_members.rs
@@ -1,4 +1,5 @@
1use hir::HasSource; 1use hir::HasSource;
2use ide_db::traits::{get_missing_assoc_items, resolve_target_trait};
2use syntax::{ 3use syntax::{
3 ast::{ 4 ast::{
4 self, 5 self,
@@ -11,7 +12,7 @@ use syntax::{
11use crate::{ 12use crate::{
12 assist_context::{AssistContext, Assists}, 13 assist_context::{AssistContext, Assists},
13 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, 14 ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams},
14 utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor}, 15 utils::{render_snippet, Cursor},
15 AssistId, AssistKind, 16 AssistId, AssistKind,
16}; 17};
17 18
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
index 7f4f80b23..48433feb9 100644
--- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -1,5 +1,5 @@
1use base_db::FileId;
2use hir::{EnumVariant, Module, ModuleDef, Name}; 1use hir::{EnumVariant, Module, ModuleDef, Name};
2use ide_db::base_db::FileId;
3use ide_db::{defs::Definition, search::Reference, RootDatabase}; 3use ide_db::{defs::Definition, search::Reference, RootDatabase};
4use itertools::Itertools; 4use itertools::Itertools;
5use rustc_hash::FxHashSet; 5use rustc_hash::FxHashSet;
diff --git a/crates/assists/src/handlers/fix_visibility.rs b/crates/assists/src/handlers/fix_visibility.rs
index 66f74150c..c86720787 100644
--- a/crates/assists/src/handlers/fix_visibility.rs
+++ b/crates/assists/src/handlers/fix_visibility.rs
@@ -1,5 +1,5 @@
1use base_db::FileId;
2use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution}; 1use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
2use ide_db::base_db::FileId;
3use syntax::{ 3use syntax::{
4 ast::{self, VisibilityOwner}, 4 ast::{self, VisibilityOwner},
5 AstNode, TextRange, TextSize, 5 AstNode, TextRange, TextSize,
diff --git a/crates/assists/src/handlers/generate_function.rs b/crates/assists/src/handlers/generate_function.rs
index d23f4293b..758188a42 100644
--- a/crates/assists/src/handlers/generate_function.rs
+++ b/crates/assists/src/handlers/generate_function.rs
@@ -1,5 +1,5 @@
1use base_db::FileId;
2use hir::HirDisplay; 1use hir::HirDisplay;
2use ide_db::base_db::FileId;
3use rustc_hash::{FxHashMap, FxHashSet}; 3use rustc_hash::{FxHashMap, FxHashSet};
4use syntax::{ 4use syntax::{
5 ast::{ 5 ast::{
diff --git a/crates/assists/src/handlers/remove_dbg.rs b/crates/assists/src/handlers/remove_dbg.rs
index e10616779..9731344b8 100644
--- a/crates/assists/src/handlers/remove_dbg.rs
+++ b/crates/assists/src/handlers/remove_dbg.rs
@@ -93,8 +93,9 @@ fn needs_parentheses_around_macro_contents(macro_contents: Vec<SyntaxElement>) -
93 if macro_contents.len() < 2 { 93 if macro_contents.len() < 2 {
94 return false; 94 return false;
95 } 95 }
96 let mut macro_contents = macro_contents.into_iter().peekable();
96 let mut unpaired_brackets_in_contents = Vec::new(); 97 let mut unpaired_brackets_in_contents = Vec::new();
97 for element in macro_contents { 98 while let Some(element) = macro_contents.next() {
98 match element.kind() { 99 match element.kind() {
99 T!['('] | T!['['] | T!['{'] => unpaired_brackets_in_contents.push(element), 100 T!['('] | T!['['] | T!['{'] => unpaired_brackets_in_contents.push(element),
100 T![')'] => { 101 T![')'] => {
@@ -118,8 +119,14 @@ fn needs_parentheses_around_macro_contents(macro_contents: Vec<SyntaxElement>) -
118 symbol_kind => { 119 symbol_kind => {
119 let symbol_not_in_bracket = unpaired_brackets_in_contents.is_empty(); 120 let symbol_not_in_bracket = unpaired_brackets_in_contents.is_empty();
120 if symbol_not_in_bracket 121 if symbol_not_in_bracket
121 && symbol_kind != SyntaxKind::COLON 122 && symbol_kind != SyntaxKind::COLON // paths
122 && symbol_kind.is_punct() 123 && (symbol_kind != SyntaxKind::DOT // field/method access
124 || macro_contents // range expressions consist of two SyntaxKind::Dot in macro invocations
125 .peek()
126 .map(|element| element.kind() == SyntaxKind::DOT)
127 .unwrap_or(false))
128 && symbol_kind != SyntaxKind::QUESTION // try operator
129 && (symbol_kind.is_punct() || symbol_kind == SyntaxKind::AS_KW)
123 { 130 {
124 return true; 131 return true;
125 } 132 }
@@ -243,6 +250,25 @@ fn main() {
243 } 250 }
244 251
245 #[test] 252 #[test]
253 fn test_remove_dbg_method_chaining() {
254 check_assist(
255 remove_dbg,
256 r#"let res = <|>dbg!(foo().bar()).baz();"#,
257 r#"let res = foo().bar().baz();"#,
258 );
259 check_assist(
260 remove_dbg,
261 r#"let res = <|>dbg!(foo.bar()).baz();"#,
262 r#"let res = foo.bar().baz();"#,
263 );
264 }
265
266 #[test]
267 fn test_remove_dbg_field_chaining() {
268 check_assist(remove_dbg, r#"let res = <|>dbg!(foo.bar).baz;"#, r#"let res = foo.bar.baz;"#);
269 }
270
271 #[test]
246 fn test_remove_dbg_from_inside_fn() { 272 fn test_remove_dbg_from_inside_fn() {
247 check_assist_target( 273 check_assist_target(
248 remove_dbg, 274 remove_dbg,
@@ -280,4 +306,59 @@ fn main() {
280}"#, 306}"#,
281 ); 307 );
282 } 308 }
309
310 #[test]
311 fn test_remove_dbg_try_expr() {
312 check_assist(
313 remove_dbg,
314 r#"let res = <|>dbg!(result?).foo();"#,
315 r#"let res = result?.foo();"#,
316 );
317 }
318
319 #[test]
320 fn test_remove_dbg_await_expr() {
321 check_assist(
322 remove_dbg,
323 r#"let res = <|>dbg!(fut.await).foo();"#,
324 r#"let res = fut.await.foo();"#,
325 );
326 }
327
328 #[test]
329 fn test_remove_dbg_as_cast() {
330 check_assist(
331 remove_dbg,
332 r#"let res = <|>dbg!(3 as usize).foo();"#,
333 r#"let res = (3 as usize).foo();"#,
334 );
335 }
336
337 #[test]
338 fn test_remove_dbg_index_expr() {
339 check_assist(
340 remove_dbg,
341 r#"let res = <|>dbg!(array[3]).foo();"#,
342 r#"let res = array[3].foo();"#,
343 );
344 check_assist(
345 remove_dbg,
346 r#"let res = <|>dbg!(tuple.3).foo();"#,
347 r#"let res = tuple.3.foo();"#,
348 );
349 }
350
351 #[test]
352 fn test_remove_dbg_range_expr() {
353 check_assist(
354 remove_dbg,
355 r#"let res = <|>dbg!(foo..bar).foo();"#,
356 r#"let res = (foo..bar).foo();"#,
357 );
358 check_assist(
359 remove_dbg,
360 r#"let res = <|>dbg!(foo..=bar).foo();"#,
361 r#"let res = (foo..=bar).foo();"#,
362 );
363 }
283} 364}
diff --git a/crates/assists/src/handlers/replace_if_let_with_match.rs b/crates/assists/src/handlers/replace_if_let_with_match.rs
index 79097621e..9a49c48c1 100644
--- a/crates/assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/assists/src/handlers/replace_if_let_with_match.rs
@@ -7,10 +7,8 @@ use syntax::{
7 AstNode, 7 AstNode,
8}; 8};
9 9
10use crate::{ 10use crate::{utils::unwrap_trivial_block, AssistContext, AssistId, AssistKind, Assists};
11 utils::{unwrap_trivial_block, TryEnum}, 11use ide_db::ty_filter::TryEnum;
12 AssistContext, AssistId, AssistKind, Assists,
13};
14 12
15// Assist: replace_if_let_with_match 13// Assist: replace_if_let_with_match
16// 14//
diff --git a/crates/assists/src/handlers/replace_let_with_if_let.rs b/crates/assists/src/handlers/replace_let_with_if_let.rs
index ed6d0c29b..a5bcbda24 100644
--- a/crates/assists/src/handlers/replace_let_with_if_let.rs
+++ b/crates/assists/src/handlers/replace_let_with_if_let.rs
@@ -9,7 +9,8 @@ use syntax::{
9 AstNode, T, 9 AstNode, T,
10}; 10};
11 11
12use crate::{utils::TryEnum, AssistContext, AssistId, AssistKind, Assists}; 12use crate::{AssistContext, AssistId, AssistKind, Assists};
13use ide_db::ty_filter::TryEnum;
13 14
14// Assist: replace_let_with_if_let 15// Assist: replace_let_with_if_let
15// 16//
diff --git a/crates/assists/src/handlers/replace_unwrap_with_match.rs b/crates/assists/src/handlers/replace_unwrap_with_match.rs
index 4043c219c..f547066f0 100644
--- a/crates/assists/src/handlers/replace_unwrap_with_match.rs
+++ b/crates/assists/src/handlers/replace_unwrap_with_match.rs
@@ -10,9 +10,10 @@ use syntax::{
10}; 10};
11 11
12use crate::{ 12use crate::{
13 utils::{render_snippet, Cursor, TryEnum}, 13 utils::{render_snippet, Cursor},
14 AssistContext, AssistId, AssistKind, Assists, 14 AssistContext, AssistId, AssistKind, Assists,
15}; 15};
16use ide_db::ty_filter::TryEnum;
16 17
17// Assist: replace_unwrap_with_match 18// Assist: replace_unwrap_with_match
18// 19//
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index 8a664f654..70a651e10 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -17,8 +17,8 @@ mod tests;
17pub mod utils; 17pub mod utils;
18pub mod ast_transform; 18pub mod ast_transform;
19 19
20use base_db::FileRange;
21use hir::Semantics; 20use hir::Semantics;
21use ide_db::base_db::FileRange;
22use ide_db::{label::Label, source_change::SourceChange, RootDatabase}; 22use ide_db::{label::Label, source_change::SourceChange, RootDatabase};
23use syntax::TextRange; 23use syntax::TextRange;
24 24
diff --git a/crates/assists/src/tests.rs b/crates/assists/src/tests.rs
index 2b687decf..849d85e76 100644
--- a/crates/assists/src/tests.rs
+++ b/crates/assists/src/tests.rs
@@ -1,7 +1,7 @@
1mod generated; 1mod generated;
2 2
3use base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
4use hir::Semantics; 3use hir::Semantics;
4use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
5use ide_db::RootDatabase; 5use ide_db::RootDatabase;
6use syntax::TextRange; 6use syntax::TextRange;
7use test_utils::{assert_eq_text, extract_offset, extract_range}; 7use test_utils::{assert_eq_text, extract_offset, extract_range};
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index 1a6b48b45..56f925ee6 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -2,14 +2,13 @@
2pub(crate) mod insert_use; 2pub(crate) mod insert_use;
3pub(crate) mod import_assets; 3pub(crate) mod import_assets;
4 4
5use std::{iter, ops}; 5use std::ops;
6 6
7use hir::{Adt, Crate, Enum, Module, ScopeDef, Semantics, Trait, Type}; 7use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait};
8use ide_db::RootDatabase; 8use ide_db::RootDatabase;
9use itertools::Itertools; 9use itertools::Itertools;
10use rustc_hash::FxHashSet;
11use syntax::{ 10use syntax::{
12 ast::{self, make, ArgListOwner, NameOwner}, 11 ast::{self, make, ArgListOwner},
13 AstNode, Direction, 12 AstNode, Direction,
14 SyntaxKind::*, 13 SyntaxKind::*,
15 SyntaxNode, TextSize, T, 14 SyntaxNode, TextSize, T,
@@ -115,72 +114,6 @@ pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor
115 } 114 }
116} 115}
117 116
118pub fn get_missing_assoc_items(
119 sema: &Semantics<RootDatabase>,
120 impl_def: &ast::Impl,
121) -> Vec<hir::AssocItem> {
122 // Names must be unique between constants and functions. However, type aliases
123 // may share the same name as a function or constant.
124 let mut impl_fns_consts = FxHashSet::default();
125 let mut impl_type = FxHashSet::default();
126
127 if let Some(item_list) = impl_def.assoc_item_list() {
128 for item in item_list.assoc_items() {
129 match item {
130 ast::AssocItem::Fn(f) => {
131 if let Some(n) = f.name() {
132 impl_fns_consts.insert(n.syntax().to_string());
133 }
134 }
135
136 ast::AssocItem::TypeAlias(t) => {
137 if let Some(n) = t.name() {
138 impl_type.insert(n.syntax().to_string());
139 }
140 }
141
142 ast::AssocItem::Const(c) => {
143 if let Some(n) = c.name() {
144 impl_fns_consts.insert(n.syntax().to_string());
145 }
146 }
147 ast::AssocItem::MacroCall(_) => (),
148 }
149 }
150 }
151
152 resolve_target_trait(sema, impl_def).map_or(vec![], |target_trait| {
153 target_trait
154 .items(sema.db)
155 .iter()
156 .filter(|i| match i {
157 hir::AssocItem::Function(f) => {
158 !impl_fns_consts.contains(&f.name(sema.db).to_string())
159 }
160 hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db).to_string()),
161 hir::AssocItem::Const(c) => c
162 .name(sema.db)
163 .map(|n| !impl_fns_consts.contains(&n.to_string()))
164 .unwrap_or_default(),
165 })
166 .cloned()
167 .collect()
168 })
169}
170
171pub(crate) fn resolve_target_trait(
172 sema: &Semantics<RootDatabase>,
173 impl_def: &ast::Impl,
174) -> Option<hir::Trait> {
175 let ast_path =
176 impl_def.trait_().map(|it| it.syntax().clone()).and_then(ast::PathType::cast)?.path()?;
177
178 match sema.resolve_path(&ast_path) {
179 Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def),
180 _ => None,
181 }
182}
183
184pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize { 117pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
185 node.children_with_tokens() 118 node.children_with_tokens()
186 .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR)) 119 .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
@@ -223,54 +156,6 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
223 } 156 }
224} 157}
225 158
226#[derive(Clone, Copy)]
227pub enum TryEnum {
228 Result,
229 Option,
230}
231
232impl TryEnum {
233 const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
234
235 pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> {
236 let enum_ = match ty.as_adt() {
237 Some(Adt::Enum(it)) => it,
238 _ => return None,
239 };
240 TryEnum::ALL.iter().find_map(|&var| {
241 if &enum_.name(sema.db).to_string() == var.type_name() {
242 return Some(var);
243 }
244 None
245 })
246 }
247
248 pub(crate) fn happy_case(self) -> &'static str {
249 match self {
250 TryEnum::Result => "Ok",
251 TryEnum::Option => "Some",
252 }
253 }
254
255 pub(crate) fn sad_pattern(self) -> ast::Pat {
256 match self {
257 TryEnum::Result => make::tuple_struct_pat(
258 make::path_unqualified(make::path_segment(make::name_ref("Err"))),
259 iter::once(make::wildcard_pat().into()),
260 )
261 .into(),
262 TryEnum::Option => make::ident_pat(make::name("None")).into(),
263 }
264 }
265
266 fn type_name(self) -> &'static str {
267 match self {
268 TryEnum::Result => "Result",
269 TryEnum::Option => "Option",
270 }
271 }
272}
273
274/// Helps with finding well-know things inside the standard library. This is 159/// Helps with finding well-know things inside the standard library. This is
275/// somewhat similar to the known paths infra inside hir, but it different; We 160/// somewhat similar to the known paths infra inside hir, but it different; We
276/// want to make sure that IDE specific paths don't become interesting inside 161/// want to make sure that IDE specific paths don't become interesting inside
diff --git a/crates/call_info/Cargo.toml b/crates/call_info/Cargo.toml
deleted file mode 100644
index 98c0bd6db..000000000
--- a/crates/call_info/Cargo.toml
+++ /dev/null
@@ -1,26 +0,0 @@
1[package]
2name = "call_info"
3version = "0.0.0"
4description = "TBD"
5license = "MIT OR Apache-2.0"
6authors = ["rust-analyzer developers"]
7edition = "2018"
8
9[lib]
10doctest = false
11
12[dependencies]
13either = "1.5.3"
14
15stdx = { path = "../stdx", version = "0.0.0" }
16syntax = { path = "../syntax", version = "0.0.0" }
17base_db = { path = "../base_db", version = "0.0.0" }
18ide_db = { path = "../ide_db", version = "0.0.0" }
19test_utils = { path = "../test_utils", version = "0.0.0" }
20
21# call_info crate should depend only on the top-level `hir` package. if you need
22# something from some `hir_xxx` subpackage, reexport the API via `hir`.
23hir = { path = "../hir", version = "0.0.0" }
24
25[dev-dependencies]
26expect-test = "1.0"
diff --git a/crates/completion/Cargo.toml b/crates/completion/Cargo.toml
index 25192456a..b79ee33f7 100644
--- a/crates/completion/Cargo.toml
+++ b/crates/completion/Cargo.toml
@@ -21,8 +21,6 @@ base_db = { path = "../base_db", version = "0.0.0" }
21ide_db = { path = "../ide_db", version = "0.0.0" } 21ide_db = { path = "../ide_db", version = "0.0.0" }
22profile = { path = "../profile", version = "0.0.0" } 22profile = { path = "../profile", version = "0.0.0" }
23test_utils = { path = "../test_utils", version = "0.0.0" } 23test_utils = { path = "../test_utils", version = "0.0.0" }
24assists = { path = "../assists", version = "0.0.0" }
25call_info = { path = "../call_info", version = "0.0.0" }
26 24
27# completions crate should depend only on the top-level `hir` package. if you need 25# completions crate should depend only on the top-level `hir` package. if you need
28# something from some `hir_xxx` subpackage, reexport the API via `hir`. 26# something from some `hir_xxx` subpackage, reexport the API via `hir`.
diff --git a/crates/completion/src/complete_mod.rs b/crates/completion/src/complete_mod.rs
index 35a57aba3..385911afa 100644
--- a/crates/completion/src/complete_mod.rs
+++ b/crates/completion/src/complete_mod.rs
@@ -1,7 +1,7 @@
1//! Completes mod declarations. 1//! Completes mod declarations.
2 2
3use base_db::{SourceDatabaseExt, VfsPath};
4use hir::{Module, ModuleSource}; 3use hir::{Module, ModuleSource};
4use ide_db::base_db::{SourceDatabaseExt, VfsPath};
5use ide_db::RootDatabase; 5use ide_db::RootDatabase;
6use rustc_hash::FxHashSet; 6use rustc_hash::FxHashSet;
7 7
diff --git a/crates/completion/src/complete_postfix.rs b/crates/completion/src/complete_postfix.rs
index 700573cf2..2622f12ab 100644
--- a/crates/completion/src/complete_postfix.rs
+++ b/crates/completion/src/complete_postfix.rs
@@ -2,7 +2,7 @@
2 2
3mod format_like; 3mod format_like;
4 4
5use assists::utils::TryEnum; 5use ide_db::ty_filter::TryEnum;
6use syntax::{ 6use syntax::{
7 ast::{self, AstNode, AstToken}, 7 ast::{self, AstNode, AstToken},
8 TextRange, TextSize, 8 TextRange, TextSize,
diff --git a/crates/completion/src/complete_trait_impl.rs b/crates/completion/src/complete_trait_impl.rs
index c06af99e2..a14be9c73 100644
--- a/crates/completion/src/complete_trait_impl.rs
+++ b/crates/completion/src/complete_trait_impl.rs
@@ -31,8 +31,8 @@
31//! } 31//! }
32//! ``` 32//! ```
33 33
34use assists::utils::get_missing_assoc_items;
35use hir::{self, HasAttrs, HasSource}; 34use hir::{self, HasAttrs, HasSource};
35use ide_db::traits::get_missing_assoc_items;
36use syntax::{ 36use syntax::{
37 ast::{self, edit, Impl}, 37 ast::{self, edit, Impl},
38 display::function_declaration, 38 display::function_declaration,
diff --git a/crates/completion/src/completion_context.rs b/crates/completion/src/completion_context.rs
index e4f86d0e0..dca304a8f 100644
--- a/crates/completion/src/completion_context.rs
+++ b/crates/completion/src/completion_context.rs
@@ -1,9 +1,8 @@
1//! See `CompletionContext` structure. 1//! See `CompletionContext` structure.
2 2
3use base_db::{FilePosition, SourceDatabase};
4use call_info::ActiveParameter;
5use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type}; 3use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type};
6use ide_db::RootDatabase; 4use ide_db::base_db::{FilePosition, SourceDatabase};
5use ide_db::{call_info::ActiveParameter, RootDatabase};
7use syntax::{ 6use syntax::{
8 algo::{find_covering_element, find_node_at_offset}, 7 algo::{find_covering_element, find_node_at_offset},
9 ast, match_ast, AstNode, NodeOrToken, 8 ast, match_ast, AstNode, NodeOrToken,
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs
index 0a60ea7f2..b72fd249d 100644
--- a/crates/completion/src/lib.rs
+++ b/crates/completion/src/lib.rs
@@ -23,7 +23,7 @@ mod complete_macro_in_item_position;
23mod complete_trait_impl; 23mod complete_trait_impl;
24mod complete_mod; 24mod complete_mod;
25 25
26use base_db::FilePosition; 26use ide_db::base_db::FilePosition;
27use ide_db::RootDatabase; 27use ide_db::RootDatabase;
28 28
29use crate::{ 29use crate::{
diff --git a/crates/completion/src/test_utils.rs b/crates/completion/src/test_utils.rs
index f2cf2561f..b02556797 100644
--- a/crates/completion/src/test_utils.rs
+++ b/crates/completion/src/test_utils.rs
@@ -1,7 +1,7 @@
1//! Runs completion for testing purposes. 1//! Runs completion for testing purposes.
2 2
3use base_db::{fixture::ChangeFixture, FileLoader, FilePosition};
4use hir::Semantics; 3use hir::Semantics;
4use ide_db::base_db::{fixture::ChangeFixture, FileLoader, FilePosition};
5use ide_db::RootDatabase; 5use ide_db::RootDatabase;
6use itertools::Itertools; 6use itertools::Itertools;
7use stdx::{format_to, trim_indent}; 7use stdx::{format_to, trim_indent};
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index e9c62c6aa..367a1b98d 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -17,9 +17,9 @@ ena = "0.14.0"
17log = "0.4.8" 17log = "0.4.8"
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19scoped-tls = "1" 19scoped-tls = "1"
20chalk-solve = "0.33" 20chalk-solve = { version = "0.34", default-features = false }
21chalk-ir = "0.33" 21chalk-ir = "0.34"
22chalk-recursive = "0.33" 22chalk-recursive = "0.34"
23 23
24stdx = { path = "../stdx", version = "0.0.0" } 24stdx = { path = "../stdx", version = "0.0.0" }
25hir_def = { path = "../hir_def", version = "0.0.0" } 25hir_def = { path = "../hir_def", version = "0.0.0" }
diff --git a/crates/hir_ty/src/diagnostics/decl_check/case_conv.rs b/crates/hir_ty/src/diagnostics/decl_check/case_conv.rs
index 324d60765..b0144a289 100644
--- a/crates/hir_ty/src/diagnostics/decl_check/case_conv.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check/case_conv.rs
@@ -1,156 +1,145 @@
1//! Functions for string case manipulation, such as detecting the identifier case, 1//! Functions for string case manipulation, such as detecting the identifier case,
2//! and converting it into appropriate form. 2//! and converting it into appropriate form.
3 3
4#[derive(Debug)] 4// Code that was taken from rustc was taken at commit 89fdb30,
5enum DetectedCase { 5// from file /compiler/rustc_lint/src/nonstandard_style.rs
6 LowerCamelCase,
7 UpperCamelCase,
8 LowerSnakeCase,
9 UpperSnakeCase,
10 Unknown,
11}
12
13fn detect_case(ident: &str) -> DetectedCase {
14 let trimmed_ident = ident.trim_matches('_');
15 let first_lowercase = trimmed_ident.starts_with(|chr: char| chr.is_ascii_lowercase());
16 let mut has_lowercase = first_lowercase;
17 let mut has_uppercase = false;
18 let mut has_underscore = false;
19
20 for chr in trimmed_ident.chars() {
21 if chr == '_' {
22 has_underscore = true;
23 } else if chr.is_ascii_uppercase() {
24 has_uppercase = true;
25 } else if chr.is_ascii_lowercase() {
26 has_lowercase = true;
27 }
28 }
29
30 if has_uppercase {
31 if !has_lowercase {
32 if has_underscore {
33 DetectedCase::UpperSnakeCase
34 } else {
35 // It has uppercase only and no underscores. Ex: "AABB"
36 // This is a camel cased acronym.
37 DetectedCase::UpperCamelCase
38 }
39 } else if !has_underscore {
40 if first_lowercase {
41 DetectedCase::LowerCamelCase
42 } else {
43 DetectedCase::UpperCamelCase
44 }
45 } else {
46 // It has uppercase, it has lowercase, it has underscore.
47 // No assumptions here
48 DetectedCase::Unknown
49 }
50 } else {
51 DetectedCase::LowerSnakeCase
52 }
53}
54 6
55/// Converts an identifier to an UpperCamelCase form. 7/// Converts an identifier to an UpperCamelCase form.
56/// Returns `None` if the string is already is UpperCamelCase. 8/// Returns `None` if the string is already is UpperCamelCase.
57pub fn to_camel_case(ident: &str) -> Option<String> { 9pub fn to_camel_case(ident: &str) -> Option<String> {
58 let detected_case = detect_case(ident); 10 if is_camel_case(ident) {
59 11 return None;
60 match detected_case {
61 DetectedCase::UpperCamelCase => return None,
62 DetectedCase::LowerCamelCase => {
63 let mut first_capitalized = false;
64 let output = ident
65 .chars()
66 .map(|chr| {
67 if !first_capitalized && chr.is_ascii_lowercase() {
68 first_capitalized = true;
69 chr.to_ascii_uppercase()
70 } else {
71 chr
72 }
73 })
74 .collect();
75 return Some(output);
76 }
77 _ => {}
78 } 12 }
79 13
80 let mut output = String::with_capacity(ident.len()); 14 // Taken from rustc.
81 15 let ret = ident
82 let mut capital_added = false; 16 .trim_matches('_')
83 for chr in ident.chars() { 17 .split('_')
84 if chr.is_alphabetic() { 18 .filter(|component| !component.is_empty())
85 if !capital_added { 19 .map(|component| {
86 output.push(chr.to_ascii_uppercase()); 20 let mut camel_cased_component = String::new();
87 capital_added = true; 21
88 } else { 22 let mut new_word = true;
89 output.push(chr.to_ascii_lowercase()); 23 let mut prev_is_lower_case = true;
24
25 for c in component.chars() {
26 // Preserve the case if an uppercase letter follows a lowercase letter, so that
27 // `camelCase` is converted to `CamelCase`.
28 if prev_is_lower_case && c.is_uppercase() {
29 new_word = true;
30 }
31
32 if new_word {
33 camel_cased_component.push_str(&c.to_uppercase().to_string());
34 } else {
35 camel_cased_component.push_str(&c.to_lowercase().to_string());
36 }
37
38 prev_is_lower_case = c.is_lowercase();
39 new_word = false;
90 } 40 }
91 } else if chr == '_' {
92 // Skip this character and make the next one capital.
93 capital_added = false;
94 } else {
95 // Put the characted as-is.
96 output.push(chr);
97 }
98 }
99 41
100 if output == ident { 42 camel_cased_component
101 // While we didn't detect the correct case at the beginning, there 43 })
102 // may be special cases: e.g. `A` is both valid CamelCase and UPPER_SNAKE_CASE. 44 .fold((String::new(), None), |(acc, prev): (String, Option<String>), next| {
103 None 45 // separate two components with an underscore if their boundary cannot
104 } else { 46 // be distinguished using a uppercase/lowercase case distinction
105 Some(output) 47 let join = if let Some(prev) = prev {
106 } 48 let l = prev.chars().last().unwrap();
49 let f = next.chars().next().unwrap();
50 !char_has_case(l) && !char_has_case(f)
51 } else {
52 false
53 };
54 (acc + if join { "_" } else { "" } + &next, Some(next))
55 })
56 .0;
57 Some(ret)
107} 58}
108 59
109/// Converts an identifier to a lower_snake_case form. 60/// Converts an identifier to a lower_snake_case form.
110/// Returns `None` if the string is already in lower_snake_case. 61/// Returns `None` if the string is already in lower_snake_case.
111pub fn to_lower_snake_case(ident: &str) -> Option<String> { 62pub fn to_lower_snake_case(ident: &str) -> Option<String> {
112 // First, assume that it's UPPER_SNAKE_CASE. 63 if is_lower_snake_case(ident) {
113 match detect_case(ident) { 64 return None;
114 DetectedCase::LowerSnakeCase => return None, 65 } else if is_upper_snake_case(ident) {
115 DetectedCase::UpperSnakeCase => { 66 return Some(ident.to_lowercase());
116 return Some(ident.chars().map(|chr| chr.to_ascii_lowercase()).collect())
117 }
118 _ => {}
119 } 67 }
120 68
121 // Otherwise, assume that it's CamelCase. 69 Some(stdx::to_lower_snake_case(ident))
122 let lower_snake_case = stdx::to_lower_snake_case(ident);
123
124 if lower_snake_case == ident {
125 // While we didn't detect the correct case at the beginning, there
126 // may be special cases: e.g. `a` is both valid camelCase and snake_case.
127 None
128 } else {
129 Some(lower_snake_case)
130 }
131} 70}
132 71
133/// Converts an identifier to an UPPER_SNAKE_CASE form. 72/// Converts an identifier to an UPPER_SNAKE_CASE form.
134/// Returns `None` if the string is already is UPPER_SNAKE_CASE. 73/// Returns `None` if the string is already is UPPER_SNAKE_CASE.
135pub fn to_upper_snake_case(ident: &str) -> Option<String> { 74pub fn to_upper_snake_case(ident: &str) -> Option<String> {
136 match detect_case(ident) { 75 if is_upper_snake_case(ident) {
137 DetectedCase::UpperSnakeCase => return None, 76 return None;
138 DetectedCase::LowerSnakeCase => { 77 } else if is_lower_snake_case(ident) {
139 return Some(ident.chars().map(|chr| chr.to_ascii_uppercase()).collect()) 78 return Some(ident.to_uppercase());
140 } 79 }
141 _ => {} 80
81 Some(stdx::to_upper_snake_case(ident))
82}
83
84// Taken from rustc.
85// Modified by replacing the use of unstable feature `array_windows`.
86fn is_camel_case(name: &str) -> bool {
87 let name = name.trim_matches('_');
88 if name.is_empty() {
89 return true;
142 } 90 }
143 91
144 // Normalize the string from whatever form it's in currently, and then just make it uppercase. 92 let mut fst = None;
145 let upper_snake_case = stdx::to_upper_snake_case(ident); 93 // start with a non-lowercase letter rather than non-uppercase
94 // ones (some scripts don't have a concept of upper/lowercase)
95 !name.chars().next().unwrap().is_lowercase()
96 && !name.contains("__")
97 && !name.chars().any(|snd| {
98 let ret = match (fst, snd) {
99 (None, _) => false,
100 (Some(fst), snd) => {
101 char_has_case(fst) && snd == '_' || char_has_case(snd) && fst == '_'
102 }
103 };
104 fst = Some(snd);
105
106 ret
107 })
108}
109
110fn is_lower_snake_case(ident: &str) -> bool {
111 is_snake_case(ident, char::is_uppercase)
112}
146 113
147 if upper_snake_case == ident { 114fn is_upper_snake_case(ident: &str) -> bool {
148 // While we didn't detect the correct case at the beginning, there 115 is_snake_case(ident, char::is_lowercase)
149 // may be special cases: e.g. `A` is both valid CamelCase and UPPER_SNAKE_CASE. 116}
150 None 117
151 } else { 118// Taken from rustc.
152 Some(upper_snake_case) 119// Modified to allow checking for both upper and lower snake case.
120fn is_snake_case<F: Fn(char) -> bool>(ident: &str, wrong_case: F) -> bool {
121 if ident.is_empty() {
122 return true;
153 } 123 }
124 let ident = ident.trim_matches('_');
125
126 let mut allow_underscore = true;
127 ident.chars().all(|c| {
128 allow_underscore = match c {
129 '_' if !allow_underscore => return false,
130 '_' => false,
131 // It would be more obvious to check for the correct case,
132 // but some characters do not have a case.
133 c if !wrong_case(c) => true,
134 _ => return false,
135 };
136 true
137 })
138}
139
140// Taken from rustc.
141fn char_has_case(c: char) -> bool {
142 c.is_lowercase() || c.is_uppercase()
154} 143}
155 144
156#[cfg(test)] 145#[cfg(test)]
@@ -173,6 +162,7 @@ mod tests {
173 check(to_lower_snake_case, "CamelCase", expect![["camel_case"]]); 162 check(to_lower_snake_case, "CamelCase", expect![["camel_case"]]);
174 check(to_lower_snake_case, "lowerCamelCase", expect![["lower_camel_case"]]); 163 check(to_lower_snake_case, "lowerCamelCase", expect![["lower_camel_case"]]);
175 check(to_lower_snake_case, "a", expect![[""]]); 164 check(to_lower_snake_case, "a", expect![[""]]);
165 check(to_lower_snake_case, "abc", expect![[""]]);
176 } 166 }
177 167
178 #[test] 168 #[test]
@@ -187,6 +177,11 @@ mod tests {
187 check(to_camel_case, "name", expect![["Name"]]); 177 check(to_camel_case, "name", expect![["Name"]]);
188 check(to_camel_case, "A", expect![[""]]); 178 check(to_camel_case, "A", expect![[""]]);
189 check(to_camel_case, "AABB", expect![[""]]); 179 check(to_camel_case, "AABB", expect![[""]]);
180 // Taken from rustc: /compiler/rustc_lint/src/nonstandard_style/tests.rs
181 check(to_camel_case, "X86_64", expect![[""]]);
182 check(to_camel_case, "x86__64", expect![["X86_64"]]);
183 check(to_camel_case, "Abc_123", expect![["Abc123"]]);
184 check(to_camel_case, "A1_b2_c3", expect![["A1B2C3"]]);
190 } 185 }
191 186
192 #[test] 187 #[test]
@@ -197,5 +192,7 @@ mod tests {
197 check(to_upper_snake_case, "CamelCase", expect![["CAMEL_CASE"]]); 192 check(to_upper_snake_case, "CamelCase", expect![["CAMEL_CASE"]]);
198 check(to_upper_snake_case, "lowerCamelCase", expect![["LOWER_CAMEL_CASE"]]); 193 check(to_upper_snake_case, "lowerCamelCase", expect![["LOWER_CAMEL_CASE"]]);
199 check(to_upper_snake_case, "A", expect![[""]]); 194 check(to_upper_snake_case, "A", expect![[""]]);
195 check(to_upper_snake_case, "ABC", expect![[""]]);
196 check(to_upper_snake_case, "X86_64", expect![[""]]);
200 } 197 }
201} 198}
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
index be3301313..dd7affcec 100644
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/hir_ty/src/traits/chalk/mapping.rs
@@ -4,8 +4,8 @@
4//! conversions. 4//! conversions.
5 5
6use chalk_ir::{ 6use chalk_ir::{
7 cast::Cast, fold::shift::Shift, interner::HasInterner, PlaceholderIndex, Scalar, TypeName, 7 cast::Cast, fold::shift::Shift, interner::HasInterner, LifetimeData, PlaceholderIndex, Scalar,
8 UniverseIndex, 8 TypeName, UniverseIndex,
9}; 9};
10use chalk_solve::rust_ir; 10use chalk_solve::rust_ir;
11 11
@@ -76,7 +76,7 @@ impl ToChalk for Ty {
76 ); 76 );
77 let bounded_ty = chalk_ir::DynTy { 77 let bounded_ty = chalk_ir::DynTy {
78 bounds: make_binders(where_clauses, 1), 78 bounds: make_binders(where_clauses, 1),
79 lifetime: FAKE_PLACEHOLDER.to_lifetime(&Interner), 79 lifetime: LifetimeData::Static.intern(&Interner),
80 }; 80 };
81 chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner) 81 chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner)
82 } 82 }
@@ -161,9 +161,6 @@ impl ToChalk for Ty {
161 } 161 }
162} 162}
163 163
164const FAKE_PLACEHOLDER: PlaceholderIndex =
165 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::MAX };
166
167/// We currently don't model lifetimes, but Chalk does. So, we have to insert a 164/// We currently don't model lifetimes, but Chalk does. So, we have to insert a
168/// fake lifetime here, because Chalks built-in logic may expect it to be there. 165/// fake lifetime here, because Chalks built-in logic may expect it to be there.
169fn ref_to_chalk( 166fn ref_to_chalk(
@@ -172,7 +169,7 @@ fn ref_to_chalk(
172 subst: Substs, 169 subst: Substs,
173) -> chalk_ir::Ty<Interner> { 170) -> chalk_ir::Ty<Interner> {
174 let arg = subst[0].clone().to_chalk(db); 171 let arg = subst[0].clone().to_chalk(db);
175 let lifetime = FAKE_PLACEHOLDER.to_lifetime(&Interner); 172 let lifetime = LifetimeData::Static.intern(&Interner);
176 chalk_ir::ApplicationTy { 173 chalk_ir::ApplicationTy {
177 name: TypeName::Ref(mutability.to_chalk(db)), 174 name: TypeName::Ref(mutability.to_chalk(db)),
178 substitution: chalk_ir::Substitution::from_iter( 175 substitution: chalk_ir::Substitution::from_iter(
@@ -205,7 +202,11 @@ fn array_to_chalk(db: &dyn HirDatabase, subst: Substs) -> chalk_ir::Ty<Interner>
205 substitution: chalk_ir::Substitution::empty(&Interner), 202 substitution: chalk_ir::Substitution::empty(&Interner),
206 } 203 }
207 .intern(&Interner); 204 .intern(&Interner);
208 let const_ = FAKE_PLACEHOLDER.to_const(&Interner, usize_ty); 205 let const_ = chalk_ir::ConstData {
206 ty: usize_ty,
207 value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: () }),
208 }
209 .intern(&Interner);
209 chalk_ir::ApplicationTy { 210 chalk_ir::ApplicationTy {
210 name: TypeName::Array, 211 name: TypeName::Array,
211 substitution: chalk_ir::Substitution::from_iter( 212 substitution: chalk_ir::Substitution::from_iter(
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index 76b52fa04..4d483580d 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -23,14 +23,12 @@ url = "2.1.1"
23stdx = { path = "../stdx", version = "0.0.0" } 23stdx = { path = "../stdx", version = "0.0.0" }
24syntax = { path = "../syntax", version = "0.0.0" } 24syntax = { path = "../syntax", version = "0.0.0" }
25text_edit = { path = "../text_edit", version = "0.0.0" } 25text_edit = { path = "../text_edit", version = "0.0.0" }
26base_db = { path = "../base_db", version = "0.0.0" }
27ide_db = { path = "../ide_db", version = "0.0.0" } 26ide_db = { path = "../ide_db", version = "0.0.0" }
28cfg = { path = "../cfg", version = "0.0.0" } 27cfg = { path = "../cfg", version = "0.0.0" }
29profile = { path = "../profile", version = "0.0.0" } 28profile = { path = "../profile", version = "0.0.0" }
30test_utils = { path = "../test_utils", version = "0.0.0" } 29test_utils = { path = "../test_utils", version = "0.0.0" }
31assists = { path = "../assists", version = "0.0.0" } 30assists = { path = "../assists", version = "0.0.0" }
32ssr = { path = "../ssr", version = "0.0.0" } 31ssr = { path = "../ssr", version = "0.0.0" }
33call_info = { path = "../call_info", version = "0.0.0" }
34completion = { path = "../completion", version = "0.0.0" } 32completion = { path = "../completion", version = "0.0.0" }
35 33
36# ide should depend only on the top-level `hir` package. if you need 34# ide should depend only on the top-level `hir` package. if you need
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs
index 9d6433fe0..8ad50a2ee 100644
--- a/crates/ide/src/call_hierarchy.rs
+++ b/crates/ide/src/call_hierarchy.rs
@@ -2,8 +2,8 @@
2 2
3use indexmap::IndexMap; 3use indexmap::IndexMap;
4 4
5use call_info::FnCallNode;
6use hir::Semantics; 5use hir::Semantics;
6use ide_db::call_info::FnCallNode;
7use ide_db::RootDatabase; 7use ide_db::RootDatabase;
8use syntax::{ast, match_ast, AstNode, TextRange}; 8use syntax::{ast, match_ast, AstNode, TextRange};
9 9
@@ -137,7 +137,7 @@ impl CallLocations {
137 137
138#[cfg(test)] 138#[cfg(test)]
139mod tests { 139mod tests {
140 use base_db::FilePosition; 140 use ide_db::base_db::FilePosition;
141 141
142 use crate::fixture; 142 use crate::fixture;
143 143
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 232074c3d..d0ee58858 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -9,11 +9,11 @@ mod field_shorthand;
9 9
10use std::cell::RefCell; 10use std::cell::RefCell;
11 11
12use base_db::SourceDatabase;
13use hir::{ 12use hir::{
14 diagnostics::{Diagnostic as _, DiagnosticSinkBuilder}, 13 diagnostics::{Diagnostic as _, DiagnosticSinkBuilder},
15 Semantics, 14 Semantics,
16}; 15};
16use ide_db::base_db::SourceDatabase;
17use ide_db::RootDatabase; 17use ide_db::RootDatabase;
18use itertools::Itertools; 18use itertools::Itertools;
19use rustc_hash::FxHashSet; 19use rustc_hash::FxHashSet;
diff --git a/crates/ide/src/diagnostics/field_shorthand.rs b/crates/ide/src/diagnostics/field_shorthand.rs
index 54e9fce9e..f41bcd619 100644
--- a/crates/ide/src/diagnostics/field_shorthand.rs
+++ b/crates/ide/src/diagnostics/field_shorthand.rs
@@ -1,7 +1,7 @@
1//! Suggests shortening `Foo { field: field }` to `Foo { field }` in both 1//! Suggests shortening `Foo { field: field }` to `Foo { field }` in both
2//! expressions and patterns. 2//! expressions and patterns.
3 3
4use base_db::FileId; 4use ide_db::base_db::FileId;
5use ide_db::source_change::SourceFileEdit; 5use ide_db::source_change::SourceFileEdit;
6use syntax::{ast, match_ast, AstNode, SyntaxNode}; 6use syntax::{ast, match_ast, AstNode, SyntaxNode};
7use text_edit::TextEdit; 7use text_edit::TextEdit;
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index 0c75e50b0..0c950003e 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -1,6 +1,5 @@
1//! Provides a way to attach fixes to the diagnostics. 1//! Provides a way to attach fixes to the diagnostics.
2//! The same module also has all curret custom fixes for the diagnostics implemented. 2//! The same module also has all curret custom fixes for the diagnostics implemented.
3use base_db::FileId;
4use hir::{ 3use hir::{
5 db::AstDatabase, 4 db::AstDatabase,
6 diagnostics::{ 5 diagnostics::{
@@ -9,6 +8,7 @@ use hir::{
9 }, 8 },
10 HasSource, HirDisplay, Semantics, VariantDef, 9 HasSource, HirDisplay, Semantics, VariantDef,
11}; 10};
11use ide_db::base_db::FileId;
12use ide_db::{ 12use ide_db::{
13 source_change::{FileSystemEdit, SourceFileEdit}, 13 source_change::{FileSystemEdit, SourceFileEdit},
14 RootDatabase, 14 RootDatabase,
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index cf9d617dc..0c429a262 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -1,8 +1,8 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use base_db::{FileId, SourceDatabase};
4use either::Either; 3use either::Either;
5use hir::{original_range, AssocItem, FieldSource, HasSource, InFile, ModuleSource}; 4use hir::{original_range, AssocItem, FieldSource, HasSource, InFile, ModuleSource};
5use ide_db::base_db::{FileId, SourceDatabase};
6use ide_db::{defs::Definition, RootDatabase}; 6use ide_db::{defs::Definition, RootDatabase};
7use syntax::{ 7use syntax::{
8 ast::{self, DocCommentsOwner, NameOwner}, 8 ast::{self, DocCommentsOwner, NameOwner},
diff --git a/crates/ide/src/fixture.rs b/crates/ide/src/fixture.rs
index ed06689f0..eb57f9224 100644
--- a/crates/ide/src/fixture.rs
+++ b/crates/ide/src/fixture.rs
@@ -1,5 +1,5 @@
1//! Utilities for creating `Analysis` instances for tests. 1//! Utilities for creating `Analysis` instances for tests.
2use base_db::fixture::ChangeFixture; 2use ide_db::base_db::fixture::ChangeFixture;
3use test_utils::{extract_annotations, RangeOrOffset}; 3use test_utils::{extract_annotations, RangeOrOffset};
4 4
5use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange}; 5use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange};
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index a87e31019..15792f947 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -100,7 +100,7 @@ pub(crate) fn reference_definition(
100 100
101#[cfg(test)] 101#[cfg(test)]
102mod tests { 102mod tests {
103 use base_db::FileRange; 103 use ide_db::base_db::FileRange;
104 use syntax::{TextRange, TextSize}; 104 use syntax::{TextRange, TextSize};
105 105
106 use crate::fixture; 106 use crate::fixture;
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index 6c586bbd1..529004878 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -74,7 +74,7 @@ fn impls_for_trait(
74 74
75#[cfg(test)] 75#[cfg(test)]
76mod tests { 76mod tests {
77 use base_db::FileRange; 77 use ide_db::base_db::FileRange;
78 78
79 use crate::fixture; 79 use crate::fixture;
80 80
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs
index 6d0df04dd..aba6bf5dc 100644
--- a/crates/ide/src/goto_type_definition.rs
+++ b/crates/ide/src/goto_type_definition.rs
@@ -54,7 +54,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
54 54
55#[cfg(test)] 55#[cfg(test)]
56mod tests { 56mod tests {
57 use base_db::FileRange; 57 use ide_db::base_db::FileRange;
58 58
59 use crate::fixture; 59 use crate::fixture;
60 60
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 0332c7be0..832192881 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1,8 +1,8 @@
1use base_db::SourceDatabase;
2use hir::{ 1use hir::{
3 Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay, 2 Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay,
4 Module, ModuleDef, ModuleSource, Semantics, 3 Module, ModuleDef, ModuleSource, Semantics,
5}; 4};
5use ide_db::base_db::SourceDatabase;
6use ide_db::{ 6use ide_db::{
7 defs::{Definition, NameClass, NameRefClass}, 7 defs::{Definition, NameClass, NameRefClass},
8 RootDatabase, 8 RootDatabase,
@@ -385,8 +385,8 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
385 385
386#[cfg(test)] 386#[cfg(test)]
387mod tests { 387mod tests {
388 use base_db::FileLoader;
389 use expect_test::{expect, Expect}; 388 use expect_test::{expect, Expect};
389 use ide_db::base_db::FileLoader;
390 390
391 use crate::fixture; 391 use crate::fixture;
392 392
@@ -638,6 +638,33 @@ fn main() { }
638 } 638 }
639 639
640 #[test] 640 #[test]
641 fn hover_shows_fn_doc_attr_raw_string() {
642 check(
643 r##"
644#[doc = r#"Raw string doc attr"#]
645pub fn foo<|>(_: &Path) {}
646
647fn main() { }
648"##,
649 expect![[r##"
650 *foo*
651
652 ```rust
653 test
654 ```
655
656 ```rust
657 pub fn foo(_: &Path)
658 ```
659
660 ---
661
662 Raw string doc attr
663 "##]],
664 );
665 }
666
667 #[test]
641 fn hover_shows_struct_field_info() { 668 fn hover_shows_struct_field_info() {
642 // Hovering over the field when instantiating 669 // Hovering over the field when instantiating
643 check( 670 check(
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index cecfae4c7..4bc733b70 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -48,11 +48,11 @@ mod doc_links;
48 48
49use std::sync::Arc; 49use std::sync::Arc;
50 50
51use base_db::{ 51use cfg::CfgOptions;
52use ide_db::base_db::{
52 salsa::{self, ParallelDatabase}, 53 salsa::{self, ParallelDatabase},
53 CheckCanceled, Env, FileLoader, FileSet, SourceDatabase, VfsPath, 54 CheckCanceled, Env, FileLoader, FileSet, SourceDatabase, VfsPath,
54}; 55};
55use cfg::CfgOptions;
56use ide_db::{ 56use ide_db::{
57 symbol_index::{self, FileSymbol}, 57 symbol_index::{self, FileSymbol},
58 LineIndexDatabase, 58 LineIndexDatabase,
@@ -80,19 +80,19 @@ pub use crate::{
80 Highlight, HighlightModifier, HighlightModifiers, HighlightTag, HighlightedRange, 80 Highlight, HighlightModifier, HighlightModifiers, HighlightTag, HighlightedRange,
81 }, 81 },
82}; 82};
83pub use call_info::CallInfo;
84pub use completion::{ 83pub use completion::{
85 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, 84 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
86}; 85};
86pub use ide_db::call_info::CallInfo;
87 87
88pub use assists::{ 88pub use assists::{
89 utils::MergeBehaviour, Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist, 89 utils::MergeBehaviour, Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist,
90}; 90};
91pub use base_db::{ 91pub use hir::{Documentation, Semantics};
92pub use ide_db::base_db::{
92 Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot, 93 Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot,
93 SourceRootId, 94 SourceRootId,
94}; 95};
95pub use hir::{Documentation, Semantics};
96pub use ide_db::{ 96pub use ide_db::{
97 label::Label, 97 label::Label,
98 line_index::{LineCol, LineIndex}, 98 line_index::{LineCol, LineIndex},
@@ -396,7 +396,7 @@ impl Analysis {
396 396
397 /// Computes parameter information for the given call expression. 397 /// Computes parameter information for the given call expression.
398 pub fn call_info(&self, position: FilePosition) -> Cancelable<Option<CallInfo>> { 398 pub fn call_info(&self, position: FilePosition) -> Cancelable<Option<CallInfo>> {
399 self.with_db(|db| call_info::call_info(db, position)) 399 self.with_db(|db| ide_db::call_info::call_info(db, position))
400 } 400 }
401 401
402 /// Computes call hierarchy candidates for the given file position. 402 /// Computes call hierarchy candidates for the given file position.
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs
index ef94acfec..6cc3b2991 100644
--- a/crates/ide/src/parent_module.rs
+++ b/crates/ide/src/parent_module.rs
@@ -1,5 +1,5 @@
1use base_db::{CrateId, FileId, FilePosition};
2use hir::Semantics; 1use hir::Semantics;
2use ide_db::base_db::{CrateId, FileId, FilePosition};
3use ide_db::RootDatabase; 3use ide_db::RootDatabase;
4use syntax::{ 4use syntax::{
5 algo::find_node_at_offset, 5 algo::find_node_at_offset,
diff --git a/crates/ide/src/prime_caches.rs b/crates/ide/src/prime_caches.rs
index 6944dbcd2..ea0acfaa0 100644
--- a/crates/ide/src/prime_caches.rs
+++ b/crates/ide/src/prime_caches.rs
@@ -3,8 +3,8 @@
3//! request takes longer to compute. This modules implemented prepopulating of 3//! request takes longer to compute. This modules implemented prepopulating of
4//! various caches, it's not really advanced at the moment. 4//! various caches, it's not really advanced at the moment.
5 5
6use base_db::SourceDatabase;
7use hir::db::DefDatabase; 6use hir::db::DefDatabase;
7use ide_db::base_db::SourceDatabase;
8 8
9use crate::RootDatabase; 9use crate::RootDatabase;
10 10
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 67ec257a8..a517081d5 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -191,8 +191,8 @@ fn get_struct_def_name_for_struct_literal_search(
191 191
192#[cfg(test)] 192#[cfg(test)]
193mod tests { 193mod tests {
194 use base_db::FileId;
195 use expect_test::{expect, Expect}; 194 use expect_test::{expect, Expect};
195 use ide_db::base_db::FileId;
196 use stdx::format_to; 196 use stdx::format_to;
197 197
198 use crate::{fixture, SearchScope}; 198 use crate::{fixture, SearchScope};
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 35aafc49d..26ac2371a 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -1,7 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use base_db::SourceDatabaseExt;
4use hir::{Module, ModuleDef, ModuleSource, Semantics}; 3use hir::{Module, ModuleDef, ModuleSource, Semantics};
4use ide_db::base_db::SourceDatabaseExt;
5use ide_db::{ 5use ide_db::{
6 defs::{Definition, NameClass, NameRefClass}, 6 defs::{Definition, NameClass, NameRefClass},
7 RootDatabase, 7 RootDatabase,
diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs
index 0af84daa0..8e91c99d7 100644
--- a/crates/ide/src/status.rs
+++ b/crates/ide/src/status.rs
@@ -1,10 +1,10 @@
1use std::{fmt, iter::FromIterator, sync::Arc}; 1use std::{fmt, iter::FromIterator, sync::Arc};
2 2
3use base_db::{ 3use hir::MacroFile;
4use ide_db::base_db::{
4 salsa::debug::{DebugQueryTable, TableEntry}, 5 salsa::debug::{DebugQueryTable, TableEntry},
5 CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId, 6 CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId,
6}; 7};
7use hir::MacroFile;
8use ide_db::{ 8use ide_db::{
9 symbol_index::{LibrarySymbolsQuery, SymbolIndex}, 9 symbol_index::{LibrarySymbolsQuery, SymbolIndex},
10 RootDatabase, 10 RootDatabase,
@@ -16,7 +16,7 @@ use stdx::format_to;
16use syntax::{ast, Parse, SyntaxNode}; 16use syntax::{ast, Parse, SyntaxNode};
17 17
18fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { 18fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
19 base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>() 19 ide_db::base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>()
20} 20}
21fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { 21fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
22 hir::db::ParseMacroQuery.in_db(db).entries::<SyntaxTreeStats>() 22 hir::db::ParseMacroQuery.in_db(db).entries::<SyntaxTreeStats>()
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 750848467..9f864179e 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -579,7 +579,14 @@ fn highlight_element(
579 } 579 }
580 } 580 }
581 T![-] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { 581 T![-] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
582 HighlightTag::NumericLiteral.into() 582 let prefix_expr = element.parent().and_then(ast::PrefixExpr::cast)?;
583
584 let expr = prefix_expr.expr()?;
585 match expr {
586 ast::Expr::Literal(_) => HighlightTag::NumericLiteral,
587 _ => HighlightTag::Operator,
588 }
589 .into()
583 } 590 }
584 _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { 591 _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
585 HighlightTag::Operator.into() 592 HighlightTag::Operator.into()
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs
index 57e2d2923..abcc5cccc 100644
--- a/crates/ide/src/syntax_highlighting/html.rs
+++ b/crates/ide/src/syntax_highlighting/html.rs
@@ -1,6 +1,6 @@
1//! Renders a bit of code as HTML. 1//! Renders a bit of code as HTML.
2 2
3use base_db::SourceDatabase; 3use ide_db::base_db::SourceDatabase;
4use oorandom::Rand32; 4use oorandom::Rand32;
5use stdx::format_to; 5use stdx::format_to;
6use syntax::{AstNode, TextRange, TextSize}; 6use syntax::{AstNode, TextRange, TextSize};
diff --git a/crates/ide/src/syntax_highlighting/injection.rs b/crates/ide/src/syntax_highlighting/injection.rs
index acd91b26c..59a74bc02 100644
--- a/crates/ide/src/syntax_highlighting/injection.rs
+++ b/crates/ide/src/syntax_highlighting/injection.rs
@@ -3,8 +3,8 @@
3use std::{collections::BTreeMap, convert::TryFrom}; 3use std::{collections::BTreeMap, convert::TryFrom};
4 4
5use ast::{HasQuotes, HasStringValue}; 5use ast::{HasQuotes, HasStringValue};
6use call_info::ActiveParameter;
7use hir::Semantics; 6use hir::Semantics;
7use ide_db::call_info::ActiveParameter;
8use itertools::Itertools; 8use itertools::Itertools;
9use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; 9use syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize};
10 10
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 0cb84866d..c6b4f5a00 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -176,6 +176,9 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
176 176
177 <span class="keyword">let</span> <span class="variable declaration callable">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="punctuation">;</span> 177 <span class="keyword">let</span> <span class="variable declaration callable">a</span> <span class="operator">=</span> <span class="punctuation">|</span><span class="value_param declaration">x</span><span class="punctuation">|</span> <span class="value_param">x</span><span class="punctuation">;</span>
178 <span class="keyword">let</span> <span class="variable declaration callable">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function">baz</span><span class="punctuation">;</span> 178 <span class="keyword">let</span> <span class="variable declaration callable">bar</span> <span class="operator">=</span> <span class="struct">Foo</span><span class="operator">::</span><span class="function">baz</span><span class="punctuation">;</span>
179
180 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="punctuation">;</span>
181 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="punctuation">;</span>
179<span class="punctuation">}</span> 182<span class="punctuation">}</span>
180 183
181<span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="punctuation">&lt;</span><span class="type_param declaration">T</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span> 184<span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="punctuation">&lt;</span><span class="type_param declaration">T</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index da20c300e..dd43f9dd9 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -150,6 +150,9 @@ fn main() {
150 150
151 let a = |x| x; 151 let a = |x| x;
152 let bar = Foo::baz; 152 let bar = Foo::baz;
153
154 let baz = -42;
155 let baz = -baz;
153} 156}
154 157
155enum Option<T> { 158enum Option<T> {
diff --git a/crates/ide/src/syntax_tree.rs b/crates/ide/src/syntax_tree.rs
index 0eed2dbd7..7941610d6 100644
--- a/crates/ide/src/syntax_tree.rs
+++ b/crates/ide/src/syntax_tree.rs
@@ -1,4 +1,4 @@
1use base_db::{FileId, SourceDatabase}; 1use ide_db::base_db::{FileId, SourceDatabase};
2use ide_db::RootDatabase; 2use ide_db::RootDatabase;
3use syntax::{ 3use syntax::{
4 algo, AstNode, NodeOrToken, SourceFile, 4 algo, AstNode, NodeOrToken, SourceFile,
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs
index 94b91f049..43458a3a2 100644
--- a/crates/ide/src/typing.rs
+++ b/crates/ide/src/typing.rs
@@ -15,7 +15,7 @@
15 15
16mod on_enter; 16mod on_enter;
17 17
18use base_db::{FilePosition, SourceDatabase}; 18use ide_db::base_db::{FilePosition, SourceDatabase};
19use ide_db::{source_change::SourceFileEdit, RootDatabase}; 19use ide_db::{source_change::SourceFileEdit, RootDatabase};
20use syntax::{ 20use syntax::{
21 algo::find_node_at_offset, 21 algo::find_node_at_offset,
diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs
index 98adef1d6..f4ea30352 100644
--- a/crates/ide/src/typing/on_enter.rs
+++ b/crates/ide/src/typing/on_enter.rs
@@ -1,7 +1,7 @@
1//! Handles the `Enter` key press. At the momently, this only continues 1//! Handles the `Enter` key press. At the momently, this only continues
2//! comments, but should handle indent some time in the future as well. 2//! comments, but should handle indent some time in the future as well.
3 3
4use base_db::{FilePosition, SourceDatabase}; 4use ide_db::base_db::{FilePosition, SourceDatabase};
5use ide_db::RootDatabase; 5use ide_db::RootDatabase;
6use syntax::{ 6use syntax::{
7 ast::{self, AstToken}, 7 ast::{self, AstToken},
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml
index 320fb15e5..72a9212f1 100644
--- a/crates/ide_db/Cargo.toml
+++ b/crates/ide_db/Cargo.toml
@@ -14,7 +14,7 @@ wasm = []
14 14
15[dependencies] 15[dependencies]
16log = "0.4.8" 16log = "0.4.8"
17rayon = "1.3.0" 17rayon = "1.5.0"
18fst = { version = "0.4", default-features = false } 18fst = { version = "0.4", default-features = false }
19rustc-hash = "1.1.0" 19rustc-hash = "1.1.0"
20once_cell = "1.3.1" 20once_cell = "1.3.1"
@@ -29,3 +29,6 @@ test_utils = { path = "../test_utils", version = "0.0.0" }
29# ide should depend only on the top-level `hir` package. if you need 29# ide should depend only on the top-level `hir` package. if you need
30# something from some `hir_xxx` subpackage, reexport the API via `hir`. 30# something from some `hir_xxx` subpackage, reexport the API via `hir`.
31hir = { path = "../hir", version = "0.0.0" } 31hir = { path = "../hir", version = "0.0.0" }
32
33[dev-dependencies]
34expect-test = "1.0"
diff --git a/crates/call_info/src/lib.rs b/crates/ide_db/src/call_info.rs
index c45406c25..83a602b9a 100644
--- a/crates/call_info/src/lib.rs
+++ b/crates/ide_db/src/call_info.rs
@@ -2,7 +2,6 @@
2use base_db::FilePosition; 2use base_db::FilePosition;
3use either::Either; 3use either::Either;
4use hir::{HasAttrs, HirDisplay, Semantics, Type}; 4use hir::{HasAttrs, HirDisplay, Semantics, Type};
5use ide_db::RootDatabase;
6use stdx::format_to; 5use stdx::format_to;
7use syntax::{ 6use syntax::{
8 ast::{self, ArgListOwner}, 7 ast::{self, ArgListOwner},
@@ -10,6 +9,8 @@ use syntax::{
10}; 9};
11use test_utils::mark; 10use test_utils::mark;
12 11
12use crate::RootDatabase;
13
13/// Contains information about a call site. Specifically the 14/// Contains information about a call site. Specifically the
14/// `FunctionSignature`and current parameter. 15/// `FunctionSignature`and current parameter.
15#[derive(Debug)] 16#[derive(Debug)]
@@ -228,9 +229,9 @@ impl FnCallNode {
228 229
229#[cfg(test)] 230#[cfg(test)]
230mod tests { 231mod tests {
232 use crate::RootDatabase;
231 use base_db::{fixture::ChangeFixture, FilePosition}; 233 use base_db::{fixture::ChangeFixture, FilePosition};
232 use expect_test::{expect, Expect}; 234 use expect_test::{expect, Expect};
233 use ide_db::RootDatabase;
234 use test_utils::{mark, RangeOrOffset}; 235 use test_utils::{mark, RangeOrOffset};
235 236
236 /// Creates analysis from a multi-file fixture, returns positions marked with <|>. 237 /// Creates analysis from a multi-file fixture, returns positions marked with <|>.
@@ -249,7 +250,7 @@ mod tests {
249 250
250 fn check(ra_fixture: &str, expect: Expect) { 251 fn check(ra_fixture: &str, expect: Expect) {
251 let (db, position) = position(ra_fixture); 252 let (db, position) = position(ra_fixture);
252 let call_info = crate::call_info(&db, position); 253 let call_info = crate::call_info::call_info(&db, position);
253 let actual = match call_info { 254 let actual = match call_info {
254 Some(call_info) => { 255 Some(call_info) => {
255 let docs = match &call_info.doc { 256 let docs = match &call_info.doc {
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs
index 7eff247c7..38ebdbf79 100644
--- a/crates/ide_db/src/lib.rs
+++ b/crates/ide_db/src/lib.rs
@@ -10,6 +10,9 @@ pub mod defs;
10pub mod search; 10pub mod search;
11pub mod imports_locator; 11pub mod imports_locator;
12pub mod source_change; 12pub mod source_change;
13pub mod ty_filter;
14pub mod traits;
15pub mod call_info;
13 16
14use std::{fmt, sync::Arc}; 17use std::{fmt, sync::Arc};
15 18
@@ -23,6 +26,9 @@ use rustc_hash::FxHashSet;
23 26
24use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; 27use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
25 28
29/// `base_db` is normally also needed in places where `ide_db` is used, so this re-export is for convenience.
30pub use base_db;
31
26#[salsa::database( 32#[salsa::database(
27 base_db::SourceDatabaseStorage, 33 base_db::SourceDatabaseStorage,
28 base_db::SourceDatabaseExtStorage, 34 base_db::SourceDatabaseExtStorage,
diff --git a/crates/ide_db/src/traits.rs b/crates/ide_db/src/traits.rs
new file mode 100644
index 000000000..f57b6dd91
--- /dev/null
+++ b/crates/ide_db/src/traits.rs
@@ -0,0 +1,227 @@
1//! Functionality for obtaining data related to traits from the DB.
2
3use crate::RootDatabase;
4use hir::Semantics;
5use rustc_hash::FxHashSet;
6use syntax::{
7 ast::{self, NameOwner},
8 AstNode,
9};
10
11/// Given the `impl` block, attempts to find the trait this `impl` corresponds to.
12pub fn resolve_target_trait(
13 sema: &Semantics<RootDatabase>,
14 impl_def: &ast::Impl,
15) -> Option<hir::Trait> {
16 let ast_path =
17 impl_def.trait_().map(|it| it.syntax().clone()).and_then(ast::PathType::cast)?.path()?;
18
19 match sema.resolve_path(&ast_path) {
20 Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def),
21 _ => None,
22 }
23}
24
25/// Given the `impl` block, returns the list of associated items (e.g. functions or types) that are
26/// missing in this `impl` block.
27pub fn get_missing_assoc_items(
28 sema: &Semantics<RootDatabase>,
29 impl_def: &ast::Impl,
30) -> Vec<hir::AssocItem> {
31 // Names must be unique between constants and functions. However, type aliases
32 // may share the same name as a function or constant.
33 let mut impl_fns_consts = FxHashSet::default();
34 let mut impl_type = FxHashSet::default();
35
36 if let Some(item_list) = impl_def.assoc_item_list() {
37 for item in item_list.assoc_items() {
38 match item {
39 ast::AssocItem::Fn(f) => {
40 if let Some(n) = f.name() {
41 impl_fns_consts.insert(n.syntax().to_string());
42 }
43 }
44
45 ast::AssocItem::TypeAlias(t) => {
46 if let Some(n) = t.name() {
47 impl_type.insert(n.syntax().to_string());
48 }
49 }
50
51 ast::AssocItem::Const(c) => {
52 if let Some(n) = c.name() {
53 impl_fns_consts.insert(n.syntax().to_string());
54 }
55 }
56 ast::AssocItem::MacroCall(_) => (),
57 }
58 }
59 }
60
61 resolve_target_trait(sema, impl_def).map_or(vec![], |target_trait| {
62 target_trait
63 .items(sema.db)
64 .iter()
65 .filter(|i| match i {
66 hir::AssocItem::Function(f) => {
67 !impl_fns_consts.contains(&f.name(sema.db).to_string())
68 }
69 hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db).to_string()),
70 hir::AssocItem::Const(c) => c
71 .name(sema.db)
72 .map(|n| !impl_fns_consts.contains(&n.to_string()))
73 .unwrap_or_default(),
74 })
75 .cloned()
76 .collect()
77 })
78}
79
80#[cfg(test)]
81mod tests {
82 use crate::RootDatabase;
83 use base_db::{fixture::ChangeFixture, FilePosition};
84 use expect_test::{expect, Expect};
85 use hir::Semantics;
86 use syntax::ast::{self, AstNode};
87 use test_utils::RangeOrOffset;
88
89 /// Creates analysis from a multi-file fixture, returns positions marked with <|>.
90 pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) {
91 let change_fixture = ChangeFixture::parse(ra_fixture);
92 let mut database = RootDatabase::default();
93 database.apply_change(change_fixture.change);
94 let (file_id, range_or_offset) =
95 change_fixture.file_position.expect("expected a marker (<|>)");
96 let offset = match range_or_offset {
97 RangeOrOffset::Range(_) => panic!(),
98 RangeOrOffset::Offset(it) => it,
99 };
100 (database, FilePosition { file_id, offset })
101 }
102
103 fn check_trait(ra_fixture: &str, expect: Expect) {
104 let (db, position) = position(ra_fixture);
105 let sema = Semantics::new(&db);
106 let file = sema.parse(position.file_id);
107 let impl_block: ast::Impl =
108 sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
109 let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block);
110 let actual = match trait_ {
111 Some(trait_) => trait_.name(&db).to_string(),
112 None => String::new(),
113 };
114 expect.assert_eq(&actual);
115 }
116
117 fn check_missing_assoc(ra_fixture: &str, expect: Expect) {
118 let (db, position) = position(ra_fixture);
119 let sema = Semantics::new(&db);
120 let file = sema.parse(position.file_id);
121 let impl_block: ast::Impl =
122 sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
123 let items = crate::traits::get_missing_assoc_items(&sema, &impl_block);
124 let actual = items
125 .into_iter()
126 .map(|item| item.name(&db).unwrap().to_string())
127 .collect::<Vec<_>>()
128 .join("\n");
129 expect.assert_eq(&actual);
130 }
131
132 #[test]
133 fn resolve_trait() {
134 check_trait(
135 r#"
136pub trait Foo {
137 fn bar();
138}
139impl Foo for u8 {
140 <|>
141}
142 "#,
143 expect![["Foo"]],
144 );
145 check_trait(
146 r#"
147pub trait Foo {
148 fn bar();
149}
150impl Foo for u8 {
151 fn bar() {
152 fn baz() {
153 <|>
154 }
155 baz();
156 }
157}
158 "#,
159 expect![["Foo"]],
160 );
161 check_trait(
162 r#"
163pub trait Foo {
164 fn bar();
165}
166pub struct Bar;
167impl Bar {
168 <|>
169}
170 "#,
171 expect![[""]],
172 );
173 }
174
175 #[test]
176 fn missing_assoc_items() {
177 check_missing_assoc(
178 r#"
179pub trait Foo {
180 const FOO: u8;
181 fn bar();
182}
183impl Foo for u8 {
184 <|>
185}"#,
186 expect![[r#"
187 FOO
188 bar"#]],
189 );
190
191 check_missing_assoc(
192 r#"
193pub trait Foo {
194 const FOO: u8;
195 fn bar();
196}
197impl Foo for u8 {
198 const FOO: u8 = 10;
199 <|>
200}"#,
201 expect![[r#"
202 bar"#]],
203 );
204
205 check_missing_assoc(
206 r#"
207pub trait Foo {
208 const FOO: u8;
209 fn bar();
210}
211impl Foo for u8 {
212 const FOO: u8 = 10;
213 fn bar() {<|>}
214}"#,
215 expect![[r#""#]],
216 );
217
218 check_missing_assoc(
219 r#"
220pub struct Foo;
221impl Foo {
222 fn bar() {<|>}
223}"#,
224 expect![[r#""#]],
225 );
226 }
227}
diff --git a/crates/ide_db/src/ty_filter.rs b/crates/ide_db/src/ty_filter.rs
new file mode 100644
index 000000000..63a945282
--- /dev/null
+++ b/crates/ide_db/src/ty_filter.rs
@@ -0,0 +1,58 @@
1//! This module contains structures for filtering the expected types.
2//! Use case for structures in this module is, for example, situation when you need to process
3//! only certain `Enum`s.
4
5use crate::RootDatabase;
6use hir::{Adt, Semantics, Type};
7use std::iter;
8use syntax::ast::{self, make};
9
10/// Enum types that implement `std::ops::Try` trait.
11#[derive(Clone, Copy)]
12pub enum TryEnum {
13 Result,
14 Option,
15}
16
17impl TryEnum {
18 const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
19
20 /// Returns `Some(..)` if the provided type is an enum that implements `std::ops::Try`.
21 pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> {
22 let enum_ = match ty.as_adt() {
23 Some(Adt::Enum(it)) => it,
24 _ => return None,
25 };
26 TryEnum::ALL.iter().find_map(|&var| {
27 if &enum_.name(sema.db).to_string() == var.type_name() {
28 return Some(var);
29 }
30 None
31 })
32 }
33
34 pub fn happy_case(self) -> &'static str {
35 match self {
36 TryEnum::Result => "Ok",
37 TryEnum::Option => "Some",
38 }
39 }
40
41 pub fn sad_pattern(self) -> ast::Pat {
42 match self {
43 TryEnum::Result => make::tuple_struct_pat(
44 make::path_unqualified(make::path_segment(make::name_ref("Err"))),
45 iter::once(make::wildcard_pat().into()),
46 )
47 .into(),
48 TryEnum::Option => make::ident_pat(make::name("None")).into(),
49 }
50 }
51
52 fn type_name(self) -> &'static str {
53 match self {
54 TryEnum::Result => "Result",
55 TryEnum::Option => "Option",
56 }
57 }
58}
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 66cf06e1a..975b24aaf 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -29,9 +29,12 @@ rustc-hash = "1.1.0"
29serde = { version = "1.0.106", features = ["derive"] } 29serde = { version = "1.0.106", features = ["derive"] }
30serde_json = "1.0.48" 30serde_json = "1.0.48"
31threadpool = "1.7.1" 31threadpool = "1.7.1"
32rayon = "1.3.1" 32rayon = "1.5"
33mimalloc = { version = "0.1.19", default-features = false, optional = true } 33mimalloc = { version = "0.1.19", default-features = false, optional = true }
34lsp-server = "0.4.0" 34lsp-server = "0.4.0"
35tracing = "0.1"
36tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] }
37tracing-tree = { version = "0.1.4" }
35 38
36stdx = { path = "../stdx", version = "0.0.0" } 39stdx = { path = "../stdx", version = "0.0.0" }
37flycheck = { path = "../flycheck", version = "0.0.0" } 40flycheck = { path = "../flycheck", version = "0.0.0" }
@@ -46,7 +49,6 @@ cfg = { path = "../cfg", version = "0.0.0" }
46toolchain = { path = "../toolchain", version = "0.0.0" } 49toolchain = { path = "../toolchain", version = "0.0.0" }
47 50
48# This should only be used in CLI 51# This should only be used in CLI
49base_db = { path = "../base_db", version = "0.0.0" }
50ide_db = { path = "../ide_db", version = "0.0.0" } 52ide_db = { path = "../ide_db", version = "0.0.0" }
51ssr = { path = "../ssr", version = "0.0.0" } 53ssr = { path = "../ssr", version = "0.0.0" }
52hir = { path = "../hir", version = "0.0.0" } 54hir = { path = "../hir", version = "0.0.0" }
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 97b246a32..4175e569e 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -68,10 +68,32 @@ fn setup_logging(log_file: Option<PathBuf>) -> Result<()> {
68 let filter = env::var("RA_LOG").ok(); 68 let filter = env::var("RA_LOG").ok();
69 logger::Logger::new(log_file, filter.as_deref()).install(); 69 logger::Logger::new(log_file, filter.as_deref()).install();
70 70
71 tracing_setup::setup_tracing()?;
72
71 profile::init(); 73 profile::init();
72 Ok(()) 74 Ok(())
73} 75}
74 76
77mod tracing_setup {
78 use tracing::subscriber;
79 use tracing_subscriber::layer::SubscriberExt;
80 use tracing_subscriber::EnvFilter;
81 use tracing_subscriber::Registry;
82 use tracing_tree::HierarchicalLayer;
83
84 pub fn setup_tracing() -> super::Result<()> {
85 let filter = EnvFilter::from_env("CHALK_DEBUG");
86 let layer = HierarchicalLayer::default()
87 .with_indent_lines(true)
88 .with_ansi(false)
89 .with_indent_amount(2)
90 .with_writer(std::io::stderr);
91 let subscriber = Registry::default().with(filter).with(layer);
92 subscriber::set_global_default(subscriber)?;
93 Ok(())
94 }
95}
96
75fn run_server() -> Result<()> { 97fn run_server() -> Result<()> {
76 log::info!("server will start"); 98 log::info!("server will start");
77 99
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs
index d1c095ba5..8e33986d5 100644
--- a/crates/rust-analyzer/src/cli/analysis_bench.rs
+++ b/crates/rust-analyzer/src/cli/analysis_bench.rs
@@ -3,13 +3,13 @@
3use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant}; 3use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant};
4 4
5use anyhow::{bail, format_err, Result}; 5use anyhow::{bail, format_err, Result};
6use base_db::{
7 salsa::{Database, Durability},
8 FileId,
9};
10use ide::{ 6use ide::{
11 Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol, 7 Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol,
12}; 8};
9use ide_db::base_db::{
10 salsa::{Database, Durability},
11 FileId,
12};
13use vfs::AbsPathBuf; 13use vfs::AbsPathBuf;
14 14
15use crate::{ 15use crate::{
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index fb2b2b000..98ef0cd68 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -6,16 +6,16 @@ use std::{
6 time::{SystemTime, UNIX_EPOCH}, 6 time::{SystemTime, UNIX_EPOCH},
7}; 7};
8 8
9use base_db::{
10 salsa::{self, ParallelDatabase},
11 SourceDatabaseExt,
12};
13use hir::{ 9use hir::{
14 db::{AstDatabase, DefDatabase, HirDatabase}, 10 db::{AstDatabase, DefDatabase, HirDatabase},
15 original_range, AssocItem, Crate, HasSource, HirDisplay, ModuleDef, 11 original_range, AssocItem, Crate, HasSource, HirDisplay, ModuleDef,
16}; 12};
17use hir_def::FunctionId; 13use hir_def::FunctionId;
18use hir_ty::{Ty, TypeWalk}; 14use hir_ty::{Ty, TypeWalk};
15use ide_db::base_db::{
16 salsa::{self, ParallelDatabase},
17 SourceDatabaseExt,
18};
19use itertools::Itertools; 19use itertools::Itertools;
20use oorandom::Rand32; 20use oorandom::Rand32;
21use rayon::prelude::*; 21use rayon::prelude::*;
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs
index a89993a2b..368f627ac 100644
--- a/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -6,9 +6,9 @@ use std::path::Path;
6use anyhow::anyhow; 6use anyhow::anyhow;
7use rustc_hash::FxHashSet; 7use rustc_hash::FxHashSet;
8 8
9use base_db::SourceDatabaseExt;
10use hir::Crate; 9use hir::Crate;
11use ide::{DiagnosticsConfig, Severity}; 10use ide::{DiagnosticsConfig, Severity};
11use ide_db::base_db::SourceDatabaseExt;
12 12
13use crate::cli::{load_cargo::load_cargo, Result}; 13use crate::cli::{load_cargo::load_cargo, Result};
14 14
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index 7ae1c9055..ab1e2ab92 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -3,9 +3,9 @@
3use std::{path::Path, sync::Arc}; 3use std::{path::Path, sync::Arc};
4 4
5use anyhow::Result; 5use anyhow::Result;
6use base_db::CrateGraph;
7use crossbeam_channel::{unbounded, Receiver}; 6use crossbeam_channel::{unbounded, Receiver};
8use ide::{AnalysisHost, Change}; 7use ide::{AnalysisHost, Change};
8use ide_db::base_db::CrateGraph;
9use project_model::{CargoConfig, ProcMacroClient, ProjectManifest, ProjectWorkspace}; 9use project_model::{CargoConfig, ProcMacroClient, ProjectManifest, ProjectWorkspace};
10use vfs::{loader::Handle, AbsPath, AbsPathBuf}; 10use vfs::{loader::Handle, AbsPath, AbsPathBuf};
11 11
diff --git a/crates/rust-analyzer/src/cli/ssr.rs b/crates/rust-analyzer/src/cli/ssr.rs
index c11e10943..a06631dac 100644
--- a/crates/rust-analyzer/src/cli/ssr.rs
+++ b/crates/rust-analyzer/src/cli/ssr.rs
@@ -4,7 +4,7 @@ use crate::cli::{load_cargo::load_cargo, Result};
4use ssr::{MatchFinder, SsrPattern, SsrRule}; 4use ssr::{MatchFinder, SsrPattern, SsrRule};
5 5
6pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> { 6pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> {
7 use base_db::SourceDatabaseExt; 7 use ide_db::base_db::SourceDatabaseExt;
8 let (host, vfs) = load_cargo(&std::env::current_dir()?, true, true)?; 8 let (host, vfs) = load_cargo(&std::env::current_dir()?, true, true)?;
9 let db = host.raw_database(); 9 let db = host.raw_database();
10 let mut match_finder = MatchFinder::at_first_file(db)?; 10 let mut match_finder = MatchFinder::at_first_file(db)?;
@@ -26,7 +26,7 @@ pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> {
26/// `debug_snippet`. This is intended for debugging and probably isn't in it's current form useful 26/// `debug_snippet`. This is intended for debugging and probably isn't in it's current form useful
27/// for much else. 27/// for much else.
28pub fn search_for_patterns(patterns: Vec<SsrPattern>, debug_snippet: Option<String>) -> Result<()> { 28pub fn search_for_patterns(patterns: Vec<SsrPattern>, debug_snippet: Option<String>) -> Result<()> {
29 use base_db::SourceDatabaseExt; 29 use ide_db::base_db::SourceDatabaseExt;
30 use ide_db::symbol_index::SymbolsDatabase; 30 use ide_db::symbol_index::SymbolsDatabase;
31 let (host, _vfs) = load_cargo(&std::env::current_dir()?, true, true)?; 31 let (host, _vfs) = load_cargo(&std::env::current_dir()?, true, true)?;
32 let db = host.raw_database(); 32 let db = host.raw_database();
diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs
index 5b9f52993..aa6b808d6 100644
--- a/crates/rust-analyzer/src/from_proto.rs
+++ b/crates/rust-analyzer/src/from_proto.rs
@@ -1,8 +1,8 @@
1//! Conversion lsp_types types to rust-analyzer specific ones. 1//! Conversion lsp_types types to rust-analyzer specific ones.
2use std::convert::TryFrom; 2use std::convert::TryFrom;
3 3
4use base_db::{FileId, FilePosition, FileRange};
5use ide::{AssistKind, LineCol, LineIndex}; 4use ide::{AssistKind, LineCol, LineIndex};
5use ide_db::base_db::{FileId, FilePosition, FileRange};
6use syntax::{TextRange, TextSize}; 6use syntax::{TextRange, TextSize};
7use vfs::AbsPathBuf; 7use vfs::AbsPathBuf;
8 8
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index dafab6a6a..673a2eebc 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -5,10 +5,10 @@
5 5
6use std::{sync::Arc, time::Instant}; 6use std::{sync::Arc, time::Instant};
7 7
8use base_db::{CrateId, VfsPath};
9use crossbeam_channel::{unbounded, Receiver, Sender}; 8use crossbeam_channel::{unbounded, Receiver, Sender};
10use flycheck::FlycheckHandle; 9use flycheck::FlycheckHandle;
11use ide::{Analysis, AnalysisHost, Change, FileId}; 10use ide::{Analysis, AnalysisHost, Change, FileId};
11use ide_db::base_db::{CrateId, VfsPath};
12use lsp_types::{SemanticTokens, Url}; 12use lsp_types::{SemanticTokens, Url};
13use parking_lot::{Mutex, RwLock}; 13use parking_lot::{Mutex, RwLock};
14use project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target}; 14use project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target};
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs
index bd888f634..1d271a9d8 100644
--- a/crates/rust-analyzer/src/lsp_utils.rs
+++ b/crates/rust-analyzer/src/lsp_utils.rs
@@ -1,8 +1,8 @@
1//! Utilities for LSP-related boilerplate code. 1//! Utilities for LSP-related boilerplate code.
2use std::{error::Error, ops::Range}; 2use std::{error::Error, ops::Range};
3 3
4use base_db::Canceled;
5use ide::LineIndex; 4use ide::LineIndex;
5use ide_db::base_db::Canceled;
6use lsp_server::Notification; 6use lsp_server::Notification;
7 7
8use crate::{from_proto, global_state::GlobalState}; 8use crate::{from_proto, global_state::GlobalState};
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index fb18f9014..ed5292733 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -5,10 +5,10 @@ use std::{
5 time::{Duration, Instant}, 5 time::{Duration, Instant},
6}; 6};
7 7
8use base_db::VfsPath;
9use crossbeam_channel::{select, Receiver}; 8use crossbeam_channel::{select, Receiver};
10use ide::PrimeCachesProgress; 9use ide::PrimeCachesProgress;
11use ide::{Canceled, FileId}; 10use ide::{Canceled, FileId};
11use ide_db::base_db::VfsPath;
12use lsp_server::{Connection, Notification, Request, Response}; 12use lsp_server::{Connection, Notification, Request, Response};
13use lsp_types::notification::Notification as _; 13use lsp_types::notification::Notification as _;
14use project_model::ProjectWorkspace; 14use project_model::ProjectWorkspace;
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index f7215f129..0eabd51bd 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -1,9 +1,9 @@
1//! Project loading & configuration updates 1//! Project loading & configuration updates
2use std::{mem, sync::Arc}; 2use std::{mem, sync::Arc};
3 3
4use base_db::{CrateGraph, SourceRoot, VfsPath};
5use flycheck::{FlycheckConfig, FlycheckHandle}; 4use flycheck::{FlycheckConfig, FlycheckHandle};
6use ide::Change; 5use ide::Change;
6use ide_db::base_db::{CrateGraph, SourceRoot, VfsPath};
7use project_model::{ProcMacroClient, ProjectWorkspace}; 7use project_model::{ProcMacroClient, ProjectWorkspace};
8use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind}; 8use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
9 9
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 0d34970bc..24a658fc6 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -4,13 +4,13 @@ use std::{
4 sync::atomic::{AtomicU32, Ordering}, 4 sync::atomic::{AtomicU32, Ordering},
5}; 5};
6 6
7use base_db::{FileId, FileRange};
8use ide::{ 7use ide::{
9 Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation, 8 Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, Documentation,
10 FileSystemEdit, Fold, FoldKind, Highlight, HighlightModifier, HighlightTag, HighlightedRange, 9 FileSystemEdit, Fold, FoldKind, Highlight, HighlightModifier, HighlightTag, HighlightedRange,
11 Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget, 10 Indel, InlayHint, InlayKind, InsertTextFormat, LineIndex, Markup, NavigationTarget,
12 ReferenceAccess, ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit, 11 ReferenceAccess, ResolvedAssist, Runnable, Severity, SourceChange, SourceFileEdit, TextEdit,
13}; 12};
13use ide_db::base_db::{FileId, FileRange};
14use itertools::Itertools; 14use itertools::Itertools;
15use syntax::{SyntaxKind, TextRange, TextSize}; 15use syntax::{SyntaxKind, TextRange, TextSize};
16 16
@@ -809,7 +809,7 @@ mod tests {
809 let completions: Vec<(String, Option<String>)> = analysis 809 let completions: Vec<(String, Option<String>)> = analysis
810 .completions( 810 .completions(
811 &ide::CompletionConfig::default(), 811 &ide::CompletionConfig::default(),
812 base_db::FilePosition { file_id, offset }, 812 ide_db::base_db::FilePosition { file_id, offset },
813 ) 813 )
814 .unwrap() 814 .unwrap()
815 .unwrap() 815 .unwrap()
diff --git a/crates/ssr/Cargo.toml b/crates/ssr/Cargo.toml
index 408140014..98ed25fb6 100644
--- a/crates/ssr/Cargo.toml
+++ b/crates/ssr/Cargo.toml
@@ -16,7 +16,6 @@ itertools = "0.9.0"
16 16
17text_edit = { path = "../text_edit", version = "0.0.0" } 17text_edit = { path = "../text_edit", version = "0.0.0" }
18syntax = { path = "../syntax", version = "0.0.0" } 18syntax = { path = "../syntax", version = "0.0.0" }
19base_db = { path = "../base_db", version = "0.0.0" }
20ide_db = { path = "../ide_db", version = "0.0.0" } 19ide_db = { path = "../ide_db", version = "0.0.0" }
21hir = { path = "../hir", version = "0.0.0" } 20hir = { path = "../hir", version = "0.0.0" }
22test_utils = { path = "../test_utils", version = "0.0.0" } 21test_utils = { path = "../test_utils", version = "0.0.0" }
diff --git a/crates/ssr/src/lib.rs b/crates/ssr/src/lib.rs
index ba669fd56..747ce495d 100644
--- a/crates/ssr/src/lib.rs
+++ b/crates/ssr/src/lib.rs
@@ -73,8 +73,8 @@ use crate::errors::bail;
73pub use crate::errors::SsrError; 73pub use crate::errors::SsrError;
74pub use crate::matching::Match; 74pub use crate::matching::Match;
75use crate::matching::MatchFailureReason; 75use crate::matching::MatchFailureReason;
76use base_db::{FileId, FilePosition, FileRange};
77use hir::Semantics; 76use hir::Semantics;
77use ide_db::base_db::{FileId, FilePosition, FileRange};
78use ide_db::source_change::SourceFileEdit; 78use ide_db::source_change::SourceFileEdit;
79use resolving::ResolvedRule; 79use resolving::ResolvedRule;
80use rustc_hash::FxHashMap; 80use rustc_hash::FxHashMap;
@@ -126,7 +126,7 @@ impl<'db> MatchFinder<'db> {
126 126
127 /// Constructs an instance using the start of the first file in `db` as the lookup context. 127 /// Constructs an instance using the start of the first file in `db` as the lookup context.
128 pub fn at_first_file(db: &'db ide_db::RootDatabase) -> Result<MatchFinder<'db>, SsrError> { 128 pub fn at_first_file(db: &'db ide_db::RootDatabase) -> Result<MatchFinder<'db>, SsrError> {
129 use base_db::SourceDatabaseExt; 129 use ide_db::base_db::SourceDatabaseExt;
130 use ide_db::symbol_index::SymbolsDatabase; 130 use ide_db::symbol_index::SymbolsDatabase;
131 if let Some(first_file_id) = db 131 if let Some(first_file_id) = db
132 .local_roots() 132 .local_roots()
@@ -160,7 +160,7 @@ impl<'db> MatchFinder<'db> {
160 160
161 /// Finds matches for all added rules and returns edits for all found matches. 161 /// Finds matches for all added rules and returns edits for all found matches.
162 pub fn edits(&self) -> Vec<SourceFileEdit> { 162 pub fn edits(&self) -> Vec<SourceFileEdit> {
163 use base_db::SourceDatabaseExt; 163 use ide_db::base_db::SourceDatabaseExt;
164 let mut matches_by_file = FxHashMap::default(); 164 let mut matches_by_file = FxHashMap::default();
165 for m in self.matches().matches { 165 for m in self.matches().matches {
166 matches_by_file 166 matches_by_file
@@ -205,7 +205,7 @@ impl<'db> MatchFinder<'db> {
205 /// them, while recording reasons why they don't match. This API is useful for command 205 /// them, while recording reasons why they don't match. This API is useful for command
206 /// line-based debugging where providing a range is difficult. 206 /// line-based debugging where providing a range is difficult.
207 pub fn debug_where_text_equal(&self, file_id: FileId, snippet: &str) -> Vec<MatchDebugInfo> { 207 pub fn debug_where_text_equal(&self, file_id: FileId, snippet: &str) -> Vec<MatchDebugInfo> {
208 use base_db::SourceDatabaseExt; 208 use ide_db::base_db::SourceDatabaseExt;
209 let file = self.sema.parse(file_id); 209 let file = self.sema.parse(file_id);
210 let mut res = Vec::new(); 210 let mut res = Vec::new();
211 let file_text = self.sema.db.file_text(file_id); 211 let file_text = self.sema.db.file_text(file_id);
diff --git a/crates/ssr/src/matching.rs b/crates/ssr/src/matching.rs
index 948862a77..99b187311 100644
--- a/crates/ssr/src/matching.rs
+++ b/crates/ssr/src/matching.rs
@@ -6,8 +6,8 @@ use crate::{
6 resolving::{ResolvedPattern, ResolvedRule, UfcsCallInfo}, 6 resolving::{ResolvedPattern, ResolvedRule, UfcsCallInfo},
7 SsrMatches, 7 SsrMatches,
8}; 8};
9use base_db::FileRange;
10use hir::Semantics; 9use hir::Semantics;
10use ide_db::base_db::FileRange;
11use rustc_hash::FxHashMap; 11use rustc_hash::FxHashMap;
12use std::{cell::Cell, iter::Peekable}; 12use std::{cell::Cell, iter::Peekable};
13use syntax::ast::{AstNode, AstToken}; 13use syntax::ast::{AstNode, AstToken};
diff --git a/crates/ssr/src/resolving.rs b/crates/ssr/src/resolving.rs
index 347cc4aad..f5ceb5729 100644
--- a/crates/ssr/src/resolving.rs
+++ b/crates/ssr/src/resolving.rs
@@ -2,7 +2,7 @@
2 2
3use crate::errors::error; 3use crate::errors::error;
4use crate::{parsing, SsrError}; 4use crate::{parsing, SsrError};
5use base_db::FilePosition; 5use ide_db::base_db::FilePosition;
6use parsing::Placeholder; 6use parsing::Placeholder;
7use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
8use syntax::{ast, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken}; 8use syntax::{ast, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken};
diff --git a/crates/ssr/src/search.rs b/crates/ssr/src/search.rs
index a595fd269..44b5db029 100644
--- a/crates/ssr/src/search.rs
+++ b/crates/ssr/src/search.rs
@@ -5,7 +5,7 @@ use crate::{
5 resolving::{ResolvedPath, ResolvedPattern, ResolvedRule}, 5 resolving::{ResolvedPath, ResolvedPattern, ResolvedRule},
6 Match, MatchFinder, 6 Match, MatchFinder,
7}; 7};
8use base_db::{FileId, FileRange}; 8use ide_db::base_db::{FileId, FileRange};
9use ide_db::{ 9use ide_db::{
10 defs::Definition, 10 defs::Definition,
11 search::{Reference, SearchScope}, 11 search::{Reference, SearchScope},
@@ -145,7 +145,7 @@ impl<'db> MatchFinder<'db> {
145 fn search_files_do(&self, mut callback: impl FnMut(FileId)) { 145 fn search_files_do(&self, mut callback: impl FnMut(FileId)) {
146 if self.restrict_ranges.is_empty() { 146 if self.restrict_ranges.is_empty() {
147 // Unrestricted search. 147 // Unrestricted search.
148 use base_db::SourceDatabaseExt; 148 use ide_db::base_db::SourceDatabaseExt;
149 use ide_db::symbol_index::SymbolsDatabase; 149 use ide_db::symbol_index::SymbolsDatabase;
150 for &root in self.sema.db.local_roots().iter() { 150 for &root in self.sema.db.local_roots().iter() {
151 let sr = self.sema.db.source_root(root); 151 let sr = self.sema.db.source_root(root);
diff --git a/crates/ssr/src/tests.rs b/crates/ssr/src/tests.rs
index 20231a9bc..63131f6ca 100644
--- a/crates/ssr/src/tests.rs
+++ b/crates/ssr/src/tests.rs
@@ -1,6 +1,6 @@
1use crate::{MatchFinder, SsrRule}; 1use crate::{MatchFinder, SsrRule};
2use base_db::{salsa::Durability, FileId, FilePosition, FileRange, SourceDatabaseExt};
3use expect_test::{expect, Expect}; 2use expect_test::{expect, Expect};
3use ide_db::base_db::{salsa::Durability, FileId, FilePosition, FileRange, SourceDatabaseExt};
4use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5use std::sync::Arc; 5use std::sync::Arc;
6use test_utils::{mark, RangeOrOffset}; 6use test_utils::{mark, RangeOrOffset};
@@ -62,7 +62,7 @@ fn parser_undefined_placeholder_in_replacement() {
62/// `code` may optionally contain a cursor marker `<|>`. If it doesn't, then the position will be 62/// `code` may optionally contain a cursor marker `<|>`. If it doesn't, then the position will be
63/// the start of the file. If there's a second cursor marker, then we'll return a single range. 63/// the start of the file. If there's a second cursor marker, then we'll return a single range.
64pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Vec<FileRange>) { 64pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Vec<FileRange>) {
65 use base_db::fixture::WithFixture; 65 use ide_db::base_db::fixture::WithFixture;
66 use ide_db::symbol_index::SymbolsDatabase; 66 use ide_db::symbol_index::SymbolsDatabase;
67 let (mut db, file_id, range_or_offset) = if code.contains(test_utils::CURSOR_MARKER) { 67 let (mut db, file_id, range_or_offset) = if code.contains(test_utils::CURSOR_MARKER) {
68 ide_db::RootDatabase::with_range_or_offset(code) 68 ide_db::RootDatabase::with_range_or_offset(code)
@@ -83,7 +83,7 @@ pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Ve
83 } 83 }
84 } 84 }
85 let mut local_roots = FxHashSet::default(); 85 let mut local_roots = FxHashSet::default();
86 local_roots.insert(base_db::fixture::WORKSPACE); 86 local_roots.insert(ide_db::base_db::fixture::WORKSPACE);
87 db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH); 87 db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
88 (db, position, selections) 88 (db, position, selections)
89} 89}
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index aa39ce554..e8de61868 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
13[dependencies] 13[dependencies]
14itertools = "0.9.0" 14itertools = "0.9.0"
15rowan = "0.10.0" 15rowan = "0.10.0"
16rustc_lexer = { version = "683.0.0", package = "rustc-ap-rustc_lexer" } 16rustc_lexer = { version = "685.0.0", package = "rustc-ap-rustc_lexer" }
17rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
18arrayvec = "0.5.1" 18arrayvec = "0.5.1"
19once_cell = "1.3.1" 19once_cell = "1.3.1"
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 50c1c157d..c5cd1c504 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -7,7 +7,7 @@ use itertools::Itertools;
7use parser::SyntaxKind; 7use parser::SyntaxKind;
8 8
9use crate::{ 9use crate::{
10 ast::{self, support, AstNode, NameOwner, SyntaxNode}, 10 ast::{self, support, token_ext::HasStringValue, AstNode, AstToken, NameOwner, SyntaxNode},
11 SmolStr, SyntaxElement, SyntaxToken, T, 11 SmolStr, SyntaxElement, SyntaxToken, T,
12}; 12};
13 13
@@ -53,8 +53,16 @@ impl ast::Attr {
53 pub fn as_simple_key_value(&self) -> Option<(SmolStr, SmolStr)> { 53 pub fn as_simple_key_value(&self) -> Option<(SmolStr, SmolStr)> {
54 let lit = self.literal()?; 54 let lit = self.literal()?;
55 let key = self.simple_name()?; 55 let key = self.simple_name()?;
56 // FIXME: escape? raw string? 56 let value_token = lit.syntax().first_token()?;
57 let value = lit.syntax().first_token()?.text().trim_matches('"').into(); 57
58 let value: SmolStr = if let Some(s) = ast::String::cast(value_token.clone()) {
59 s.value()?.into()
60 } else if let Some(s) = ast::RawString::cast(value_token) {
61 s.value()?.into()
62 } else {
63 return None;
64 };
65
58 Some((key, value)) 66 Some((key, value))
59 } 67 }
60 68