aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/assist_ctx.rs52
-rw-r--r--crates/ra_assists/src/assists/add_derive.rs30
-rw-r--r--crates/ra_assists/src/assists/add_explicit_type.rs27
-rw-r--r--crates/ra_assists/src/assists/add_impl.rs31
-rw-r--r--crates/ra_assists/src/assists/add_import.rs (renamed from crates/ra_assists/src/assists/auto_import.rs)249
-rw-r--r--crates/ra_assists/src/assists/add_missing_impl_members.rs72
-rw-r--r--crates/ra_assists/src/assists/apply_demorgan.rs37
-rw-r--r--crates/ra_assists/src/assists/change_visibility.rs33
-rw-r--r--crates/ra_assists/src/assists/early_return.rs56
-rw-r--r--crates/ra_assists/src/assists/fill_match_arms.rs38
-rw-r--r--crates/ra_assists/src/assists/flip_binexpr.rs28
-rw-r--r--crates/ra_assists/src/assists/flip_comma.rs27
-rw-r--r--crates/ra_assists/src/assists/flip_trait_bound.rs117
-rw-r--r--crates/ra_assists/src/assists/inline_local_variable.rs34
-rw-r--r--crates/ra_assists/src/assists/introduce_variable.rs26
-rw-r--r--crates/ra_assists/src/assists/merge_match_arms.rs36
-rw-r--r--crates/ra_assists/src/assists/move_bounds.rs77
-rw-r--r--crates/ra_assists/src/assists/move_guard.rs70
-rw-r--r--crates/ra_assists/src/assists/raw_string.rs227
-rw-r--r--crates/ra_assists/src/assists/remove_dbg.rs30
-rw-r--r--crates/ra_assists/src/assists/replace_if_let_with_match.rs38
-rw-r--r--crates/ra_assists/src/assists/split_import.rs23
-rw-r--r--crates/ra_assists/src/doc_tests.rs34
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs526
-rw-r--r--crates/ra_assists/src/lib.rs95
-rw-r--r--crates/ra_db/src/lib.rs5
-rw-r--r--crates/ra_hir/Cargo.toml8
-rw-r--r--crates/ra_hir/src/adt.rs11
-rw-r--r--crates/ra_hir/src/code_model.rs182
-rw-r--r--crates/ra_hir/src/code_model/src.rs30
-rw-r--r--crates/ra_hir/src/db.rs94
-rw-r--r--crates/ra_hir/src/debug.rs6
-rw-r--r--crates/ra_hir/src/expr.rs6
-rw-r--r--crates/ra_hir/src/expr/lower.rs26
-rw-r--r--crates/ra_hir/src/expr/validation.rs2
-rw-r--r--crates/ra_hir/src/from_source.rs52
-rw-r--r--crates/ra_hir/src/generics.rs20
-rw-r--r--crates/ra_hir/src/ids.rs363
-rw-r--r--crates/ra_hir/src/impl_block.rs24
-rw-r--r--crates/ra_hir/src/lang_item.rs16
-rw-r--r--crates/ra_hir/src/lib.rs40
-rw-r--r--crates/ra_hir/src/marks.rs1
-rw-r--r--crates/ra_hir/src/mock.rs1
-rw-r--r--crates/ra_hir/src/nameres.rs51
-rw-r--r--crates/ra_hir/src/nameres/collector.rs56
-rw-r--r--crates/ra_hir/src/nameres/tests/mod_resolution.rs2
-rw-r--r--crates/ra_hir/src/resolve.rs41
-rw-r--r--crates/ra_hir/src/source_binder.rs73
-rw-r--r--crates/ra_hir/src/traits.rs7
-rw-r--r--crates/ra_hir/src/ty.rs4
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs3
-rw-r--r--crates/ra_hir/src/ty/infer.rs8
-rw-r--r--crates/ra_hir/src/ty/infer/coerce.rs3
-rw-r--r--crates/ra_hir/src/ty/infer/expr.rs5
-rw-r--r--crates/ra_hir/src/ty/infer/path.rs6
-rw-r--r--crates/ra_hir/src/ty/lower.rs23
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs15
-rw-r--r--crates/ra_hir/src/ty/primitive.rs22
-rw-r--r--crates/ra_hir/src/ty/traits.rs6
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs157
-rw-r--r--crates/ra_hir/src/type_alias.rs5
-rw-r--r--crates/ra_hir_def/Cargo.toml21
-rw-r--r--crates/ra_hir_def/src/attr.rs (renamed from crates/ra_hir/src/attr.rs)28
-rw-r--r--crates/ra_hir_def/src/builtin_type.rs63
-rw-r--r--crates/ra_hir_def/src/db.rs40
-rw-r--r--crates/ra_hir_def/src/lib.rs362
-rw-r--r--crates/ra_hir_def/src/nameres.rs5
-rw-r--r--crates/ra_hir_def/src/nameres/mod_resolution.rs (renamed from crates/ra_hir/src/nameres/mod_resolution.rs)30
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs (renamed from crates/ra_hir/src/nameres/raw.rs)109
-rw-r--r--crates/ra_hir_def/src/path.rs (renamed from crates/ra_hir/src/path.rs)115
-rw-r--r--crates/ra_hir_def/src/type_ref.rs (renamed from crates/ra_hir/src/type_ref.rs)8
-rw-r--r--crates/ra_hir_expand/Cargo.toml15
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs (renamed from crates/ra_hir/src/source_id.rs)115
-rw-r--r--crates/ra_hir_expand/src/db.rs104
-rw-r--r--crates/ra_hir_expand/src/either.rs (renamed from crates/ra_hir/src/either.rs)0
-rw-r--r--crates/ra_hir_expand/src/hygiene.rs46
-rw-r--r--crates/ra_hir_expand/src/lib.rs153
-rw-r--r--crates/ra_hir_expand/src/name.rs (renamed from crates/ra_hir/src/name.rs)78
-rw-r--r--crates/ra_ide_api/Cargo.toml5
-rw-r--r--crates/ra_ide_api/src/call_info.rs183
-rw-r--r--crates/ra_ide_api/src/change.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs4
-rw-r--r--crates/ra_ide_api/src/completion/complete_postfix.rs6
-rw-r--r--crates/ra_ide_api/src/completion/completion_item.rs12
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs74
-rw-r--r--crates/ra_ide_api/src/db.rs1
-rw-r--r--crates/ra_ide_api/src/diagnostics.rs9
-rw-r--r--crates/ra_ide_api/src/display/function_signature.rs112
-rw-r--r--crates/ra_ide_api/src/extend_selection.rs82
-rw-r--r--crates/ra_ide_api/src/impls.rs4
-rw-r--r--crates/ra_ide_api/src/lib.rs129
-rw-r--r--crates/ra_ide_api/src/parent_module.rs5
-rw-r--r--crates/ra_ide_api/src/references/rename.rs24
-rw-r--r--crates/ra_ide_api/src/references/search_scope.rs7
-rw-r--r--crates/ra_ide_api/src/runnables.rs14
-rw-r--r--crates/ra_ide_api/src/source_change.rs119
-rw-r--r--crates/ra_ide_api/src/typing.rs359
-rw-r--r--crates/ra_lsp_server/src/caps.rs2
-rw-r--r--crates/ra_lsp_server/src/config.rs14
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs35
-rw-r--r--crates/ra_mbe/src/mbe_expander/matcher.rs3
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs2
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs3
-rw-r--r--crates/ra_syntax/src/ast.rs24
-rw-r--r--crates/ra_syntax/src/ast/make.rs6
-rw-r--r--crates/ra_syntax/src/ast/traits.rs19
-rw-r--r--crates/ra_syntax/src/lib.rs14
-rw-r--r--crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt91
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rs5
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.txt101
-rw-r--r--crates/ra_text_edit/src/text_edit.rs18
-rw-r--r--crates/test_utils/src/lib.rs34
113 files changed, 4034 insertions, 2169 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index e270c5d60..1908bdec9 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -1,11 +1,11 @@
1//! FIXME: write short doc here 1//! This module defines `AssistCtx` -- the API surface that is exposed to assists.
2 2
3use hir::db::HirDatabase; 3use hir::db::HirDatabase;
4use ra_db::FileRange; 4use ra_db::FileRange;
5use ra_fmt::{leading_indent, reindent}; 5use ra_fmt::{leading_indent, reindent};
6use ra_syntax::{ 6use ra_syntax::{
7 algo::{self, find_covering_element, find_node_at_offset}, 7 algo::{self, find_covering_element, find_node_at_offset},
8 AstNode, SourceFile, SyntaxElement, SyntaxNode, SyntaxToken, TextRange, TextUnit, 8 AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextUnit,
9 TokenAtOffset, 9 TokenAtOffset,
10}; 10};
11use ra_text_edit::TextEditBuilder; 11use ra_text_edit::TextEditBuilder;
@@ -14,8 +14,8 @@ use crate::{AssistAction, AssistId, AssistLabel};
14 14
15#[derive(Clone, Debug)] 15#[derive(Clone, Debug)]
16pub(crate) enum Assist { 16pub(crate) enum Assist {
17 Unresolved(Vec<AssistLabel>), 17 Unresolved { label: AssistLabel },
18 Resolved(Vec<(AssistLabel, AssistAction)>), 18 Resolved { label: AssistLabel, action: AssistAction },
19} 19}
20 20
21/// `AssistCtx` allows to apply an assist or check if it could be applied. 21/// `AssistCtx` allows to apply an assist or check if it could be applied.
@@ -54,7 +54,6 @@ pub(crate) struct AssistCtx<'a, DB> {
54 pub(crate) frange: FileRange, 54 pub(crate) frange: FileRange,
55 source_file: SourceFile, 55 source_file: SourceFile,
56 should_compute_edit: bool, 56 should_compute_edit: bool,
57 assist: Assist,
58} 57}
59 58
60impl<'a, DB> Clone for AssistCtx<'a, DB> { 59impl<'a, DB> Clone for AssistCtx<'a, DB> {
@@ -64,7 +63,6 @@ impl<'a, DB> Clone for AssistCtx<'a, DB> {
64 frange: self.frange, 63 frange: self.frange,
65 source_file: self.source_file.clone(), 64 source_file: self.source_file.clone(),
66 should_compute_edit: self.should_compute_edit, 65 should_compute_edit: self.should_compute_edit,
67 assist: self.assist.clone(),
68 } 66 }
69 } 67 }
70} 68}
@@ -75,43 +73,41 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
75 F: FnOnce(AssistCtx<DB>) -> T, 73 F: FnOnce(AssistCtx<DB>) -> T,
76 { 74 {
77 let parse = db.parse(frange.file_id); 75 let parse = db.parse(frange.file_id);
78 let assist =
79 if should_compute_edit { Assist::Resolved(vec![]) } else { Assist::Unresolved(vec![]) };
80 76
81 let ctx = AssistCtx { db, frange, source_file: parse.tree(), should_compute_edit, assist }; 77 let ctx = AssistCtx { db, frange, source_file: parse.tree(), should_compute_edit };
82 f(ctx) 78 f(ctx)
83 } 79 }
84 80
85 pub(crate) fn add_action( 81 pub(crate) fn add_assist(
86 &mut self, 82 self,
87 id: AssistId, 83 id: AssistId,
88 label: impl Into<String>, 84 label: impl Into<String>,
89 f: impl FnOnce(&mut AssistBuilder), 85 f: impl FnOnce(&mut AssistBuilder),
90 ) -> &mut Self { 86 ) -> Option<Assist> {
91 let label = AssistLabel { label: label.into(), id }; 87 let label = AssistLabel { label: label.into(), id };
92 match &mut self.assist { 88 let assist = if self.should_compute_edit {
93 Assist::Unresolved(labels) => labels.push(label), 89 let action = {
94 Assist::Resolved(labels_actions) => { 90 let mut edit = AssistBuilder::default();
95 let action = { 91 f(&mut edit);
96 let mut edit = AssistBuilder::default(); 92 edit.build()
97 f(&mut edit); 93 };
98 edit.build() 94 Assist::Resolved { label, action }
99 }; 95 } else {
100 labels_actions.push((label, action)); 96 Assist::Unresolved { label }
101 } 97 };
102 }
103 self
104 }
105 98
106 pub(crate) fn build(self) -> Option<Assist> { 99 Some(assist)
107 Some(self.assist)
108 } 100 }
109 101
110 pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> { 102 pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> {
111 self.source_file.syntax().token_at_offset(self.frange.range.start()) 103 self.source_file.syntax().token_at_offset(self.frange.range.start())
112 } 104 }
113 105
114 pub(crate) fn node_at_offset<N: AstNode>(&self) -> Option<N> { 106 pub(crate) fn find_token_at_offset(&self, kind: SyntaxKind) -> Option<SyntaxToken> {
107 self.token_at_offset().find(|it| it.kind() == kind)
108 }
109
110 pub(crate) fn find_node_at_offset<N: AstNode>(&self) -> Option<N> {
115 find_node_at_offset(self.source_file.syntax(), self.frange.range.start()) 111 find_node_at_offset(self.source_file.syntax(), self.frange.range.start())
116 } 112 }
117 pub(crate) fn covering_element(&self) -> SyntaxElement { 113 pub(crate) fn covering_element(&self) -> SyntaxElement {
diff --git a/crates/ra_assists/src/assists/add_derive.rs b/crates/ra_assists/src/assists/add_derive.rs
index 77ecc33c9..764b17bd8 100644
--- a/crates/ra_assists/src/assists/add_derive.rs
+++ b/crates/ra_assists/src/assists/add_derive.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use hir::db::HirDatabase; 1use hir::db::HirDatabase;
4use ra_syntax::{ 2use ra_syntax::{
5 ast::{self, AstNode, AttrsOwner}, 3 ast::{self, AstNode, AttrsOwner},
@@ -9,10 +7,28 @@ use ra_syntax::{
9 7
10use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
11 9
12pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10// Assist: add_derive
13 let nominal = ctx.node_at_offset::<ast::NominalDef>()?; 11//
12// Adds a new `#[derive()]` clause to a struct or enum.
13//
14// ```
15// struct Point {
16// x: u32,
17// y: u32,<|>
18// }
19// ```
20// ->
21// ```
22// #[derive()]
23// struct Point {
24// x: u32,
25// y: u32,
26// }
27// ```
28pub(crate) fn add_derive(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
29 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
14 let node_start = derive_insertion_offset(&nominal)?; 30 let node_start = derive_insertion_offset(&nominal)?;
15 ctx.add_action(AssistId("add_derive"), "add `#[derive]`", |edit| { 31 ctx.add_assist(AssistId("add_derive"), "add `#[derive]`", |edit| {
16 let derive_attr = nominal 32 let derive_attr = nominal
17 .attrs() 33 .attrs()
18 .filter_map(|x| x.as_simple_call()) 34 .filter_map(|x| x.as_simple_call())
@@ -28,9 +44,7 @@ pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist>
28 }; 44 };
29 edit.target(nominal.syntax().text_range()); 45 edit.target(nominal.syntax().text_range());
30 edit.set_cursor(offset) 46 edit.set_cursor(offset)
31 }); 47 })
32
33 ctx.build()
34} 48}
35 49
36// Insert `derive` after doc comments. 50// Insert `derive` after doc comments.
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs
index 8c83dc987..ddda1a0f2 100644
--- a/crates/ra_assists/src/assists/add_explicit_type.rs
+++ b/crates/ra_assists/src/assists/add_explicit_type.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use hir::{db::HirDatabase, HirDisplay, Ty}; 1use hir::{db::HirDatabase, HirDisplay, Ty};
4use ra_syntax::{ 2use ra_syntax::{
5 ast::{self, AstNode, LetStmt, NameOwner}, 3 ast::{self, AstNode, LetStmt, NameOwner},
@@ -8,9 +6,23 @@ use ra_syntax::{
8 6
9use crate::{Assist, AssistCtx, AssistId}; 7use crate::{Assist, AssistCtx, AssistId};
10 8
11/// Add explicit type assist. 9// Assist: add_explicit_type
12pub(crate) fn add_explicit_type(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10//
13 let stmt = ctx.node_at_offset::<LetStmt>()?; 11// Specify type for a let binding.
12//
13// ```
14// fn main() {
15// let x<|> = 92;
16// }
17// ```
18// ->
19// ```
20// fn main() {
21// let x: i32 = 92;
22// }
23// ```
24pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
25 let stmt = ctx.find_node_at_offset::<LetStmt>()?;
14 let expr = stmt.initializer()?; 26 let expr = stmt.initializer()?;
15 let pat = stmt.pat()?; 27 let pat = stmt.pat()?;
16 // Must be a binding 28 // Must be a binding
@@ -35,11 +47,10 @@ pub(crate) fn add_explicit_type(mut ctx: AssistCtx<impl HirDatabase>) -> Option<
35 return None; 47 return None;
36 } 48 }
37 49
38 ctx.add_action(AssistId("add_explicit_type"), "add explicit type", |edit| { 50 ctx.add_assist(AssistId("add_explicit_type"), "add explicit type", |edit| {
39 edit.target(pat_range); 51 edit.target(pat_range);
40 edit.insert(name_range.end(), format!(": {}", ty.display(db))); 52 edit.insert(name_range.end(), format!(": {}", ty.display(db)));
41 }); 53 })
42 ctx.build()
43} 54}
44 55
45/// Returns true if any type parameter is unknown 56/// Returns true if any type parameter is unknown
diff --git a/crates/ra_assists/src/assists/add_impl.rs b/crates/ra_assists/src/assists/add_impl.rs
index 94801fbc9..7da0cfd0d 100644
--- a/crates/ra_assists/src/assists/add_impl.rs
+++ b/crates/ra_assists/src/assists/add_impl.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use format_buf::format; 1use format_buf::format;
4use hir::db::HirDatabase; 2use hir::db::HirDatabase;
5use join_to_string::join; 3use join_to_string::join;
@@ -10,10 +8,29 @@ use ra_syntax::{
10 8
11use crate::{Assist, AssistCtx, AssistId}; 9use crate::{Assist, AssistCtx, AssistId};
12 10
13pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 11// Assist: add_impl
14 let nominal = ctx.node_at_offset::<ast::NominalDef>()?; 12//
13// Adds a new inherent impl for a type.
14//
15// ```
16// struct Ctx<T: Clone> {
17// data: T,<|>
18// }
19// ```
20// ->
21// ```
22// struct Ctx<T: Clone> {
23// data: T,
24// }
25//
26// impl<T: Clone> Ctx<T> {
27//
28// }
29// ```
30pub(crate) fn add_impl(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
31 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
15 let name = nominal.name()?; 32 let name = nominal.name()?;
16 ctx.add_action(AssistId("add_impl"), "add impl", |edit| { 33 ctx.add_assist(AssistId("add_impl"), "add impl", |edit| {
17 edit.target(nominal.syntax().text_range()); 34 edit.target(nominal.syntax().text_range());
18 let type_params = nominal.type_param_list(); 35 let type_params = nominal.type_param_list();
19 let start_offset = nominal.syntax().text_range().end(); 36 let start_offset = nominal.syntax().text_range().end();
@@ -37,9 +54,7 @@ pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
37 edit.set_cursor(start_offset + TextUnit::of_str(&buf)); 54 edit.set_cursor(start_offset + TextUnit::of_str(&buf));
38 buf.push_str("\n}"); 55 buf.push_str("\n}");
39 edit.insert(start_offset, buf); 56 edit.insert(start_offset, buf);
40 }); 57 })
41
42 ctx.build()
43} 58}
44 59
45#[cfg(test)] 60#[cfg(test)]
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/add_import.rs
index 02c58e7c6..363ade016 100644
--- a/crates/ra_assists/src/assists/auto_import.rs
+++ b/crates/ra_assists/src/assists/add_import.rs
@@ -1,18 +1,81 @@
1//! FIXME: write short doc here
2
3use hir::{self, db::HirDatabase}; 1use hir::{self, db::HirDatabase};
4use ra_text_edit::TextEditBuilder;
5
6use crate::{
7 assist_ctx::{Assist, AssistCtx},
8 AssistId,
9};
10use ra_syntax::{ 2use ra_syntax::{
11 ast::{self, NameOwner}, 3 ast::{self, NameOwner},
12 AstNode, Direction, SmolStr, 4 AstNode, Direction, SmolStr,
13 SyntaxKind::{PATH, PATH_SEGMENT}, 5 SyntaxKind::{PATH, PATH_SEGMENT},
14 SyntaxNode, TextRange, T, 6 SyntaxNode, TextRange, T,
15}; 7};
8use ra_text_edit::TextEditBuilder;
9
10use crate::{
11 assist_ctx::{Assist, AssistCtx},
12 AssistId,
13};
14
15/// This function produces sequence of text edits into edit
16/// to import the target path in the most appropriate scope given
17/// the cursor position
18pub fn auto_import_text_edit(
19 // Ideally the position of the cursor, used to
20 position: &SyntaxNode,
21 // The statement to use as anchor (last resort)
22 anchor: &SyntaxNode,
23 // The path to import as a sequence of strings
24 target: &[SmolStr],
25 edit: &mut TextEditBuilder,
26) {
27 let container = position.ancestors().find_map(|n| {
28 if let Some(module) = ast::Module::cast(n.clone()) {
29 return module.item_list().map(|it| it.syntax().clone());
30 }
31 ast::SourceFile::cast(n).map(|it| it.syntax().clone())
32 });
33
34 if let Some(container) = container {
35 let action = best_action_for_target(container, anchor.clone(), target);
36 make_assist(&action, target, edit);
37 }
38}
39
40// Assist: add_import
41//
42// Adds a use statement for a given fully-qualified path.
43//
44// ```
45// fn process(map: std::collections::<|>HashMap<String, String>) {}
46// ```
47// ->
48// ```
49// use std::collections::HashMap;
50//
51// fn process(map: HashMap<String, String>) {}
52// ```
53pub(crate) fn add_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
54 let path: ast::Path = ctx.find_node_at_offset()?;
55 // We don't want to mess with use statements
56 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() {
57 return None;
58 }
59
60 let hir_path = hir::Path::from_ast(path.clone())?;
61 let segments = collect_hir_path_segments(&hir_path)?;
62 if segments.len() < 2 {
63 return None;
64 }
65
66 let module = path.syntax().ancestors().find_map(ast::Module::cast);
67 let position = match module.and_then(|it| it.item_list()) {
68 Some(item_list) => item_list.syntax().clone(),
69 None => {
70 let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?;
71 current_file.syntax().clone()
72 }
73 };
74
75 ctx.add_assist(AssistId("add_import"), format!("import {}", fmt_segments(&segments)), |edit| {
76 apply_auto_import(&position, &path, &segments, edit.text_edit_builder());
77 })
78}
16 79
17fn collect_path_segments_raw( 80fn collect_path_segments_raw(
18 segments: &mut Vec<ast::PathSegment>, 81 segments: &mut Vec<ast::PathSegment>,
@@ -61,9 +124,9 @@ fn fmt_segments_raw(segments: &[SmolStr], buf: &mut String) {
61 } 124 }
62} 125}
63 126
64// Returns the numeber of common segments. 127/// Returns the number of common segments.
65fn compare_path_segments(left: &[SmolStr], right: &[ast::PathSegment]) -> usize { 128fn compare_path_segments(left: &[SmolStr], right: &[ast::PathSegment]) -> usize {
66 left.iter().zip(right).filter(|(l, r)| compare_path_segment(l, r)).count() 129 left.iter().zip(right).take_while(|(l, r)| compare_path_segment(l, r)).count()
67} 130}
68 131
69fn compare_path_segment(a: &SmolStr, b: &ast::PathSegment) -> bool { 132fn compare_path_segment(a: &SmolStr, b: &ast::PathSegment) -> bool {
@@ -84,7 +147,7 @@ fn compare_path_segment_with_name(a: &SmolStr, b: &ast::Name) -> bool {
84 a == b.text() 147 a == b.text()
85} 148}
86 149
87#[derive(Clone)] 150#[derive(Clone, Debug)]
88enum ImportAction { 151enum ImportAction {
89 Nothing, 152 Nothing,
90 // Add a brand new use statement. 153 // Add a brand new use statement.
@@ -154,9 +217,17 @@ impl ImportAction {
154 ( 217 (
155 ImportAction::AddNestedImport { common_segments: n, .. }, 218 ImportAction::AddNestedImport { common_segments: n, .. },
156 ImportAction::AddInTreeList { common_segments: m, .. }, 219 ImportAction::AddInTreeList { common_segments: m, .. },
157 ) => n > m, 220 )
158 ( 221 | (
222 ImportAction::AddInTreeList { common_segments: n, .. },
223 ImportAction::AddNestedImport { common_segments: m, .. },
224 )
225 | (
159 ImportAction::AddInTreeList { common_segments: n, .. }, 226 ImportAction::AddInTreeList { common_segments: n, .. },
227 ImportAction::AddInTreeList { common_segments: m, .. },
228 )
229 | (
230 ImportAction::AddNestedImport { common_segments: n, .. },
160 ImportAction::AddNestedImport { common_segments: m, .. }, 231 ImportAction::AddNestedImport { common_segments: m, .. },
161 ) => n > m, 232 ) => n > m,
162 (ImportAction::AddInTreeList { .. }, _) => true, 233 (ImportAction::AddInTreeList { .. }, _) => true,
@@ -226,7 +297,7 @@ fn walk_use_tree_for_best_action(
226 common if common == left.len() && left.len() == right.len() => { 297 common if common == left.len() && left.len() == right.len() => {
227 // e.g: target is std::fmt and we can have 298 // e.g: target is std::fmt and we can have
228 // 1- use std::fmt; 299 // 1- use std::fmt;
229 // 2- use std::fmt:{ ... } 300 // 2- use std::fmt::{ ... }
230 if let Some(list) = tree_list { 301 if let Some(list) = tree_list {
231 // In case 2 we need to add self to the nested list 302 // In case 2 we need to add self to the nested list
232 // unless it's already there 303 // unless it's already there
@@ -474,7 +545,7 @@ fn make_assist_add_nested_import(
474 if add_colon_colon { 545 if add_colon_colon {
475 buf.push_str("::"); 546 buf.push_str("::");
476 } 547 }
477 buf.push_str("{ "); 548 buf.push_str("{");
478 if add_self { 549 if add_self {
479 buf.push_str("self, "); 550 buf.push_str("self, ");
480 } 551 }
@@ -505,7 +576,7 @@ fn apply_auto_import(
505 } 576 }
506} 577}
507 578
508pub fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { 579fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> {
509 let mut ps = Vec::<SmolStr>::with_capacity(10); 580 let mut ps = Vec::<SmolStr>::with_capacity(10);
510 match path.kind { 581 match path.kind {
511 hir::PathKind::Abs => ps.push("".into()), 582 hir::PathKind::Abs => ps.push("".into()),
@@ -521,87 +592,16 @@ pub fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> {
521 Some(ps) 592 Some(ps)
522} 593}
523 594
524// This function produces sequence of text edits into edit
525// to import the target path in the most appropriate scope given
526// the cursor position
527pub fn auto_import_text_edit(
528 // Ideally the position of the cursor, used to
529 position: &SyntaxNode,
530 // The statement to use as anchor (last resort)
531 anchor: &SyntaxNode,
532 // The path to import as a sequence of strings
533 target: &[SmolStr],
534 edit: &mut TextEditBuilder,
535) {
536 let container = position.ancestors().find_map(|n| {
537 if let Some(module) = ast::Module::cast(n.clone()) {
538 return module.item_list().map(|it| it.syntax().clone());
539 }
540 ast::SourceFile::cast(n).map(|it| it.syntax().clone())
541 });
542
543 if let Some(container) = container {
544 let action = best_action_for_target(container, anchor.clone(), target);
545 make_assist(&action, target, edit);
546 }
547}
548
549pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
550 let path: ast::Path = ctx.node_at_offset()?;
551 // We don't want to mess with use statements
552 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() {
553 return None;
554 }
555
556 let hir_path = hir::Path::from_ast(path.clone())?;
557 let segments = collect_hir_path_segments(&hir_path)?;
558 if segments.len() < 2 {
559 return None;
560 }
561
562 if let Some(module) = path.syntax().ancestors().find_map(ast::Module::cast) {
563 if let (Some(item_list), Some(name)) = (module.item_list(), module.name()) {
564 ctx.add_action(
565 AssistId("auto_import"),
566 format!("import {} in mod {}", fmt_segments(&segments), name.text()),
567 |edit| {
568 apply_auto_import(
569 item_list.syntax(),
570 &path,
571 &segments,
572 edit.text_edit_builder(),
573 );
574 },
575 );
576 }
577 } else {
578 let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?;
579 ctx.add_action(
580 AssistId("auto_import"),
581 format!("import {} in the current file", fmt_segments(&segments)),
582 |edit| {
583 apply_auto_import(
584 current_file.syntax(),
585 &path,
586 &segments,
587 edit.text_edit_builder(),
588 );
589 },
590 );
591 }
592
593 ctx.build()
594}
595
596#[cfg(test)] 595#[cfg(test)]
597mod tests { 596mod tests {
598 use super::*;
599 use crate::helpers::{check_assist, check_assist_not_applicable}; 597 use crate::helpers::{check_assist, check_assist_not_applicable};
600 598
599 use super::*;
600
601 #[test] 601 #[test]
602 fn test_auto_import_add_use_no_anchor() { 602 fn test_auto_import_add_use_no_anchor() {
603 check_assist( 603 check_assist(
604 auto_import, 604 add_import,
605 " 605 "
606std::fmt::Debug<|> 606std::fmt::Debug<|>
607 ", 607 ",
@@ -615,7 +615,7 @@ Debug<|>
615 #[test] 615 #[test]
616 fn test_auto_import_add_use_no_anchor_with_item_below() { 616 fn test_auto_import_add_use_no_anchor_with_item_below() {
617 check_assist( 617 check_assist(
618 auto_import, 618 add_import,
619 " 619 "
620std::fmt::Debug<|> 620std::fmt::Debug<|>
621 621
@@ -636,7 +636,7 @@ fn main() {
636 #[test] 636 #[test]
637 fn test_auto_import_add_use_no_anchor_with_item_above() { 637 fn test_auto_import_add_use_no_anchor_with_item_above() {
638 check_assist( 638 check_assist(
639 auto_import, 639 add_import,
640 " 640 "
641fn main() { 641fn main() {
642} 642}
@@ -657,7 +657,7 @@ Debug<|>
657 #[test] 657 #[test]
658 fn test_auto_import_add_use_no_anchor_2seg() { 658 fn test_auto_import_add_use_no_anchor_2seg() {
659 check_assist( 659 check_assist(
660 auto_import, 660 add_import,
661 " 661 "
662std::fmt<|>::Debug 662std::fmt<|>::Debug
663 ", 663 ",
@@ -672,7 +672,7 @@ fmt<|>::Debug
672 #[test] 672 #[test]
673 fn test_auto_import_add_use() { 673 fn test_auto_import_add_use() {
674 check_assist( 674 check_assist(
675 auto_import, 675 add_import,
676 " 676 "
677use stdx; 677use stdx;
678 678
@@ -692,7 +692,7 @@ impl Debug<|> for Foo {
692 #[test] 692 #[test]
693 fn test_auto_import_file_use_other_anchor() { 693 fn test_auto_import_file_use_other_anchor() {
694 check_assist( 694 check_assist(
695 auto_import, 695 add_import,
696 " 696 "
697impl std::fmt::Debug<|> for Foo { 697impl std::fmt::Debug<|> for Foo {
698} 698}
@@ -709,7 +709,7 @@ impl Debug<|> for Foo {
709 #[test] 709 #[test]
710 fn test_auto_import_add_use_other_anchor_indent() { 710 fn test_auto_import_add_use_other_anchor_indent() {
711 check_assist( 711 check_assist(
712 auto_import, 712 add_import,
713 " 713 "
714 impl std::fmt::Debug<|> for Foo { 714 impl std::fmt::Debug<|> for Foo {
715 } 715 }
@@ -726,7 +726,7 @@ impl Debug<|> for Foo {
726 #[test] 726 #[test]
727 fn test_auto_import_split_different() { 727 fn test_auto_import_split_different() {
728 check_assist( 728 check_assist(
729 auto_import, 729 add_import,
730 " 730 "
731use std::fmt; 731use std::fmt;
732 732
@@ -734,7 +734,7 @@ impl std::io<|> for Foo {
734} 734}
735 ", 735 ",
736 " 736 "
737use std::{ io, fmt}; 737use std::{io, fmt};
738 738
739impl io<|> for Foo { 739impl io<|> for Foo {
740} 740}
@@ -745,7 +745,7 @@ impl io<|> for Foo {
745 #[test] 745 #[test]
746 fn test_auto_import_split_self_for_use() { 746 fn test_auto_import_split_self_for_use() {
747 check_assist( 747 check_assist(
748 auto_import, 748 add_import,
749 " 749 "
750use std::fmt; 750use std::fmt;
751 751
@@ -753,7 +753,7 @@ impl std::fmt::Debug<|> for Foo {
753} 753}
754 ", 754 ",
755 " 755 "
756use std::fmt::{ self, Debug, }; 756use std::fmt::{self, Debug, };
757 757
758impl Debug<|> for Foo { 758impl Debug<|> for Foo {
759} 759}
@@ -764,7 +764,7 @@ impl Debug<|> for Foo {
764 #[test] 764 #[test]
765 fn test_auto_import_split_self_for_target() { 765 fn test_auto_import_split_self_for_target() {
766 check_assist( 766 check_assist(
767 auto_import, 767 add_import,
768 " 768 "
769use std::fmt::Debug; 769use std::fmt::Debug;
770 770
@@ -772,7 +772,7 @@ impl std::fmt<|> for Foo {
772} 772}
773 ", 773 ",
774 " 774 "
775use std::fmt::{ self, Debug}; 775use std::fmt::{self, Debug};
776 776
777impl fmt<|> for Foo { 777impl fmt<|> for Foo {
778} 778}
@@ -783,7 +783,7 @@ impl fmt<|> for Foo {
783 #[test] 783 #[test]
784 fn test_auto_import_add_to_nested_self_nested() { 784 fn test_auto_import_add_to_nested_self_nested() {
785 check_assist( 785 check_assist(
786 auto_import, 786 add_import,
787 " 787 "
788use std::fmt::{Debug, nested::{Display}}; 788use std::fmt::{Debug, nested::{Display}};
789 789
@@ -802,7 +802,7 @@ impl nested<|> for Foo {
802 #[test] 802 #[test]
803 fn test_auto_import_add_to_nested_self_already_included() { 803 fn test_auto_import_add_to_nested_self_already_included() {
804 check_assist( 804 check_assist(
805 auto_import, 805 add_import,
806 " 806 "
807use std::fmt::{Debug, nested::{self, Display}}; 807use std::fmt::{Debug, nested::{self, Display}};
808 808
@@ -821,7 +821,7 @@ impl nested<|> for Foo {
821 #[test] 821 #[test]
822 fn test_auto_import_add_to_nested_nested() { 822 fn test_auto_import_add_to_nested_nested() {
823 check_assist( 823 check_assist(
824 auto_import, 824 add_import,
825 " 825 "
826use std::fmt::{Debug, nested::{Display}}; 826use std::fmt::{Debug, nested::{Display}};
827 827
@@ -840,7 +840,7 @@ impl Debug<|> for Foo {
840 #[test] 840 #[test]
841 fn test_auto_import_split_common_target_longer() { 841 fn test_auto_import_split_common_target_longer() {
842 check_assist( 842 check_assist(
843 auto_import, 843 add_import,
844 " 844 "
845use std::fmt::Debug; 845use std::fmt::Debug;
846 846
@@ -848,7 +848,7 @@ impl std::fmt::nested::Display<|> for Foo {
848} 848}
849", 849",
850 " 850 "
851use std::fmt::{ nested::Display, Debug}; 851use std::fmt::{nested::Display, Debug};
852 852
853impl Display<|> for Foo { 853impl Display<|> for Foo {
854} 854}
@@ -859,7 +859,7 @@ impl Display<|> for Foo {
859 #[test] 859 #[test]
860 fn test_auto_import_split_common_use_longer() { 860 fn test_auto_import_split_common_use_longer() {
861 check_assist( 861 check_assist(
862 auto_import, 862 add_import,
863 " 863 "
864use std::fmt::nested::Debug; 864use std::fmt::nested::Debug;
865 865
@@ -867,7 +867,7 @@ impl std::fmt::Display<|> for Foo {
867} 867}
868", 868",
869 " 869 "
870use std::fmt::{ Display, nested::Debug}; 870use std::fmt::{Display, nested::Debug};
871 871
872impl Display<|> for Foo { 872impl Display<|> for Foo {
873} 873}
@@ -876,9 +876,32 @@ impl Display<|> for Foo {
876 } 876 }
877 877
878 #[test] 878 #[test]
879 fn test_auto_import_use_nested_import() {
880 check_assist(
881 add_import,
882 "
883use crate::{
884 ty::{Substs, Ty},
885 AssocItem,
886};
887
888fn foo() { crate::ty::lower<|>::trait_env() }
889",
890 "
891use crate::{
892 ty::{Substs, Ty, lower},
893 AssocItem,
894};
895
896fn foo() { lower<|>::trait_env() }
897",
898 );
899 }
900
901 #[test]
879 fn test_auto_import_alias() { 902 fn test_auto_import_alias() {
880 check_assist( 903 check_assist(
881 auto_import, 904 add_import,
882 " 905 "
883use std::fmt as foo; 906use std::fmt as foo;
884 907
@@ -897,7 +920,7 @@ impl Debug<|> for Foo {
897 #[test] 920 #[test]
898 fn test_auto_import_not_applicable_one_segment() { 921 fn test_auto_import_not_applicable_one_segment() {
899 check_assist_not_applicable( 922 check_assist_not_applicable(
900 auto_import, 923 add_import,
901 " 924 "
902impl foo<|> for Foo { 925impl foo<|> for Foo {
903} 926}
@@ -908,7 +931,7 @@ impl foo<|> for Foo {
908 #[test] 931 #[test]
909 fn test_auto_import_not_applicable_in_use() { 932 fn test_auto_import_not_applicable_in_use() {
910 check_assist_not_applicable( 933 check_assist_not_applicable(
911 auto_import, 934 add_import,
912 " 935 "
913use std::fmt<|>; 936use std::fmt<|>;
914", 937",
@@ -918,7 +941,7 @@ use std::fmt<|>;
918 #[test] 941 #[test]
919 fn test_auto_import_add_use_no_anchor_in_mod_mod() { 942 fn test_auto_import_add_use_no_anchor_in_mod_mod() {
920 check_assist( 943 check_assist(
921 auto_import, 944 add_import,
922 " 945 "
923mod foo { 946mod foo {
924 mod bar { 947 mod bar {
diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs
index 565b96fb5..41de23921 100644
--- a/crates/ra_assists/src/assists/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use hir::{db::HirDatabase, HasSource}; 1use hir::{db::HirDatabase, HasSource};
4use ra_syntax::{ 2use ra_syntax::{
5 ast::{self, edit, make, AstNode, NameOwner}, 3 ast::{self, edit, make, AstNode, NameOwner},
@@ -14,6 +12,34 @@ enum AddMissingImplMembersMode {
14 NoDefaultMethods, 12 NoDefaultMethods,
15} 13}
16 14
15// Assist: add_impl_missing_members
16//
17// Adds scaffold for required impl members.
18//
19// ```
20// trait T {
21// Type X;
22// fn foo(&self);
23// fn bar(&self) {}
24// }
25//
26// impl T for () {<|>
27//
28// }
29// ```
30// ->
31// ```
32// trait T {
33// Type X;
34// fn foo(&self);
35// fn bar(&self) {}
36// }
37//
38// impl T for () {
39// fn foo(&self) { unimplemented!() }
40//
41// }
42// ```
17pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 43pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
18 add_missing_impl_members_inner( 44 add_missing_impl_members_inner(
19 ctx, 45 ctx,
@@ -23,6 +49,38 @@ pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Opti
23 ) 49 )
24} 50}
25 51
52// Assist: add_impl_default_members
53//
54// Adds scaffold for overriding default impl members.
55//
56// ```
57// trait T {
58// Type X;
59// fn foo(&self);
60// fn bar(&self) {}
61// }
62//
63// impl T for () {
64// Type X = ();
65// fn foo(&self) {}<|>
66//
67// }
68// ```
69// ->
70// ```
71// trait T {
72// Type X;
73// fn foo(&self);
74// fn bar(&self) {}
75// }
76//
77// impl T for () {
78// Type X = ();
79// fn foo(&self) {}
80// fn bar(&self) {}
81//
82// }
83// ```
26pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 84pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
27 add_missing_impl_members_inner( 85 add_missing_impl_members_inner(
28 ctx, 86 ctx,
@@ -33,12 +91,12 @@ pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> O
33} 91}
34 92
35fn add_missing_impl_members_inner( 93fn add_missing_impl_members_inner(
36 mut ctx: AssistCtx<impl HirDatabase>, 94 ctx: AssistCtx<impl HirDatabase>,
37 mode: AddMissingImplMembersMode, 95 mode: AddMissingImplMembersMode,
38 assist_id: &'static str, 96 assist_id: &'static str,
39 label: &'static str, 97 label: &'static str,
40) -> Option<Assist> { 98) -> Option<Assist> {
41 let impl_node = ctx.node_at_offset::<ast::ImplBlock>()?; 99 let impl_node = ctx.find_node_at_offset::<ast::ImplBlock>()?;
42 let impl_item_list = impl_node.item_list()?; 100 let impl_item_list = impl_node.item_list()?;
43 101
44 let trait_def = { 102 let trait_def = {
@@ -75,7 +133,7 @@ fn add_missing_impl_members_inner(
75 return None; 133 return None;
76 } 134 }
77 135
78 ctx.add_action(AssistId(assist_id), label, |edit| { 136 ctx.add_assist(AssistId(assist_id), label, |edit| {
79 let n_existing_items = impl_item_list.impl_items().count(); 137 let n_existing_items = impl_item_list.impl_items().count();
80 let items = missing_items 138 let items = missing_items
81 .into_iter() 139 .into_iter()
@@ -92,9 +150,7 @@ fn add_missing_impl_members_inner(
92 150
93 edit.replace_ast(impl_item_list, new_impl_item_list); 151 edit.replace_ast(impl_item_list, new_impl_item_list);
94 edit.set_cursor(cursor_position); 152 edit.set_cursor(cursor_position);
95 }); 153 })
96
97 ctx.build()
98} 154}
99 155
100fn add_body(fn_def: ast::FnDef) -> ast::FnDef { 156fn add_body(fn_def: ast::FnDef) -> ast::FnDef {
diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs
index 5f2b0dd18..068da1774 100644
--- a/crates/ra_assists/src/assists/apply_demorgan.rs
+++ b/crates/ra_assists/src/assists/apply_demorgan.rs
@@ -1,20 +1,30 @@
1//! This contains the functions associated with the demorgan assist.
2//! This assist transforms boolean expressions of the form `!a || !b` into
3//! `!(a && b)`.
4use hir::db::HirDatabase; 1use hir::db::HirDatabase;
5use ra_syntax::ast::{self, AstNode}; 2use ra_syntax::ast::{self, AstNode};
6use ra_syntax::SyntaxNode; 3use ra_syntax::SyntaxNode;
7 4
8use crate::{Assist, AssistCtx, AssistId}; 5use crate::{Assist, AssistCtx, AssistId};
9 6
10/// Assist for applying demorgan's law 7// Assist: apply_demorgan
11/// 8//
12/// This transforms expressions of the form `!l || !r` into `!(l && r)`. 9// Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
13/// This also works with `&&`. This assist can only be applied with the cursor 10// This transforms expressions of the form `!l || !r` into `!(l && r)`.
14/// on either `||` or `&&`, with both operands being a negation of some kind. 11// This also works with `&&`. This assist can only be applied with the cursor
15/// This means something of the form `!x` or `x != y`. 12// on either `||` or `&&`, with both operands being a negation of some kind.
16pub(crate) fn apply_demorgan(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 13// This means something of the form `!x` or `x != y`.
17 let expr = ctx.node_at_offset::<ast::BinExpr>()?; 14//
15// ```
16// fn main() {
17// if x != 4 ||<|> !y {}
18// }
19// ```
20// ->
21// ```
22// fn main() {
23// if !(x == 4 && y) {}
24// }
25// ```
26pub(crate) fn apply_demorgan(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
27 let expr = ctx.find_node_at_offset::<ast::BinExpr>()?;
18 let op = expr.op_kind()?; 28 let op = expr.op_kind()?;
19 let op_range = expr.op_token()?.text_range(); 29 let op_range = expr.op_token()?.text_range();
20 let opposite_op = opposite_logic_op(op)?; 30 let opposite_op = opposite_logic_op(op)?;
@@ -29,13 +39,12 @@ pub(crate) fn apply_demorgan(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Ass
29 let not_lhs = undo_negation(lhs)?; 39 let not_lhs = undo_negation(lhs)?;
30 let not_rhs = undo_negation(rhs)?; 40 let not_rhs = undo_negation(rhs)?;
31 41
32 ctx.add_action(AssistId("apply_demorgan"), "apply demorgan's law", |edit| { 42 ctx.add_assist(AssistId("apply_demorgan"), "apply demorgan's law", |edit| {
33 edit.target(op_range); 43 edit.target(op_range);
34 edit.replace(op_range, opposite_op); 44 edit.replace(op_range, opposite_op);
35 edit.replace(lhs_range, format!("!({}", not_lhs)); 45 edit.replace(lhs_range, format!("!({}", not_lhs));
36 edit.replace(rhs_range, format!("{})", not_rhs)); 46 edit.replace(rhs_range, format!("{})", not_rhs));
37 }); 47 })
38 ctx.build()
39} 48}
40 49
41// Return the opposite text for a given logical operator, if it makes sense 50// Return the opposite text for a given logical operator, if it makes sense
diff --git a/crates/ra_assists/src/assists/change_visibility.rs b/crates/ra_assists/src/assists/change_visibility.rs
index df92c6b67..132c9dc1d 100644
--- a/crates/ra_assists/src/assists/change_visibility.rs
+++ b/crates/ra_assists/src/assists/change_visibility.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use hir::db::HirDatabase; 1use hir::db::HirDatabase;
4use ra_syntax::{ 2use ra_syntax::{
5 ast::{self, NameOwner, VisibilityOwner}, 3 ast::{self, NameOwner, VisibilityOwner},
@@ -13,14 +11,25 @@ use ra_syntax::{
13 11
14use crate::{Assist, AssistCtx, AssistId}; 12use crate::{Assist, AssistCtx, AssistId};
15 13
14// Assist: change_visibility
15//
16// Adds or changes existing visibility specifier.
17//
18// ```
19// <|>fn frobnicate() {}
20// ```
21// ->
22// ```
23// pub(crate) fn frobnicate() {}
24// ```
16pub(crate) fn change_visibility(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 25pub(crate) fn change_visibility(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
17 if let Some(vis) = ctx.node_at_offset::<ast::Visibility>() { 26 if let Some(vis) = ctx.find_node_at_offset::<ast::Visibility>() {
18 return change_vis(ctx, vis); 27 return change_vis(ctx, vis);
19 } 28 }
20 add_vis(ctx) 29 add_vis(ctx)
21} 30}
22 31
23fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 32fn add_vis(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
24 let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() { 33 let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() {
25 T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true, 34 T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true,
26 _ => false, 35 _ => false,
@@ -48,13 +57,11 @@ fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
48 (vis_offset(field.syntax()), ident.text_range()) 57 (vis_offset(field.syntax()), ident.text_range())
49 }; 58 };
50 59
51 ctx.add_action(AssistId("change_visibility"), "make pub(crate)", |edit| { 60 ctx.add_assist(AssistId("change_visibility"), "make pub(crate)", |edit| {
52 edit.target(target); 61 edit.target(target);
53 edit.insert(offset, "pub(crate) "); 62 edit.insert(offset, "pub(crate) ");
54 edit.set_cursor(offset); 63 edit.set_cursor(offset);
55 }); 64 })
56
57 ctx.build()
58} 65}
59 66
60fn vis_offset(node: &SyntaxNode) -> TextUnit { 67fn vis_offset(node: &SyntaxNode) -> TextUnit {
@@ -68,24 +75,20 @@ fn vis_offset(node: &SyntaxNode) -> TextUnit {
68 .unwrap_or_else(|| node.text_range().start()) 75 .unwrap_or_else(|| node.text_range().start())
69} 76}
70 77
71fn change_vis(mut ctx: AssistCtx<impl HirDatabase>, vis: ast::Visibility) -> Option<Assist> { 78fn change_vis(ctx: AssistCtx<impl HirDatabase>, vis: ast::Visibility) -> Option<Assist> {
72 if vis.syntax().text() == "pub" { 79 if vis.syntax().text() == "pub" {
73 ctx.add_action(AssistId("change_visibility"), "change to pub(crate)", |edit| { 80 return ctx.add_assist(AssistId("change_visibility"), "change to pub(crate)", |edit| {
74 edit.target(vis.syntax().text_range()); 81 edit.target(vis.syntax().text_range());
75 edit.replace(vis.syntax().text_range(), "pub(crate)"); 82 edit.replace(vis.syntax().text_range(), "pub(crate)");
76 edit.set_cursor(vis.syntax().text_range().start()) 83 edit.set_cursor(vis.syntax().text_range().start())
77 }); 84 });
78
79 return ctx.build();
80 } 85 }
81 if vis.syntax().text() == "pub(crate)" { 86 if vis.syntax().text() == "pub(crate)" {
82 ctx.add_action(AssistId("change_visibility"), "change to pub", |edit| { 87 return ctx.add_assist(AssistId("change_visibility"), "change to pub", |edit| {
83 edit.target(vis.syntax().text_range()); 88 edit.target(vis.syntax().text_range());
84 edit.replace(vis.syntax().text_range(), "pub"); 89 edit.replace(vis.syntax().text_range(), "pub");
85 edit.set_cursor(vis.syntax().text_range().start()); 90 edit.set_cursor(vis.syntax().text_range().start());
86 }); 91 });
87
88 return ctx.build();
89 } 92 }
90 None 93 None
91} 94}
diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs
index f7d7e12e7..ad6c5695a 100644
--- a/crates/ra_assists/src/assists/early_return.rs
+++ b/crates/ra_assists/src/assists/early_return.rs
@@ -1,26 +1,3 @@
1//! Assist: `convert_to_guarded_return`
2//!
3//! Replace a large conditional with a guarded return.
4//!
5//! ```text
6//! fn <|>main() {
7//! if cond {
8//! foo();
9//! bar();
10//! }
11//! }
12//! ```
13//! ->
14//! ```text
15//! fn main() {
16//! if !cond {
17//! return;
18//! }
19//! foo();
20//! bar();
21//! }
22//! ```
23
24use std::ops::RangeInclusive; 1use std::ops::RangeInclusive;
25 2
26use hir::db::HirDatabase; 3use hir::db::HirDatabase;
@@ -36,8 +13,30 @@ use crate::{
36 AssistId, 13 AssistId,
37}; 14};
38 15
39pub(crate) fn convert_to_guarded_return(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 16// Assist: convert_to_guarded_return
40 let if_expr: ast::IfExpr = ctx.node_at_offset()?; 17//
18// Replace a large conditional with a guarded return.
19//
20// ```
21// fn main() {
22// <|>if cond {
23// foo();
24// bar();
25// }
26// }
27// ```
28// ->
29// ```
30// fn main() {
31// if !cond {
32// return;
33// }
34// foo();
35// bar();
36// }
37// ```
38pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
39 let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
41 let expr = if_expr.condition()?.expr()?; 40 let expr = if_expr.condition()?.expr()?;
42 let then_block = if_expr.then_branch()?.block()?; 41 let then_block = if_expr.then_branch()?.block()?;
43 if if_expr.else_branch().is_some() { 42 if if_expr.else_branch().is_some() {
@@ -51,7 +50,7 @@ pub(crate) fn convert_to_guarded_return(mut ctx: AssistCtx<impl HirDatabase>) ->
51 } 50 }
52 51
53 // check for early return and continue 52 // check for early return and continue
54 let first_in_then_block = then_block.syntax().first_child()?.clone(); 53 let first_in_then_block = then_block.syntax().first_child()?;
55 if ast::ReturnExpr::can_cast(first_in_then_block.kind()) 54 if ast::ReturnExpr::can_cast(first_in_then_block.kind())
56 || ast::ContinueExpr::can_cast(first_in_then_block.kind()) 55 || ast::ContinueExpr::can_cast(first_in_then_block.kind())
57 || first_in_then_block 56 || first_in_then_block
@@ -76,7 +75,7 @@ pub(crate) fn convert_to_guarded_return(mut ctx: AssistCtx<impl HirDatabase>) ->
76 then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; 75 then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?;
77 let cursor_position = ctx.frange.range.start(); 76 let cursor_position = ctx.frange.range.start();
78 77
79 ctx.add_action(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { 78 ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| {
80 let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); 79 let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
81 let new_if_expr = 80 let new_if_expr =
82 if_indent_level.increase_indent(make::if_expression(&expr, early_expression)); 81 if_indent_level.increase_indent(make::if_expression(&expr, early_expression));
@@ -106,8 +105,7 @@ pub(crate) fn convert_to_guarded_return(mut ctx: AssistCtx<impl HirDatabase>) ->
106 edit.target(if_expr.syntax().text_range()); 105 edit.target(if_expr.syntax().text_range());
107 edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap()); 106 edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap());
108 edit.set_cursor(cursor_position); 107 edit.set_cursor(cursor_position);
109 }); 108 })
110 ctx.build()
111} 109}
112 110
113#[cfg(test)] 111#[cfg(test)]
diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs
index e3f30b5de..2b74f355c 100644
--- a/crates/ra_assists/src/assists/fill_match_arms.rs
+++ b/crates/ra_assists/src/assists/fill_match_arms.rs
@@ -7,8 +7,32 @@ use ra_syntax::ast::{self, edit::IndentLevel, make, AstNode, NameOwner};
7 7
8use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
9 9
10pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10// Assist: fill_match_arms
11 let match_expr = ctx.node_at_offset::<ast::MatchExpr>()?; 11//
12// Adds missing clauses to a `match` expression.
13//
14// ```
15// enum Action { Move { distance: u32 }, Stop }
16//
17// fn handle(action: Action) {
18// match action {
19// <|>
20// }
21// }
22// ```
23// ->
24// ```
25// enum Action { Move { distance: u32 }, Stop }
26//
27// fn handle(action: Action) {
28// match action {
29// Action::Move { distance } => (),
30// Action::Stop => (),
31// }
32// }
33// ```
34pub(crate) fn fill_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
35 let match_expr = ctx.find_node_at_offset::<ast::MatchExpr>()?;
12 let match_arm_list = match_expr.match_arm_list()?; 36 let match_arm_list = match_expr.match_arm_list()?;
13 37
14 // We already have some match arms, so we don't provide any assists. 38 // We already have some match arms, so we don't provide any assists.
@@ -29,7 +53,7 @@ pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As
29 }; 53 };
30 let variant_list = enum_def.variant_list()?; 54 let variant_list = enum_def.variant_list()?;
31 55
32 ctx.add_action(AssistId("fill_match_arms"), "fill match arms", |edit| { 56 ctx.add_assist(AssistId("fill_match_arms"), "fill match arms", |edit| {
33 let indent_level = IndentLevel::from_node(match_arm_list.syntax()); 57 let indent_level = IndentLevel::from_node(match_arm_list.syntax());
34 58
35 let new_arm_list = { 59 let new_arm_list = {
@@ -43,9 +67,7 @@ pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As
43 edit.target(match_expr.syntax().text_range()); 67 edit.target(match_expr.syntax().text_range());
44 edit.set_cursor(expr.syntax().text_range().start()); 68 edit.set_cursor(expr.syntax().text_range().start());
45 edit.replace_ast(match_arm_list, new_arm_list); 69 edit.replace_ast(match_arm_list, new_arm_list);
46 }); 70 })
47
48 ctx.build()
49} 71}
50 72
51fn is_trivial(arm: &ast::MatchArm) -> bool { 73fn is_trivial(arm: &ast::MatchArm) -> bool {
@@ -130,7 +152,7 @@ mod tests {
130 A::Bs => (), 152 A::Bs => (),
131 A::Cs(_) => (), 153 A::Cs(_) => (),
132 A::Ds(_, _) => (), 154 A::Ds(_, _) => (),
133 A::Es{ x, y } => (), 155 A::Es { x, y } => (),
134 } 156 }
135 } 157 }
136 "#, 158 "#,
@@ -183,7 +205,7 @@ mod tests {
183 205
184 fn foo(a: &mut A) { 206 fn foo(a: &mut A) {
185 match <|>a { 207 match <|>a {
186 A::Es{ x, y } => (), 208 A::Es { x, y } => (),
187 } 209 }
188 } 210 }
189 "#, 211 "#,
diff --git a/crates/ra_assists/src/assists/flip_binexpr.rs b/crates/ra_assists/src/assists/flip_binexpr.rs
index c51035282..386045eb0 100644
--- a/crates/ra_assists/src/assists/flip_binexpr.rs
+++ b/crates/ra_assists/src/assists/flip_binexpr.rs
@@ -1,13 +1,25 @@
1//! FIXME: write short doc here
2
3use hir::db::HirDatabase; 1use hir::db::HirDatabase;
4use ra_syntax::ast::{AstNode, BinExpr, BinOp}; 2use ra_syntax::ast::{AstNode, BinExpr, BinOp};
5 3
6use crate::{Assist, AssistCtx, AssistId}; 4use crate::{Assist, AssistCtx, AssistId};
7 5
8/// Flip binary expression assist. 6// Assist: flip_binexpr
9pub(crate) fn flip_binexpr(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 7//
10 let expr = ctx.node_at_offset::<BinExpr>()?; 8// Flips operands of a binary expression.
9//
10// ```
11// fn main() {
12// let _ = 90 +<|> 2;
13// }
14// ```
15// ->
16// ```
17// fn main() {
18// let _ = 2 + 90;
19// }
20// ```
21pub(crate) fn flip_binexpr(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
22 let expr = ctx.find_node_at_offset::<BinExpr>()?;
11 let lhs = expr.lhs()?.syntax().clone(); 23 let lhs = expr.lhs()?.syntax().clone();
12 let rhs = expr.rhs()?.syntax().clone(); 24 let rhs = expr.rhs()?.syntax().clone();
13 let op_range = expr.op_token()?.text_range(); 25 let op_range = expr.op_token()?.text_range();
@@ -22,16 +34,14 @@ pub(crate) fn flip_binexpr(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assis
22 return None; 34 return None;
23 } 35 }
24 36
25 ctx.add_action(AssistId("flip_binexpr"), "flip binary expression", |edit| { 37 ctx.add_assist(AssistId("flip_binexpr"), "flip binary expression", |edit| {
26 edit.target(op_range); 38 edit.target(op_range);
27 if let FlipAction::FlipAndReplaceOp(new_op) = action { 39 if let FlipAction::FlipAndReplaceOp(new_op) = action {
28 edit.replace(op_range, new_op); 40 edit.replace(op_range, new_op);
29 } 41 }
30 edit.replace(lhs.text_range(), rhs.text()); 42 edit.replace(lhs.text_range(), rhs.text());
31 edit.replace(rhs.text_range(), lhs.text()); 43 edit.replace(rhs.text_range(), lhs.text());
32 }); 44 })
33
34 ctx.build()
35} 45}
36 46
37enum FlipAction { 47enum FlipAction {
diff --git a/crates/ra_assists/src/assists/flip_comma.rs b/crates/ra_assists/src/assists/flip_comma.rs
index e31cc5e7d..9be1c1dc6 100644
--- a/crates/ra_assists/src/assists/flip_comma.rs
+++ b/crates/ra_assists/src/assists/flip_comma.rs
@@ -1,12 +1,25 @@
1//! FIXME: write short doc here
2
3use hir::db::HirDatabase; 1use hir::db::HirDatabase;
4use ra_syntax::{algo::non_trivia_sibling, Direction, T}; 2use ra_syntax::{algo::non_trivia_sibling, Direction, T};
5 3
6use crate::{Assist, AssistCtx, AssistId}; 4use crate::{Assist, AssistCtx, AssistId};
7 5
8pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 6// Assist: flip_comma
9 let comma = ctx.token_at_offset().find(|leaf| leaf.kind() == T![,])?; 7//
8// Flips two comma-separated items.
9//
10// ```
11// fn main() {
12// ((1, 2),<|> (3, 4));
13// }
14// ```
15// ->
16// ```
17// fn main() {
18// ((3, 4), (1, 2));
19// }
20// ```
21pub(crate) fn flip_comma(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
22 let comma = ctx.find_token_at_offset(T![,])?;
10 let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; 23 let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?;
11 let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; 24 let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?;
12 25
@@ -16,13 +29,11 @@ pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist>
16 return None; 29 return None;
17 } 30 }
18 31
19 ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| { 32 ctx.add_assist(AssistId("flip_comma"), "flip comma", |edit| {
20 edit.target(comma.text_range()); 33 edit.target(comma.text_range());
21 edit.replace(prev.text_range(), next.to_string()); 34 edit.replace(prev.text_range(), next.to_string());
22 edit.replace(next.text_range(), prev.to_string()); 35 edit.replace(next.text_range(), prev.to_string());
23 }); 36 })
24
25 ctx.build()
26} 37}
27 38
28#[cfg(test)] 39#[cfg(test)]
diff --git a/crates/ra_assists/src/assists/flip_trait_bound.rs b/crates/ra_assists/src/assists/flip_trait_bound.rs
new file mode 100644
index 000000000..6017b39dd
--- /dev/null
+++ b/crates/ra_assists/src/assists/flip_trait_bound.rs
@@ -0,0 +1,117 @@
1use hir::db::HirDatabase;
2use ra_syntax::{
3 algo::non_trivia_sibling,
4 ast::{self, AstNode},
5 Direction, T,
6};
7
8use crate::{Assist, AssistCtx, AssistId};
9
10// Assist: flip_trait_bound
11//
12// Flips two trait bounds.
13//
14// ```
15// fn foo<T: Clone +<|> Copy>() { }
16// ```
17// ->
18// ```
19// fn foo<T: Copy + Clone>() { }
20// ```
21pub(crate) fn flip_trait_bound(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
22 // We want to replicate the behavior of `flip_binexpr` by only suggesting
23 // the assist when the cursor is on a `+`
24 let plus = ctx.find_token_at_offset(T![+])?;
25
26 // Make sure we're in a `TypeBoundList`
27 if ast::TypeBoundList::cast(plus.parent()).is_none() {
28 return None;
29 }
30
31 let (before, after) = (
32 non_trivia_sibling(plus.clone().into(), Direction::Prev)?,
33 non_trivia_sibling(plus.clone().into(), Direction::Next)?,
34 );
35
36 ctx.add_assist(AssistId("flip_trait_bound"), "flip trait bound", |edit| {
37 edit.target(plus.text_range());
38 edit.replace(before.text_range(), after.to_string());
39 edit.replace(after.text_range(), before.to_string());
40 })
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46
47 use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target};
48
49 #[test]
50 fn flip_trait_bound_assist_available() {
51 check_assist_target(flip_trait_bound, "struct S<T> where T: A <|>+ B + C { }", "+")
52 }
53
54 #[test]
55 fn flip_trait_bound_not_applicable_for_single_trait_bound() {
56 check_assist_not_applicable(flip_trait_bound, "struct S<T> where T: <|>A { }")
57 }
58
59 #[test]
60 fn flip_trait_bound_works_for_struct() {
61 check_assist(
62 flip_trait_bound,
63 "struct S<T> where T: A <|>+ B { }",
64 "struct S<T> where T: B <|>+ A { }",
65 )
66 }
67
68 #[test]
69 fn flip_trait_bound_works_for_trait_impl() {
70 check_assist(
71 flip_trait_bound,
72 "impl X for S<T> where T: A +<|> B { }",
73 "impl X for S<T> where T: B +<|> A { }",
74 )
75 }
76
77 #[test]
78 fn flip_trait_bound_works_for_fn() {
79 check_assist(flip_trait_bound, "fn f<T: A <|>+ B>(t: T) { }", "fn f<T: B <|>+ A>(t: T) { }")
80 }
81
82 #[test]
83 fn flip_trait_bound_works_for_fn_where_clause() {
84 check_assist(
85 flip_trait_bound,
86 "fn f<T>(t: T) where T: A +<|> B { }",
87 "fn f<T>(t: T) where T: B +<|> A { }",
88 )
89 }
90
91 #[test]
92 fn flip_trait_bound_works_for_lifetime() {
93 check_assist(
94 flip_trait_bound,
95 "fn f<T>(t: T) where T: A <|>+ 'static { }",
96 "fn f<T>(t: T) where T: 'static <|>+ A { }",
97 )
98 }
99
100 #[test]
101 fn flip_trait_bound_works_for_complex_bounds() {
102 check_assist(
103 flip_trait_bound,
104 "struct S<T> where T: A<T> <|>+ b_mod::B<T> + C<T> { }",
105 "struct S<T> where T: b_mod::B<T> <|>+ A<T> + C<T> { }",
106 )
107 }
108
109 #[test]
110 fn flip_trait_bound_works_for_long_bounds() {
111 check_assist(
112 flip_trait_bound,
113 "struct S<T> where T: A + B + C + D + E + F +<|> G + H + I + J { }",
114 "struct S<T> where T: A + B + C + D + E + G +<|> F + H + I + J { }",
115 )
116 }
117}
diff --git a/crates/ra_assists/src/assists/inline_local_variable.rs b/crates/ra_assists/src/assists/inline_local_variable.rs
index 9bd64decc..a7fd9b6d2 100644
--- a/crates/ra_assists/src/assists/inline_local_variable.rs
+++ b/crates/ra_assists/src/assists/inline_local_variable.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use hir::db::HirDatabase; 1use hir::db::HirDatabase;
4use ra_syntax::{ 2use ra_syntax::{
5 ast::{self, AstNode, AstToken}, 3 ast::{self, AstNode, AstToken},
@@ -9,8 +7,24 @@ use ra_syntax::{
9use crate::assist_ctx::AssistBuilder; 7use crate::assist_ctx::AssistBuilder;
10use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
11 9
12pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10// Assist: inline_local_variable
13 let let_stmt = ctx.node_at_offset::<ast::LetStmt>()?; 11//
12// Inlines local variable.
13//
14// ```
15// fn main() {
16// let x<|> = 1 + 2;
17// x * 4;
18// }
19// ```
20// ->
21// ```
22// fn main() {
23// (1 + 2) * 4;
24// }
25// ```
26pub(crate) fn inline_local_varialbe(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
27 let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?;
14 let bind_pat = match let_stmt.pat()? { 28 let bind_pat = match let_stmt.pat()? {
15 ast::Pat::BindPat(pat) => pat, 29 ast::Pat::BindPat(pat) => pat,
16 _ => return None, 30 _ => return None,
@@ -37,10 +51,8 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt
37 let mut wrap_in_parens = vec![true; refs.len()]; 51 let mut wrap_in_parens = vec![true; refs.len()];
38 52
39 for (i, desc) in refs.iter().enumerate() { 53 for (i, desc) in refs.iter().enumerate() {
40 let usage_node = ctx 54 let usage_node =
41 .covering_node_for_range(desc.range) 55 ctx.covering_node_for_range(desc.range).ancestors().find_map(ast::PathExpr::cast)?;
42 .ancestors()
43 .find_map(|node| ast::PathExpr::cast(node))?;
44 let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast); 56 let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast);
45 let usage_parent = match usage_parent_option { 57 let usage_parent = match usage_parent_option {
46 Some(u) => u, 58 Some(u) => u,
@@ -79,7 +91,7 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt
79 let init_str = initializer_expr.syntax().text().to_string(); 91 let init_str = initializer_expr.syntax().text().to_string();
80 let init_in_paren = format!("({})", &init_str); 92 let init_in_paren = format!("({})", &init_str);
81 93
82 ctx.add_action( 94 ctx.add_assist(
83 AssistId("inline_local_variable"), 95 AssistId("inline_local_variable"),
84 "inline local variable", 96 "inline local variable",
85 move |edit: &mut AssistBuilder| { 97 move |edit: &mut AssistBuilder| {
@@ -93,9 +105,7 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt
93 } 105 }
94 edit.set_cursor(delete_range.start()) 106 edit.set_cursor(delete_range.start())
95 }, 107 },
96 ); 108 )
97
98 ctx.build()
99} 109}
100 110
101#[cfg(test)] 111#[cfg(test)]
diff --git a/crates/ra_assists/src/assists/introduce_variable.rs b/crates/ra_assists/src/assists/introduce_variable.rs
index 43378c4b0..0623d4475 100644
--- a/crates/ra_assists/src/assists/introduce_variable.rs
+++ b/crates/ra_assists/src/assists/introduce_variable.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use format_buf::format; 1use format_buf::format;
4use hir::db::HirDatabase; 2use hir::db::HirDatabase;
5use ra_syntax::{ 3use ra_syntax::{
@@ -14,7 +12,23 @@ use test_utils::tested_by;
14 12
15use crate::{Assist, AssistCtx, AssistId}; 13use crate::{Assist, AssistCtx, AssistId};
16 14
17pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 15// Assist: introduce_variable
16//
17// Extracts subexpression into a variable.
18//
19// ```
20// fn main() {
21// <|>(1 + 2)<|> * 4;
22// }
23// ```
24// ->
25// ```
26// fn main() {
27// let var_name = (1 + 2);
28// var_name * 4;
29// }
30// ```
31pub(crate) fn introduce_variable(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
18 if ctx.frange.range.is_empty() { 32 if ctx.frange.range.is_empty() {
19 return None; 33 return None;
20 } 34 }
@@ -29,7 +43,7 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option
29 if indent.kind() != WHITESPACE { 43 if indent.kind() != WHITESPACE {
30 return None; 44 return None;
31 } 45 }
32 ctx.add_action(AssistId("introduce_variable"), "introduce variable", move |edit| { 46 ctx.add_assist(AssistId("introduce_variable"), "introduce variable", move |edit| {
33 let mut buf = String::new(); 47 let mut buf = String::new();
34 48
35 let cursor_offset = if wrap_in_block { 49 let cursor_offset = if wrap_in_block {
@@ -74,9 +88,7 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option
74 } 88 }
75 } 89 }
76 edit.set_cursor(anchor_stmt.text_range().start() + cursor_offset); 90 edit.set_cursor(anchor_stmt.text_range().start() + cursor_offset);
77 }); 91 })
78
79 ctx.build()
80} 92}
81 93
82/// Check whether the node is a valid expression which can be extracted to a variable. 94/// Check whether the node is a valid expression which can be extracted to a variable.
diff --git a/crates/ra_assists/src/assists/merge_match_arms.rs b/crates/ra_assists/src/assists/merge_match_arms.rs
index 17baa98f9..e9f2cae91 100644
--- a/crates/ra_assists/src/assists/merge_match_arms.rs
+++ b/crates/ra_assists/src/assists/merge_match_arms.rs
@@ -1,11 +1,33 @@
1//! FIXME: write short doc here
2
3use crate::{Assist, AssistCtx, AssistId, TextRange, TextUnit}; 1use crate::{Assist, AssistCtx, AssistId, TextRange, TextUnit};
4use hir::db::HirDatabase; 2use hir::db::HirDatabase;
5use ra_syntax::ast::{AstNode, MatchArm}; 3use ra_syntax::ast::{AstNode, MatchArm};
6 4
7pub(crate) fn merge_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 5// Assist: merge_match_arms
8 let current_arm = ctx.node_at_offset::<MatchArm>()?; 6//
7// Merges identical match arms.
8//
9// ```
10// enum Action { Move { distance: u32 }, Stop }
11//
12// fn handle(action: Action) {
13// match action {
14// <|>Action::Move(..) => foo(),
15// Action::Stop => foo(),
16// }
17// }
18// ```
19// ->
20// ```
21// enum Action { Move { distance: u32 }, Stop }
22//
23// fn handle(action: Action) {
24// match action {
25// Action::Move(..) | Action::Stop => foo(),
26// }
27// }
28// ```
29pub(crate) fn merge_match_arms(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
30 let current_arm = ctx.find_node_at_offset::<MatchArm>()?;
9 31
10 // We check if the following match arm matches this one. We could, but don't, 32 // We check if the following match arm matches this one. We could, but don't,
11 // compare to the previous match arm as well. 33 // compare to the previous match arm as well.
@@ -30,7 +52,7 @@ pub(crate) fn merge_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<A
30 52
31 let cursor_to_end = current_arm.syntax().text_range().end() - ctx.frange.range.start(); 53 let cursor_to_end = current_arm.syntax().text_range().end() - ctx.frange.range.start();
32 54
33 ctx.add_action(AssistId("merge_match_arms"), "merge match arms", |edit| { 55 ctx.add_assist(AssistId("merge_match_arms"), "merge match arms", |edit| {
34 fn contains_placeholder(a: &MatchArm) -> bool { 56 fn contains_placeholder(a: &MatchArm) -> bool {
35 a.pats().any(|x| match x { 57 a.pats().any(|x| match x {
36 ra_syntax::ast::Pat::PlaceholderPat(..) => true, 58 ra_syntax::ast::Pat::PlaceholderPat(..) => true,
@@ -58,9 +80,7 @@ pub(crate) fn merge_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<A
58 edit.target(current_arm.syntax().text_range()); 80 edit.target(current_arm.syntax().text_range());
59 edit.replace(TextRange::from_to(start, end), arm); 81 edit.replace(TextRange::from_to(start, end), arm);
60 edit.set_cursor(start + offset); 82 edit.set_cursor(start + offset);
61 }); 83 })
62
63 ctx.build()
64} 84}
65 85
66#[cfg(test)] 86#[cfg(test)]
diff --git a/crates/ra_assists/src/assists/move_bounds.rs b/crates/ra_assists/src/assists/move_bounds.rs
index d2444b6b9..3145d7625 100644
--- a/crates/ra_assists/src/assists/move_bounds.rs
+++ b/crates/ra_assists/src/assists/move_bounds.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use hir::db::HirDatabase; 1use hir::db::HirDatabase;
4use ra_syntax::{ 2use ra_syntax::{
5 ast::{self, edit, make, AstNode, NameOwner, TypeBoundsOwner}, 3 ast::{self, edit, make, AstNode, NameOwner, TypeBoundsOwner},
@@ -9,8 +7,23 @@ use ra_syntax::{
9 7
10use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
11 9
12pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10// Assist: move_bounds_to_where_clause
13 let type_param_list = ctx.node_at_offset::<ast::TypeParamList>()?; 11//
12// Moves inline type bounds to a where clause.
13//
14// ```
15// fn apply<T, U, <|>F: FnOnce(T) -> U>(f: F, x: T) -> U {
16// f(x)
17// }
18// ```
19// ->
20// ```
21// fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U {
22// f(x)
23// }
24// ```
25pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
26 let type_param_list = ctx.find_node_at_offset::<ast::TypeParamList>()?;
14 27
15 let mut type_params = type_param_list.type_params(); 28 let mut type_params = type_param_list.type_params();
16 if type_params.all(|p| p.type_bound_list().is_none()) { 29 if type_params.all(|p| p.type_bound_list().is_none()) {
@@ -33,38 +46,30 @@ pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx<impl HirDatabase>)
33 _ => return None, 46 _ => return None,
34 }; 47 };
35 48
36 ctx.add_action( 49 ctx.add_assist(AssistId("move_bounds_to_where_clause"), "move_bounds_to_where_clause", |edit| {
37 AssistId("move_bounds_to_where_clause"), 50 let new_params = type_param_list
38 "move_bounds_to_where_clause", 51 .type_params()
39 |edit| { 52 .filter(|it| it.type_bound_list().is_some())
40 let new_params = type_param_list 53 .map(|type_param| {
41 .type_params() 54 let without_bounds = type_param.remove_bounds();
42 .filter(|it| it.type_bound_list().is_some()) 55 (type_param, without_bounds)
43 .map(|type_param| { 56 });
44 let without_bounds = type_param.remove_bounds(); 57
45 (type_param, without_bounds) 58 let new_type_param_list = edit::replace_descendants(&type_param_list, new_params);
46 }); 59 edit.replace_ast(type_param_list.clone(), new_type_param_list);
47 60
48 let new_type_param_list = edit::replace_descendants(&type_param_list, new_params); 61 let where_clause = {
49 edit.replace_ast(type_param_list.clone(), new_type_param_list); 62 let predicates = type_param_list.type_params().filter_map(build_predicate);
50 63 make::where_clause(predicates)
51 let where_clause = { 64 };
52 let predicates = type_param_list.type_params().filter_map(build_predicate); 65
53 make::where_clause(predicates) 66 let to_insert = match anchor.prev_sibling_or_token() {
54 }; 67 Some(ref elem) if elem.kind() == WHITESPACE => format!("{} ", where_clause.syntax()),
55 68 _ => format!(" {}", where_clause.syntax()),
56 let to_insert = match anchor.prev_sibling_or_token() { 69 };
57 Some(ref elem) if elem.kind() == WHITESPACE => { 70 edit.insert(anchor.text_range().start(), to_insert);
58 format!("{} ", where_clause.syntax()) 71 edit.target(type_param_list.syntax().text_range());
59 } 72 })
60 _ => format!(" {}", where_clause.syntax()),
61 };
62 edit.insert(anchor.text_range().start(), to_insert);
63 edit.target(type_param_list.syntax().text_range());
64 },
65 );
66
67 ctx.build()
68} 73}
69 74
70fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { 75fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> {
diff --git a/crates/ra_assists/src/assists/move_guard.rs b/crates/ra_assists/src/assists/move_guard.rs
index 51aea6334..b49ec6172 100644
--- a/crates/ra_assists/src/assists/move_guard.rs
+++ b/crates/ra_assists/src/assists/move_guard.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use hir::db::HirDatabase; 1use hir::db::HirDatabase;
4use ra_syntax::{ 2use ra_syntax::{
5 ast, 3 ast,
@@ -9,8 +7,33 @@ use ra_syntax::{
9 7
10use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
11 9
12pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10// Assist: move_guard_to_arm_body
13 let match_arm = ctx.node_at_offset::<MatchArm>()?; 11//
12// Moves match guard into match arm body.
13//
14// ```
15// enum Action { Move { distance: u32 }, Stop }
16//
17// fn handle(action: Action) {
18// match action {
19// Action::Move { distance } <|>if distance > 10 => foo(),
20// _ => (),
21// }
22// }
23// ```
24// ->
25// ```
26// enum Action { Move { distance: u32 }, Stop }
27//
28// fn handle(action: Action) {
29// match action {
30// Action::Move { distance } => if distance > 10 { foo() },
31// _ => (),
32// }
33// }
34// ```
35pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
36 let match_arm = ctx.find_node_at_offset::<MatchArm>()?;
14 let guard = match_arm.guard()?; 37 let guard = match_arm.guard()?;
15 let space_before_guard = guard.syntax().prev_sibling_or_token(); 38 let space_before_guard = guard.syntax().prev_sibling_or_token();
16 39
@@ -18,7 +41,7 @@ pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx<impl HirDatabase>) -> Op
18 let arm_expr = match_arm.expr()?; 41 let arm_expr = match_arm.expr()?;
19 let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); 42 let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text());
20 43
21 ctx.add_action(AssistId("move_guard_to_arm_body"), "move guard to arm body", |edit| { 44 ctx.add_assist(AssistId("move_guard_to_arm_body"), "move guard to arm body", |edit| {
22 edit.target(guard.syntax().text_range()); 45 edit.target(guard.syntax().text_range());
23 let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) { 46 let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) {
24 Some(tok) => { 47 Some(tok) => {
@@ -38,12 +61,36 @@ pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx<impl HirDatabase>) -> Op
38 edit.set_cursor( 61 edit.set_cursor(
39 arm_expr.syntax().text_range().start() + TextUnit::from(3) - offseting_amount, 62 arm_expr.syntax().text_range().start() + TextUnit::from(3) - offseting_amount,
40 ); 63 );
41 }); 64 })
42 ctx.build()
43} 65}
44 66
45pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 67// Assist: move_arm_cond_to_match_guard
46 let match_arm: MatchArm = ctx.node_at_offset::<MatchArm>()?; 68//
69// Moves if expression from match arm body into a guard.
70//
71// ```
72// enum Action { Move { distance: u32 }, Stop }
73//
74// fn handle(action: Action) {
75// match action {
76// Action::Move { distance } => <|>if distance > 10 { foo() },
77// _ => (),
78// }
79// }
80// ```
81// ->
82// ```
83// enum Action { Move { distance: u32 }, Stop }
84//
85// fn handle(action: Action) {
86// match action {
87// Action::Move { distance } if distance > 10 => foo(),
88// _ => (),
89// }
90// }
91// ```
92pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
93 let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?;
47 let last_match_pat = match_arm.pats().last()?; 94 let last_match_pat = match_arm.pats().last()?;
48 95
49 let arm_body = match_arm.expr()?; 96 let arm_body = match_arm.expr()?;
@@ -62,7 +109,7 @@ pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx<impl HirDatabase>)
62 109
63 let buf = format!(" if {}", cond.syntax().text()); 110 let buf = format!(" if {}", cond.syntax().text());
64 111
65 ctx.add_action( 112 ctx.add_assist(
66 AssistId("move_arm_cond_to_match_guard"), 113 AssistId("move_arm_cond_to_match_guard"),
67 "move condition to match guard", 114 "move condition to match guard",
68 |edit| { 115 |edit| {
@@ -79,8 +126,7 @@ pub(crate) fn move_arm_cond_to_match_guard(mut ctx: AssistCtx<impl HirDatabase>)
79 edit.insert(last_match_pat.syntax().text_range().end(), buf); 126 edit.insert(last_match_pat.syntax().text_range().end(), buf);
80 edit.set_cursor(last_match_pat.syntax().text_range().end() + TextUnit::from(1)); 127 edit.set_cursor(last_match_pat.syntax().text_range().end() + TextUnit::from(1));
81 }, 128 },
82 ); 129 )
83 ctx.build()
84} 130}
85 131
86#[cfg(test)] 132#[cfg(test)]
diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs
index 2d2e31e51..58f7157ae 100644
--- a/crates/ra_assists/src/assists/raw_string.rs
+++ b/crates/ra_assists/src/assists/raw_string.rs
@@ -1,17 +1,29 @@
1//! FIXME: write short doc here
2
3use hir::db::HirDatabase; 1use hir::db::HirDatabase;
4use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; 2use ra_syntax::{
3 SyntaxKind::{RAW_STRING, STRING},
4 TextRange, TextUnit,
5};
5use rustc_lexer; 6use rustc_lexer;
6 7
7use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
8 9
9pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10// Assist: make_raw_string
10 let literal = ctx.node_at_offset::<Literal>()?; 11//
11 if literal.token().kind() != ra_syntax::SyntaxKind::STRING { 12// Adds `r#` to a plain string literal.
12 return None; 13//
13 } 14// ```
14 let token = literal.token(); 15// fn main() {
16// "Hello,<|> World!";
17// }
18// ```
19// ->
20// ```
21// fn main() {
22// r#"Hello, World!"#;
23// }
24// ```
25pub(crate) fn make_raw_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
26 let token = ctx.find_token_at_offset(STRING)?;
15 let text = token.text().as_str(); 27 let text = token.text().as_str();
16 let usual_string_range = find_usual_string_range(text)?; 28 let usual_string_range = find_usual_string_range(text)?;
17 let start_of_inside = usual_string_range.start().to_usize() + 1; 29 let start_of_inside = usual_string_range.start().to_usize() + 1;
@@ -29,97 +41,131 @@ pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As
29 if error.is_err() { 41 if error.is_err() {
30 return None; 42 return None;
31 } 43 }
32 ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| { 44 ctx.add_assist(AssistId("make_raw_string"), "make raw string", |edit| {
33 edit.target(literal.syntax().text_range()); 45 edit.target(token.text_range());
34 let max_hash_streak = count_hashes(&unescaped); 46 let max_hash_streak = count_hashes(&unescaped);
35 let mut hashes = String::with_capacity(max_hash_streak + 1); 47 let mut hashes = String::with_capacity(max_hash_streak + 1);
36 for _ in 0..hashes.capacity() { 48 for _ in 0..hashes.capacity() {
37 hashes.push('#'); 49 hashes.push('#');
38 } 50 }
39 edit.replace( 51 edit.replace(token.text_range(), format!("r{}\"{}\"{}", hashes, unescaped, hashes));
40 literal.syntax().text_range(), 52 })
41 format!("r{}\"{}\"{}", hashes, unescaped, hashes),
42 );
43 });
44 ctx.build()
45}
46
47fn count_hashes(s: &str) -> usize {
48 let mut max_hash_streak = 0usize;
49 for idx in s.match_indices("\"#").map(|(i, _)| i) {
50 let (_, sub) = s.split_at(idx + 1);
51 let nb_hash = sub.chars().take_while(|c| *c == '#').count();
52 if nb_hash > max_hash_streak {
53 max_hash_streak = nb_hash;
54 }
55 }
56 max_hash_streak
57}
58
59fn find_usual_string_range(s: &str) -> Option<TextRange> {
60 Some(TextRange::from_to(
61 TextUnit::from(s.find('"')? as u32),
62 TextUnit::from(s.rfind('"')? as u32),
63 ))
64} 53}
65 54
66pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 55// Assist: make_usual_string
67 let literal = ctx.node_at_offset::<Literal>()?; 56//
68 if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { 57// Turns a raw string into a plain string.
69 return None; 58//
70 } 59// ```
71 let token = literal.token(); 60// fn main() {
61// r#"Hello,<|> "World!""#;
62// }
63// ```
64// ->
65// ```
66// fn main() {
67// "Hello, \"World!\"";
68// }
69// ```
70pub(crate) fn make_usual_string(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
71 let token = ctx.find_token_at_offset(RAW_STRING)?;
72 let text = token.text().as_str(); 72 let text = token.text().as_str();
73 let usual_string_range = find_usual_string_range(text)?; 73 let usual_string_range = find_usual_string_range(text)?;
74 ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| { 74 ctx.add_assist(AssistId("make_usual_string"), "make usual string", |edit| {
75 edit.target(literal.syntax().text_range()); 75 edit.target(token.text_range());
76 // parse inside string to escape `"` 76 // parse inside string to escape `"`
77 let start_of_inside = usual_string_range.start().to_usize() + 1; 77 let start_of_inside = usual_string_range.start().to_usize() + 1;
78 let end_of_inside = usual_string_range.end().to_usize(); 78 let end_of_inside = usual_string_range.end().to_usize();
79 let inside_str = &text[start_of_inside..end_of_inside]; 79 let inside_str = &text[start_of_inside..end_of_inside];
80 let escaped = inside_str.escape_default().to_string(); 80 let escaped = inside_str.escape_default().to_string();
81 edit.replace(literal.syntax().text_range(), format!("\"{}\"", escaped)); 81 edit.replace(token.text_range(), format!("\"{}\"", escaped));
82 }); 82 })
83 ctx.build()
84} 83}
85 84
86pub(crate) fn add_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 85// Assist: add_hash
87 let literal = ctx.node_at_offset::<Literal>()?; 86//
88 if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { 87// Adds a hash to a raw string literal.
89 return None; 88//
90 } 89// ```
91 ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| { 90// fn main() {
92 edit.target(literal.syntax().text_range()); 91// r#"Hello,<|> World!"#;
93 edit.insert(literal.syntax().text_range().start() + TextUnit::of_char('r'), "#"); 92// }
94 edit.insert(literal.syntax().text_range().end(), "#"); 93// ```
95 }); 94// ->
96 ctx.build() 95// ```
96// fn main() {
97// r##"Hello, World!"##;
98// }
99// ```
100pub(crate) fn add_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
101 let token = ctx.find_token_at_offset(RAW_STRING)?;
102 ctx.add_assist(AssistId("add_hash"), "add hash to raw string", |edit| {
103 edit.target(token.text_range());
104 edit.insert(token.text_range().start() + TextUnit::of_char('r'), "#");
105 edit.insert(token.text_range().end(), "#");
106 })
97} 107}
98 108
99pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 109// Assist: remove_hash
100 let literal = ctx.node_at_offset::<Literal>()?; 110//
101 if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { 111// Removes a hash from a raw string literal.
102 return None; 112//
103 } 113// ```
104 let token = literal.token(); 114// fn main() {
115// r#"Hello,<|> World!"#;
116// }
117// ```
118// ->
119// ```
120// fn main() {
121// r"Hello, World!";
122// }
123// ```
124pub(crate) fn remove_hash(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
125 let token = ctx.find_token_at_offset(RAW_STRING)?;
105 let text = token.text().as_str(); 126 let text = token.text().as_str();
106 if text.starts_with("r\"") { 127 if text.starts_with("r\"") {
107 // no hash to remove 128 // no hash to remove
108 return None; 129 return None;
109 } 130 }
110 ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| { 131 ctx.add_assist(AssistId("remove_hash"), "remove hash from raw string", |edit| {
111 edit.target(literal.syntax().text_range()); 132 edit.target(token.text_range());
112 let result = &text[2..text.len() - 1]; 133 let result = &text[2..text.len() - 1];
113 let result = if result.starts_with("\"") { 134 let result = if result.starts_with('\"') {
114 // no more hash, escape 135 // no more hash, escape
115 let internal_str = &result[1..result.len() - 1]; 136 let internal_str = &result[1..result.len() - 1];
116 format!("\"{}\"", internal_str.escape_default().to_string()) 137 format!("\"{}\"", internal_str.escape_default().to_string())
117 } else { 138 } else {
118 result.to_owned() 139 result.to_owned()
119 }; 140 };
120 edit.replace(literal.syntax().text_range(), format!("r{}", result)); 141 edit.replace(token.text_range(), format!("r{}", result));
121 }); 142 })
122 ctx.build() 143}
144
145fn count_hashes(s: &str) -> usize {
146 let mut max_hash_streak = 0usize;
147 for idx in s.match_indices("\"#").map(|(i, _)| i) {
148 let (_, sub) = s.split_at(idx + 1);
149 let nb_hash = sub.chars().take_while(|c| *c == '#').count();
150 if nb_hash > max_hash_streak {
151 max_hash_streak = nb_hash;
152 }
153 }
154 max_hash_streak
155}
156
157fn find_usual_string_range(s: &str) -> Option<TextRange> {
158 let left_quote = s.find('"')?;
159 let right_quote = s.rfind('"')?;
160 if left_quote == right_quote {
161 // `s` only contains one quote
162 None
163 } else {
164 Some(TextRange::from_to(
165 TextUnit::from(left_quote as u32),
166 TextUnit::from(right_quote as u32),
167 ))
168 }
123} 169}
124 170
125#[cfg(test)] 171#[cfg(test)]
@@ -159,6 +205,23 @@ string"#;
159 } 205 }
160 206
161 #[test] 207 #[test]
208 fn make_raw_string_works_inside_macros() {
209 check_assist(
210 make_raw_string,
211 r#"
212 fn f() {
213 format!(<|>"x = {}", 92)
214 }
215 "#,
216 r##"
217 fn f() {
218 format!(<|>r#"x = {}"#, 92)
219 }
220 "##,
221 )
222 }
223
224 #[test]
162 fn make_raw_string_hashes_inside_works() { 225 fn make_raw_string_hashes_inside_works() {
163 check_assist( 226 check_assist(
164 make_raw_string, 227 make_raw_string,
@@ -212,6 +275,30 @@ string"###;
212 } 275 }
213 276
214 #[test] 277 #[test]
278 fn make_raw_string_not_works_on_partial_string() {
279 check_assist_not_applicable(
280 make_raw_string,
281 r#"
282 fn f() {
283 let s = "foo<|>
284 }
285 "#,
286 )
287 }
288
289 #[test]
290 fn make_usual_string_not_works_on_partial_string() {
291 check_assist_not_applicable(
292 make_usual_string,
293 r#"
294 fn main() {
295 let s = r#"bar<|>
296 }
297 "#,
298 )
299 }
300
301 #[test]
215 fn add_hash_target() { 302 fn add_hash_target() {
216 check_assist_target( 303 check_assist_target(
217 add_hash, 304 add_hash,
diff --git a/crates/ra_assists/src/assists/remove_dbg.rs b/crates/ra_assists/src/assists/remove_dbg.rs
index 1a7e2b305..aedf8747f 100644
--- a/crates/ra_assists/src/assists/remove_dbg.rs
+++ b/crates/ra_assists/src/assists/remove_dbg.rs
@@ -1,14 +1,28 @@
1//! FIXME: write short doc here
2
3use crate::{Assist, AssistCtx, AssistId};
4use hir::db::HirDatabase; 1use hir::db::HirDatabase;
5use ra_syntax::{ 2use ra_syntax::{
6 ast::{self, AstNode}, 3 ast::{self, AstNode},
7 TextUnit, T, 4 TextUnit, T,
8}; 5};
9 6
10pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 7use crate::{Assist, AssistCtx, AssistId};
11 let macro_call = ctx.node_at_offset::<ast::MacroCall>()?; 8
9// Assist: remove_dbg
10//
11// Removes `dbg!()` macro call.
12//
13// ```
14// fn main() {
15// <|>dbg!(92);
16// }
17// ```
18// ->
19// ```
20// fn main() {
21// 92;
22// }
23// ```
24pub(crate) fn remove_dbg(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
25 let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;
12 26
13 if !is_valid_macrocall(&macro_call, "dbg")? { 27 if !is_valid_macrocall(&macro_call, "dbg")? {
14 return None; 28 return None;
@@ -44,13 +58,11 @@ pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist>
44 text.slice(without_parens).to_string() 58 text.slice(without_parens).to_string()
45 }; 59 };
46 60
47 ctx.add_action(AssistId("remove_dbg"), "remove dbg!()", |edit| { 61 ctx.add_assist(AssistId("remove_dbg"), "remove dbg!()", |edit| {
48 edit.target(macro_call.syntax().text_range()); 62 edit.target(macro_call.syntax().text_range());
49 edit.replace(macro_range, macro_content); 63 edit.replace(macro_range, macro_content);
50 edit.set_cursor(cursor_pos); 64 edit.set_cursor(cursor_pos);
51 }); 65 })
52
53 ctx.build()
54} 66}
55 67
56/// Verifies that the given macro_call actually matches the given name 68/// Verifies that the given macro_call actually matches the given name
diff --git a/crates/ra_assists/src/assists/replace_if_let_with_match.rs b/crates/ra_assists/src/assists/replace_if_let_with_match.rs
index 749ff338a..dff84d865 100644
--- a/crates/ra_assists/src/assists/replace_if_let_with_match.rs
+++ b/crates/ra_assists/src/assists/replace_if_let_with_match.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use format_buf::format; 1use format_buf::format;
4use hir::db::HirDatabase; 2use hir::db::HirDatabase;
5use ra_fmt::extract_trivial_expression; 3use ra_fmt::extract_trivial_expression;
@@ -7,8 +5,34 @@ use ra_syntax::{ast, AstNode};
7 5
8use crate::{Assist, AssistCtx, AssistId}; 6use crate::{Assist, AssistCtx, AssistId};
9 7
10pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 8// Assist: replace_if_let_with_match
11 let if_expr: ast::IfExpr = ctx.node_at_offset()?; 9//
10// Replaces `if let` with an else branch with a `match` expression.
11//
12// ```
13// enum Action { Move { distance: u32 }, Stop }
14//
15// fn handle(action: Action) {
16// <|>if let Action::Move { distance } = action {
17// foo(distance)
18// } else {
19// bar()
20// }
21// }
22// ```
23// ->
24// ```
25// enum Action { Move { distance: u32 }, Stop }
26//
27// fn handle(action: Action) {
28// match action {
29// Action::Move { distance } => foo(distance),
30// _ => bar(),
31// }
32// }
33// ```
34pub(crate) fn replace_if_let_with_match(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
35 let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
12 let cond = if_expr.condition()?; 36 let cond = if_expr.condition()?;
13 let pat = cond.pat()?; 37 let pat = cond.pat()?;
14 let expr = cond.expr()?; 38 let expr = cond.expr()?;
@@ -18,14 +42,12 @@ pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) ->
18 ast::ElseBranch::IfExpr(_) => return None, 42 ast::ElseBranch::IfExpr(_) => return None,
19 }; 43 };
20 44
21 ctx.add_action(AssistId("replace_if_let_with_match"), "replace with match", |edit| { 45 ctx.add_assist(AssistId("replace_if_let_with_match"), "replace with match", |edit| {
22 let match_expr = build_match_expr(expr, pat, then_block, else_block); 46 let match_expr = build_match_expr(expr, pat, then_block, else_block);
23 edit.target(if_expr.syntax().text_range()); 47 edit.target(if_expr.syntax().text_range());
24 edit.replace_node_and_indent(if_expr.syntax(), match_expr); 48 edit.replace_node_and_indent(if_expr.syntax(), match_expr);
25 edit.set_cursor(if_expr.syntax().text_range().start()) 49 edit.set_cursor(if_expr.syntax().text_range().start())
26 }); 50 })
27
28 ctx.build()
29} 51}
30 52
31fn build_match_expr( 53fn build_match_expr(
diff --git a/crates/ra_assists/src/assists/split_import.rs b/crates/ra_assists/src/assists/split_import.rs
index fe3e64af5..5f8d6b0be 100644
--- a/crates/ra_assists/src/assists/split_import.rs
+++ b/crates/ra_assists/src/assists/split_import.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use std::iter::successors; 1use std::iter::successors;
4 2
5use hir::db::HirDatabase; 3use hir::db::HirDatabase;
@@ -7,8 +5,19 @@ use ra_syntax::{ast, AstNode, TextUnit, T};
7 5
8use crate::{Assist, AssistCtx, AssistId}; 6use crate::{Assist, AssistCtx, AssistId};
9 7
10pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 8// Assist: split_import
11 let colon_colon = ctx.token_at_offset().find(|leaf| leaf.kind() == T![::])?; 9//
10// Wraps the tail of import into braces.
11//
12// ```
13// use std::<|>collections::HashMap;
14// ```
15// ->
16// ```
17// use std::{collections::HashMap};
18// ```
19pub(crate) fn split_import(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
20 let colon_colon = ctx.find_token_at_offset(T![::])?;
12 let path = ast::Path::cast(colon_colon.parent())?; 21 let path = ast::Path::cast(colon_colon.parent())?;
13 let top_path = successors(Some(path), |it| it.parent_path()).last()?; 22 let top_path = successors(Some(path), |it| it.parent_path()).last()?;
14 23
@@ -23,14 +32,12 @@ pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assis
23 None => top_path.syntax().text_range().end(), 32 None => top_path.syntax().text_range().end(),
24 }; 33 };
25 34
26 ctx.add_action(AssistId("split_import"), "split import", |edit| { 35 ctx.add_assist(AssistId("split_import"), "split import", |edit| {
27 edit.target(colon_colon.text_range()); 36 edit.target(colon_colon.text_range());
28 edit.insert(l_curly, "{"); 37 edit.insert(l_curly, "{");
29 edit.insert(r_curly, "}"); 38 edit.insert(r_curly, "}");
30 edit.set_cursor(l_curly + TextUnit::of_str("{")); 39 edit.set_cursor(l_curly + TextUnit::of_str("{"));
31 }); 40 })
32
33 ctx.build()
34} 41}
35 42
36#[cfg(test)] 43#[cfg(test)]
diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs
new file mode 100644
index 000000000..6e1e3de84
--- /dev/null
+++ b/crates/ra_assists/src/doc_tests.rs
@@ -0,0 +1,34 @@
1//! Each assist definition has a special comment, which specifies docs and
2//! example.
3//!
4//! We collect all the example and write the as tests in this module.
5
6mod generated;
7
8use hir::mock::MockDatabase;
9use ra_db::FileRange;
10use test_utils::{assert_eq_text, extract_range_or_offset};
11
12fn check(assist_id: &str, before: &str, after: &str) {
13 let (selection, before) = extract_range_or_offset(before);
14 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
15 let frange = FileRange { file_id, range: selection.into() };
16
17 let (_assist_id, action) = crate::assists(&db, frange)
18 .into_iter()
19 .find(|(id, _)| id.id.0 == assist_id)
20 .unwrap_or_else(|| {
21 panic!(
22 "\n\nAssist is not applicable: {}\nAvailable assists: {}",
23 assist_id,
24 crate::assists(&db, frange)
25 .into_iter()
26 .map(|(id, _)| id.id.0)
27 .collect::<Vec<_>>()
28 .join(", ")
29 )
30 });
31
32 let actual = action.edit.apply(&before);
33 assert_eq_text!(after, &actual);
34}
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
new file mode 100644
index 000000000..1bee76f59
--- /dev/null
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -0,0 +1,526 @@
1//! Generated file, do not edit by hand, see `crate/ra_tools/src/codegen`
2
3use super::check;
4
5#[test]
6fn doctest_add_derive() {
7 check(
8 "add_derive",
9 r#####"
10struct Point {
11 x: u32,
12 y: u32,<|>
13}
14"#####,
15 r#####"
16#[derive()]
17struct Point {
18 x: u32,
19 y: u32,
20}
21"#####,
22 )
23}
24
25#[test]
26fn doctest_add_explicit_type() {
27 check(
28 "add_explicit_type",
29 r#####"
30fn main() {
31 let x<|> = 92;
32}
33"#####,
34 r#####"
35fn main() {
36 let x: i32 = 92;
37}
38"#####,
39 )
40}
41
42#[test]
43fn doctest_add_hash() {
44 check(
45 "add_hash",
46 r#####"
47fn main() {
48 r#"Hello,<|> World!"#;
49}
50"#####,
51 r#####"
52fn main() {
53 r##"Hello, World!"##;
54}
55"#####,
56 )
57}
58
59#[test]
60fn doctest_add_impl() {
61 check(
62 "add_impl",
63 r#####"
64struct Ctx<T: Clone> {
65 data: T,<|>
66}
67"#####,
68 r#####"
69struct Ctx<T: Clone> {
70 data: T,
71}
72
73impl<T: Clone> Ctx<T> {
74
75}
76"#####,
77 )
78}
79
80#[test]
81fn doctest_add_impl_default_members() {
82 check(
83 "add_impl_default_members",
84 r#####"
85trait T {
86 Type X;
87 fn foo(&self);
88 fn bar(&self) {}
89}
90
91impl T for () {
92 Type X = ();
93 fn foo(&self) {}<|>
94
95}
96"#####,
97 r#####"
98trait T {
99 Type X;
100 fn foo(&self);
101 fn bar(&self) {}
102}
103
104impl T for () {
105 Type X = ();
106 fn foo(&self) {}
107 fn bar(&self) {}
108
109}
110"#####,
111 )
112}
113
114#[test]
115fn doctest_add_impl_missing_members() {
116 check(
117 "add_impl_missing_members",
118 r#####"
119trait T {
120 Type X;
121 fn foo(&self);
122 fn bar(&self) {}
123}
124
125impl T for () {<|>
126
127}
128"#####,
129 r#####"
130trait T {
131 Type X;
132 fn foo(&self);
133 fn bar(&self) {}
134}
135
136impl T for () {
137 fn foo(&self) { unimplemented!() }
138
139}
140"#####,
141 )
142}
143
144#[test]
145fn doctest_add_import() {
146 check(
147 "add_import",
148 r#####"
149fn process(map: std::collections::<|>HashMap<String, String>) {}
150"#####,
151 r#####"
152use std::collections::HashMap;
153
154fn process(map: HashMap<String, String>) {}
155"#####,
156 )
157}
158
159#[test]
160fn doctest_apply_demorgan() {
161 check(
162 "apply_demorgan",
163 r#####"
164fn main() {
165 if x != 4 ||<|> !y {}
166}
167"#####,
168 r#####"
169fn main() {
170 if !(x == 4 && y) {}
171}
172"#####,
173 )
174}
175
176#[test]
177fn doctest_change_visibility() {
178 check(
179 "change_visibility",
180 r#####"
181<|>fn frobnicate() {}
182"#####,
183 r#####"
184pub(crate) fn frobnicate() {}
185"#####,
186 )
187}
188
189#[test]
190fn doctest_convert_to_guarded_return() {
191 check(
192 "convert_to_guarded_return",
193 r#####"
194fn main() {
195 <|>if cond {
196 foo();
197 bar();
198 }
199}
200"#####,
201 r#####"
202fn main() {
203 if !cond {
204 return;
205 }
206 foo();
207 bar();
208}
209"#####,
210 )
211}
212
213#[test]
214fn doctest_fill_match_arms() {
215 check(
216 "fill_match_arms",
217 r#####"
218enum Action { Move { distance: u32 }, Stop }
219
220fn handle(action: Action) {
221 match action {
222 <|>
223 }
224}
225"#####,
226 r#####"
227enum Action { Move { distance: u32 }, Stop }
228
229fn handle(action: Action) {
230 match action {
231 Action::Move { distance } => (),
232 Action::Stop => (),
233 }
234}
235"#####,
236 )
237}
238
239#[test]
240fn doctest_flip_binexpr() {
241 check(
242 "flip_binexpr",
243 r#####"
244fn main() {
245 let _ = 90 +<|> 2;
246}
247"#####,
248 r#####"
249fn main() {
250 let _ = 2 + 90;
251}
252"#####,
253 )
254}
255
256#[test]
257fn doctest_flip_comma() {
258 check(
259 "flip_comma",
260 r#####"
261fn main() {
262 ((1, 2),<|> (3, 4));
263}
264"#####,
265 r#####"
266fn main() {
267 ((3, 4), (1, 2));
268}
269"#####,
270 )
271}
272
273#[test]
274fn doctest_flip_trait_bound() {
275 check(
276 "flip_trait_bound",
277 r#####"
278fn foo<T: Clone +<|> Copy>() { }
279"#####,
280 r#####"
281fn foo<T: Copy + Clone>() { }
282"#####,
283 )
284}
285
286#[test]
287fn doctest_inline_local_variable() {
288 check(
289 "inline_local_variable",
290 r#####"
291fn main() {
292 let x<|> = 1 + 2;
293 x * 4;
294}
295"#####,
296 r#####"
297fn main() {
298 (1 + 2) * 4;
299}
300"#####,
301 )
302}
303
304#[test]
305fn doctest_introduce_variable() {
306 check(
307 "introduce_variable",
308 r#####"
309fn main() {
310 <|>(1 + 2)<|> * 4;
311}
312"#####,
313 r#####"
314fn main() {
315 let var_name = (1 + 2);
316 var_name * 4;
317}
318"#####,
319 )
320}
321
322#[test]
323fn doctest_make_raw_string() {
324 check(
325 "make_raw_string",
326 r#####"
327fn main() {
328 "Hello,<|> World!";
329}
330"#####,
331 r#####"
332fn main() {
333 r#"Hello, World!"#;
334}
335"#####,
336 )
337}
338
339#[test]
340fn doctest_make_usual_string() {
341 check(
342 "make_usual_string",
343 r#####"
344fn main() {
345 r#"Hello,<|> "World!""#;
346}
347"#####,
348 r#####"
349fn main() {
350 "Hello, \"World!\"";
351}
352"#####,
353 )
354}
355
356#[test]
357fn doctest_merge_match_arms() {
358 check(
359 "merge_match_arms",
360 r#####"
361enum Action { Move { distance: u32 }, Stop }
362
363fn handle(action: Action) {
364 match action {
365 <|>Action::Move(..) => foo(),
366 Action::Stop => foo(),
367 }
368}
369"#####,
370 r#####"
371enum Action { Move { distance: u32 }, Stop }
372
373fn handle(action: Action) {
374 match action {
375 Action::Move(..) | Action::Stop => foo(),
376 }
377}
378"#####,
379 )
380}
381
382#[test]
383fn doctest_move_arm_cond_to_match_guard() {
384 check(
385 "move_arm_cond_to_match_guard",
386 r#####"
387enum Action { Move { distance: u32 }, Stop }
388
389fn handle(action: Action) {
390 match action {
391 Action::Move { distance } => <|>if distance > 10 { foo() },
392 _ => (),
393 }
394}
395"#####,
396 r#####"
397enum Action { Move { distance: u32 }, Stop }
398
399fn handle(action: Action) {
400 match action {
401 Action::Move { distance } if distance > 10 => foo(),
402 _ => (),
403 }
404}
405"#####,
406 )
407}
408
409#[test]
410fn doctest_move_bounds_to_where_clause() {
411 check(
412 "move_bounds_to_where_clause",
413 r#####"
414fn apply<T, U, <|>F: FnOnce(T) -> U>(f: F, x: T) -> U {
415 f(x)
416}
417"#####,
418 r#####"
419fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U {
420 f(x)
421}
422"#####,
423 )
424}
425
426#[test]
427fn doctest_move_guard_to_arm_body() {
428 check(
429 "move_guard_to_arm_body",
430 r#####"
431enum Action { Move { distance: u32 }, Stop }
432
433fn handle(action: Action) {
434 match action {
435 Action::Move { distance } <|>if distance > 10 => foo(),
436 _ => (),
437 }
438}
439"#####,
440 r#####"
441enum Action { Move { distance: u32 }, Stop }
442
443fn handle(action: Action) {
444 match action {
445 Action::Move { distance } => if distance > 10 { foo() },
446 _ => (),
447 }
448}
449"#####,
450 )
451}
452
453#[test]
454fn doctest_remove_dbg() {
455 check(
456 "remove_dbg",
457 r#####"
458fn main() {
459 <|>dbg!(92);
460}
461"#####,
462 r#####"
463fn main() {
464 92;
465}
466"#####,
467 )
468}
469
470#[test]
471fn doctest_remove_hash() {
472 check(
473 "remove_hash",
474 r#####"
475fn main() {
476 r#"Hello,<|> World!"#;
477}
478"#####,
479 r#####"
480fn main() {
481 r"Hello, World!";
482}
483"#####,
484 )
485}
486
487#[test]
488fn doctest_replace_if_let_with_match() {
489 check(
490 "replace_if_let_with_match",
491 r#####"
492enum Action { Move { distance: u32 }, Stop }
493
494fn handle(action: Action) {
495 <|>if let Action::Move { distance } = action {
496 foo(distance)
497 } else {
498 bar()
499 }
500}
501"#####,
502 r#####"
503enum Action { Move { distance: u32 }, Stop }
504
505fn handle(action: Action) {
506 match action {
507 Action::Move { distance } => foo(distance),
508 _ => bar(),
509 }
510}
511"#####,
512 )
513}
514
515#[test]
516fn doctest_split_import() {
517 check(
518 "split_import",
519 r#####"
520use std::<|>collections::HashMap;
521"#####,
522 r#####"
523use std::{collections::HashMap};
524"#####,
525 )
526}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index ab77b46a9..38599d4f1 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -7,15 +7,16 @@
7 7
8mod assist_ctx; 8mod assist_ctx;
9mod marks; 9mod marks;
10#[cfg(test)]
11mod doc_tests;
10 12
11use hir::db::HirDatabase; 13use hir::db::HirDatabase;
12use itertools::Itertools;
13use ra_db::FileRange; 14use ra_db::FileRange;
14use ra_syntax::{TextRange, TextUnit}; 15use ra_syntax::{TextRange, TextUnit};
15use ra_text_edit::TextEdit; 16use ra_text_edit::TextEdit;
16 17
17pub(crate) use crate::assist_ctx::{Assist, AssistCtx}; 18pub(crate) use crate::assist_ctx::{Assist, AssistCtx};
18pub use crate::assists::auto_import::auto_import_text_edit; 19pub use crate::assists::add_import::auto_import_text_edit;
19 20
20/// Unique identifier of the assist, should not be shown to the user 21/// Unique identifier of the assist, should not be shown to the user
21/// directly. 22/// directly.
@@ -36,7 +37,7 @@ pub struct AssistAction {
36 pub target: Option<TextRange>, 37 pub target: Option<TextRange>,
37} 38}
38 39
39/// Return all the assists eapplicable at the given position. 40/// Return all the assists applicable at the given position.
40/// 41///
41/// Assists are returned in the "unresolved" state, that is only labels are 42/// Assists are returned in the "unresolved" state, that is only labels are
42/// returned, without actual edits. 43/// returned, without actual edits.
@@ -49,10 +50,10 @@ where
49 .iter() 50 .iter()
50 .filter_map(|f| f(ctx.clone())) 51 .filter_map(|f| f(ctx.clone()))
51 .map(|a| match a { 52 .map(|a| match a {
52 Assist::Unresolved(labels) => labels, 53 Assist::Unresolved { label } => label,
53 Assist::Resolved(..) => unreachable!(), 54 Assist::Resolved { .. } => unreachable!(),
54 }) 55 })
55 .concat() 56 .collect()
56 }) 57 })
57} 58}
58 59
@@ -71,10 +72,10 @@ where
71 .iter() 72 .iter()
72 .filter_map(|f| f(ctx.clone())) 73 .filter_map(|f| f(ctx.clone()))
73 .map(|a| match a { 74 .map(|a| match a {
74 Assist::Resolved(labels_actions) => labels_actions, 75 Assist::Resolved { label, action } => (label, action),
75 Assist::Unresolved(..) => unreachable!(), 76 Assist::Unresolved { .. } => unreachable!(),
76 }) 77 })
77 .concat(); 78 .collect::<Vec<_>>();
78 a.sort_by(|a, b| match (a.1.target, b.1.target) { 79 a.sort_by(|a, b| match (a.1.target, b.1.target) {
79 (Some(a), Some(b)) => a.len().cmp(&b.len()), 80 (Some(a), Some(b)) => a.len().cmp(&b.len()),
80 (Some(_), None) => Ordering::Less, 81 (Some(_), None) => Ordering::Less,
@@ -95,6 +96,7 @@ mod assists {
95 mod apply_demorgan; 96 mod apply_demorgan;
96 mod flip_comma; 97 mod flip_comma;
97 mod flip_binexpr; 98 mod flip_binexpr;
99 mod flip_trait_bound;
98 mod change_visibility; 100 mod change_visibility;
99 mod fill_match_arms; 101 mod fill_match_arms;
100 mod merge_match_arms; 102 mod merge_match_arms;
@@ -104,7 +106,7 @@ mod assists {
104 mod replace_if_let_with_match; 106 mod replace_if_let_with_match;
105 mod split_import; 107 mod split_import;
106 mod remove_dbg; 108 mod remove_dbg;
107 pub(crate) mod auto_import; 109 pub(crate) mod add_import;
108 mod add_missing_impl_members; 110 mod add_missing_impl_members;
109 mod move_guard; 111 mod move_guard;
110 mod move_bounds; 112 mod move_bounds;
@@ -121,11 +123,12 @@ mod assists {
121 merge_match_arms::merge_match_arms, 123 merge_match_arms::merge_match_arms,
122 flip_comma::flip_comma, 124 flip_comma::flip_comma,
123 flip_binexpr::flip_binexpr, 125 flip_binexpr::flip_binexpr,
126 flip_trait_bound::flip_trait_bound,
124 introduce_variable::introduce_variable, 127 introduce_variable::introduce_variable,
125 replace_if_let_with_match::replace_if_let_with_match, 128 replace_if_let_with_match::replace_if_let_with_match,
126 split_import::split_import, 129 split_import::split_import,
127 remove_dbg::remove_dbg, 130 remove_dbg::remove_dbg,
128 auto_import::auto_import, 131 add_import::add_import,
129 add_missing_impl_members::add_missing_impl_members, 132 add_missing_impl_members::add_missing_impl_members,
130 add_missing_impl_members::add_missing_default_members, 133 add_missing_impl_members::add_missing_default_members,
131 inline_local_variable::inline_local_varialbe, 134 inline_local_variable::inline_local_varialbe,
@@ -155,51 +158,17 @@ mod helpers {
155 before: &str, 158 before: &str,
156 after: &str, 159 after: &str,
157 ) { 160 ) {
158 check_assist_nth_action(assist, before, after, 0)
159 }
160
161 pub(crate) fn check_assist_range(
162 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
163 before: &str,
164 after: &str,
165 ) {
166 check_assist_range_nth_action(assist, before, after, 0)
167 }
168
169 pub(crate) fn check_assist_target(
170 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
171 before: &str,
172 target: &str,
173 ) {
174 check_assist_target_nth_action(assist, before, target, 0)
175 }
176
177 pub(crate) fn check_assist_range_target(
178 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
179 before: &str,
180 target: &str,
181 ) {
182 check_assist_range_target_nth_action(assist, before, target, 0)
183 }
184
185 pub(crate) fn check_assist_nth_action(
186 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
187 before: &str,
188 after: &str,
189 index: usize,
190 ) {
191 let (before_cursor_pos, before) = extract_offset(before); 161 let (before_cursor_pos, before) = extract_offset(before);
192 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); 162 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
193 let frange = 163 let frange =
194 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; 164 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
195 let assist = 165 let assist =
196 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 166 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
197 let labels_actions = match assist { 167 let action = match assist {
198 Assist::Unresolved(_) => unreachable!(), 168 Assist::Unresolved { .. } => unreachable!(),
199 Assist::Resolved(labels_actions) => labels_actions, 169 Assist::Resolved { action, .. } => action,
200 }; 170 };
201 171
202 let (_, action) = labels_actions.get(index).expect("expect assist action at index");
203 let actual = action.edit.apply(&before); 172 let actual = action.edit.apply(&before);
204 let actual_cursor_pos = match action.cursor_position { 173 let actual_cursor_pos = match action.cursor_position {
205 None => action 174 None => action
@@ -212,23 +181,21 @@ mod helpers {
212 assert_eq_text!(after, &actual); 181 assert_eq_text!(after, &actual);
213 } 182 }
214 183
215 pub(crate) fn check_assist_range_nth_action( 184 pub(crate) fn check_assist_range(
216 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, 185 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
217 before: &str, 186 before: &str,
218 after: &str, 187 after: &str,
219 index: usize,
220 ) { 188 ) {
221 let (range, before) = extract_range(before); 189 let (range, before) = extract_range(before);
222 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); 190 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
223 let frange = FileRange { file_id, range }; 191 let frange = FileRange { file_id, range };
224 let assist = 192 let assist =
225 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 193 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
226 let labels_actions = match assist { 194 let action = match assist {
227 Assist::Unresolved(_) => unreachable!(), 195 Assist::Unresolved { .. } => unreachable!(),
228 Assist::Resolved(labels_actions) => labels_actions, 196 Assist::Resolved { action, .. } => action,
229 }; 197 };
230 198
231 let (_, action) = labels_actions.get(index).expect("expect assist action at index");
232 let mut actual = action.edit.apply(&before); 199 let mut actual = action.edit.apply(&before);
233 if let Some(pos) = action.cursor_position { 200 if let Some(pos) = action.cursor_position {
234 actual = add_cursor(&actual, pos); 201 actual = add_cursor(&actual, pos);
@@ -236,11 +203,10 @@ mod helpers {
236 assert_eq_text!(after, &actual); 203 assert_eq_text!(after, &actual);
237 } 204 }
238 205
239 pub(crate) fn check_assist_target_nth_action( 206 pub(crate) fn check_assist_target(
240 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, 207 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
241 before: &str, 208 before: &str,
242 target: &str, 209 target: &str,
243 index: usize,
244 ) { 210 ) {
245 let (before_cursor_pos, before) = extract_offset(before); 211 let (before_cursor_pos, before) = extract_offset(before);
246 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); 212 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
@@ -248,33 +214,30 @@ mod helpers {
248 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; 214 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
249 let assist = 215 let assist =
250 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 216 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
251 let labels_actions = match assist { 217 let action = match assist {
252 Assist::Unresolved(_) => unreachable!(), 218 Assist::Unresolved { .. } => unreachable!(),
253 Assist::Resolved(labels_actions) => labels_actions, 219 Assist::Resolved { action, .. } => action,
254 }; 220 };
255 221
256 let (_, action) = labels_actions.get(index).expect("expect assist action at index");
257 let range = action.target.expect("expected target on action"); 222 let range = action.target.expect("expected target on action");
258 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); 223 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target);
259 } 224 }
260 225
261 pub(crate) fn check_assist_range_target_nth_action( 226 pub(crate) fn check_assist_range_target(
262 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>, 227 assist: fn(AssistCtx<MockDatabase>) -> Option<Assist>,
263 before: &str, 228 before: &str,
264 target: &str, 229 target: &str,
265 index: usize,
266 ) { 230 ) {
267 let (range, before) = extract_range(before); 231 let (range, before) = extract_range(before);
268 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); 232 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
269 let frange = FileRange { file_id, range }; 233 let frange = FileRange { file_id, range };
270 let assist = 234 let assist =
271 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); 235 AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable");
272 let labels_actions = match assist { 236 let action = match assist {
273 Assist::Unresolved(_) => unreachable!(), 237 Assist::Unresolved { .. } => unreachable!(),
274 Assist::Resolved(labels_actions) => labels_actions, 238 Assist::Resolved { action, .. } => action,
275 }; 239 };
276 240
277 let (_, action) = labels_actions.get(index).expect("expect assist action at index");
278 let range = action.target.expect("expected target on action"); 241 let range = action.target.expect("expected target on action");
279 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); 242 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target);
280 } 243 }
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index fc5d6d396..0d1ab4843 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -134,10 +134,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
134 ) -> Option<FileId> { 134 ) -> Option<FileId> {
135 let path = { 135 let path = {
136 let mut path = self.0.file_relative_path(anchor); 136 let mut path = self.0.file_relative_path(anchor);
137 // Workaround for relative path API: turn `lib.rs` into ``. 137 assert!(path.pop());
138 if !path.pop() {
139 path = RelativePathBuf::default();
140 }
141 path.push(relative_path); 138 path.push(relative_path);
142 path.normalize() 139 path.normalize()
143 }; 140 };
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index 54c09788a..5df371bc0 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -19,12 +19,14 @@ ra_cfg = { path = "../ra_cfg" }
19ra_db = { path = "../ra_db" } 19ra_db = { path = "../ra_db" }
20mbe = { path = "../ra_mbe", package = "ra_mbe" } 20mbe = { path = "../ra_mbe", package = "ra_mbe" }
21tt = { path = "../ra_tt", package = "ra_tt" } 21tt = { path = "../ra_tt", package = "ra_tt" }
22hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" }
23hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
22test_utils = { path = "../test_utils" } 24test_utils = { path = "../test_utils" }
23ra_prof = { path = "../ra_prof" } 25ra_prof = { path = "../ra_prof" }
24 26
25chalk-solve = { git = "https://github.com/rust-lang/chalk.git" } 27chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" }
26chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git" } 28chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" }
27chalk-ir = { git = "https://github.com/rust-lang/chalk.git" } 29chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" }
28lalrpop-intern = "0.15.1" 30lalrpop-intern = "0.15.1"
29 31
30[dev-dependencies] 32[dev-dependencies]
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index 3e9cd3c63..4fa2062bd 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -3,13 +3,14 @@
3 3
4use std::sync::Arc; 4use std::sync::Arc;
5 5
6use hir_def::{type_ref::TypeRef, LocalEnumVariantId};
7use hir_expand::name::AsName;
6use ra_arena::{impl_arena_id, Arena, RawId}; 8use ra_arena::{impl_arena_id, Arena, RawId};
7use ra_syntax::ast::{self, NameOwner, StructKind, TypeAscriptionOwner}; 9use ra_syntax::ast::{self, NameOwner, StructKind, TypeAscriptionOwner};
8 10
9use crate::{ 11use crate::{
10 db::{AstDatabase, DefDatabase, HirDatabase}, 12 db::{AstDatabase, DefDatabase, HirDatabase},
11 type_ref::TypeRef, 13 Enum, EnumVariant, FieldSource, HasSource, Module, Name, Source, Struct, StructField,
12 AsName, Enum, EnumVariant, FieldSource, HasSource, Module, Name, Source, Struct, StructField,
13}; 14};
14 15
15impl Struct { 16impl Struct {
@@ -67,7 +68,7 @@ impl EnumVariant {
67#[derive(Debug, Clone, PartialEq, Eq)] 68#[derive(Debug, Clone, PartialEq, Eq)]
68pub struct EnumData { 69pub struct EnumData {
69 pub(crate) name: Option<Name>, 70 pub(crate) name: Option<Name>,
70 pub(crate) variants: Arena<EnumVariantId, EnumVariantData>, 71 pub(crate) variants: Arena<LocalEnumVariantId, EnumVariantData>,
71} 72}
72 73
73impl EnumData { 74impl EnumData {
@@ -84,10 +85,6 @@ impl EnumData {
84 } 85 }
85} 86}
86 87
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
88pub(crate) struct EnumVariantId(RawId);
89impl_arena_id!(EnumVariantId);
90
91#[derive(Debug, Clone, PartialEq, Eq)] 88#[derive(Debug, Clone, PartialEq, Eq)]
92pub(crate) struct EnumVariantData { 89pub(crate) struct EnumVariantData {
93 pub(crate) name: Option<Name>, 90 pub(crate) name: Option<Name>,
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 8eb3c577d..b32aa145e 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -5,11 +5,17 @@ pub(crate) mod docs;
5 5
6use std::sync::Arc; 6use std::sync::Arc;
7 7
8use ra_db::{CrateId, Edition, FileId}; 8use hir_def::{
9 builtin_type::BuiltinType,
10 type_ref::{Mutability, TypeRef},
11 CrateModuleId, LocalEnumVariantId, ModuleId,
12};
13use hir_expand::name::{self, AsName};
14use ra_db::{CrateId, Edition};
9use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 15use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
10 16
11use crate::{ 17use crate::{
12 adt::{EnumVariantId, StructFieldId, VariantDef}, 18 adt::{StructFieldId, VariantDef},
13 db::{AstDatabase, DefDatabase, HirDatabase}, 19 db::{AstDatabase, DefDatabase, HirDatabase},
14 diagnostics::DiagnosticSink, 20 diagnostics::DiagnosticSink,
15 expr::{validation::ExprValidator, Body, BodySourceMap}, 21 expr::{validation::ExprValidator, Body, BodySourceMap},
@@ -19,20 +25,11 @@ use crate::{
19 TypeAliasId, 25 TypeAliasId,
20 }, 26 },
21 impl_block::ImplBlock, 27 impl_block::ImplBlock,
22 name::{ 28 nameres::{ImportId, ModuleScope, Namespace},
23 BOOL, CHAR, F32, F64, I128, I16, I32, I64, I8, ISIZE, SELF_TYPE, STR, U128, U16, U32, U64,
24 U8, USIZE,
25 },
26 nameres::{CrateModuleId, ImportId, ModuleScope, Namespace},
27 resolve::{Resolver, Scope, TypeNs}, 29 resolve::{Resolver, Scope, TypeNs},
28 traits::TraitData, 30 traits::TraitData,
29 ty::{ 31 ty::{InferenceResult, TraitRef},
30 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness}, 32 Either, HasSource, Name, Ty,
31 InferenceResult, TraitRef,
32 },
33 type_ref::Mutability,
34 type_ref::TypeRef,
35 AsName, AstId, Either, HasSource, Name, Ty,
36}; 33};
37 34
38/// hir::Crate describes a single crate. It's the main interface with which 35/// hir::Crate describes a single crate. It's the main interface with which
@@ -67,8 +64,7 @@ impl Crate {
67 64
68 pub fn root_module(self, db: &impl DefDatabase) -> Option<Module> { 65 pub fn root_module(self, db: &impl DefDatabase) -> Option<Module> {
69 let module_id = db.crate_def_map(self).root(); 66 let module_id = db.crate_def_map(self).root();
70 let module = Module { krate: self, module_id }; 67 Some(Module::new(self, module_id))
71 Some(module)
72 } 68 }
73 69
74 pub fn edition(self, db: &impl DefDatabase) -> Edition { 70 pub fn edition(self, db: &impl DefDatabase) -> Edition {
@@ -83,43 +79,7 @@ impl Crate {
83 79
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 80#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
85pub struct Module { 81pub struct Module {
86 pub(crate) krate: Crate, 82 pub(crate) id: ModuleId,
87 pub(crate) module_id: CrateModuleId,
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
91pub enum BuiltinType {
92 Char,
93 Bool,
94 Str,
95 Int(IntTy),
96 Float(FloatTy),
97}
98
99impl BuiltinType {
100 #[rustfmt::skip]
101 pub(crate) const ALL: &'static [(Name, BuiltinType)] = &[
102 (CHAR, BuiltinType::Char),
103 (BOOL, BuiltinType::Bool),
104 (STR, BuiltinType::Str),
105
106 (ISIZE, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::Xsize })),
107 (I8, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X8 })),
108 (I16, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X16 })),
109 (I32, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X32 })),
110 (I64, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X64 })),
111 (I128, BuiltinType::Int(IntTy { signedness: Signedness::Signed, bitness: IntBitness::X128 })),
112
113 (USIZE, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::Xsize })),
114 (U8, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X8 })),
115 (U16, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X16 })),
116 (U32, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X32 })),
117 (U64, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X64 })),
118 (U128, BuiltinType::Int(IntTy { signedness: Signedness::Unsigned, bitness: IntBitness::X128 })),
119
120 (F32, BuiltinType::Float(FloatTy { bitness: FloatBitness::X32 })),
121 (F64, BuiltinType::Float(FloatTy { bitness: FloatBitness::X64 })),
122 ];
123} 83}
124 84
125/// The defs which can be visible in the module. 85/// The defs which can be visible in the module.
@@ -148,39 +108,19 @@ impl_froms!(
148 BuiltinType 108 BuiltinType
149); 109);
150 110
151pub enum ModuleSource { 111pub use hir_def::ModuleSource;
152 SourceFile(ast::SourceFile),
153 Module(ast::Module),
154}
155 112
156impl ModuleSource { 113impl Module {
157 pub(crate) fn new( 114 pub(crate) fn new(krate: Crate, crate_module_id: CrateModuleId) -> Module {
158 db: &(impl DefDatabase + AstDatabase), 115 Module { id: ModuleId { krate: krate.crate_id, module_id: crate_module_id } }
159 file_id: Option<FileId>,
160 decl_id: Option<AstId<ast::Module>>,
161 ) -> ModuleSource {
162 match (file_id, decl_id) {
163 (Some(file_id), _) => {
164 let source_file = db.parse(file_id).tree();
165 ModuleSource::SourceFile(source_file)
166 }
167 (None, Some(item_id)) => {
168 let module = item_id.to_node(db);
169 assert!(module.item_list().is_some(), "expected inline module");
170 ModuleSource::Module(module)
171 }
172 (None, None) => panic!(),
173 }
174 } 116 }
175}
176 117
177impl Module {
178 /// Name of this module. 118 /// Name of this module.
179 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 119 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
180 let def_map = db.crate_def_map(self.krate); 120 let def_map = db.crate_def_map(self.krate());
181 let parent = def_map[self.module_id].parent?; 121 let parent = def_map[self.id.module_id].parent?;
182 def_map[parent].children.iter().find_map(|(name, module_id)| { 122 def_map[parent].children.iter().find_map(|(name, module_id)| {
183 if *module_id == self.module_id { 123 if *module_id == self.id.module_id {
184 Some(name.clone()) 124 Some(name.clone())
185 } else { 125 } else {
186 None 126 None
@@ -200,29 +140,29 @@ impl Module {
200 } 140 }
201 141
202 /// Returns the crate this module is part of. 142 /// Returns the crate this module is part of.
203 pub fn krate(self, _db: &impl DefDatabase) -> Option<Crate> { 143 pub fn krate(self) -> Crate {
204 Some(self.krate) 144 Crate { crate_id: self.id.krate }
205 } 145 }
206 146
207 /// Topmost parent of this module. Every module has a `crate_root`, but some 147 /// Topmost parent of this module. Every module has a `crate_root`, but some
208 /// might be missing `krate`. This can happen if a module's file is not included 148 /// might be missing `krate`. This can happen if a module's file is not included
209 /// in the module tree of any target in `Cargo.toml`. 149 /// in the module tree of any target in `Cargo.toml`.
210 pub fn crate_root(self, db: &impl DefDatabase) -> Module { 150 pub fn crate_root(self, db: &impl DefDatabase) -> Module {
211 let def_map = db.crate_def_map(self.krate); 151 let def_map = db.crate_def_map(self.krate());
212 self.with_module_id(def_map.root()) 152 self.with_module_id(def_map.root())
213 } 153 }
214 154
215 /// Finds a child module with the specified name. 155 /// Finds a child module with the specified name.
216 pub fn child(self, db: &impl HirDatabase, name: &Name) -> Option<Module> { 156 pub fn child(self, db: &impl HirDatabase, name: &Name) -> Option<Module> {
217 let def_map = db.crate_def_map(self.krate); 157 let def_map = db.crate_def_map(self.krate());
218 let child_id = def_map[self.module_id].children.get(name)?; 158 let child_id = def_map[self.id.module_id].children.get(name)?;
219 Some(self.with_module_id(*child_id)) 159 Some(self.with_module_id(*child_id))
220 } 160 }
221 161
222 /// Iterates over all child modules. 162 /// Iterates over all child modules.
223 pub fn children(self, db: &impl DefDatabase) -> impl Iterator<Item = Module> { 163 pub fn children(self, db: &impl DefDatabase) -> impl Iterator<Item = Module> {
224 let def_map = db.crate_def_map(self.krate); 164 let def_map = db.crate_def_map(self.krate());
225 let children = def_map[self.module_id] 165 let children = def_map[self.id.module_id]
226 .children 166 .children
227 .iter() 167 .iter()
228 .map(|(_, module_id)| self.with_module_id(*module_id)) 168 .map(|(_, module_id)| self.with_module_id(*module_id))
@@ -232,8 +172,8 @@ impl Module {
232 172
233 /// Finds a parent module. 173 /// Finds a parent module.
234 pub fn parent(self, db: &impl DefDatabase) -> Option<Module> { 174 pub fn parent(self, db: &impl DefDatabase) -> Option<Module> {
235 let def_map = db.crate_def_map(self.krate); 175 let def_map = db.crate_def_map(self.krate());
236 let parent_id = def_map[self.module_id].parent?; 176 let parent_id = def_map[self.id.module_id].parent?;
237 Some(self.with_module_id(parent_id)) 177 Some(self.with_module_id(parent_id))
238 } 178 }
239 179
@@ -249,11 +189,11 @@ impl Module {
249 189
250 /// Returns a `ModuleScope`: a set of items, visible in this module. 190 /// Returns a `ModuleScope`: a set of items, visible in this module.
251 pub fn scope(self, db: &impl HirDatabase) -> ModuleScope { 191 pub fn scope(self, db: &impl HirDatabase) -> ModuleScope {
252 db.crate_def_map(self.krate)[self.module_id].scope.clone() 192 db.crate_def_map(self.krate())[self.id.module_id].scope.clone()
253 } 193 }
254 194
255 pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) { 195 pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
256 db.crate_def_map(self.krate).add_diagnostics(db, self.module_id, sink); 196 db.crate_def_map(self.krate()).add_diagnostics(db, self.id.module_id, sink);
257 for decl in self.declarations(db) { 197 for decl in self.declarations(db) {
258 match decl { 198 match decl {
259 crate::ModuleDef::Function(f) => f.diagnostics(db, sink), 199 crate::ModuleDef::Function(f) => f.diagnostics(db, sink),
@@ -277,13 +217,13 @@ impl Module {
277 } 217 }
278 218
279 pub(crate) fn resolver(self, db: &impl DefDatabase) -> Resolver { 219 pub(crate) fn resolver(self, db: &impl DefDatabase) -> Resolver {
280 let def_map = db.crate_def_map(self.krate); 220 let def_map = db.crate_def_map(self.krate());
281 Resolver::default().push_module_scope(def_map, self.module_id) 221 Resolver::default().push_module_scope(def_map, self.id.module_id)
282 } 222 }
283 223
284 pub fn declarations(self, db: &impl DefDatabase) -> Vec<ModuleDef> { 224 pub fn declarations(self, db: &impl DefDatabase) -> Vec<ModuleDef> {
285 let def_map = db.crate_def_map(self.krate); 225 let def_map = db.crate_def_map(self.krate());
286 def_map[self.module_id] 226 def_map[self.id.module_id]
287 .scope 227 .scope
288 .entries() 228 .entries()
289 .filter_map(|(_name, res)| if res.import.is_none() { Some(res.def) } else { None }) 229 .filter_map(|(_name, res)| if res.import.is_none() { Some(res.def) } else { None })
@@ -303,7 +243,7 @@ impl Module {
303 } 243 }
304 244
305 fn with_module_id(self, module_id: CrateModuleId) -> Module { 245 fn with_module_id(self, module_id: CrateModuleId) -> Module {
306 Module { module_id, krate: self.krate } 246 Module::new(self.krate(), module_id)
307 } 247 }
308} 248}
309 249
@@ -340,11 +280,11 @@ pub struct Struct {
340 280
341impl Struct { 281impl Struct {
342 pub fn module(self, db: &impl DefDatabase) -> Module { 282 pub fn module(self, db: &impl DefDatabase) -> Module {
343 self.id.module(db) 283 Module { id: self.id.module(db) }
344 } 284 }
345 285
346 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 286 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
347 self.module(db).krate(db) 287 Some(self.module(db).krate())
348 } 288 }
349 289
350 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 290 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
@@ -402,7 +342,7 @@ impl Union {
402 } 342 }
403 343
404 pub fn module(self, db: &impl HirDatabase) -> Module { 344 pub fn module(self, db: &impl HirDatabase) -> Module {
405 self.id.module(db) 345 Module { id: self.id.module(db) }
406 } 346 }
407 347
408 pub fn ty(self, db: &impl HirDatabase) -> Ty { 348 pub fn ty(self, db: &impl HirDatabase) -> Ty {
@@ -428,11 +368,11 @@ pub struct Enum {
428 368
429impl Enum { 369impl Enum {
430 pub fn module(self, db: &impl DefDatabase) -> Module { 370 pub fn module(self, db: &impl DefDatabase) -> Module {
431 self.id.module(db) 371 Module { id: self.id.module(db) }
432 } 372 }
433 373
434 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 374 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
435 self.module(db).krate(db) 375 Some(self.module(db).krate())
436 } 376 }
437 377
438 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 378 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
@@ -470,7 +410,7 @@ impl Enum {
470#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 410#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
471pub struct EnumVariant { 411pub struct EnumVariant {
472 pub(crate) parent: Enum, 412 pub(crate) parent: Enum,
473 pub(crate) id: EnumVariantId, 413 pub(crate) id: LocalEnumVariantId,
474} 414}
475 415
476impl EnumVariant { 416impl EnumVariant {
@@ -523,12 +463,14 @@ impl Adt {
523 } 463 }
524 464
525 pub fn krate(self, db: &impl HirDatabase) -> Option<Crate> { 465 pub fn krate(self, db: &impl HirDatabase) -> Option<Crate> {
526 match self { 466 Some(
527 Adt::Struct(s) => s.module(db), 467 match self {
528 Adt::Union(s) => s.module(db), 468 Adt::Struct(s) => s.module(db),
529 Adt::Enum(e) => e.module(db), 469 Adt::Union(s) => s.module(db),
530 } 470 Adt::Enum(e) => e.module(db),
531 .krate(db) 471 }
472 .krate(),
473 )
532 } 474 }
533 475
534 pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver { 476 pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver {
@@ -643,7 +585,7 @@ impl FnData {
643 let self_type = if let Some(type_ref) = self_param.ascribed_type() { 585 let self_type = if let Some(type_ref) = self_param.ascribed_type() {
644 TypeRef::from_ast(type_ref) 586 TypeRef::from_ast(type_ref)
645 } else { 587 } else {
646 let self_type = TypeRef::Path(SELF_TYPE.into()); 588 let self_type = TypeRef::Path(name::SELF_TYPE.into());
647 match self_param.kind() { 589 match self_param.kind() {
648 ast::SelfParamKind::Owned => self_type, 590 ast::SelfParamKind::Owned => self_type,
649 ast::SelfParamKind::Ref => { 591 ast::SelfParamKind::Ref => {
@@ -692,11 +634,11 @@ impl FnData {
692 634
693impl Function { 635impl Function {
694 pub fn module(self, db: &impl DefDatabase) -> Module { 636 pub fn module(self, db: &impl DefDatabase) -> Module {
695 self.id.module(db) 637 Module { id: self.id.module(db) }
696 } 638 }
697 639
698 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 640 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
699 self.module(db).krate(db) 641 Some(self.module(db).krate())
700 } 642 }
701 643
702 pub fn name(self, db: &impl HirDatabase) -> Name { 644 pub fn name(self, db: &impl HirDatabase) -> Name {
@@ -770,11 +712,11 @@ pub struct Const {
770 712
771impl Const { 713impl Const {
772 pub fn module(self, db: &impl DefDatabase) -> Module { 714 pub fn module(self, db: &impl DefDatabase) -> Module {
773 self.id.module(db) 715 Module { id: self.id.module(db) }
774 } 716 }
775 717
776 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 718 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
777 self.module(db).krate(db) 719 Some(self.module(db).krate())
778 } 720 }
779 721
780 pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> { 722 pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> {
@@ -867,11 +809,11 @@ pub struct Static {
867 809
868impl Static { 810impl Static {
869 pub fn module(self, db: &impl DefDatabase) -> Module { 811 pub fn module(self, db: &impl DefDatabase) -> Module {
870 self.id.module(db) 812 Module { id: self.id.module(db) }
871 } 813 }
872 814
873 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 815 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
874 self.module(db).krate(db) 816 Some(self.module(db).krate())
875 } 817 }
876 818
877 pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> { 819 pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> {
@@ -896,7 +838,7 @@ pub struct Trait {
896 838
897impl Trait { 839impl Trait {
898 pub fn module(self, db: &impl DefDatabase) -> Module { 840 pub fn module(self, db: &impl DefDatabase) -> Module {
899 self.id.module(db) 841 Module { id: self.id.module(db) }
900 } 842 }
901 843
902 pub fn name(self, db: &impl DefDatabase) -> Option<Name> { 844 pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
@@ -917,9 +859,7 @@ impl Trait {
917 .where_predicates 859 .where_predicates
918 .iter() 860 .iter()
919 .filter_map(|pred| match &pred.type_ref { 861 .filter_map(|pred| match &pred.type_ref {
920 TypeRef::Path(p) if p.as_ident() == Some(&crate::name::SELF_TYPE) => { 862 TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(),
921 pred.bound.as_path()
922 }
923 _ => None, 863 _ => None,
924 }) 864 })
925 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) { 865 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) {
@@ -998,11 +938,11 @@ pub struct TypeAlias {
998 938
999impl TypeAlias { 939impl TypeAlias {
1000 pub fn module(self, db: &impl DefDatabase) -> Module { 940 pub fn module(self, db: &impl DefDatabase) -> Module {
1001 self.id.module(db) 941 Module { id: self.id.module(db) }
1002 } 942 }
1003 943
1004 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 944 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
1005 self.module(db).krate(db) 945 Some(self.module(db).krate())
1006 } 946 }
1007 947
1008 /// The containing impl block, if this is a method. 948 /// The containing impl block, if this is a method.
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index fdae26906..5c7f61eef 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -1,9 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_syntax::{ 3use ra_syntax::ast::{self, AstNode};
4 ast::{self, AstNode},
5 SyntaxNode,
6};
7 4
8use crate::{ 5use crate::{
9 db::{AstDatabase, DefDatabase, HirDatabase}, 6 db::{AstDatabase, DefDatabase, HirDatabase},
@@ -12,34 +9,21 @@ use crate::{
12 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, 9 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
13}; 10};
14 11
15#[derive(Debug, PartialEq, Eq, Clone, Copy)] 12pub use hir_def::Source;
16pub struct Source<T> {
17 pub file_id: HirFileId,
18 pub ast: T,
19}
20 13
21pub trait HasSource { 14pub trait HasSource {
22 type Ast; 15 type Ast;
23 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<Self::Ast>; 16 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<Self::Ast>;
24} 17}
25 18
26impl<T> Source<T> {
27 pub(crate) fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
28 Source { file_id: self.file_id, ast: f(self.ast) }
29 }
30 pub(crate) fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode {
31 db.parse_or_expand(self.file_id).expect("source created from invalid file")
32 }
33}
34
35/// NB: Module is !HasSource, because it has two source nodes at the same time: 19/// NB: Module is !HasSource, because it has two source nodes at the same time:
36/// definition and declaration. 20/// definition and declaration.
37impl Module { 21impl Module {
38 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. 22 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
39 pub fn definition_source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ModuleSource> { 23 pub fn definition_source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ModuleSource> {
40 let def_map = db.crate_def_map(self.krate); 24 let def_map = db.crate_def_map(self.krate());
41 let decl_id = def_map[self.module_id].declaration; 25 let decl_id = def_map[self.id.module_id].declaration;
42 let file_id = def_map[self.module_id].definition; 26 let file_id = def_map[self.id.module_id].definition;
43 let ast = ModuleSource::new(db, file_id, decl_id); 27 let ast = ModuleSource::new(db, file_id, decl_id);
44 let file_id = file_id.map(HirFileId::from).unwrap_or_else(|| decl_id.unwrap().file_id()); 28 let file_id = file_id.map(HirFileId::from).unwrap_or_else(|| decl_id.unwrap().file_id());
45 Source { file_id, ast } 29 Source { file_id, ast }
@@ -51,8 +35,8 @@ impl Module {
51 self, 35 self,
52 db: &(impl DefDatabase + AstDatabase), 36 db: &(impl DefDatabase + AstDatabase),
53 ) -> Option<Source<ast::Module>> { 37 ) -> Option<Source<ast::Module>> {
54 let def_map = db.crate_def_map(self.krate); 38 let def_map = db.crate_def_map(self.krate());
55 let decl = def_map[self.module_id].declaration?; 39 let decl = def_map[self.id.module_id].declaration?;
56 let ast = decl.to_node(db); 40 let ast = decl.to_node(db);
57 Some(Source { file_id: decl.file_id(), ast }) 41 Some(Source { file_id: decl.file_id(), ast })
58 } 42 }
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 489a3b19c..ebfd970eb 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -2,8 +2,8 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use ra_db::{salsa, SourceDatabase}; 5use ra_db::salsa;
6use ra_syntax::{ast, Parse, SmolStr, SyntaxNode}; 6use ra_syntax::SmolStr;
7 7
8use crate::{ 8use crate::{
9 adt::{EnumData, StructData}, 9 adt::{EnumData, StructData},
@@ -12,81 +12,30 @@ use crate::{
12 ids, 12 ids,
13 impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks}, 13 impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks},
14 lang_item::{LangItemTarget, LangItems}, 14 lang_item::{LangItemTarget, LangItems},
15 nameres::{CrateDefMap, ImportSourceMap, Namespace, RawItems}, 15 nameres::{CrateDefMap, Namespace},
16 traits::TraitData, 16 traits::TraitData,
17 ty::{ 17 ty::{
18 method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate, 18 method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate,
19 InferenceResult, Substs, Ty, TypableDef, TypeCtor, 19 InferenceResult, Substs, Ty, TypableDef, TypeCtor,
20 }, 20 },
21 type_alias::TypeAliasData, 21 type_alias::TypeAliasData,
22 AstIdMap, Const, ConstData, Crate, DefWithBody, Enum, ErasedFileAstId, ExprScopes, FnData, 22 Const, ConstData, Crate, DefWithBody, Enum, ExprScopes, FnData, Function, Module, Static,
23 Function, HirFileId, MacroCallLoc, MacroDefId, Module, Static, Struct, StructField, Trait, 23 Struct, StructField, Trait, TypeAlias,
24 TypeAlias,
25}; 24};
26 25
27/// We store all interned things in the single QueryGroup. 26pub use hir_def::db::{
28/// 27 DefDatabase2, DefDatabase2Storage, InternDatabase, InternDatabaseStorage, RawItemsQuery,
29/// This is done mainly to allow both "volatile" `AstDatabase` and "stable" 28 RawItemsWithSourceMapQuery,
30/// `DefDatabase` to access macros, without adding hard dependencies between the 29};
31/// two. 30pub use hir_expand::db::{
32#[salsa::query_group(InternDatabaseStorage)] 31 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
33pub trait InternDatabase: SourceDatabase { 32 ParseMacroQuery,
34 #[salsa::interned] 33};
35 fn intern_macro(&self, macro_call: MacroCallLoc) -> ids::MacroCallId;
36 #[salsa::interned]
37 fn intern_function(&self, loc: ids::ItemLoc<ast::FnDef>) -> ids::FunctionId;
38 #[salsa::interned]
39 fn intern_struct(&self, loc: ids::ItemLoc<ast::StructDef>) -> ids::StructId;
40 #[salsa::interned]
41 fn intern_enum(&self, loc: ids::ItemLoc<ast::EnumDef>) -> ids::EnumId;
42 #[salsa::interned]
43 fn intern_const(&self, loc: ids::ItemLoc<ast::ConstDef>) -> ids::ConstId;
44 #[salsa::interned]
45 fn intern_static(&self, loc: ids::ItemLoc<ast::StaticDef>) -> ids::StaticId;
46 #[salsa::interned]
47 fn intern_trait(&self, loc: ids::ItemLoc<ast::TraitDef>) -> ids::TraitId;
48 #[salsa::interned]
49 fn intern_type_alias(&self, loc: ids::ItemLoc<ast::TypeAliasDef>) -> ids::TypeAliasId;
50
51 // Interned IDs for Chalk integration
52 #[salsa::interned]
53 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId;
54 #[salsa::interned]
55 fn intern_impl(&self, impl_: Impl) -> ids::GlobalImplId;
56}
57
58/// This database has access to source code, so queries here are not really
59/// incremental.
60#[salsa::query_group(AstDatabaseStorage)]
61pub trait AstDatabase: InternDatabase {
62 #[salsa::invoke(crate::source_id::AstIdMap::ast_id_map_query)]
63 fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
64
65 #[salsa::transparent]
66 #[salsa::invoke(crate::source_id::AstIdMap::file_item_query)]
67 fn ast_id_to_node(&self, file_id: HirFileId, ast_id: ErasedFileAstId) -> SyntaxNode;
68
69 #[salsa::transparent]
70 #[salsa::invoke(crate::ids::HirFileId::parse_or_expand_query)]
71 fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>;
72
73 #[salsa::invoke(crate::ids::HirFileId::parse_macro_query)]
74 fn parse_macro(&self, macro_file: ids::MacroFile) -> Option<Parse<SyntaxNode>>;
75
76 #[salsa::invoke(crate::ids::macro_def_query)]
77 fn macro_def(&self, macro_id: MacroDefId) -> Option<Arc<mbe::MacroRules>>;
78
79 #[salsa::invoke(crate::ids::macro_arg_query)]
80 fn macro_arg(&self, macro_call: ids::MacroCallId) -> Option<Arc<tt::Subtree>>;
81
82 #[salsa::invoke(crate::ids::macro_expand_query)]
83 fn macro_expand(&self, macro_call: ids::MacroCallId) -> Result<Arc<tt::Subtree>, String>;
84}
85 34
86// This database uses `AstDatabase` internally, 35// This database uses `AstDatabase` internally,
87#[salsa::query_group(DefDatabaseStorage)] 36#[salsa::query_group(DefDatabaseStorage)]
88#[salsa::requires(AstDatabase)] 37#[salsa::requires(AstDatabase)]
89pub trait DefDatabase: InternDatabase + HirDebugDatabase { 38pub trait DefDatabase: HirDebugDatabase + DefDatabase2 {
90 #[salsa::invoke(crate::adt::StructData::struct_data_query)] 39 #[salsa::invoke(crate::adt::StructData::struct_data_query)]
91 fn struct_data(&self, s: Struct) -> Arc<StructData>; 40 fn struct_data(&self, s: Struct) -> Arc<StructData>;
92 41
@@ -99,15 +48,6 @@ pub trait DefDatabase: InternDatabase + HirDebugDatabase {
99 #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)] 48 #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)]
100 fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex; 49 fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex;
101 50
102 #[salsa::invoke(RawItems::raw_items_with_source_map_query)]
103 fn raw_items_with_source_map(
104 &self,
105 file_id: HirFileId,
106 ) -> (Arc<RawItems>, Arc<ImportSourceMap>);
107
108 #[salsa::invoke(RawItems::raw_items_query)]
109 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;
110
111 #[salsa::invoke(CrateDefMap::crate_def_map_query)] 51 #[salsa::invoke(CrateDefMap::crate_def_map_query)]
112 fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>; 52 fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>;
113 53
@@ -202,6 +142,12 @@ pub trait HirDatabase: DefDatabase + AstDatabase {
202 #[salsa::invoke(crate::ty::traits::trait_solver_query)] 142 #[salsa::invoke(crate::ty::traits::trait_solver_query)]
203 fn trait_solver(&self, krate: Crate) -> crate::ty::traits::TraitSolver; 143 fn trait_solver(&self, krate: Crate) -> crate::ty::traits::TraitSolver;
204 144
145 // Interned IDs for Chalk integration
146 #[salsa::interned]
147 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId;
148 #[salsa::interned]
149 fn intern_impl(&self, impl_: Impl) -> ids::GlobalImplId;
150
205 #[salsa::invoke(crate::ty::traits::chalk::associated_ty_data_query)] 151 #[salsa::invoke(crate::ty::traits::chalk::associated_ty_data_query)]
206 fn associated_ty_data(&self, id: chalk_ir::TypeId) -> Arc<chalk_rust_ir::AssociatedTyDatum>; 152 fn associated_ty_data(&self, id: chalk_ir::TypeId) -> Arc<chalk_rust_ir::AssociatedTyDatum>;
207 153
diff --git a/crates/ra_hir/src/debug.rs b/crates/ra_hir/src/debug.rs
index 48b69000b..4f3e922c3 100644
--- a/crates/ra_hir/src/debug.rs
+++ b/crates/ra_hir/src/debug.rs
@@ -36,12 +36,6 @@ impl Module {
36 } 36 }
37} 37}
38 38
39impl HirFileId {
40 pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ {
41 debug_fn(move |fmt| db.debug_hir_file_id(self, fmt))
42 }
43}
44
45pub trait HirDebugHelper: HirDatabase { 39pub trait HirDebugHelper: HirDatabase {
46 fn crate_name(&self, _krate: CrateId) -> Option<String> { 40 fn crate_name(&self, _krate: CrateId) -> Option<String> {
47 None 41 None
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index d238741ba..6e23197a4 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -6,15 +6,17 @@ pub(crate) mod validation;
6 6
7use std::{ops::Index, sync::Arc}; 7use std::{ops::Index, sync::Arc};
8 8
9use hir_def::{
10 path::GenericArgs,
11 type_ref::{Mutability, TypeRef},
12};
9use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 13use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
10use ra_syntax::{ast, AstPtr}; 14use ra_syntax::{ast, AstPtr};
11use rustc_hash::FxHashMap; 15use rustc_hash::FxHashMap;
12 16
13use crate::{ 17use crate::{
14 db::HirDatabase, 18 db::HirDatabase,
15 path::GenericArgs,
16 ty::primitive::{UncertainFloatTy, UncertainIntTy}, 19 ty::primitive::{UncertainFloatTy, UncertainIntTy},
17 type_ref::{Mutability, TypeRef},
18 DefWithBody, Either, HasSource, Name, Path, Resolver, Source, 20 DefWithBody, Either, HasSource, Name, Path, Resolver, Source,
19}; 21};
20 22
diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs
index 50ea429ea..6463dd65e 100644
--- a/crates/ra_hir/src/expr/lower.rs
+++ b/crates/ra_hir/src/expr/lower.rs
@@ -1,5 +1,10 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir_def::{path::GenericArgs, type_ref::TypeRef};
4use hir_expand::{
5 hygiene::Hygiene,
6 name::{self, AsName, Name},
7};
3use ra_arena::Arena; 8use ra_arena::Arena;
4use ra_syntax::{ 9use ra_syntax::{
5 ast::{ 10 ast::{
@@ -12,11 +17,8 @@ use test_utils::tested_by;
12 17
13use crate::{ 18use crate::{
14 db::HirDatabase, 19 db::HirDatabase,
15 name::{AsName, Name, SELF_PARAM},
16 path::GenericArgs,
17 ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, 20 ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy},
18 type_ref::TypeRef, 21 AstId, DefWithBody, Either, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path, Resolver,
19 DefWithBody, Either, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path, Resolver,
20 Source, 22 Source,
21}; 23};
22 24
@@ -78,7 +80,7 @@ where
78 let ptr = AstPtr::new(&self_param); 80 let ptr = AstPtr::new(&self_param);
79 let param_pat = self.alloc_pat( 81 let param_pat = self.alloc_pat(
80 Pat::Bind { 82 Pat::Bind {
81 name: SELF_PARAM, 83 name: name::SELF_PARAM,
82 mode: BindingAnnotation::Unannotated, 84 mode: BindingAnnotation::Unannotated,
83 subpat: None, 85 subpat: None,
84 }, 86 },
@@ -458,15 +460,14 @@ where
458 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 460 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
459 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 461 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
460 ast::Expr::MacroCall(e) => { 462 ast::Expr::MacroCall(e) => {
461 let ast_id = self 463 let ast_id = AstId::new(
462 .db 464 self.current_file_id,
463 .ast_id_map(self.current_file_id) 465 self.db.ast_id_map(self.current_file_id).ast_id(&e),
464 .ast_id(&e) 466 );
465 .with_file_id(self.current_file_id);
466 467
467 if let Some(path) = e.path().and_then(|path| self.parse_path(path)) { 468 if let Some(path) = e.path().and_then(|path| self.parse_path(path)) {
468 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) { 469 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) {
469 let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db); 470 let call_id = self.db.intern_macro(MacroCallLoc { def: def.id, ast_id });
470 let file_id = call_id.as_file(MacroFileKind::Expr); 471 let file_id = call_id.as_file(MacroFileKind::Expr);
471 if let Some(node) = self.db.parse_or_expand(file_id) { 472 if let Some(node) = self.db.parse_or_expand(file_id) {
472 if let Some(expr) = ast::Expr::cast(node) { 473 if let Some(expr) = ast::Expr::cast(node) {
@@ -596,7 +597,8 @@ where
596 } 597 }
597 598
598 fn parse_path(&mut self, path: ast::Path) -> Option<Path> { 599 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
599 Path::from_src(Source { ast: path, file_id: self.current_file_id }, self.db) 600 let hygiene = Hygiene::new(self.db, self.current_file_id);
601 Path::from_src(path, &hygiene)
600 } 602 }
601} 603}
602 604
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
index 1aa853c3e..c685edda1 100644
--- a/crates/ra_hir/src/expr/validation.rs
+++ b/crates/ra_hir/src/expr/validation.rs
@@ -2,6 +2,7 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::path::known;
5use ra_syntax::ast; 6use ra_syntax::ast;
6use rustc_hash::FxHashSet; 7use rustc_hash::FxHashSet;
7 8
@@ -9,7 +10,6 @@ use crate::{
9 db::HirDatabase, 10 db::HirDatabase,
10 diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, 11 diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr},
11 expr::AstPtr, 12 expr::AstPtr,
12 path::known,
13 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, 13 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
14 Adt, Function, Name, Path, 14 Adt, Function, Name, Path,
15}; 15};
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index f80d8eb5f..a9de01455 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -1,17 +1,12 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_db::{FileId, FilePosition}; 3use hir_expand::name::AsName;
4use ra_syntax::{ 4use ra_syntax::ast::{self, AstNode, NameOwner};
5 algo::find_node_at_offset,
6 ast::{self, AstNode, NameOwner},
7 SyntaxNode,
8};
9 5
10use crate::{ 6use crate::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 7 db::{AstDatabase, DefDatabase, HirDatabase},
12 ids::{AstItemDef, LocationCtx}, 8 ids::{AstItemDef, LocationCtx},
13 name::AsName, 9 AstId, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module,
14 Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module,
15 ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, 10 ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef,
16}; 11};
17 12
@@ -129,41 +124,6 @@ impl FromSource for StructField {
129 } 124 }
130} 125}
131 126
132// FIXME: simplify it
133impl ModuleSource {
134 pub fn from_position(
135 db: &(impl DefDatabase + AstDatabase),
136 position: FilePosition,
137 ) -> ModuleSource {
138 let parse = db.parse(position.file_id);
139 match &find_node_at_offset::<ast::Module>(parse.tree().syntax(), position.offset) {
140 Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()),
141 _ => {
142 let source_file = parse.tree();
143 ModuleSource::SourceFile(source_file)
144 }
145 }
146 }
147
148 pub fn from_child_node(
149 db: &(impl DefDatabase + AstDatabase),
150 file_id: FileId,
151 child: &SyntaxNode,
152 ) -> ModuleSource {
153 if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) {
154 ModuleSource::Module(m)
155 } else {
156 let source_file = db.parse(file_id).tree();
157 ModuleSource::SourceFile(source_file)
158 }
159 }
160
161 pub fn from_file_id(db: &(impl DefDatabase + AstDatabase), file_id: FileId) -> ModuleSource {
162 let source_file = db.parse(file_id).tree();
163 ModuleSource::SourceFile(source_file)
164 }
165}
166
167impl Module { 127impl Module {
168 pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> { 128 pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> {
169 let src_parent = Source { 129 let src_parent = Source {
@@ -183,7 +143,7 @@ impl Module {
183 ModuleSource::Module(ref module) => { 143 ModuleSource::Module(ref module) => {
184 assert!(!module.has_semi()); 144 assert!(!module.has_semi());
185 let ast_id_map = db.ast_id_map(src.file_id); 145 let ast_id_map = db.ast_id_map(src.file_id);
186 let item_id = ast_id_map.ast_id(module).with_file_id(src.file_id); 146 let item_id = AstId::new(src.file_id, ast_id_map.ast_id(module));
187 Some(item_id) 147 Some(item_id)
188 } 148 }
189 ModuleSource::SourceFile(_) => None, 149 ModuleSource::SourceFile(_) => None,
@@ -195,7 +155,7 @@ impl Module {
195 .find_map(|krate| { 155 .find_map(|krate| {
196 let def_map = db.crate_def_map(krate); 156 let def_map = db.crate_def_map(krate);
197 let module_id = def_map.find_module_by_source(src.file_id, decl_id)?; 157 let module_id = def_map.find_module_by_source(src.file_id, decl_id)?;
198 Some(Module { krate, module_id }) 158 Some(Module::new(krate, module_id))
199 }) 159 })
200 } 160 }
201} 161}
@@ -208,6 +168,6 @@ where
208 let module_src = 168 let module_src =
209 crate::ModuleSource::from_child_node(db, src.file_id.original_file(db), &src.ast.syntax()); 169 crate::ModuleSource::from_child_node(db, src.file_id.original_file(db), &src.ast.syntax());
210 let module = Module::from_definition(db, Source { file_id: src.file_id, ast: module_src })?; 170 let module = Module::from_definition(db, Source { file_id: src.file_id, ast: module_src })?;
211 let ctx = LocationCtx::new(db, module, src.file_id); 171 let ctx = LocationCtx::new(db, module.id, src.file_id);
212 Some(DEF::from_ast(ctx, &src.ast)) 172 Some(DEF::from_ast(ctx, &src.ast))
213} 173}
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index 4ce7551c3..52e1fbf29 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -5,15 +5,17 @@
5 5
6use std::sync::Arc; 6use std::sync::Arc;
7 7
8use hir_def::{
9 path::Path,
10 type_ref::{TypeBound, TypeRef},
11};
12use hir_expand::name::{self, AsName};
8use ra_syntax::ast::{self, DefaultTypeParamOwner, NameOwner, TypeBoundsOwner, TypeParamsOwner}; 13use ra_syntax::ast::{self, DefaultTypeParamOwner, NameOwner, TypeBoundsOwner, TypeParamsOwner};
9 14
10use crate::{ 15use crate::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 16 db::{AstDatabase, DefDatabase, HirDatabase},
12 name::SELF_TYPE, 17 Adt, Const, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct, Trait,
13 path::Path, 18 TypeAlias, Union,
14 type_ref::{TypeBound, TypeRef},
15 Adt, AsName, Const, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct,
16 Trait, TypeAlias, Union,
17}; 19};
18 20
19/// Data about a generic parameter (to a function, struct, impl, ...). 21/// Data about a generic parameter (to a function, struct, impl, ...).
@@ -94,11 +96,15 @@ impl GenericParams {
94 GenericDef::Adt(Adt::Enum(it)) => generics.fill(&it.source(db).ast, start), 96 GenericDef::Adt(Adt::Enum(it)) => generics.fill(&it.source(db).ast, start),
95 GenericDef::Trait(it) => { 97 GenericDef::Trait(it) => {
96 // traits get the Self type as an implicit first type parameter 98 // traits get the Self type as an implicit first type parameter
97 generics.params.push(GenericParam { idx: start, name: SELF_TYPE, default: None }); 99 generics.params.push(GenericParam {
100 idx: start,
101 name: name::SELF_TYPE,
102 default: None,
103 });
98 generics.fill(&it.source(db).ast, start + 1); 104 generics.fill(&it.source(db).ast, start + 1);
99 // add super traits as bounds on Self 105 // add super traits as bounds on Self
100 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar 106 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
101 let self_param = TypeRef::Path(SELF_TYPE.into()); 107 let self_param = TypeRef::Path(name::SELF_TYPE.into());
102 generics.fill_bounds(&it.source(db).ast, self_param); 108 generics.fill_bounds(&it.source(db).ast, self_param);
103 } 109 }
104 GenericDef::TypeAlias(it) => generics.fill(&it.source(db).ast, start), 110 GenericDef::TypeAlias(it) => generics.fill(&it.source(db).ast, start),
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 499dcafea..fe083c0c6 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -1,168 +1,17 @@
1//! FIXME: write short doc here 1//! hir makes heavy use of ids: integer (u32) handlers to various things. You
2 2//! can think of id as a pointer (but without a lifetime) or a file descriptor
3use std::{ 3//! (but for hir objects).
4 hash::{Hash, Hasher}, 4//!
5 sync::Arc, 5//! This module defines a bunch of ids we are using. The most important ones are
6}; 6//! probably `HirFileId` and `DefId`.
7 7
8use mbe::MacroRules; 8use ra_db::salsa;
9use ra_db::{salsa, FileId}; 9
10use ra_prof::profile; 10pub use hir_def::{
11use ra_syntax::{ast, AstNode, Parse, SyntaxNode}; 11 AstItemDef, ConstId, EnumId, FunctionId, ItemLoc, LocationCtx, StaticId, StructId, TraitId,
12 12 TypeAliasId,
13use crate::{
14 db::{AstDatabase, DefDatabase, InternDatabase},
15 AstId, Crate, FileAstId, Module, Source,
16}; 13};
17 14pub use hir_expand::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, MacroFileKind};
18/// hir makes heavy use of ids: integer (u32) handlers to various things. You
19/// can think of id as a pointer (but without a lifetime) or a file descriptor
20/// (but for hir objects).
21///
22/// This module defines a bunch of ids we are using. The most important ones are
23/// probably `HirFileId` and `DefId`.
24
25/// Input to the analyzer is a set of files, where each file is identified by
26/// `FileId` and contains source code. However, another source of source code in
27/// Rust are macros: each macro can be thought of as producing a "temporary
28/// file". To assign an id to such a file, we use the id of the macro call that
29/// produced the file. So, a `HirFileId` is either a `FileId` (source code
30/// written by user), or a `MacroCallId` (source code produced by macro).
31///
32/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
33/// containing the call plus the offset of the macro call in the file. Note that
34/// this is a recursive definition! However, the size_of of `HirFileId` is
35/// finite (because everything bottoms out at the real `FileId`) and small
36/// (`MacroCallId` uses the location interner).
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub struct HirFileId(HirFileIdRepr);
39
40impl HirFileId {
41 /// For macro-expansion files, returns the file original source file the
42 /// expansion originated from.
43 pub fn original_file(self, db: &impl InternDatabase) -> FileId {
44 match self.0 {
45 HirFileIdRepr::File(file_id) => file_id,
46 HirFileIdRepr::Macro(macro_file) => {
47 let loc = macro_file.macro_call_id.loc(db);
48 loc.ast_id.file_id().original_file(db)
49 }
50 }
51 }
52
53 /// Get the crate which the macro lives in, if it is a macro file.
54 pub(crate) fn macro_crate(self, db: &impl AstDatabase) -> Option<Crate> {
55 match self.0 {
56 HirFileIdRepr::File(_) => None,
57 HirFileIdRepr::Macro(macro_file) => {
58 let loc = macro_file.macro_call_id.loc(db);
59 Some(loc.def.krate)
60 }
61 }
62 }
63
64 pub(crate) fn parse_or_expand_query(
65 db: &impl AstDatabase,
66 file_id: HirFileId,
67 ) -> Option<SyntaxNode> {
68 match file_id.0 {
69 HirFileIdRepr::File(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
70 HirFileIdRepr::Macro(macro_file) => {
71 db.parse_macro(macro_file).map(|it| it.syntax_node())
72 }
73 }
74 }
75
76 pub(crate) fn parse_macro_query(
77 db: &impl AstDatabase,
78 macro_file: MacroFile,
79 ) -> Option<Parse<SyntaxNode>> {
80 let _p = profile("parse_macro_query");
81 let macro_call_id = macro_file.macro_call_id;
82 let tt = db
83 .macro_expand(macro_call_id)
84 .map_err(|err| {
85 // Note:
86 // The final goal we would like to make all parse_macro success,
87 // such that the following log will not call anyway.
88 log::warn!("fail on macro_parse: (reason: {})", err,);
89 })
90 .ok()?;
91 match macro_file.macro_file_kind {
92 MacroFileKind::Items => mbe::token_tree_to_items(&tt).ok().map(Parse::to_syntax),
93 MacroFileKind::Expr => mbe::token_tree_to_expr(&tt).ok().map(Parse::to_syntax),
94 }
95 }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
99enum HirFileIdRepr {
100 File(FileId),
101 Macro(MacroFile),
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
105pub struct MacroFile {
106 macro_call_id: MacroCallId,
107 macro_file_kind: MacroFileKind,
108}
109
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
111pub(crate) enum MacroFileKind {
112 Items,
113 Expr,
114}
115
116impl From<FileId> for HirFileId {
117 fn from(file_id: FileId) -> HirFileId {
118 HirFileId(HirFileIdRepr::File(file_id))
119 }
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
123pub struct MacroDefId {
124 pub(crate) ast_id: AstId<ast::MacroCall>,
125 pub(crate) krate: Crate,
126}
127
128pub(crate) fn macro_def_query(db: &impl AstDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> {
129 let macro_call = id.ast_id.to_node(db);
130 let arg = macro_call.token_tree()?;
131 let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| {
132 log::warn!("fail on macro_def to token tree: {:#?}", arg);
133 None
134 })?;
135 let rules = MacroRules::parse(&tt).ok().or_else(|| {
136 log::warn!("fail on macro_def parse: {:#?}", tt);
137 None
138 })?;
139 Some(Arc::new(rules))
140}
141
142pub(crate) fn macro_arg_query(db: &impl AstDatabase, id: MacroCallId) -> Option<Arc<tt::Subtree>> {
143 let loc = id.loc(db);
144 let macro_call = loc.ast_id.to_node(db);
145 let arg = macro_call.token_tree()?;
146 let (tt, _) = mbe::ast_to_token_tree(&arg)?;
147 Some(Arc::new(tt))
148}
149
150pub(crate) fn macro_expand_query(
151 db: &impl AstDatabase,
152 id: MacroCallId,
153) -> Result<Arc<tt::Subtree>, String> {
154 let loc = id.loc(db);
155 let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?;
156
157 let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
158 let tt = macro_rules.expand(&macro_arg).map_err(|err| format!("{:?}", err))?;
159 // Set a hard limit for the expanded tt
160 let count = tt.count();
161 if count > 65536 {
162 return Err(format!("Total tokens count exceed limit : count = {}", count));
163 }
164 Ok(Arc::new(tt))
165}
166 15
167macro_rules! impl_intern_key { 16macro_rules! impl_intern_key {
168 ($name:ident) => { 17 ($name:ident) => {
@@ -177,192 +26,6 @@ macro_rules! impl_intern_key {
177 }; 26 };
178} 27}
179 28
180/// `MacroCallId` identifies a particular macro invocation, like
181/// `println!("Hello, {}", world)`.
182#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
183pub struct MacroCallId(salsa::InternId);
184impl_intern_key!(MacroCallId);
185
186#[derive(Debug, Clone, PartialEq, Eq, Hash)]
187pub struct MacroCallLoc {
188 pub(crate) def: MacroDefId,
189 pub(crate) ast_id: AstId<ast::MacroCall>,
190}
191
192impl MacroCallId {
193 pub(crate) fn loc(self, db: &impl InternDatabase) -> MacroCallLoc {
194 db.lookup_intern_macro(self)
195 }
196
197 pub(crate) fn as_file(self, kind: MacroFileKind) -> HirFileId {
198 let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind };
199 HirFileId(HirFileIdRepr::Macro(macro_file))
200 }
201}
202
203impl MacroCallLoc {
204 pub(crate) fn id(self, db: &impl InternDatabase) -> MacroCallId {
205 db.intern_macro(self)
206 }
207}
208
209#[derive(Debug)]
210pub struct ItemLoc<N: AstNode> {
211 pub(crate) module: Module,
212 ast_id: AstId<N>,
213}
214
215impl<N: AstNode> PartialEq for ItemLoc<N> {
216 fn eq(&self, other: &Self) -> bool {
217 self.module == other.module && self.ast_id == other.ast_id
218 }
219}
220impl<N: AstNode> Eq for ItemLoc<N> {}
221impl<N: AstNode> Hash for ItemLoc<N> {
222 fn hash<H: Hasher>(&self, hasher: &mut H) {
223 self.module.hash(hasher);
224 self.ast_id.hash(hasher);
225 }
226}
227
228impl<N: AstNode> Clone for ItemLoc<N> {
229 fn clone(&self) -> ItemLoc<N> {
230 ItemLoc { module: self.module, ast_id: self.ast_id }
231 }
232}
233
234#[derive(Clone, Copy)]
235pub(crate) struct LocationCtx<DB> {
236 db: DB,
237 module: Module,
238 file_id: HirFileId,
239}
240
241impl<'a, DB: DefDatabase> LocationCtx<&'a DB> {
242 pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> {
243 LocationCtx { db, module, file_id }
244 }
245}
246
247impl<'a, DB: DefDatabase + AstDatabase> LocationCtx<&'a DB> {
248 pub(crate) fn to_def<N, DEF>(self, ast: &N) -> DEF
249 where
250 N: AstNode,
251 DEF: AstItemDef<N>,
252 {
253 DEF::from_ast(self, ast)
254 }
255}
256
257pub(crate) trait AstItemDef<N: AstNode>: salsa::InternKey + Clone {
258 fn intern(db: &impl DefDatabase, loc: ItemLoc<N>) -> Self;
259 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<N>;
260
261 fn from_ast(ctx: LocationCtx<&(impl AstDatabase + DefDatabase)>, ast: &N) -> Self {
262 let items = ctx.db.ast_id_map(ctx.file_id);
263 let item_id = items.ast_id(ast);
264 Self::from_ast_id(ctx, item_id)
265 }
266 fn from_ast_id(ctx: LocationCtx<&impl DefDatabase>, ast_id: FileAstId<N>) -> Self {
267 let loc = ItemLoc { module: ctx.module, ast_id: ast_id.with_file_id(ctx.file_id) };
268 Self::intern(ctx.db, loc)
269 }
270 fn source(self, db: &(impl AstDatabase + DefDatabase)) -> Source<N> {
271 let loc = self.lookup_intern(db);
272 let ast = loc.ast_id.to_node(db);
273 Source { file_id: loc.ast_id.file_id(), ast }
274 }
275 fn module(self, db: &impl DefDatabase) -> Module {
276 let loc = self.lookup_intern(db);
277 loc.module
278 }
279}
280
281#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
282pub struct FunctionId(salsa::InternId);
283impl_intern_key!(FunctionId);
284
285impl AstItemDef<ast::FnDef> for FunctionId {
286 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::FnDef>) -> Self {
287 db.intern_function(loc)
288 }
289 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::FnDef> {
290 db.lookup_intern_function(self)
291 }
292}
293
294#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
295pub struct StructId(salsa::InternId);
296impl_intern_key!(StructId);
297impl AstItemDef<ast::StructDef> for StructId {
298 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
299 db.intern_struct(loc)
300 }
301 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::StructDef> {
302 db.lookup_intern_struct(self)
303 }
304}
305
306#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
307pub struct EnumId(salsa::InternId);
308impl_intern_key!(EnumId);
309impl AstItemDef<ast::EnumDef> for EnumId {
310 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::EnumDef>) -> Self {
311 db.intern_enum(loc)
312 }
313 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::EnumDef> {
314 db.lookup_intern_enum(self)
315 }
316}
317
318#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
319pub struct ConstId(salsa::InternId);
320impl_intern_key!(ConstId);
321impl AstItemDef<ast::ConstDef> for ConstId {
322 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::ConstDef>) -> Self {
323 db.intern_const(loc)
324 }
325 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::ConstDef> {
326 db.lookup_intern_const(self)
327 }
328}
329
330#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
331pub struct StaticId(salsa::InternId);
332impl_intern_key!(StaticId);
333impl AstItemDef<ast::StaticDef> for StaticId {
334 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::StaticDef>) -> Self {
335 db.intern_static(loc)
336 }
337 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::StaticDef> {
338 db.lookup_intern_static(self)
339 }
340}
341
342#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
343pub struct TraitId(salsa::InternId);
344impl_intern_key!(TraitId);
345impl AstItemDef<ast::TraitDef> for TraitId {
346 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::TraitDef>) -> Self {
347 db.intern_trait(loc)
348 }
349 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::TraitDef> {
350 db.lookup_intern_trait(self)
351 }
352}
353
354#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
355pub struct TypeAliasId(salsa::InternId);
356impl_intern_key!(TypeAliasId);
357impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
358 fn intern(db: &impl DefDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self {
359 db.intern_type_alias(loc)
360 }
361 fn lookup_intern(self, db: &impl DefDatabase) -> ItemLoc<ast::TypeAliasDef> {
362 db.lookup_intern_type_alias(self)
363 }
364}
365
366/// This exists just for Chalk, because Chalk just has a single `StructId` where 29/// This exists just for Chalk, because Chalk just has a single `StructId` where
367/// we have different kinds of ADTs, primitive types and special type 30/// we have different kinds of ADTs, primitive types and special type
368/// constructors like tuples and function pointers. 31/// constructors like tuples and function pointers.
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index 33ef87563..b1a014074 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -3,6 +3,8 @@
3use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
4use std::sync::Arc; 4use std::sync::Arc;
5 5
6use hir_def::{attr::Attr, type_ref::TypeRef};
7use hir_expand::hygiene::Hygiene;
6use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 8use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
7use ra_cfg::CfgOptions; 9use ra_cfg::CfgOptions;
8use ra_syntax::{ 10use ra_syntax::{
@@ -11,7 +13,6 @@ use ra_syntax::{
11}; 13};
12 14
13use crate::{ 15use crate::{
14 attr::Attr,
15 code_model::{Module, ModuleSource}, 16 code_model::{Module, ModuleSource},
16 db::{AstDatabase, DefDatabase, HirDatabase}, 17 db::{AstDatabase, DefDatabase, HirDatabase},
17 generics::HasGenericParams, 18 generics::HasGenericParams,
@@ -19,8 +20,7 @@ use crate::{
19 ids::MacroCallLoc, 20 ids::MacroCallLoc,
20 resolve::Resolver, 21 resolve::Resolver,
21 ty::Ty, 22 ty::Ty,
22 type_ref::TypeRef, 23 AssocItem, AstId, Const, Function, HasSource, HirFileId, MacroFileKind, Path, Source, TraitRef,
23 AssocItem, Const, Function, HasSource, HirFileId, MacroFileKind, Path, Source, TraitRef,
24 TypeAlias, 24 TypeAlias,
25}; 25};
26 26
@@ -129,7 +129,7 @@ impl ImplData {
129 ) -> Self { 129 ) -> Self {
130 let target_trait = node.target_trait().map(TypeRef::from_ast); 130 let target_trait = node.target_trait().map(TypeRef::from_ast);
131 let target_type = TypeRef::from_ast_opt(node.target_type()); 131 let target_type = TypeRef::from_ast_opt(node.target_type());
132 let ctx = LocationCtx::new(db, module, file_id); 132 let ctx = LocationCtx::new(db, module.id, file_id);
133 let negative = node.is_negative(); 133 let negative = node.is_negative();
134 let items = if let Some(item_list) = node.item_list() { 134 let items = if let Some(item_list) = node.item_list() {
135 item_list 135 item_list
@@ -182,7 +182,7 @@ impl ModuleImplBlocks {
182 ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) { 182 ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) {
183 let mut source_map = ImplSourceMap::default(); 183 let mut source_map = ImplSourceMap::default();
184 let crate_graph = db.crate_graph(); 184 let crate_graph = db.crate_graph();
185 let cfg_options = crate_graph.cfg_options(module.krate.crate_id()); 185 let cfg_options = crate_graph.cfg_options(module.id.krate);
186 186
187 let result = ModuleImplBlocks::collect(db, cfg_options, module, &mut source_map); 187 let result = ModuleImplBlocks::collect(db, cfg_options, module, &mut source_map);
188 (Arc::new(result), Arc::new(source_map)) 188 (Arc::new(result), Arc::new(source_map))
@@ -228,10 +228,11 @@ impl ModuleImplBlocks {
228 owner: &dyn ast::ModuleItemOwner, 228 owner: &dyn ast::ModuleItemOwner,
229 file_id: HirFileId, 229 file_id: HirFileId,
230 ) { 230 ) {
231 let hygiene = Hygiene::new(db, file_id);
231 for item in owner.items_with_macros() { 232 for item in owner.items_with_macros() {
232 match item { 233 match item {
233 ast::ItemOrMacro::Item(ast::ModuleItem::ImplBlock(impl_block_ast)) => { 234 ast::ItemOrMacro::Item(ast::ModuleItem::ImplBlock(impl_block_ast)) => {
234 let attrs = Attr::from_attrs_owner(file_id, &impl_block_ast, db); 235 let attrs = Attr::from_attrs_owner(&impl_block_ast, &hygiene);
235 if attrs.map_or(false, |attrs| { 236 if attrs.map_or(false, |attrs| {
236 attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false)) 237 attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false))
237 }) { 238 }) {
@@ -248,7 +249,7 @@ impl ModuleImplBlocks {
248 } 249 }
249 ast::ItemOrMacro::Item(_) => (), 250 ast::ItemOrMacro::Item(_) => (),
250 ast::ItemOrMacro::Macro(macro_call) => { 251 ast::ItemOrMacro::Macro(macro_call) => {
251 let attrs = Attr::from_attrs_owner(file_id, &macro_call, db); 252 let attrs = Attr::from_attrs_owner(&macro_call, &hygiene);
252 if attrs.map_or(false, |attrs| { 253 if attrs.map_or(false, |attrs| {
253 attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false)) 254 attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false))
254 }) { 255 }) {
@@ -256,14 +257,13 @@ impl ModuleImplBlocks {
256 } 257 }
257 258
258 //FIXME: we should really cut down on the boilerplate required to process a macro 259 //FIXME: we should really cut down on the boilerplate required to process a macro
259 let ast_id = db.ast_id_map(file_id).ast_id(&macro_call).with_file_id(file_id); 260 let ast_id = AstId::new(file_id, db.ast_id_map(file_id).ast_id(&macro_call));
260 if let Some(path) = macro_call 261 if let Some(path) =
261 .path() 262 macro_call.path().and_then(|path| Path::from_src(path, &hygiene))
262 .and_then(|path| Path::from_src(Source { ast: path, file_id }, db))
263 { 263 {
264 if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path) 264 if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path)
265 { 265 {
266 let call_id = MacroCallLoc { def: def.id, ast_id }.id(db); 266 let call_id = db.intern_macro(MacroCallLoc { def: def.id, ast_id });
267 let file_id = call_id.as_file(MacroFileKind::Items); 267 let file_id = call_id.as_file(MacroFileKind::Items);
268 if let Some(item_list) = 268 if let Some(item_list) =
269 db.parse_or_expand(file_id).and_then(ast::MacroItems::cast) 269 db.parse_or_expand(file_id).and_then(ast::MacroItems::cast)
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs
index 6c4e8ffbd..e1780ed38 100644
--- a/crates/ra_hir/src/lang_item.rs
+++ b/crates/ra_hir/src/lang_item.rs
@@ -22,14 +22,14 @@ pub enum LangItemTarget {
22 22
23impl LangItemTarget { 23impl LangItemTarget {
24 pub(crate) fn krate(&self, db: &impl HirDatabase) -> Option<Crate> { 24 pub(crate) fn krate(&self, db: &impl HirDatabase) -> Option<Crate> {
25 match self { 25 Some(match self {
26 LangItemTarget::Enum(e) => e.module(db).krate(db), 26 LangItemTarget::Enum(e) => e.module(db).krate(),
27 LangItemTarget::Function(f) => f.module(db).krate(db), 27 LangItemTarget::Function(f) => f.module(db).krate(),
28 LangItemTarget::ImplBlock(i) => i.module().krate(db), 28 LangItemTarget::ImplBlock(i) => i.module().krate(),
29 LangItemTarget::Static(s) => s.module(db).krate(db), 29 LangItemTarget::Static(s) => s.module(db).krate(),
30 LangItemTarget::Struct(s) => s.module(db).krate(db), 30 LangItemTarget::Struct(s) => s.module(db).krate(),
31 LangItemTarget::Trait(t) => t.module(db).krate(db), 31 LangItemTarget::Trait(t) => t.module(db).krate(),
32 } 32 })
33 } 33 }
34} 34}
35 35
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index ca261e8f5..40f5562b4 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -26,25 +26,19 @@ macro_rules! impl_froms {
26 } 26 }
27} 27}
28 28
29mod either;
30pub mod debug; 29pub mod debug;
31 30
32pub mod db; 31pub mod db;
33#[macro_use] 32#[macro_use]
34pub mod mock; 33pub mod mock;
35mod path;
36pub mod source_binder; 34pub mod source_binder;
37 35
38mod source_id;
39mod ids; 36mod ids;
40mod name;
41mod nameres; 37mod nameres;
42mod adt; 38mod adt;
43mod traits; 39mod traits;
44mod type_alias; 40mod type_alias;
45mod type_ref;
46mod ty; 41mod ty;
47mod attr;
48mod impl_block; 42mod impl_block;
49mod expr; 43mod expr;
50mod lang_item; 44mod lang_item;
@@ -60,37 +54,35 @@ pub mod from_source;
60#[cfg(test)] 54#[cfg(test)]
61mod marks; 55mod marks;
62 56
63use crate::{ 57use hir_expand::AstId;
64 ids::MacroFileKind, 58
65 name::AsName, 59use crate::{ids::MacroFileKind, resolve::Resolver};
66 resolve::Resolver,
67 source_id::{AstId, FileAstId},
68};
69 60
70pub use self::{ 61pub use crate::{
71 adt::VariantDef, 62 adt::VariantDef,
72 either::Either, 63 code_model::{
64 docs::{DocDef, Docs, Documentation},
65 src::{HasBodySource, HasSource, Source},
66 Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum,
67 EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef,
68 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
69 },
73 expr::ExprScopes, 70 expr::ExprScopes,
74 from_source::FromSource, 71 from_source::FromSource,
75 generics::{GenericDef, GenericParam, GenericParams, HasGenericParams}, 72 generics::{GenericDef, GenericParam, GenericParams, HasGenericParams},
76 ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, 73 ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile},
77 impl_block::ImplBlock, 74 impl_block::ImplBlock,
78 name::Name,
79 nameres::{ImportId, Namespace, PerNs}, 75 nameres::{ImportId, Namespace, PerNs},
80 path::{Path, PathKind},
81 resolve::ScopeDef, 76 resolve::ScopeDef,
82 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, 77 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
83 source_id::{AstIdMap, ErasedFileAstId},
84 ty::{ 78 ty::{
85 display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, 79 display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
86 }, 80 },
87 type_ref::Mutability,
88}; 81};
89 82
90pub use self::code_model::{ 83pub use hir_def::{
91 docs::{DocDef, Docs, Documentation}, 84 builtin_type::BuiltinType,
92 src::{HasBodySource, HasSource, Source}, 85 path::{Path, PathKind},
93 Adt, AssocItem, BuiltinType, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, 86 type_ref::Mutability,
94 Enum, EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef,
95 ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
96}; 87};
88pub use hir_expand::{either::Either, name::Name};
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index 79af24b20..b423489a1 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -2,6 +2,7 @@
2 2
3test_utils::marks!( 3test_utils::marks!(
4 bogus_paths 4 bogus_paths
5 // FIXME: restore this mark once hir is split
5 name_res_works_for_broken_modules 6 name_res_works_for_broken_modules
6 can_import_enum_variant 7 can_import_enum_variant
7 type_var_cycles_resolve_completely 8 type_var_cycles_resolve_completely
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 0b278deb3..35dfaf3ba 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -22,6 +22,7 @@ pub const WORKSPACE: SourceRootId = SourceRootId(0);
22 db::InternDatabaseStorage, 22 db::InternDatabaseStorage,
23 db::AstDatabaseStorage, 23 db::AstDatabaseStorage,
24 db::DefDatabaseStorage, 24 db::DefDatabaseStorage,
25 db::DefDatabase2Storage,
25 db::HirDatabaseStorage 26 db::HirDatabaseStorage
26)] 27)]
27#[derive(Debug)] 28#[derive(Debug)]
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 67adcfa28..7ba031827 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -48,16 +48,15 @@
48//! on the result 48//! on the result
49 49
50mod per_ns; 50mod per_ns;
51mod raw;
52mod collector; 51mod collector;
53mod mod_resolution;
54#[cfg(test)] 52#[cfg(test)]
55mod tests; 53mod tests;
56 54
57use std::sync::Arc; 55use std::sync::Arc;
58 56
57use hir_def::{builtin_type::BuiltinType, CrateModuleId};
59use once_cell::sync::Lazy; 58use once_cell::sync::Lazy;
60use ra_arena::{impl_arena_id, Arena, RawId}; 59use ra_arena::Arena;
61use ra_db::{Edition, FileId}; 60use ra_db::{Edition, FileId};
62use ra_prof::profile; 61use ra_prof::profile;
63use ra_syntax::ast; 62use ra_syntax::ast;
@@ -69,16 +68,12 @@ use crate::{
69 diagnostics::DiagnosticSink, 68 diagnostics::DiagnosticSink,
70 ids::MacroDefId, 69 ids::MacroDefId,
71 nameres::diagnostics::DefDiagnostic, 70 nameres::diagnostics::DefDiagnostic,
72 Adt, AstId, BuiltinType, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, 71 Adt, AstId, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait,
73 Trait,
74}; 72};
75 73
76pub(crate) use self::raw::{ImportSourceMap, RawItems}; 74pub use self::per_ns::{Namespace, PerNs};
77 75
78pub use self::{ 76pub use hir_def::nameres::raw::ImportId;
79 per_ns::{Namespace, PerNs},
80 raw::ImportId,
81};
82 77
83/// Contains all top-level defs from a macro-expanded crate 78/// Contains all top-level defs from a macro-expanded crate
84#[derive(Debug, PartialEq, Eq)] 79#[derive(Debug, PartialEq, Eq)]
@@ -115,13 +110,8 @@ impl std::ops::Index<CrateModuleId> for CrateDefMap {
115 } 110 }
116} 111}
117 112
118/// An ID of a module, **local** to a specific crate
119#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
120pub(crate) struct CrateModuleId(RawId);
121impl_arena_id!(CrateModuleId);
122
123#[derive(Default, Debug, PartialEq, Eq)] 113#[derive(Default, Debug, PartialEq, Eq)]
124pub(crate) struct ModuleData { 114pub struct ModuleData {
125 pub(crate) parent: Option<CrateModuleId>, 115 pub(crate) parent: Option<CrateModuleId>,
126 pub(crate) children: FxHashMap<Name, CrateModuleId>, 116 pub(crate) children: FxHashMap<Name, CrateModuleId>,
127 pub(crate) scope: ModuleScope, 117 pub(crate) scope: ModuleScope,
@@ -332,10 +322,11 @@ impl CrateDefMap {
332 ) -> ResolvePathResult { 322 ) -> ResolvePathResult {
333 let mut segments = path.segments.iter().enumerate(); 323 let mut segments = path.segments.iter().enumerate();
334 let mut curr_per_ns: PerNs = match path.kind { 324 let mut curr_per_ns: PerNs = match path.kind {
335 PathKind::DollarCrate(krate) => { 325 PathKind::DollarCrate(crate_id) => {
326 let krate = Crate { crate_id };
336 if krate == self.krate { 327 if krate == self.krate {
337 tested_by!(macro_dollar_crate_self); 328 tested_by!(macro_dollar_crate_self);
338 PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) 329 PerNs::types(Module::new(self.krate, self.root).into())
339 } else { 330 } else {
340 match krate.root_module(db) { 331 match krate.root_module(db) {
341 Some(module) => { 332 Some(module) => {
@@ -346,12 +337,8 @@ impl CrateDefMap {
346 } 337 }
347 } 338 }
348 } 339 }
349 PathKind::Crate => { 340 PathKind::Crate => PerNs::types(Module::new(self.krate, self.root).into()),
350 PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) 341 PathKind::Self_ => PerNs::types(Module::new(self.krate, original_module).into()),
351 }
352 PathKind::Self_ => {
353 PerNs::types(Module { krate: self.krate, module_id: original_module }.into())
354 }
355 // plain import or absolute path in 2015: crate-relative with 342 // plain import or absolute path in 2015: crate-relative with
356 // fallback to extern prelude (with the simplification in 343 // fallback to extern prelude (with the simplification in
357 // rust-lang/rust#57745) 344 // rust-lang/rust#57745)
@@ -377,7 +364,7 @@ impl CrateDefMap {
377 } 364 }
378 PathKind::Super => { 365 PathKind::Super => {
379 if let Some(p) = self.modules[original_module].parent { 366 if let Some(p) = self.modules[original_module].parent {
380 PerNs::types(Module { krate: self.krate, module_id: p }.into()) 367 PerNs::types(Module::new(self.krate, p).into())
381 } else { 368 } else {
382 log::debug!("super path in root module"); 369 log::debug!("super path in root module");
383 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 370 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
@@ -419,12 +406,12 @@ impl CrateDefMap {
419 406
420 curr_per_ns = match curr { 407 curr_per_ns = match curr {
421 ModuleDef::Module(module) => { 408 ModuleDef::Module(module) => {
422 if module.krate != self.krate { 409 if module.krate() != self.krate {
423 let path = 410 let path =
424 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; 411 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
425 log::debug!("resolving {:?} in other crate", path); 412 log::debug!("resolving {:?} in other crate", path);
426 let defp_map = db.crate_def_map(module.krate); 413 let defp_map = db.crate_def_map(module.krate());
427 let (def, s) = defp_map.resolve_path(db, module.module_id, &path); 414 let (def, s) = defp_map.resolve_path(db, module.id.module_id, &path);
428 return ResolvePathResult::with( 415 return ResolvePathResult::with(
429 def, 416 def,
430 ReachedFixedPoint::Yes, 417 ReachedFixedPoint::Yes,
@@ -433,7 +420,7 @@ impl CrateDefMap {
433 } 420 }
434 421
435 // Since it is a qualified path here, it should not contains legacy macros 422 // Since it is a qualified path here, it should not contains legacy macros
436 match self[module.module_id].scope.get(&segment.name) { 423 match self[module.id.module_id].scope.get(&segment.name) {
437 Some(res) => res.def, 424 Some(res) => res.def,
438 _ => { 425 _ => {
439 log::debug!("path segment {:?} not found", segment.name); 426 log::debug!("path segment {:?} not found", segment.name);
@@ -511,14 +498,14 @@ impl CrateDefMap {
511 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs { 498 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs {
512 if let Some(prelude) = self.prelude { 499 if let Some(prelude) = self.prelude {
513 let keep; 500 let keep;
514 let def_map = if prelude.krate == self.krate { 501 let def_map = if prelude.krate() == self.krate {
515 self 502 self
516 } else { 503 } else {
517 // Extend lifetime 504 // Extend lifetime
518 keep = db.crate_def_map(prelude.krate); 505 keep = db.crate_def_map(prelude.krate());
519 &keep 506 &keep
520 }; 507 };
521 def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def) 508 def_map[prelude.id.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
522 } else { 509 } else {
523 PerNs::none() 510 PerNs::none()
524 } 511 }
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index b5fe16bfa..ee0a4c99f 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -1,5 +1,10 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir_def::{
4 attr::Attr,
5 nameres::{mod_resolution::ModDir, raw},
6};
7use hir_expand::name;
3use ra_cfg::CfgOptions; 8use ra_cfg::CfgOptions;
4use ra_db::FileId; 9use ra_db::FileId;
5use ra_syntax::{ast, SmolStr}; 10use ra_syntax::{ast, SmolStr};
@@ -7,13 +12,11 @@ use rustc_hash::FxHashMap;
7use test_utils::tested_by; 12use test_utils::tested_by;
8 13
9use crate::{ 14use crate::{
10 attr::Attr,
11 db::DefDatabase, 15 db::DefDatabase,
12 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, 16 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind},
13 name::MACRO_RULES,
14 nameres::{ 17 nameres::{
15 diagnostics::DefDiagnostic, mod_resolution::ModDir, raw, Crate, CrateDefMap, CrateModuleId, 18 diagnostics::DefDiagnostic, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef,
16 ModuleData, ModuleDef, PerNs, ReachedFixedPoint, Resolution, ResolveMode, 19 PerNs, ReachedFixedPoint, Resolution, ResolveMode,
17 }, 20 },
18 Adt, AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, 21 Adt, AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static,
19 Struct, Trait, TypeAlias, Union, 22 Struct, Trait, TypeAlias, Union,
@@ -212,7 +215,7 @@ where
212 215
213 if let Some(ModuleDef::Module(m)) = res.take_types() { 216 if let Some(ModuleDef::Module(m)) = res.take_types() {
214 tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); 217 tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
215 self.import_all_macros_exported(current_module_id, m.krate); 218 self.import_all_macros_exported(current_module_id, m.krate());
216 } 219 }
217 } 220 }
218 221
@@ -289,11 +292,11 @@ where
289 if import.is_prelude { 292 if import.is_prelude {
290 tested_by!(std_prelude); 293 tested_by!(std_prelude);
291 self.def_map.prelude = Some(m); 294 self.def_map.prelude = Some(m);
292 } else if m.krate != self.def_map.krate { 295 } else if m.krate() != self.def_map.krate {
293 tested_by!(glob_across_crates); 296 tested_by!(glob_across_crates);
294 // glob import from other crate => we can just import everything once 297 // glob import from other crate => we can just import everything once
295 let item_map = self.db.crate_def_map(m.krate); 298 let item_map = self.db.crate_def_map(m.krate());
296 let scope = &item_map[m.module_id].scope; 299 let scope = &item_map[m.id.module_id].scope;
297 300
298 // Module scoped macros is included 301 // Module scoped macros is included
299 let items = scope 302 let items = scope
@@ -307,7 +310,7 @@ where
307 // glob import from same crate => we do an initial 310 // glob import from same crate => we do an initial
308 // import, and then need to propagate any further 311 // import, and then need to propagate any further
309 // additions 312 // additions
310 let scope = &self.def_map[m.module_id].scope; 313 let scope = &self.def_map[m.id.module_id].scope;
311 314
312 // Module scoped macros is included 315 // Module scoped macros is included
313 let items = scope 316 let items = scope
@@ -319,7 +322,7 @@ where
319 self.update(module_id, Some(import_id), &items); 322 self.update(module_id, Some(import_id), &items);
320 // record the glob import in case we add further items 323 // record the glob import in case we add further items
321 self.glob_imports 324 self.glob_imports
322 .entry(m.module_id) 325 .entry(m.id.module_id)
323 .or_default() 326 .or_default()
324 .push((module_id, import_id)); 327 .push((module_id, import_id));
325 } 328 }
@@ -448,7 +451,7 @@ where
448 ); 451 );
449 452
450 if let Some(def) = resolved_res.resolved_def.get_macros() { 453 if let Some(def) = resolved_res.resolved_def.get_macros() {
451 let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db); 454 let call_id = self.db.intern_macro(MacroCallLoc { def: def.id, ast_id: *ast_id });
452 resolved.push((*module_id, call_id, def.id)); 455 resolved.push((*module_id, call_id, def.id));
453 res = ReachedFixedPoint::No; 456 res = ReachedFixedPoint::No;
454 return false; 457 return false;
@@ -523,9 +526,10 @@ where
523 526
524 // Prelude module is always considered to be `#[macro_use]`. 527 // Prelude module is always considered to be `#[macro_use]`.
525 if let Some(prelude_module) = self.def_collector.def_map.prelude { 528 if let Some(prelude_module) = self.def_collector.def_map.prelude {
526 if prelude_module.krate != self.def_collector.def_map.krate { 529 if prelude_module.krate() != self.def_collector.def_map.krate {
527 tested_by!(prelude_is_macro_use); 530 tested_by!(prelude_is_macro_use);
528 self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); 531 self.def_collector
532 .import_all_macros_exported(self.module_id, prelude_module.krate());
529 } 533 }
530 } 534 }
531 535
@@ -567,7 +571,7 @@ where
567 // inline module, just recurse 571 // inline module, just recurse
568 raw::ModuleData::Definition { name, items, ast_id } => { 572 raw::ModuleData::Definition { name, items, ast_id } => {
569 let module_id = 573 let module_id =
570 self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); 574 self.push_child_module(name.clone(), AstId::new(self.file_id, *ast_id), None);
571 575
572 ModCollector { 576 ModCollector {
573 def_collector: &mut *self.def_collector, 577 def_collector: &mut *self.def_collector,
@@ -583,7 +587,7 @@ where
583 } 587 }
584 // out of line module, resolve, parse and recurse 588 // out of line module, resolve, parse and recurse
585 raw::ModuleData::Declaration { name, ast_id } => { 589 raw::ModuleData::Declaration { name, ast_id } => {
586 let ast_id = ast_id.with_file_id(self.file_id); 590 let ast_id = AstId::new(self.file_id, *ast_id);
587 match self.mod_dir.resolve_declaration( 591 match self.mod_dir.resolve_declaration(
588 self.def_collector.db, 592 self.def_collector.db,
589 self.file_id, 593 self.file_id,
@@ -631,9 +635,7 @@ where
631 modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone(); 635 modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone();
632 modules[self.module_id].children.insert(name.clone(), res); 636 modules[self.module_id].children.insert(name.clone(), res);
633 let resolution = Resolution { 637 let resolution = Resolution {
634 def: PerNs::types( 638 def: PerNs::types(Module::new(self.def_collector.def_map.krate, res).into()),
635 Module { krate: self.def_collector.def_map.krate, module_id: res }.into(),
636 ),
637 import: None, 639 import: None,
638 }; 640 };
639 self.def_collector.update(self.module_id, None, &[(name, resolution)]); 641 self.def_collector.update(self.module_id, None, &[(name, resolution)]);
@@ -641,8 +643,8 @@ where
641 } 643 }
642 644
643 fn define_def(&mut self, def: &raw::DefData) { 645 fn define_def(&mut self, def: &raw::DefData) {
644 let module = Module { krate: self.def_collector.def_map.krate, module_id: self.module_id }; 646 let module = Module::new(self.def_collector.def_map.krate, self.module_id);
645 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); 647 let ctx = LocationCtx::new(self.def_collector.db, module.id, self.file_id);
646 648
647 macro_rules! def { 649 macro_rules! def {
648 ($kind:ident, $ast_id:ident) => { 650 ($kind:ident, $ast_id:ident) => {
@@ -671,28 +673,26 @@ where
671 } 673 }
672 674
673 fn collect_macro(&mut self, mac: &raw::MacroData) { 675 fn collect_macro(&mut self, mac: &raw::MacroData) {
676 let ast_id = AstId::new(self.file_id, mac.ast_id);
677
674 // Case 1: macro rules, define a macro in crate-global mutable scope 678 // Case 1: macro rules, define a macro in crate-global mutable scope
675 if is_macro_rules(&mac.path) { 679 if is_macro_rules(&mac.path) {
676 if let Some(name) = &mac.name { 680 if let Some(name) = &mac.name {
677 let macro_id = MacroDefId { 681 let macro_id =
678 ast_id: mac.ast_id.with_file_id(self.file_id), 682 MacroDefId { ast_id, krate: self.def_collector.def_map.krate.crate_id };
679 krate: self.def_collector.def_map.krate,
680 };
681 let macro_ = MacroDef { id: macro_id }; 683 let macro_ = MacroDef { id: macro_id };
682 self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export); 684 self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export);
683 } 685 }
684 return; 686 return;
685 } 687 }
686 688
687 let ast_id = mac.ast_id.with_file_id(self.file_id);
688
689 // Case 2: try to resolve in legacy scope and expand macro_rules, triggering 689 // Case 2: try to resolve in legacy scope and expand macro_rules, triggering
690 // recursive item collection. 690 // recursive item collection.
691 if let Some(macro_def) = mac.path.as_ident().and_then(|name| { 691 if let Some(macro_def) = mac.path.as_ident().and_then(|name| {
692 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) 692 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
693 }) { 693 }) {
694 let def = macro_def.id; 694 let def = macro_def.id;
695 let macro_call_id = MacroCallLoc { def, ast_id }.id(self.def_collector.db); 695 let macro_call_id = self.def_collector.db.intern_macro(MacroCallLoc { def, ast_id });
696 696
697 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def); 697 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def);
698 return; 698 return;
@@ -728,7 +728,7 @@ where
728} 728}
729 729
730fn is_macro_rules(path: &Path) -> bool { 730fn is_macro_rules(path: &Path) -> bool {
731 path.as_ident() == Some(&MACRO_RULES) 731 path.as_ident() == Some(&name::MACRO_RULES)
732} 732}
733 733
734#[cfg(test)] 734#[cfg(test)]
diff --git a/crates/ra_hir/src/nameres/tests/mod_resolution.rs b/crates/ra_hir/src/nameres/tests/mod_resolution.rs
index f569aacdc..abfe8b1c3 100644
--- a/crates/ra_hir/src/nameres/tests/mod_resolution.rs
+++ b/crates/ra_hir/src/nameres/tests/mod_resolution.rs
@@ -2,7 +2,7 @@ use super::*;
2 2
3#[test] 3#[test]
4fn name_res_works_for_broken_modules() { 4fn name_res_works_for_broken_modules() {
5 covers!(name_res_works_for_broken_modules); 5 // covers!(name_res_works_for_broken_modules);
6 let map = def_map( 6 let map = def_map(
7 " 7 "
8 //- /lib.rs 8 //- /lib.rs
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 3c797c0c3..75b24d386 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -1,6 +1,12 @@
1//! Name resolution. 1//! Name resolution.
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use hir_def::{
5 builtin_type::BuiltinType,
6 path::{Path, PathKind},
7 CrateModuleId,
8};
9use hir_expand::name::{self, Name};
4use rustc_hash::FxHashSet; 10use rustc_hash::FxHashSet;
5 11
6use crate::{ 12use crate::{
@@ -12,11 +18,8 @@ use crate::{
12 }, 18 },
13 generics::GenericParams, 19 generics::GenericParams,
14 impl_block::ImplBlock, 20 impl_block::ImplBlock,
15 name::{Name, SELF_PARAM, SELF_TYPE}, 21 nameres::{CrateDefMap, PerNs},
16 nameres::{CrateDefMap, CrateModuleId, PerNs}, 22 Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, Trait, TypeAlias,
17 path::{Path, PathKind},
18 Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct,
19 Trait, TypeAlias,
20}; 23};
21 24
22#[derive(Debug, Clone, Default)] 25#[derive(Debug, Clone, Default)]
@@ -149,13 +152,13 @@ impl Resolver {
149 } 152 }
150 } 153 }
151 Scope::ImplBlockScope(impl_) => { 154 Scope::ImplBlockScope(impl_) => {
152 if first_name == &SELF_TYPE { 155 if first_name == &name::SELF_TYPE {
153 let idx = if path.segments.len() == 1 { None } else { Some(1) }; 156 let idx = if path.segments.len() == 1 { None } else { Some(1) };
154 return Some((TypeNs::SelfType(*impl_), idx)); 157 return Some((TypeNs::SelfType(*impl_), idx));
155 } 158 }
156 } 159 }
157 Scope::AdtScope(adt) => { 160 Scope::AdtScope(adt) => {
158 if first_name == &SELF_TYPE { 161 if first_name == &name::SELF_TYPE {
159 let idx = if path.segments.len() == 1 { None } else { Some(1) }; 162 let idx = if path.segments.len() == 1 { None } else { Some(1) };
160 return Some((TypeNs::AdtSelfType(*adt), idx)); 163 return Some((TypeNs::AdtSelfType(*adt), idx));
161 } 164 }
@@ -204,7 +207,7 @@ impl Resolver {
204 return None; 207 return None;
205 } 208 }
206 let n_segments = path.segments.len(); 209 let n_segments = path.segments.len();
207 let tmp = SELF_PARAM; 210 let tmp = name::SELF_PARAM;
208 let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; 211 let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name };
209 let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); 212 let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
210 for scope in self.scopes.iter().rev() { 213 for scope in self.scopes.iter().rev() {
@@ -240,13 +243,13 @@ impl Resolver {
240 Scope::GenericParams(_) => continue, 243 Scope::GenericParams(_) => continue,
241 244
242 Scope::ImplBlockScope(impl_) if n_segments > 1 => { 245 Scope::ImplBlockScope(impl_) if n_segments > 1 => {
243 if first_name == &SELF_TYPE { 246 if first_name == &name::SELF_TYPE {
244 let ty = TypeNs::SelfType(*impl_); 247 let ty = TypeNs::SelfType(*impl_);
245 return Some(ResolveValueResult::Partial(ty, 1)); 248 return Some(ResolveValueResult::Partial(ty, 1));
246 } 249 }
247 } 250 }
248 Scope::AdtScope(adt) if n_segments > 1 => { 251 Scope::AdtScope(adt) if n_segments > 1 => {
249 if first_name == &SELF_TYPE { 252 if first_name == &name::SELF_TYPE {
250 let ty = TypeNs::AdtSelfType(*adt); 253 let ty = TypeNs::AdtSelfType(*adt);
251 return Some(ResolveValueResult::Partial(ty, 1)); 254 return Some(ResolveValueResult::Partial(ty, 1));
252 } 255 }
@@ -330,8 +333,8 @@ impl Resolver {
330 for scope in &self.scopes { 333 for scope in &self.scopes {
331 if let Scope::ModuleScope(m) = scope { 334 if let Scope::ModuleScope(m) = scope {
332 if let Some(prelude) = m.crate_def_map.prelude() { 335 if let Some(prelude) = m.crate_def_map.prelude() {
333 let prelude_def_map = db.crate_def_map(prelude.krate); 336 let prelude_def_map = db.crate_def_map(prelude.krate());
334 traits.extend(prelude_def_map[prelude.module_id].scope.traits()); 337 traits.extend(prelude_def_map[prelude.id.module_id].scope.traits());
335 } 338 }
336 traits.extend(m.crate_def_map[m.module_id].scope.traits()); 339 traits.extend(m.crate_def_map[m.module_id].scope.traits());
337 } 340 }
@@ -444,10 +447,12 @@ impl Scope {
444 f(name.clone(), ScopeDef::ModuleDef(*def)); 447 f(name.clone(), ScopeDef::ModuleDef(*def));
445 }); 448 });
446 if let Some(prelude) = m.crate_def_map.prelude() { 449 if let Some(prelude) = m.crate_def_map.prelude() {
447 let prelude_def_map = db.crate_def_map(prelude.krate); 450 let prelude_def_map = db.crate_def_map(prelude.krate());
448 prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| { 451 prelude_def_map[prelude.id.module_id].scope.entries().for_each(
449 f(name.clone(), res.def.into()); 452 |(name, res)| {
450 }); 453 f(name.clone(), res.def.into());
454 },
455 );
451 } 456 }
452 } 457 }
453 Scope::GenericParams(gp) => { 458 Scope::GenericParams(gp) => {
@@ -456,10 +461,10 @@ impl Scope {
456 } 461 }
457 } 462 }
458 Scope::ImplBlockScope(i) => { 463 Scope::ImplBlockScope(i) => {
459 f(SELF_TYPE, ScopeDef::ImplSelfType(*i)); 464 f(name::SELF_TYPE, ScopeDef::ImplSelfType(*i));
460 } 465 }
461 Scope::AdtScope(i) => { 466 Scope::AdtScope(i) => {
462 f(SELF_TYPE, ScopeDef::AdtSelfType(*i)); 467 f(name::SELF_TYPE, ScopeDef::AdtSelfType(*i));
463 } 468 }
464 Scope::ExprScope(e) => { 469 Scope::ExprScope(e) => {
465 e.expr_scopes.entries(e.scope_id).iter().for_each(|e| { 470 e.expr_scopes.entries(e.scope_id).iter().for_each(|e| {
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index a907d6a9f..152bc71bd 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -7,10 +7,12 @@
7//! purely for "IDE needs". 7//! purely for "IDE needs".
8use std::sync::Arc; 8use std::sync::Arc;
9 9
10use hir_def::path::known;
11use hir_expand::name::AsName;
10use ra_db::FileId; 12use ra_db::FileId;
11use ra_syntax::{ 13use ra_syntax::{
12 ast::{self, AstNode}, 14 ast::{self, AstNode},
13 AstPtr, 15 match_ast, AstPtr,
14 SyntaxKind::*, 16 SyntaxKind::*,
15 SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, 17 SyntaxNode, SyntaxNodePtr, TextRange, TextUnit,
16}; 18};
@@ -24,11 +26,10 @@ use crate::{
24 BodySourceMap, 26 BodySourceMap,
25 }, 27 },
26 ids::LocationCtx, 28 ids::LocationCtx,
27 path::known,
28 resolve::{ScopeDef, TypeNs, ValueNs}, 29 resolve::{ScopeDef, TypeNs, ValueNs},
29 ty::method_resolution::implements_trait, 30 ty::method_resolution::implements_trait,
30 AsName, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, MacroDef, 31 Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, MacroDef, Module,
31 Module, Name, Path, Resolver, Static, Struct, Ty, 32 Name, Path, Resolver, Static, Struct, Ty,
32}; 33};
33 34
34fn try_get_resolver_for_node( 35fn try_get_resolver_for_node(
@@ -36,24 +37,34 @@ fn try_get_resolver_for_node(
36 file_id: FileId, 37 file_id: FileId,
37 node: &SyntaxNode, 38 node: &SyntaxNode,
38) -> Option<Resolver> { 39) -> Option<Resolver> {
39 if let Some(module) = ast::Module::cast(node.clone()) { 40 match_ast! {
40 let src = crate::Source { file_id: file_id.into(), ast: module }; 41 match node {
41 Some(crate::Module::from_declaration(db, src)?.resolver(db)) 42 ast::Module(it) => {
42 } else if let Some(file) = ast::SourceFile::cast(node.clone()) { 43 let src = crate::Source { file_id: file_id.into(), ast: it };
43 let src = 44 Some(crate::Module::from_declaration(db, src)?.resolver(db))
44 crate::Source { file_id: file_id.into(), ast: crate::ModuleSource::SourceFile(file) }; 45 },
45 Some(crate::Module::from_definition(db, src)?.resolver(db)) 46 ast::SourceFile(it) => {
46 } else if let Some(s) = ast::StructDef::cast(node.clone()) { 47 let src =
47 let src = crate::Source { file_id: file_id.into(), ast: s }; 48 crate::Source { file_id: file_id.into(), ast: crate::ModuleSource::SourceFile(it) };
48 Some(Struct::from_source(db, src)?.resolver(db)) 49 Some(crate::Module::from_definition(db, src)?.resolver(db))
49 } else if let Some(e) = ast::EnumDef::cast(node.clone()) { 50 },
50 let src = crate::Source { file_id: file_id.into(), ast: e }; 51 ast::StructDef(it) => {
51 Some(Enum::from_source(db, src)?.resolver(db)) 52 let src = crate::Source { file_id: file_id.into(), ast: it };
52 } else if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { 53 Some(Struct::from_source(db, src)?.resolver(db))
53 Some(def_with_body_from_child_node(db, file_id, node)?.resolver(db)) 54 },
54 } else { 55 ast::EnumDef(it) => {
55 // FIXME add missing cases 56 let src = crate::Source { file_id: file_id.into(), ast: it };
56 None 57 Some(Enum::from_source(db, src)?.resolver(db))
58 },
59 _ => {
60 if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF {
61 Some(def_with_body_from_child_node(db, file_id, node)?.resolver(db))
62 } else {
63 // FIXME add missing cases
64 None
65 }
66 },
67 }
57 } 68 }
58} 69}
59 70
@@ -64,19 +75,17 @@ fn def_with_body_from_child_node(
64) -> Option<DefWithBody> { 75) -> Option<DefWithBody> {
65 let src = crate::ModuleSource::from_child_node(db, file_id, node); 76 let src = crate::ModuleSource::from_child_node(db, file_id, node);
66 let module = Module::from_definition(db, crate::Source { file_id: file_id.into(), ast: src })?; 77 let module = Module::from_definition(db, crate::Source { file_id: file_id.into(), ast: src })?;
67 let ctx = LocationCtx::new(db, module, file_id.into()); 78 let ctx = LocationCtx::new(db, module.id, file_id.into());
68 79
69 node.ancestors().find_map(|node| { 80 node.ancestors().find_map(|node| {
70 if let Some(def) = ast::FnDef::cast(node.clone()) { 81 match_ast! {
71 return Some(Function { id: ctx.to_def(&def) }.into()); 82 match node {
72 } 83 ast::FnDef(def) => { Some(Function {id: ctx.to_def(&def) }.into()) },
73 if let Some(def) = ast::ConstDef::cast(node.clone()) { 84 ast::ConstDef(def) => { Some(Const { id: ctx.to_def(&def) }.into()) },
74 return Some(Const { id: ctx.to_def(&def) }.into()); 85 ast::StaticDef(def) => { Some(Static { id: ctx.to_def(&def) }.into()) },
75 } 86 _ => { None },
76 if let Some(def) = ast::StaticDef::cast(node) { 87 }
77 return Some(Static { id: ctx.to_def(&def) }.into());
78 } 88 }
79 None
80 }) 89 })
81} 90}
82 91
diff --git a/crates/ra_hir/src/traits.rs b/crates/ra_hir/src/traits.rs
index e39511518..1a45dacba 100644
--- a/crates/ra_hir/src/traits.rs
+++ b/crates/ra_hir/src/traits.rs
@@ -1,14 +1,15 @@
1//! HIR for trait definitions. 1//! HIR for trait definitions.
2 2
3use rustc_hash::FxHashMap;
4use std::sync::Arc; 3use std::sync::Arc;
5 4
5use hir_expand::name::AsName;
6
6use ra_syntax::ast::{self, NameOwner}; 7use ra_syntax::ast::{self, NameOwner};
8use rustc_hash::FxHashMap;
7 9
8use crate::{ 10use crate::{
9 db::{AstDatabase, DefDatabase}, 11 db::{AstDatabase, DefDatabase},
10 ids::LocationCtx, 12 ids::LocationCtx,
11 name::AsName,
12 AssocItem, Const, Function, HasSource, Module, Name, Trait, TypeAlias, 13 AssocItem, Const, Function, HasSource, Module, Name, Trait, TypeAlias,
13}; 14};
14 15
@@ -27,7 +28,7 @@ impl TraitData {
27 let src = tr.source(db); 28 let src = tr.source(db);
28 let name = src.ast.name().map(|n| n.as_name()); 29 let name = src.ast.name().map(|n| n.as_name());
29 let module = tr.module(db); 30 let module = tr.module(db);
30 let ctx = LocationCtx::new(db, module, src.file_id); 31 let ctx = LocationCtx::new(db, module.id, src.file_id);
31 let auto = src.ast.is_auto(); 32 let auto = src.ast.is_auto();
32 let items = if let Some(item_list) = src.ast.item_list() { 33 let items = if let Some(item_list) = src.ast.item_list() {
33 item_list 34 item_list
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index cc9746f6d..d2bfcdc7d 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -17,8 +17,8 @@ use std::sync::Arc;
17use std::{fmt, iter, mem}; 17use std::{fmt, iter, mem};
18 18
19use crate::{ 19use crate::{
20 db::HirDatabase, expr::ExprId, type_ref::Mutability, util::make_mut_slice, Adt, Crate, 20 db::HirDatabase, expr::ExprId, util::make_mut_slice, Adt, Crate, DefWithBody, GenericParams,
21 DefWithBody, GenericParams, HasGenericParams, Name, Trait, TypeAlias, 21 HasGenericParams, Mutability, Name, Trait, TypeAlias,
22}; 22};
23use display::{HirDisplay, HirFormatter}; 23use display::{HirDisplay, HirFormatter};
24 24
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
index 02492ca14..3645ee831 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -5,10 +5,11 @@
5 5
6use std::iter::successors; 6use std::iter::successors;
7 7
8use hir_expand::name;
8use log::{info, warn}; 9use log::{info, warn};
9 10
10use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk}; 11use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk};
11use crate::{db::HirDatabase, name, HasGenericParams, Resolver}; 12use crate::{db::HirDatabase, HasGenericParams, Resolver};
12 13
13const AUTODEREF_RECURSION_LIMIT: usize = 10; 14const AUTODEREF_RECURSION_LIMIT: usize = 10;
14 15
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index ebaff998e..6694467a3 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -21,6 +21,11 @@ use std::sync::Arc;
21use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; 21use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
22use rustc_hash::FxHashMap; 22use rustc_hash::FxHashMap;
23 23
24use hir_def::{
25 path::known,
26 type_ref::{Mutability, TypeRef},
27};
28use hir_expand::name;
24use ra_arena::map::ArenaMap; 29use ra_arena::map::ArenaMap;
25use ra_prof::profile; 30use ra_prof::profile;
26use test_utils::tested_by; 31use test_utils::tested_by;
@@ -37,11 +42,8 @@ use crate::{
37 db::HirDatabase, 42 db::HirDatabase,
38 diagnostics::DiagnosticSink, 43 diagnostics::DiagnosticSink,
39 expr::{BindingAnnotation, Body, ExprId, PatId}, 44 expr::{BindingAnnotation, Body, ExprId, PatId},
40 name,
41 path::known,
42 resolve::{Resolver, TypeNs}, 45 resolve::{Resolver, TypeNs},
43 ty::infer::diagnostics::InferenceDiagnostic, 46 ty::infer::diagnostics::InferenceDiagnostic,
44 type_ref::{Mutability, TypeRef},
45 Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Path, StructField, 47 Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Path, StructField,
46}; 48};
47 49
diff --git a/crates/ra_hir/src/ty/infer/coerce.rs b/crates/ra_hir/src/ty/infer/coerce.rs
index 0429a9866..6ea135126 100644
--- a/crates/ra_hir/src/ty/infer/coerce.rs
+++ b/crates/ra_hir/src/ty/infer/coerce.rs
@@ -14,8 +14,7 @@ use crate::{
14 lang_item::LangItemTarget, 14 lang_item::LangItemTarget,
15 resolve::Resolver, 15 resolve::Resolver,
16 ty::{autoderef, Substs, Ty, TypeCtor, TypeWalk}, 16 ty::{autoderef, Substs, Ty, TypeCtor, TypeWalk},
17 type_ref::Mutability, 17 Adt, Mutability,
18 Adt,
19}; 18};
20 19
21impl<'a, D: HirDatabase> InferenceContext<'a, D> { 20impl<'a, D: HirDatabase> InferenceContext<'a, D> {
diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs
index f8807c742..fed52df39 100644
--- a/crates/ra_hir/src/ty/infer/expr.rs
+++ b/crates/ra_hir/src/ty/infer/expr.rs
@@ -3,14 +3,15 @@
3use std::iter::{repeat, repeat_with}; 3use std::iter::{repeat, repeat_with};
4use std::sync::Arc; 4use std::sync::Arc;
5 5
6use hir_def::path::{GenericArg, GenericArgs};
7use hir_expand::name;
8
6use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; 9use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch};
7use crate::{ 10use crate::{
8 db::HirDatabase, 11 db::HirDatabase,
9 expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, 12 expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
10 generics::{GenericParams, HasGenericParams}, 13 generics::{GenericParams, HasGenericParams},
11 name,
12 nameres::Namespace, 14 nameres::Namespace,
13 path::{GenericArg, GenericArgs},
14 ty::{ 15 ty::{
15 autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Obligation, 16 autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Obligation,
16 ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, 17 ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs
index db979353a..77aa35ce1 100644
--- a/crates/ra_hir/src/ty/infer/path.rs
+++ b/crates/ra_hir/src/ty/infer/path.rs
@@ -1,5 +1,7 @@
1//! Path expression resolution. 1//! Path expression resolution.
2 2
3use hir_def::path::PathSegment;
4
3use super::{ExprOrPatId, InferenceContext, TraitRef}; 5use super::{ExprOrPatId, InferenceContext, TraitRef};
4use crate::{ 6use crate::{
5 db::HirDatabase, 7 db::HirDatabase,
@@ -131,7 +133,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
131 fn resolve_trait_assoc_item( 133 fn resolve_trait_assoc_item(
132 &mut self, 134 &mut self,
133 trait_ref: TraitRef, 135 trait_ref: TraitRef,
134 segment: &crate::path::PathSegment, 136 segment: &PathSegment,
135 id: ExprOrPatId, 137 id: ExprOrPatId,
136 ) -> Option<(ValueNs, Option<Substs>)> { 138 ) -> Option<(ValueNs, Option<Substs>)> {
137 let trait_ = trait_ref.trait_; 139 let trait_ = trait_ref.trait_;
@@ -170,7 +172,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
170 fn resolve_ty_assoc_item( 172 fn resolve_ty_assoc_item(
171 &mut self, 173 &mut self,
172 ty: Ty, 174 ty: Ty,
173 segment: &crate::path::PathSegment, 175 segment: &PathSegment,
174 id: ExprOrPatId, 176 id: ExprOrPatId,
175 ) -> Option<(ValueNs, Option<Substs>)> { 177 ) -> Option<(ValueNs, Option<Substs>)> {
176 if let Ty::Unknown = ty { 178 if let Ty::Unknown = ty {
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 366556134..dd7cd979f 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -8,6 +8,12 @@
8use std::iter; 8use std::iter;
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use hir_def::{
12 builtin_type::BuiltinType,
13 path::{GenericArg, PathSegment},
14 type_ref::{TypeBound, TypeRef},
15};
16
11use super::{ 17use super::{
12 FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 18 FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
13 TypeWalk, 19 TypeWalk,
@@ -18,13 +24,14 @@ use crate::{
18 generics::HasGenericParams, 24 generics::HasGenericParams,
19 generics::{GenericDef, WherePredicate}, 25 generics::{GenericDef, WherePredicate},
20 nameres::Namespace, 26 nameres::Namespace,
21 path::{GenericArg, PathSegment},
22 resolve::{Resolver, TypeNs}, 27 resolve::{Resolver, TypeNs},
23 ty::Adt, 28 ty::{
24 type_ref::{TypeBound, TypeRef}, 29 primitive::{FloatTy, IntTy},
30 Adt,
31 },
25 util::make_mut_slice, 32 util::make_mut_slice,
26 BuiltinType, Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, 33 Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, Trait,
27 Trait, TypeAlias, Union, 34 TypeAlias, Union,
28}; 35};
29 36
30impl Ty { 37impl Ty {
@@ -640,8 +647,10 @@ fn type_for_builtin(def: BuiltinType) -> Ty {
640 BuiltinType::Char => TypeCtor::Char, 647 BuiltinType::Char => TypeCtor::Char,
641 BuiltinType::Bool => TypeCtor::Bool, 648 BuiltinType::Bool => TypeCtor::Bool,
642 BuiltinType::Str => TypeCtor::Str, 649 BuiltinType::Str => TypeCtor::Str,
643 BuiltinType::Int(ty) => TypeCtor::Int(ty.into()), 650 BuiltinType::Int { signedness, bitness } => {
644 BuiltinType::Float(ty) => TypeCtor::Float(ty.into()), 651 TypeCtor::Int(IntTy { signedness, bitness }.into())
652 }
653 BuiltinType::Float { bitness } => TypeCtor::Float(FloatTy { bitness }.into()),
645 }) 654 })
646} 655}
647 656
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index ad2ab560d..eb69344f6 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -5,18 +5,17 @@
5use std::sync::Arc; 5use std::sync::Arc;
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use hir_def::CrateModuleId;
8use rustc_hash::FxHashMap; 9use rustc_hash::FxHashMap;
9 10
10use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; 11use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef};
11use crate::{ 12use crate::{
12 db::HirDatabase, 13 db::HirDatabase,
13 impl_block::{ImplBlock, ImplId}, 14 impl_block::{ImplBlock, ImplId},
14 nameres::CrateModuleId,
15 resolve::Resolver, 15 resolve::Resolver,
16 ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy}, 16 ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy},
17 ty::{Ty, TypeCtor}, 17 ty::{Ty, TypeCtor},
18 type_ref::Mutability, 18 AssocItem, Crate, Function, Module, Mutability, Name, Trait,
19 AssocItem, Crate, Function, Module, Name, Trait,
20}; 19};
21 20
22/// This is used as a key for indexing impls. 21/// This is used as a key for indexing impls.
@@ -50,7 +49,7 @@ impl CrateImplBlocks {
50 let fingerprint = TyFingerprint::for_impl(ty); 49 let fingerprint = TyFingerprint::for_impl(ty);
51 fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flat_map(|i| i.iter()).map( 50 fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flat_map(|i| i.iter()).map(
52 move |(module_id, impl_id)| { 51 move |(module_id, impl_id)| {
53 let module = Module { krate: self.krate, module_id: *module_id }; 52 let module = Module::new(self.krate, *module_id);
54 ImplBlock::from_id(module, *impl_id) 53 ImplBlock::from_id(module, *impl_id)
55 }, 54 },
56 ) 55 )
@@ -62,7 +61,7 @@ impl CrateImplBlocks {
62 ) -> impl Iterator<Item = ImplBlock> + 'a { 61 ) -> impl Iterator<Item = ImplBlock> + 'a {
63 self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map( 62 self.impls_by_trait.get(&tr).into_iter().flat_map(|i| i.iter()).map(
64 move |(module_id, impl_id)| { 63 move |(module_id, impl_id)| {
65 let module = Module { krate: self.krate, module_id: *module_id }; 64 let module = Module::new(self.krate, *module_id);
66 ImplBlock::from_id(module, *impl_id) 65 ImplBlock::from_id(module, *impl_id)
67 }, 66 },
68 ) 67 )
@@ -71,7 +70,7 @@ impl CrateImplBlocks {
71 pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplBlock> + 'a { 70 pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplBlock> + 'a {
72 self.impls.values().chain(self.impls_by_trait.values()).flat_map(|i| i.iter()).map( 71 self.impls.values().chain(self.impls_by_trait.values()).flat_map(|i| i.iter()).map(
73 move |(module_id, impl_id)| { 72 move |(module_id, impl_id)| {
74 let module = Module { krate: self.krate, module_id: *module_id }; 73 let module = Module::new(self.krate, *module_id);
75 ImplBlock::from_id(module, *impl_id) 74 ImplBlock::from_id(module, *impl_id)
76 }, 75 },
77 ) 76 )
@@ -90,14 +89,14 @@ impl CrateImplBlocks {
90 self.impls_by_trait 89 self.impls_by_trait
91 .entry(tr.trait_) 90 .entry(tr.trait_)
92 .or_insert_with(Vec::new) 91 .or_insert_with(Vec::new)
93 .push((module.module_id, impl_id)); 92 .push((module.id.module_id, impl_id));
94 } 93 }
95 } else { 94 } else {
96 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { 95 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
97 self.impls 96 self.impls
98 .entry(target_ty_fp) 97 .entry(target_ty_fp)
99 .or_insert_with(Vec::new) 98 .or_insert_with(Vec::new)
100 .push((module.module_id, impl_id)); 99 .push((module.id.module_id, impl_id));
101 } 100 }
102 } 101 }
103 } 102 }
diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs
index 8966f9d1d..1749752f1 100644
--- a/crates/ra_hir/src/ty/primitive.rs
+++ b/crates/ra_hir/src/ty/primitive.rs
@@ -2,27 +2,7 @@
2 2
3use std::fmt; 3use std::fmt;
4 4
5#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 5pub use hir_def::builtin_type::{FloatBitness, IntBitness, Signedness};
6pub enum Signedness {
7 Signed,
8 Unsigned,
9}
10
11#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
12pub enum IntBitness {
13 Xsize,
14 X8,
15 X16,
16 X32,
17 X64,
18 X128,
19}
20
21#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
22pub enum FloatBitness {
23 X32,
24 X64,
25}
26 6
27#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 7#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
28pub enum UncertainIntTy { 8pub enum UncertainIntTy {
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index 0cb5c3798..4f1eab150 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -1,7 +1,7 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::sync::{Arc, Mutex}; 2use std::sync::{Arc, Mutex};
3 3
4use chalk_ir::cast::Cast; 4use chalk_ir::{cast::Cast, family::ChalkIr};
5use log::debug; 5use log::debug;
6use ra_db::salsa; 6use ra_db::salsa;
7use ra_prof::profile; 7use ra_prof::profile;
@@ -33,7 +33,7 @@ impl TraitSolver {
33 fn solve( 33 fn solve(
34 &self, 34 &self,
35 db: &impl HirDatabase, 35 db: &impl HirDatabase,
36 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal>>, 36 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<ChalkIr>>>,
37 ) -> Option<chalk_solve::Solution> { 37 ) -> Option<chalk_solve::Solution> {
38 let context = ChalkContext { db, krate: self.krate }; 38 let context = ChalkContext { db, krate: self.krate };
39 debug!("solve goal: {:?}", goal); 39 debug!("solve goal: {:?}", goal);
@@ -196,7 +196,7 @@ pub(crate) fn trait_solve_query(
196} 196}
197 197
198fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution { 198fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution {
199 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution>| { 199 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<ChalkIr>>| {
200 let value = subst 200 let value = subst
201 .value 201 .value
202 .parameters 202 .parameters
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 00aaf65d9..39ef92182 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -4,11 +4,13 @@ use std::sync::Arc;
4use log::debug; 4use log::debug;
5 5
6use chalk_ir::{ 6use chalk_ir::{
7 cast::Cast, Identifier, ImplId, Parameter, PlaceholderIndex, TypeId, TypeKindId, TypeName, 7 cast::Cast, family::ChalkIr, Identifier, ImplId, Parameter, PlaceholderIndex, TypeId,
8 UniverseIndex, 8 TypeKindId, TypeName, UniverseIndex,
9}; 9};
10use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; 10use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum};
11 11
12use hir_expand::name;
13
12use ra_db::salsa::{InternId, InternKey}; 14use ra_db::salsa::{InternId, InternKey};
13 15
14use super::{Canonical, ChalkContext, Impl, Obligation}; 16use super::{Canonical, ChalkContext, Impl, Obligation};
@@ -38,8 +40,8 @@ where
38} 40}
39 41
40impl ToChalk for Ty { 42impl ToChalk for Ty {
41 type Chalk = chalk_ir::Ty; 43 type Chalk = chalk_ir::Ty<ChalkIr>;
42 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty { 44 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty<ChalkIr> {
43 match self { 45 match self {
44 Ty::Apply(apply_ty) => { 46 Ty::Apply(apply_ty) => {
45 let name = match apply_ty.ctor { 47 let name = match apply_ty.ctor {
@@ -62,21 +64,19 @@ impl ToChalk for Ty {
62 chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast() 64 chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast()
63 } 65 }
64 Ty::Param { idx, .. } => { 66 Ty::Param { idx, .. } => {
65 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty() 67 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty::<ChalkIr>()
66 } 68 }
67 Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize), 69 Ty::Bound(idx) => chalk_ir::Ty::BoundVar(idx as usize),
68 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), 70 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
69 // FIXME this is clearly incorrect, but probably not too incorrect 71 // FIXME use Chalk's Dyn/Opaque once the bugs with that are fixed
70 // and I'm not sure what to actually do with Ty::Unknown
71 // maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty)
72 //
73 // FIXME also dyn and impl Trait are currently handled like Unknown because Chalk doesn't have them yet
74 Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => { 72 Ty::Unknown | Ty::Dyn(_) | Ty::Opaque(_) => {
75 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty() 73 let parameters = Vec::new();
74 let name = TypeName::Error;
75 chalk_ir::ApplicationTy { name, parameters }.cast()
76 } 76 }
77 } 77 }
78 } 78 }
79 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { 79 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty<ChalkIr>) -> Self {
80 match chalk { 80 match chalk {
81 chalk_ir::Ty::Apply(apply_ty) => { 81 chalk_ir::Ty::Apply(apply_ty) => {
82 // FIXME this is kind of hacky due to the fact that 82 // FIXME this is kind of hacky due to the fact that
@@ -92,6 +92,7 @@ impl ToChalk for Ty {
92 let parameters = from_chalk(db, apply_ty.parameters); 92 let parameters = from_chalk(db, apply_ty.parameters);
93 Ty::Apply(ApplicationTy { ctor, parameters }) 93 Ty::Apply(ApplicationTy { ctor, parameters })
94 } 94 }
95 TypeName::Error => Ty::Unknown,
95 // FIXME handle TypeKindId::Trait/Type here 96 // FIXME handle TypeKindId::Trait/Type here
96 TypeName::TypeKindId(_) => unimplemented!(), 97 TypeName::TypeKindId(_) => unimplemented!(),
97 TypeName::Placeholder(idx) => { 98 TypeName::Placeholder(idx) => {
@@ -108,18 +109,30 @@ impl ToChalk for Ty {
108 chalk_ir::Ty::ForAll(_) => unimplemented!(), 109 chalk_ir::Ty::ForAll(_) => unimplemented!(),
109 chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32), 110 chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32),
110 chalk_ir::Ty::InferenceVar(_iv) => Ty::Unknown, 111 chalk_ir::Ty::InferenceVar(_iv) => Ty::Unknown,
112 chalk_ir::Ty::Dyn(where_clauses) => {
113 assert_eq!(where_clauses.binders.len(), 1);
114 let predicates =
115 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect();
116 Ty::Dyn(predicates)
117 }
118 chalk_ir::Ty::Opaque(where_clauses) => {
119 assert_eq!(where_clauses.binders.len(), 1);
120 let predicates =
121 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect();
122 Ty::Opaque(predicates)
123 }
111 } 124 }
112 } 125 }
113} 126}
114 127
115impl ToChalk for Substs { 128impl ToChalk for Substs {
116 type Chalk = Vec<chalk_ir::Parameter>; 129 type Chalk = Vec<chalk_ir::Parameter<ChalkIr>>;
117 130
118 fn to_chalk(self, db: &impl HirDatabase) -> Vec<Parameter> { 131 fn to_chalk(self, db: &impl HirDatabase) -> Vec<Parameter<ChalkIr>> {
119 self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect() 132 self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect()
120 } 133 }
121 134
122 fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter>) -> Substs { 135 fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter<ChalkIr>>) -> Substs {
123 let tys = parameters 136 let tys = parameters
124 .into_iter() 137 .into_iter()
125 .map(|p| match p { 138 .map(|p| match p {
@@ -132,15 +145,15 @@ impl ToChalk for Substs {
132} 145}
133 146
134impl ToChalk for TraitRef { 147impl ToChalk for TraitRef {
135 type Chalk = chalk_ir::TraitRef; 148 type Chalk = chalk_ir::TraitRef<ChalkIr>;
136 149
137 fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef { 150 fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef<ChalkIr> {
138 let trait_id = self.trait_.to_chalk(db); 151 let trait_id = self.trait_.to_chalk(db);
139 let parameters = self.substs.to_chalk(db); 152 let parameters = self.substs.to_chalk(db);
140 chalk_ir::TraitRef { trait_id, parameters } 153 chalk_ir::TraitRef { trait_id, parameters }
141 } 154 }
142 155
143 fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef) -> Self { 156 fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef<ChalkIr>) -> Self {
144 let trait_ = from_chalk(db, trait_ref.trait_id); 157 let trait_ = from_chalk(db, trait_ref.trait_id);
145 let substs = from_chalk(db, trait_ref.parameters); 158 let substs = from_chalk(db, trait_ref.parameters);
146 TraitRef { trait_, substs } 159 TraitRef { trait_, substs }
@@ -151,11 +164,11 @@ impl ToChalk for Trait {
151 type Chalk = chalk_ir::TraitId; 164 type Chalk = chalk_ir::TraitId;
152 165
153 fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TraitId { 166 fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TraitId {
154 self.id.into() 167 chalk_ir::TraitId(id_to_chalk(self.id))
155 } 168 }
156 169
157 fn from_chalk(_db: &impl HirDatabase, trait_id: chalk_ir::TraitId) -> Trait { 170 fn from_chalk(_db: &impl HirDatabase, trait_id: chalk_ir::TraitId) -> Trait {
158 Trait { id: trait_id.into() } 171 Trait { id: id_from_chalk(trait_id.0) }
159 } 172 }
160} 173}
161 174
@@ -187,18 +200,18 @@ impl ToChalk for TypeAlias {
187 type Chalk = chalk_ir::TypeId; 200 type Chalk = chalk_ir::TypeId;
188 201
189 fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TypeId { 202 fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TypeId {
190 self.id.into() 203 chalk_ir::TypeId(id_to_chalk(self.id))
191 } 204 }
192 205
193 fn from_chalk(_db: &impl HirDatabase, impl_id: chalk_ir::TypeId) -> TypeAlias { 206 fn from_chalk(_db: &impl HirDatabase, type_alias_id: chalk_ir::TypeId) -> TypeAlias {
194 TypeAlias { id: impl_id.into() } 207 TypeAlias { id: id_from_chalk(type_alias_id.0) }
195 } 208 }
196} 209}
197 210
198impl ToChalk for GenericPredicate { 211impl ToChalk for GenericPredicate {
199 type Chalk = chalk_ir::QuantifiedWhereClause; 212 type Chalk = chalk_ir::QuantifiedWhereClause<ChalkIr>;
200 213
201 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause { 214 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause<ChalkIr> {
202 match self { 215 match self {
203 GenericPredicate::Implemented(trait_ref) => { 216 GenericPredicate::Implemented(trait_ref) => {
204 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) 217 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0)
@@ -221,25 +234,40 @@ impl ToChalk for GenericPredicate {
221 } 234 }
222 235
223 fn from_chalk( 236 fn from_chalk(
224 _db: &impl HirDatabase, 237 db: &impl HirDatabase,
225 _where_clause: chalk_ir::QuantifiedWhereClause, 238 where_clause: chalk_ir::QuantifiedWhereClause<ChalkIr>,
226 ) -> GenericPredicate { 239 ) -> GenericPredicate {
227 // This should never need to be called 240 match where_clause.value {
228 unimplemented!() 241 chalk_ir::WhereClause::Implemented(tr) => {
242 if tr.trait_id == UNKNOWN_TRAIT {
243 // FIXME we need an Error enum on the Chalk side to avoid this
244 return GenericPredicate::Error;
245 }
246 GenericPredicate::Implemented(from_chalk(db, tr))
247 }
248 chalk_ir::WhereClause::ProjectionEq(projection_eq) => {
249 let projection_ty = from_chalk(db, projection_eq.projection);
250 let ty = from_chalk(db, projection_eq.ty);
251 GenericPredicate::Projection(super::ProjectionPredicate { projection_ty, ty })
252 }
253 }
229 } 254 }
230} 255}
231 256
232impl ToChalk for ProjectionTy { 257impl ToChalk for ProjectionTy {
233 type Chalk = chalk_ir::ProjectionTy; 258 type Chalk = chalk_ir::ProjectionTy<ChalkIr>;
234 259
235 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy { 260 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy<ChalkIr> {
236 chalk_ir::ProjectionTy { 261 chalk_ir::ProjectionTy {
237 associated_ty_id: self.associated_ty.to_chalk(db), 262 associated_ty_id: self.associated_ty.to_chalk(db),
238 parameters: self.parameters.to_chalk(db), 263 parameters: self.parameters.to_chalk(db),
239 } 264 }
240 } 265 }
241 266
242 fn from_chalk(db: &impl HirDatabase, projection_ty: chalk_ir::ProjectionTy) -> ProjectionTy { 267 fn from_chalk(
268 db: &impl HirDatabase,
269 projection_ty: chalk_ir::ProjectionTy<ChalkIr>,
270 ) -> ProjectionTy {
243 ProjectionTy { 271 ProjectionTy {
244 associated_ty: from_chalk(db, projection_ty.associated_ty_id), 272 associated_ty: from_chalk(db, projection_ty.associated_ty_id),
245 parameters: from_chalk(db, projection_ty.parameters), 273 parameters: from_chalk(db, projection_ty.parameters),
@@ -248,31 +276,31 @@ impl ToChalk for ProjectionTy {
248} 276}
249 277
250impl ToChalk for super::ProjectionPredicate { 278impl ToChalk for super::ProjectionPredicate {
251 type Chalk = chalk_ir::Normalize; 279 type Chalk = chalk_ir::Normalize<ChalkIr>;
252 280
253 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize { 281 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize<ChalkIr> {
254 chalk_ir::Normalize { 282 chalk_ir::Normalize {
255 projection: self.projection_ty.to_chalk(db), 283 projection: self.projection_ty.to_chalk(db),
256 ty: self.ty.to_chalk(db), 284 ty: self.ty.to_chalk(db),
257 } 285 }
258 } 286 }
259 287
260 fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize) -> Self { 288 fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize<ChalkIr>) -> Self {
261 unimplemented!() 289 unimplemented!()
262 } 290 }
263} 291}
264 292
265impl ToChalk for Obligation { 293impl ToChalk for Obligation {
266 type Chalk = chalk_ir::DomainGoal; 294 type Chalk = chalk_ir::DomainGoal<ChalkIr>;
267 295
268 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal { 296 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal<ChalkIr> {
269 match self { 297 match self {
270 Obligation::Trait(tr) => tr.to_chalk(db).cast(), 298 Obligation::Trait(tr) => tr.to_chalk(db).cast(),
271 Obligation::Projection(pr) => pr.to_chalk(db).cast(), 299 Obligation::Projection(pr) => pr.to_chalk(db).cast(),
272 } 300 }
273 } 301 }
274 302
275 fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal) -> Self { 303 fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal<ChalkIr>) -> Self {
276 unimplemented!() 304 unimplemented!()
277 } 305 }
278} 306}
@@ -296,16 +324,16 @@ where
296} 324}
297 325
298impl ToChalk for Arc<super::TraitEnvironment> { 326impl ToChalk for Arc<super::TraitEnvironment> {
299 type Chalk = Arc<chalk_ir::Environment>; 327 type Chalk = chalk_ir::Environment<ChalkIr>;
300 328
301 fn to_chalk(self, db: &impl HirDatabase) -> Arc<chalk_ir::Environment> { 329 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Environment<ChalkIr> {
302 let mut clauses = Vec::new(); 330 let mut clauses = Vec::new();
303 for pred in &self.predicates { 331 for pred in &self.predicates {
304 if pred.is_error() { 332 if pred.is_error() {
305 // for env, we just ignore errors 333 // for env, we just ignore errors
306 continue; 334 continue;
307 } 335 }
308 let program_clause: chalk_ir::ProgramClause = pred.clone().to_chalk(db).cast(); 336 let program_clause: chalk_ir::ProgramClause<ChalkIr> = pred.clone().to_chalk(db).cast();
309 clauses.push(program_clause.into_from_env_clause()); 337 clauses.push(program_clause.into_from_env_clause());
310 } 338 }
311 chalk_ir::Environment::new().add_clauses(clauses) 339 chalk_ir::Environment::new().add_clauses(clauses)
@@ -313,13 +341,16 @@ impl ToChalk for Arc<super::TraitEnvironment> {
313 341
314 fn from_chalk( 342 fn from_chalk(
315 _db: &impl HirDatabase, 343 _db: &impl HirDatabase,
316 _env: Arc<chalk_ir::Environment>, 344 _env: chalk_ir::Environment<ChalkIr>,
317 ) -> Arc<super::TraitEnvironment> { 345 ) -> Arc<super::TraitEnvironment> {
318 unimplemented!() 346 unimplemented!()
319 } 347 }
320} 348}
321 349
322impl<T: ToChalk> ToChalk for super::InEnvironment<T> { 350impl<T: ToChalk> ToChalk for super::InEnvironment<T>
351where
352 T::Chalk: chalk_ir::family::HasTypeFamily<TypeFamily = ChalkIr>,
353{
323 type Chalk = chalk_ir::InEnvironment<T::Chalk>; 354 type Chalk = chalk_ir::InEnvironment<T::Chalk>;
324 355
325 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> { 356 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> {
@@ -351,7 +382,7 @@ fn convert_where_clauses(
351 db: &impl HirDatabase, 382 db: &impl HirDatabase,
352 def: GenericDef, 383 def: GenericDef,
353 substs: &Substs, 384 substs: &Substs,
354) -> Vec<chalk_ir::QuantifiedWhereClause> { 385) -> Vec<chalk_ir::QuantifiedWhereClause<ChalkIr>> {
355 let generic_predicates = db.generic_predicates(def); 386 let generic_predicates = db.generic_predicates(def);
356 let mut result = Vec::with_capacity(generic_predicates.len()); 387 let mut result = Vec::with_capacity(generic_predicates.len());
357 for pred in generic_predicates.iter() { 388 for pred in generic_predicates.iter() {
@@ -384,7 +415,7 @@ where
384 fn impls_for_trait( 415 fn impls_for_trait(
385 &self, 416 &self,
386 trait_id: chalk_ir::TraitId, 417 trait_id: chalk_ir::TraitId,
387 parameters: &[Parameter], 418 parameters: &[Parameter<ChalkIr>],
388 ) -> Vec<ImplId> { 419 ) -> Vec<ImplId> {
389 debug!("impls_for_trait {:?}", trait_id); 420 debug!("impls_for_trait {:?}", trait_id);
390 if trait_id == UNKNOWN_TRAIT { 421 if trait_id == UNKNOWN_TRAIT {
@@ -430,13 +461,13 @@ where
430 } 461 }
431 fn split_projection<'p>( 462 fn split_projection<'p>(
432 &self, 463 &self,
433 projection: &'p chalk_ir::ProjectionTy, 464 projection: &'p chalk_ir::ProjectionTy<ChalkIr>,
434 ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) { 465 ) -> (Arc<AssociatedTyDatum>, &'p [Parameter<ChalkIr>], &'p [Parameter<ChalkIr>]) {
435 debug!("split_projection {:?}", projection); 466 debug!("split_projection {:?}", projection);
436 // we don't support GATs, so I think this should always be correct currently 467 // we don't support GATs, so I think this should always be correct currently
437 (self.db.associated_ty_data(projection.associated_ty_id), &projection.parameters, &[]) 468 (self.db.associated_ty_data(projection.associated_ty_id), &projection.parameters, &[])
438 } 469 }
439 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause> { 470 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<ChalkIr>> {
440 vec![] 471 vec![]
441 } 472 }
442 fn local_impls_to_coherence_check( 473 fn local_impls_to_coherence_check(
@@ -508,7 +539,7 @@ pub(crate) fn trait_datum_query(
508 let trait_ref = trait_.trait_ref(db).subst(&bound_vars).to_chalk(db); 539 let trait_ref = trait_.trait_ref(db).subst(&bound_vars).to_chalk(db);
509 let flags = chalk_rust_ir::TraitFlags { 540 let flags = chalk_rust_ir::TraitFlags {
510 auto: trait_.is_auto(db), 541 auto: trait_.is_auto(db),
511 upstream: trait_.module(db).krate(db) != Some(krate), 542 upstream: trait_.module(db).krate() != krate,
512 non_enumerable: true, 543 non_enumerable: true,
513 // FIXME set these flags correctly 544 // FIXME set these flags correctly
514 marker: false, 545 marker: false,
@@ -596,7 +627,7 @@ fn impl_block_datum(
596 .target_trait_ref(db) 627 .target_trait_ref(db)
597 .expect("FIXME handle unresolved impl block trait ref") 628 .expect("FIXME handle unresolved impl block trait ref")
598 .subst(&bound_vars); 629 .subst(&bound_vars);
599 let impl_type = if impl_block.module().krate(db) == Some(krate) { 630 let impl_type = if impl_block.module().krate() == krate {
600 chalk_rust_ir::ImplType::Local 631 chalk_rust_ir::ImplType::Local
601 } else { 632 } else {
602 chalk_rust_ir::ImplType::External 633 chalk_rust_ir::ImplType::External
@@ -705,7 +736,7 @@ fn closure_fn_trait_impl_datum(
705 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(), 736 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
706 }; 737 };
707 738
708 let output_ty_id = fn_once_trait.associated_type_by_name(db, &crate::name::OUTPUT_TYPE)?; 739 let output_ty_id = fn_once_trait.associated_type_by_name(db, &name::OUTPUT_TYPE)?;
709 740
710 let output_ty_value = chalk_rust_ir::AssociatedTyValue { 741 let output_ty_value = chalk_rust_ir::AssociatedTyValue {
711 associated_ty_id: output_ty_id.to_chalk(db), 742 associated_ty_id: output_ty_id.to_chalk(db),
@@ -746,30 +777,6 @@ fn id_to_chalk<T: InternKey>(salsa_id: T) -> chalk_ir::RawId {
746 chalk_ir::RawId { index: salsa_id.as_intern_id().as_u32() } 777 chalk_ir::RawId { index: salsa_id.as_intern_id().as_u32() }
747} 778}
748 779
749impl From<chalk_ir::TraitId> for crate::ids::TraitId {
750 fn from(trait_id: chalk_ir::TraitId) -> Self {
751 id_from_chalk(trait_id.0)
752 }
753}
754
755impl From<crate::ids::TraitId> for chalk_ir::TraitId {
756 fn from(trait_id: crate::ids::TraitId) -> Self {
757 chalk_ir::TraitId(id_to_chalk(trait_id))
758 }
759}
760
761impl From<chalk_ir::TypeId> for crate::ids::TypeAliasId {
762 fn from(type_id: chalk_ir::TypeId) -> Self {
763 id_from_chalk(type_id.0)
764 }
765}
766
767impl From<crate::ids::TypeAliasId> for chalk_ir::TypeId {
768 fn from(type_id: crate::ids::TypeAliasId) -> Self {
769 chalk_ir::TypeId(id_to_chalk(type_id))
770 }
771}
772
773impl From<chalk_ir::StructId> for crate::ids::TypeCtorId { 780impl From<chalk_ir::StructId> for crate::ids::TypeCtorId {
774 fn from(struct_id: chalk_ir::StructId) -> Self { 781 fn from(struct_id: chalk_ir::StructId) -> Self {
775 id_from_chalk(struct_id.0) 782 id_from_chalk(struct_id.0)
diff --git a/crates/ra_hir/src/type_alias.rs b/crates/ra_hir/src/type_alias.rs
index 674a46102..078e6295e 100644
--- a/crates/ra_hir/src/type_alias.rs
+++ b/crates/ra_hir/src/type_alias.rs
@@ -2,12 +2,13 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::type_ref::TypeRef;
6use hir_expand::name::{AsName, Name};
7
5use ra_syntax::ast::NameOwner; 8use ra_syntax::ast::NameOwner;
6 9
7use crate::{ 10use crate::{
8 db::{AstDatabase, DefDatabase}, 11 db::{AstDatabase, DefDatabase},
9 name::{AsName, Name},
10 type_ref::TypeRef,
11 HasSource, TypeAlias, 12 HasSource, TypeAlias,
12}; 13};
13 14
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml
new file mode 100644
index 000000000..746c907e8
--- /dev/null
+++ b/crates/ra_hir_def/Cargo.toml
@@ -0,0 +1,21 @@
1[package]
2edition = "2018"
3name = "ra_hir_def"
4version = "0.1.0"
5authors = ["rust-analyzer developers"]
6
7[dependencies]
8log = "0.4.5"
9once_cell = "1.0.1"
10relative-path = "1.0.0"
11rustc-hash = "1.0"
12
13ra_arena = { path = "../ra_arena" }
14ra_db = { path = "../ra_db" }
15ra_syntax = { path = "../ra_syntax" }
16ra_prof = { path = "../ra_prof" }
17hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" }
18test_utils = { path = "../test_utils" }
19mbe = { path = "../ra_mbe", package = "ra_mbe" }
20ra_cfg = { path = "../ra_cfg" }
21tt = { path = "../ra_tt", package = "ra_tt" }
diff --git a/crates/ra_hir/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index bd159a566..0e961ca12 100644
--- a/crates/ra_hir/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -2,6 +2,7 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_expand::hygiene::Hygiene;
5use mbe::ast_to_token_tree; 6use mbe::ast_to_token_tree;
6use ra_cfg::CfgOptions; 7use ra_cfg::CfgOptions;
7use ra_syntax::{ 8use ra_syntax::{
@@ -10,10 +11,10 @@ use ra_syntax::{
10}; 11};
11use tt::Subtree; 12use tt::Subtree;
12 13
13use crate::{db::AstDatabase, path::Path, HirFileId, Source}; 14use crate::path::Path;
14 15
15#[derive(Debug, Clone, PartialEq, Eq)] 16#[derive(Debug, Clone, PartialEq, Eq)]
16pub(crate) struct Attr { 17pub struct Attr {
17 pub(crate) path: Path, 18 pub(crate) path: Path,
18 pub(crate) input: Option<AttrInput>, 19 pub(crate) input: Option<AttrInput>,
19} 20}
@@ -25,11 +26,8 @@ pub enum AttrInput {
25} 26}
26 27
27impl Attr { 28impl Attr {
28 pub(crate) fn from_src( 29 pub(crate) fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
29 Source { file_id, ast }: Source<ast::Attr>, 30 let path = Path::from_src(ast.path()?, hygiene)?;
30 db: &impl AstDatabase,
31 ) -> Option<Attr> {
32 let path = Path::from_src(Source { file_id, ast: ast.path()? }, db)?;
33 let input = match ast.input() { 31 let input = match ast.input() {
34 None => None, 32 None => None,
35 Some(ast::AttrInput::Literal(lit)) => { 33 Some(ast::AttrInput::Literal(lit)) => {
@@ -45,26 +43,22 @@ impl Attr {
45 Some(Attr { path, input }) 43 Some(Attr { path, input })
46 } 44 }
47 45
48 pub(crate) fn from_attrs_owner( 46 pub fn from_attrs_owner(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Option<Arc<[Attr]>> {
49 file_id: HirFileId,
50 owner: &dyn AttrsOwner,
51 db: &impl AstDatabase,
52 ) -> Option<Arc<[Attr]>> {
53 let mut attrs = owner.attrs().peekable(); 47 let mut attrs = owner.attrs().peekable();
54 if attrs.peek().is_none() { 48 if attrs.peek().is_none() {
55 // Avoid heap allocation 49 // Avoid heap allocation
56 return None; 50 return None;
57 } 51 }
58 Some(attrs.flat_map(|ast| Attr::from_src(Source { file_id, ast }, db)).collect()) 52 Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect())
59 } 53 }
60 54
61 pub(crate) fn is_simple_atom(&self, name: &str) -> bool { 55 pub fn is_simple_atom(&self, name: &str) -> bool {
62 // FIXME: Avoid cloning 56 // FIXME: Avoid cloning
63 self.path.as_ident().map_or(false, |s| s.to_string() == name) 57 self.path.as_ident().map_or(false, |s| s.to_string() == name)
64 } 58 }
65 59
66 // FIXME: handle cfg_attr :-) 60 // FIXME: handle cfg_attr :-)
67 pub(crate) fn as_cfg(&self) -> Option<&Subtree> { 61 pub fn as_cfg(&self) -> Option<&Subtree> {
68 if !self.is_simple_atom("cfg") { 62 if !self.is_simple_atom("cfg") {
69 return None; 63 return None;
70 } 64 }
@@ -74,7 +68,7 @@ impl Attr {
74 } 68 }
75 } 69 }
76 70
77 pub(crate) fn as_path(&self) -> Option<&SmolStr> { 71 pub fn as_path(&self) -> Option<&SmolStr> {
78 if !self.is_simple_atom("path") { 72 if !self.is_simple_atom("path") {
79 return None; 73 return None;
80 } 74 }
@@ -84,7 +78,7 @@ impl Attr {
84 } 78 }
85 } 79 }
86 80
87 pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Option<bool> { 81 pub fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Option<bool> {
88 cfg_options.is_cfg_enabled(self.as_cfg()?) 82 cfg_options.is_cfg_enabled(self.as_cfg()?)
89 } 83 }
90} 84}
diff --git a/crates/ra_hir_def/src/builtin_type.rs b/crates/ra_hir_def/src/builtin_type.rs
new file mode 100644
index 000000000..12929caa9
--- /dev/null
+++ b/crates/ra_hir_def/src/builtin_type.rs
@@ -0,0 +1,63 @@
1//! This module defines built-in types.
2//!
3//! A peculiarity of built-in types is that they are always available and are
4//! not associated with any particular crate.
5
6use hir_expand::name::{self, Name};
7
8#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
9pub enum Signedness {
10 Signed,
11 Unsigned,
12}
13
14#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
15pub enum IntBitness {
16 Xsize,
17 X8,
18 X16,
19 X32,
20 X64,
21 X128,
22}
23
24#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
25pub enum FloatBitness {
26 X32,
27 X64,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
31pub enum BuiltinType {
32 Char,
33 Bool,
34 Str,
35 Int { signedness: Signedness, bitness: IntBitness },
36 Float { bitness: FloatBitness },
37}
38
39impl BuiltinType {
40 #[rustfmt::skip]
41 pub const ALL: &'static [(Name, BuiltinType)] = &[
42 (name::CHAR, BuiltinType::Char),
43 (name::BOOL, BuiltinType::Bool),
44 (name::STR, BuiltinType::Str ),
45
46 (name::ISIZE, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::Xsize }),
47 (name::I8, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X8 }),
48 (name::I16, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X16 }),
49 (name::I32, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X32 }),
50 (name::I64, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X64 }),
51 (name::I128, BuiltinType::Int { signedness: Signedness::Signed, bitness: IntBitness::X128 }),
52
53 (name::USIZE, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::Xsize }),
54 (name::U8, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X8 }),
55 (name::U16, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X16 }),
56 (name::U32, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X32 }),
57 (name::U64, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X64 }),
58 (name::U128, BuiltinType::Int { signedness: Signedness::Unsigned, bitness: IntBitness::X128 }),
59
60 (name::F32, BuiltinType::Float { bitness: FloatBitness::X32 }),
61 (name::F64, BuiltinType::Float { bitness: FloatBitness::X64 }),
62 ];
63}
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
new file mode 100644
index 000000000..b271636b0
--- /dev/null
+++ b/crates/ra_hir_def/src/db.rs
@@ -0,0 +1,40 @@
1//! Defines database & queries for name resolution.
2use std::sync::Arc;
3
4use hir_expand::{db::AstDatabase, HirFileId};
5use ra_db::{salsa, SourceDatabase};
6use ra_syntax::ast;
7
8use crate::nameres::raw::{ImportSourceMap, RawItems};
9
10#[salsa::query_group(InternDatabaseStorage)]
11pub trait InternDatabase: SourceDatabase {
12 #[salsa::interned]
13 fn intern_function(&self, loc: crate::ItemLoc<ast::FnDef>) -> crate::FunctionId;
14 #[salsa::interned]
15 fn intern_struct(&self, loc: crate::ItemLoc<ast::StructDef>) -> crate::StructId;
16 #[salsa::interned]
17 fn intern_union(&self, loc: crate::ItemLoc<ast::StructDef>) -> crate::UnionId;
18 #[salsa::interned]
19 fn intern_enum(&self, loc: crate::ItemLoc<ast::EnumDef>) -> crate::EnumId;
20 #[salsa::interned]
21 fn intern_const(&self, loc: crate::ItemLoc<ast::ConstDef>) -> crate::ConstId;
22 #[salsa::interned]
23 fn intern_static(&self, loc: crate::ItemLoc<ast::StaticDef>) -> crate::StaticId;
24 #[salsa::interned]
25 fn intern_trait(&self, loc: crate::ItemLoc<ast::TraitDef>) -> crate::TraitId;
26 #[salsa::interned]
27 fn intern_type_alias(&self, loc: crate::ItemLoc<ast::TypeAliasDef>) -> crate::TypeAliasId;
28}
29
30#[salsa::query_group(DefDatabase2Storage)]
31pub trait DefDatabase2: InternDatabase + AstDatabase {
32 #[salsa::invoke(RawItems::raw_items_with_source_map_query)]
33 fn raw_items_with_source_map(
34 &self,
35 file_id: HirFileId,
36 ) -> (Arc<RawItems>, Arc<ImportSourceMap>);
37
38 #[salsa::invoke(RawItems::raw_items_query)]
39 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;
40}
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
new file mode 100644
index 000000000..93ad40005
--- /dev/null
+++ b/crates/ra_hir_def/src/lib.rs
@@ -0,0 +1,362 @@
1//! `hir_def` crate contains everything between macro expansion and type
2//! inference.
3//!
4//! It defines various items (structs, enums, traits) which comprises Rust code,
5//! as well as an algorithm for resolving paths to such entities.
6//!
7//! Note that `hir_def` is a work in progress, so not all of the above is
8//! actually true.
9
10pub mod db;
11pub mod attr;
12pub mod path;
13pub mod type_ref;
14pub mod builtin_type;
15
16// FIXME: this should be private
17pub mod nameres;
18
19use std::hash::{Hash, Hasher};
20
21use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId};
22use ra_arena::{impl_arena_id, RawId};
23use ra_db::{salsa, CrateId, FileId};
24use ra_syntax::{ast, AstNode, SyntaxNode};
25
26use crate::{builtin_type::BuiltinType, db::InternDatabase};
27
28#[derive(Debug, PartialEq, Eq, Clone, Copy)]
29pub struct Source<T> {
30 pub file_id: HirFileId,
31 pub ast: T,
32}
33
34pub enum ModuleSource {
35 SourceFile(ast::SourceFile),
36 Module(ast::Module),
37}
38
39impl ModuleSource {
40 pub fn new(
41 db: &impl db::DefDatabase2,
42 file_id: Option<FileId>,
43 decl_id: Option<AstId<ast::Module>>,
44 ) -> ModuleSource {
45 match (file_id, decl_id) {
46 (Some(file_id), _) => {
47 let source_file = db.parse(file_id).tree();
48 ModuleSource::SourceFile(source_file)
49 }
50 (None, Some(item_id)) => {
51 let module = item_id.to_node(db);
52 assert!(module.item_list().is_some(), "expected inline module");
53 ModuleSource::Module(module)
54 }
55 (None, None) => panic!(),
56 }
57 }
58
59 // FIXME: this methods do not belong here
60 pub fn from_position(
61 db: &impl db::DefDatabase2,
62 position: ra_db::FilePosition,
63 ) -> ModuleSource {
64 let parse = db.parse(position.file_id);
65 match &ra_syntax::algo::find_node_at_offset::<ast::Module>(
66 parse.tree().syntax(),
67 position.offset,
68 ) {
69 Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()),
70 _ => {
71 let source_file = parse.tree();
72 ModuleSource::SourceFile(source_file)
73 }
74 }
75 }
76
77 pub fn from_child_node(
78 db: &impl db::DefDatabase2,
79 file_id: FileId,
80 child: &SyntaxNode,
81 ) -> ModuleSource {
82 if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) {
83 ModuleSource::Module(m)
84 } else {
85 let source_file = db.parse(file_id).tree();
86 ModuleSource::SourceFile(source_file)
87 }
88 }
89
90 pub fn from_file_id(db: &impl db::DefDatabase2, file_id: FileId) -> ModuleSource {
91 let source_file = db.parse(file_id).tree();
92 ModuleSource::SourceFile(source_file)
93 }
94}
95
96impl<T> Source<T> {
97 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
98 Source { file_id: self.file_id, ast: f(self.ast) }
99 }
100 pub fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode {
101 db.parse_or_expand(self.file_id).expect("source created from invalid file")
102 }
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
106pub struct ModuleId {
107 pub krate: CrateId,
108 pub module_id: CrateModuleId,
109}
110
111/// An ID of a module, **local** to a specific crate
112// FIXME: rename to `LocalModuleId`.
113#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
114pub struct CrateModuleId(RawId);
115impl_arena_id!(CrateModuleId);
116
117macro_rules! impl_intern_key {
118 ($name:ident) => {
119 impl salsa::InternKey for $name {
120 fn from_intern_id(v: salsa::InternId) -> Self {
121 $name(v)
122 }
123 fn as_intern_id(&self) -> salsa::InternId {
124 self.0
125 }
126 }
127 };
128}
129
130#[derive(Debug)]
131pub struct ItemLoc<N: AstNode> {
132 pub(crate) module: ModuleId,
133 ast_id: AstId<N>,
134}
135
136impl<N: AstNode> PartialEq for ItemLoc<N> {
137 fn eq(&self, other: &Self) -> bool {
138 self.module == other.module && self.ast_id == other.ast_id
139 }
140}
141impl<N: AstNode> Eq for ItemLoc<N> {}
142impl<N: AstNode> Hash for ItemLoc<N> {
143 fn hash<H: Hasher>(&self, hasher: &mut H) {
144 self.module.hash(hasher);
145 self.ast_id.hash(hasher);
146 }
147}
148
149impl<N: AstNode> Clone for ItemLoc<N> {
150 fn clone(&self) -> ItemLoc<N> {
151 ItemLoc { module: self.module, ast_id: self.ast_id }
152 }
153}
154
155#[derive(Clone, Copy)]
156pub struct LocationCtx<DB> {
157 db: DB,
158 module: ModuleId,
159 file_id: HirFileId,
160}
161
162impl<'a, DB> LocationCtx<&'a DB> {
163 pub fn new(db: &'a DB, module: ModuleId, file_id: HirFileId) -> LocationCtx<&'a DB> {
164 LocationCtx { db, module, file_id }
165 }
166}
167
168impl<'a, DB: AstDatabase + InternDatabase> LocationCtx<&'a DB> {
169 pub fn to_def<N, DEF>(self, ast: &N) -> DEF
170 where
171 N: AstNode,
172 DEF: AstItemDef<N>,
173 {
174 DEF::from_ast(self, ast)
175 }
176}
177
178pub trait AstItemDef<N: AstNode>: salsa::InternKey + Clone {
179 fn intern(db: &impl InternDatabase, loc: ItemLoc<N>) -> Self;
180 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<N>;
181
182 fn from_ast(ctx: LocationCtx<&(impl AstDatabase + InternDatabase)>, ast: &N) -> Self {
183 let items = ctx.db.ast_id_map(ctx.file_id);
184 let item_id = items.ast_id(ast);
185 Self::from_ast_id(ctx, item_id)
186 }
187 fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId<N>) -> Self {
188 let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) };
189 Self::intern(ctx.db, loc)
190 }
191 fn source(self, db: &(impl AstDatabase + InternDatabase)) -> Source<N> {
192 let loc = self.lookup_intern(db);
193 let ast = loc.ast_id.to_node(db);
194 Source { file_id: loc.ast_id.file_id(), ast }
195 }
196 fn module(self, db: &impl InternDatabase) -> ModuleId {
197 let loc = self.lookup_intern(db);
198 loc.module
199 }
200}
201
202#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
203pub struct FunctionId(salsa::InternId);
204impl_intern_key!(FunctionId);
205
206impl AstItemDef<ast::FnDef> for FunctionId {
207 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::FnDef>) -> Self {
208 db.intern_function(loc)
209 }
210 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::FnDef> {
211 db.lookup_intern_function(self)
212 }
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
216pub struct StructId(salsa::InternId);
217impl_intern_key!(StructId);
218impl AstItemDef<ast::StructDef> for StructId {
219 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
220 db.intern_struct(loc)
221 }
222 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
223 db.lookup_intern_struct(self)
224 }
225}
226
227#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
228pub struct UnionId(salsa::InternId);
229impl_intern_key!(UnionId);
230impl AstItemDef<ast::StructDef> for UnionId {
231 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
232 db.intern_union(loc)
233 }
234 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
235 db.lookup_intern_union(self)
236 }
237}
238
239#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
240pub struct EnumId(salsa::InternId);
241impl_intern_key!(EnumId);
242impl AstItemDef<ast::EnumDef> for EnumId {
243 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::EnumDef>) -> Self {
244 db.intern_enum(loc)
245 }
246 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::EnumDef> {
247 db.lookup_intern_enum(self)
248 }
249}
250
251// FIXME: rename to `VariantId`, only enums can ave variants
252#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
253pub struct EnumVariantId {
254 parent: EnumId,
255 local_id: LocalEnumVariantId,
256}
257
258#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
259pub struct LocalEnumVariantId(RawId);
260impl_arena_id!(LocalEnumVariantId);
261
262#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
263pub struct ConstId(salsa::InternId);
264impl_intern_key!(ConstId);
265impl AstItemDef<ast::ConstDef> for ConstId {
266 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ConstDef>) -> Self {
267 db.intern_const(loc)
268 }
269 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ConstDef> {
270 db.lookup_intern_const(self)
271 }
272}
273
274#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
275pub struct StaticId(salsa::InternId);
276impl_intern_key!(StaticId);
277impl AstItemDef<ast::StaticDef> for StaticId {
278 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StaticDef>) -> Self {
279 db.intern_static(loc)
280 }
281 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StaticDef> {
282 db.lookup_intern_static(self)
283 }
284}
285
286#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
287pub struct TraitId(salsa::InternId);
288impl_intern_key!(TraitId);
289impl AstItemDef<ast::TraitDef> for TraitId {
290 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TraitDef>) -> Self {
291 db.intern_trait(loc)
292 }
293 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TraitDef> {
294 db.lookup_intern_trait(self)
295 }
296}
297
298#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
299pub struct TypeAliasId(salsa::InternId);
300impl_intern_key!(TypeAliasId);
301impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
302 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TypeAliasDef>) -> Self {
303 db.intern_type_alias(loc)
304 }
305 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TypeAliasDef> {
306 db.lookup_intern_type_alias(self)
307 }
308}
309
310macro_rules! impl_froms {
311 ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => {
312 $(
313 impl From<$v> for $e {
314 fn from(it: $v) -> $e {
315 $e::$v(it)
316 }
317 }
318 $($(
319 impl From<$sv> for $e {
320 fn from(it: $sv) -> $e {
321 $e::$v($v::$sv(it))
322 }
323 }
324 )*)?
325 )*
326 }
327}
328
329/// A Data Type
330#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
331pub enum AdtId {
332 StructId(StructId),
333 UnionId(UnionId),
334 EnumId(EnumId),
335}
336impl_froms!(AdtId: StructId, UnionId, EnumId);
337
338/// The defs which can be visible in the module.
339#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
340pub enum ModuleDefId {
341 ModuleId(ModuleId),
342 FunctionId(FunctionId),
343 AdtId(AdtId),
344 // Can't be directly declared, but can be imported.
345 EnumVariantId(EnumVariantId),
346 ConstId(ConstId),
347 StaticId(StaticId),
348 TraitId(TraitId),
349 TypeAliasId(TypeAliasId),
350 BuiltinType(BuiltinType),
351}
352impl_froms!(
353 ModuleDefId: ModuleId,
354 FunctionId,
355 AdtId(StructId, EnumId, UnionId),
356 EnumVariantId,
357 ConstId,
358 StaticId,
359 TraitId,
360 TypeAliasId,
361 BuiltinType
362);
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
new file mode 100644
index 000000000..11ba8a777
--- /dev/null
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -0,0 +1,5 @@
1//! FIXME: write short doc here
2
3// FIXME: review privacy of submodules
4pub mod raw;
5pub mod mod_resolution;
diff --git a/crates/ra_hir/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs
index e8b808514..7d7e2779a 100644
--- a/crates/ra_hir/src/nameres/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs
@@ -1,12 +1,13 @@
1//! This module resolves `mod foo;` declaration to file. 1//! This module resolves `mod foo;` declaration to file.
2use hir_expand::name::Name;
2use ra_db::FileId; 3use ra_db::FileId;
3use ra_syntax::SmolStr; 4use ra_syntax::SmolStr;
4use relative_path::RelativePathBuf; 5use relative_path::RelativePathBuf;
5 6
6use crate::{db::DefDatabase, HirFileId, Name}; 7use crate::{db::DefDatabase2, HirFileId};
7 8
8#[derive(Clone, Debug)] 9#[derive(Clone, Debug)]
9pub(super) struct ModDir { 10pub struct ModDir {
10 /// `.` for `mod.rs`, `lib.rs` 11 /// `.` for `mod.rs`, `lib.rs`
11 /// `./foo` for `foo.rs` 12 /// `./foo` for `foo.rs`
12 /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs` 13 /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs`
@@ -16,24 +17,17 @@ pub(super) struct ModDir {
16} 17}
17 18
18impl ModDir { 19impl ModDir {
19 pub(super) fn root() -> ModDir { 20 pub fn root() -> ModDir {
20 ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false } 21 ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false }
21 } 22 }
22 23
23 pub(super) fn descend_into_definition( 24 pub fn descend_into_definition(&self, name: &Name, attr_path: Option<&SmolStr>) -> ModDir {
24 &self,
25 name: &Name,
26 attr_path: Option<&SmolStr>,
27 ) -> ModDir {
28 let mut path = self.path.clone(); 25 let mut path = self.path.clone();
29 match attr_to_path(attr_path) { 26 match attr_to_path(attr_path) {
30 None => path.push(&name.to_string()), 27 None => path.push(&name.to_string()),
31 Some(attr_path) => { 28 Some(attr_path) => {
32 if self.root_non_dir_owner { 29 if self.root_non_dir_owner {
33 // Workaround for relative path API: turn `lib.rs` into ``. 30 assert!(path.pop());
34 if !path.pop() {
35 path = RelativePathBuf::default();
36 }
37 } 31 }
38 path.push(attr_path); 32 path.push(attr_path);
39 } 33 }
@@ -41,24 +35,20 @@ impl ModDir {
41 ModDir { path, root_non_dir_owner: false } 35 ModDir { path, root_non_dir_owner: false }
42 } 36 }
43 37
44 pub(super) fn resolve_declaration( 38 pub fn resolve_declaration(
45 &self, 39 &self,
46 db: &impl DefDatabase, 40 db: &impl DefDatabase2,
47 file_id: HirFileId, 41 file_id: HirFileId,
48 name: &Name, 42 name: &Name,
49 attr_path: Option<&SmolStr>, 43 attr_path: Option<&SmolStr>,
50 ) -> Result<(FileId, ModDir), RelativePathBuf> { 44 ) -> Result<(FileId, ModDir), RelativePathBuf> {
51 let empty_path = RelativePathBuf::default();
52 let file_id = file_id.original_file(db); 45 let file_id = file_id.original_file(db);
53 46
54 let mut candidate_files = Vec::new(); 47 let mut candidate_files = Vec::new();
55 match attr_to_path(attr_path) { 48 match attr_to_path(attr_path) {
56 Some(attr_path) => { 49 Some(attr_path) => {
57 let base = if self.root_non_dir_owner { 50 let base =
58 self.path.parent().unwrap_or(&empty_path) 51 if self.root_non_dir_owner { self.path.parent().unwrap() } else { &self.path };
59 } else {
60 &self.path
61 };
62 candidate_files.push(base.join(attr_path)) 52 candidate_files.push(base.join(attr_path))
63 } 53 }
64 None => { 54 None => {
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index 57f2929c3..86c05d602 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -2,18 +2,20 @@
2 2
3use std::{ops::Index, sync::Arc}; 3use std::{ops::Index, sync::Arc};
4 4
5use hir_expand::{
6 ast_id_map::AstIdMap,
7 db::AstDatabase,
8 either::Either,
9 hygiene::Hygiene,
10 name::{AsName, Name},
11};
5use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 12use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
6use ra_syntax::{ 13use ra_syntax::{
7 ast::{self, AttrsOwner, NameOwner}, 14 ast::{self, AttrsOwner, NameOwner},
8 AstNode, AstPtr, SourceFile, 15 AstNode, AstPtr, SourceFile,
9}; 16};
10use test_utils::tested_by;
11 17
12use crate::{ 18use crate::{attr::Attr, db::DefDatabase2, path::Path, FileAstId, HirFileId, ModuleSource, Source};
13 attr::Attr,
14 db::{AstDatabase, DefDatabase},
15 AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, Source,
16};
17 19
18/// `RawItems` is a set of top-level items in a file (except for impls). 20/// `RawItems` is a set of top-level items in a file (except for impls).
19/// 21///
@@ -37,10 +39,8 @@ pub struct ImportSourceMap {
37type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>; 39type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>;