diff options
Diffstat (limited to 'crates')
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 | ||
3 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
4 | use ra_db::FileRange; | 4 | use ra_db::FileRange; |
5 | use ra_fmt::{leading_indent, reindent}; | 5 | use ra_fmt::{leading_indent, reindent}; |
6 | use ra_syntax::{ | 6 | use 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 | }; |
11 | use ra_text_edit::TextEditBuilder; | 11 | use ra_text_edit::TextEditBuilder; |
@@ -14,8 +14,8 @@ use crate::{AssistAction, AssistId, AssistLabel}; | |||
14 | 14 | ||
15 | #[derive(Clone, Debug)] | 15 | #[derive(Clone, Debug)] |
16 | pub(crate) enum Assist { | 16 | pub(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 | ||
60 | impl<'a, DB> Clone for AssistCtx<'a, DB> { | 59 | impl<'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 | |||
3 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
4 | use ra_syntax::{ | 2 | use ra_syntax::{ |
5 | ast::{self, AstNode, AttrsOwner}, | 3 | ast::{self, AstNode, AttrsOwner}, |
@@ -9,10 +7,28 @@ use ra_syntax::{ | |||
9 | 7 | ||
10 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{Assist, AssistCtx, AssistId}; |
11 | 9 | ||
12 | pub(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 | // ``` | ||
28 | pub(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 | |||
3 | use hir::{db::HirDatabase, HirDisplay, Ty}; | 1 | use hir::{db::HirDatabase, HirDisplay, Ty}; |
4 | use ra_syntax::{ | 2 | use ra_syntax::{ |
5 | ast::{self, AstNode, LetStmt, NameOwner}, | 3 | ast::{self, AstNode, LetStmt, NameOwner}, |
@@ -8,9 +6,23 @@ use ra_syntax::{ | |||
8 | 6 | ||
9 | use crate::{Assist, AssistCtx, AssistId}; | 7 | use crate::{Assist, AssistCtx, AssistId}; |
10 | 8 | ||
11 | /// Add explicit type assist. | 9 | // Assist: add_explicit_type |
12 | pub(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 | // ``` | ||
24 | pub(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 | |||
3 | use format_buf::format; | 1 | use format_buf::format; |
4 | use hir::db::HirDatabase; | 2 | use hir::db::HirDatabase; |
5 | use join_to_string::join; | 3 | use join_to_string::join; |
@@ -10,10 +8,29 @@ use ra_syntax::{ | |||
10 | 8 | ||
11 | use crate::{Assist, AssistCtx, AssistId}; | 9 | use crate::{Assist, AssistCtx, AssistId}; |
12 | 10 | ||
13 | pub(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 | // ``` | ||
30 | pub(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 | |||
3 | use hir::{self, db::HirDatabase}; | 1 | use hir::{self, db::HirDatabase}; |
4 | use ra_text_edit::TextEditBuilder; | ||
5 | |||
6 | use crate::{ | ||
7 | assist_ctx::{Assist, AssistCtx}, | ||
8 | AssistId, | ||
9 | }; | ||
10 | use ra_syntax::{ | 2 | use 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 | }; |
8 | use ra_text_edit::TextEditBuilder; | ||
9 | |||
10 | use 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 | ||
18 | pub 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 | // ``` | ||
53 | pub(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 | ||
17 | fn collect_path_segments_raw( | 80 | fn 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. |
65 | fn compare_path_segments(left: &[SmolStr], right: &[ast::PathSegment]) -> usize { | 128 | fn 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 | ||
69 | fn compare_path_segment(a: &SmolStr, b: &ast::PathSegment) -> bool { | 132 | fn 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)] |
88 | enum ImportAction { | 151 | enum 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 | ||
508 | pub fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { | 579 | fn 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 | ||
527 | pub 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 | |||
549 | pub(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)] |
597 | mod tests { | 596 | mod 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 | " |
606 | std::fmt::Debug<|> | 606 | std::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 | " |
620 | std::fmt::Debug<|> | 620 | std::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 | " |
641 | fn main() { | 641 | fn 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 | " |
662 | std::fmt<|>::Debug | 662 | std::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 | " |
677 | use stdx; | 677 | use 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 | " |
697 | impl std::fmt::Debug<|> for Foo { | 697 | impl 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 | " |
731 | use std::fmt; | 731 | use std::fmt; |
732 | 732 | ||
@@ -734,7 +734,7 @@ impl std::io<|> for Foo { | |||
734 | } | 734 | } |
735 | ", | 735 | ", |
736 | " | 736 | " |
737 | use std::{ io, fmt}; | 737 | use std::{io, fmt}; |
738 | 738 | ||
739 | impl io<|> for Foo { | 739 | impl 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 | " |
750 | use std::fmt; | 750 | use std::fmt; |
751 | 751 | ||
@@ -753,7 +753,7 @@ impl std::fmt::Debug<|> for Foo { | |||
753 | } | 753 | } |
754 | ", | 754 | ", |
755 | " | 755 | " |
756 | use std::fmt::{ self, Debug, }; | 756 | use std::fmt::{self, Debug, }; |
757 | 757 | ||
758 | impl Debug<|> for Foo { | 758 | impl 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 | " |
769 | use std::fmt::Debug; | 769 | use std::fmt::Debug; |
770 | 770 | ||
@@ -772,7 +772,7 @@ impl std::fmt<|> for Foo { | |||
772 | } | 772 | } |
773 | ", | 773 | ", |
774 | " | 774 | " |
775 | use std::fmt::{ self, Debug}; | 775 | use std::fmt::{self, Debug}; |
776 | 776 | ||
777 | impl fmt<|> for Foo { | 777 | impl 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 | " |
788 | use std::fmt::{Debug, nested::{Display}}; | 788 | use 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 | " |
807 | use std::fmt::{Debug, nested::{self, Display}}; | 807 | use 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 | " |
826 | use std::fmt::{Debug, nested::{Display}}; | 826 | use 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 | " |
845 | use std::fmt::Debug; | 845 | use std::fmt::Debug; |
846 | 846 | ||
@@ -848,7 +848,7 @@ impl std::fmt::nested::Display<|> for Foo { | |||
848 | } | 848 | } |
849 | ", | 849 | ", |
850 | " | 850 | " |
851 | use std::fmt::{ nested::Display, Debug}; | 851 | use std::fmt::{nested::Display, Debug}; |
852 | 852 | ||
853 | impl Display<|> for Foo { | 853 | impl 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 | " |
864 | use std::fmt::nested::Debug; | 864 | use std::fmt::nested::Debug; |
865 | 865 | ||
@@ -867,7 +867,7 @@ impl std::fmt::Display<|> for Foo { | |||
867 | } | 867 | } |
868 | ", | 868 | ", |
869 | " | 869 | " |
870 | use std::fmt::{ Display, nested::Debug}; | 870 | use std::fmt::{Display, nested::Debug}; |
871 | 871 | ||
872 | impl Display<|> for Foo { | 872 | impl 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 | " | ||
883 | use crate::{ | ||
884 | ty::{Substs, Ty}, | ||
885 | AssocItem, | ||
886 | }; | ||
887 | |||
888 | fn foo() { crate::ty::lower<|>::trait_env() } | ||
889 | ", | ||
890 | " | ||
891 | use crate::{ | ||
892 | ty::{Substs, Ty, lower}, | ||
893 | AssocItem, | ||
894 | }; | ||
895 | |||
896 | fn 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 | " |
883 | use std::fmt as foo; | 906 | use 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 | " |
902 | impl foo<|> for Foo { | 925 | impl 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 | " |
913 | use std::fmt<|>; | 936 | use 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 | " |
923 | mod foo { | 946 | mod 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 | |||
3 | use hir::{db::HirDatabase, HasSource}; | 1 | use hir::{db::HirDatabase, HasSource}; |
4 | use ra_syntax::{ | 2 | use 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 | // ``` | ||
17 | pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 43 | pub(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 | // ``` | ||
26 | pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 84 | pub(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 | ||
35 | fn add_missing_impl_members_inner( | 93 | fn 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 | ||
100 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { | 156 | fn 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)`. | ||
4 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
5 | use ra_syntax::ast::{self, AstNode}; | 2 | use ra_syntax::ast::{self, AstNode}; |
6 | use ra_syntax::SyntaxNode; | 3 | use ra_syntax::SyntaxNode; |
7 | 4 | ||
8 | use crate::{Assist, AssistCtx, AssistId}; | 5 | use 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. |
16 | pub(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 | // ``` | ||
26 | pub(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 | |||
3 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
4 | use ra_syntax::{ | 2 | use ra_syntax::{ |
5 | ast::{self, NameOwner, VisibilityOwner}, | 3 | ast::{self, NameOwner, VisibilityOwner}, |
@@ -13,14 +11,25 @@ use ra_syntax::{ | |||
13 | 11 | ||
14 | use crate::{Assist, AssistCtx, AssistId}; | 12 | use 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 | // ``` | ||
16 | pub(crate) fn change_visibility(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 25 | pub(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 | ||
23 | fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 32 | fn 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 | ||
60 | fn vis_offset(node: &SyntaxNode) -> TextUnit { | 67 | fn 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 | ||
71 | fn change_vis(mut ctx: AssistCtx<impl HirDatabase>, vis: ast::Visibility) -> Option<Assist> { | 78 | fn 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 | |||
24 | use std::ops::RangeInclusive; | 1 | use std::ops::RangeInclusive; |
25 | 2 | ||
26 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
@@ -36,8 +13,30 @@ use crate::{ | |||
36 | AssistId, | 13 | AssistId, |
37 | }; | 14 | }; |
38 | 15 | ||
39 | pub(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 | // ``` | ||
38 | pub(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 | ||
8 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{Assist, AssistCtx, AssistId}; |
9 | 9 | ||
10 | pub(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 | // ``` | ||
34 | pub(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 | ||
51 | fn is_trivial(arm: &ast::MatchArm) -> bool { | 73 | fn 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 | |||
3 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
4 | use ra_syntax::ast::{AstNode, BinExpr, BinOp}; | 2 | use ra_syntax::ast::{AstNode, BinExpr, BinOp}; |
5 | 3 | ||
6 | use crate::{Assist, AssistCtx, AssistId}; | 4 | use crate::{Assist, AssistCtx, AssistId}; |
7 | 5 | ||
8 | /// Flip binary expression assist. | 6 | // Assist: flip_binexpr |
9 | pub(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 | // ``` | ||
21 | pub(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 | ||
37 | enum FlipAction { | 47 | enum 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 | |||
3 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
4 | use ra_syntax::{algo::non_trivia_sibling, Direction, T}; | 2 | use ra_syntax::{algo::non_trivia_sibling, Direction, T}; |
5 | 3 | ||
6 | use crate::{Assist, AssistCtx, AssistId}; | 4 | use crate::{Assist, AssistCtx, AssistId}; |
7 | 5 | ||
8 | pub(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 | // ``` | ||
21 | pub(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 @@ | |||
1 | use hir::db::HirDatabase; | ||
2 | use ra_syntax::{ | ||
3 | algo::non_trivia_sibling, | ||
4 | ast::{self, AstNode}, | ||
5 | Direction, T, | ||
6 | }; | ||
7 | |||
8 | use 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 | // ``` | ||
21 | pub(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)] | ||
44 | mod 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 | |||
3 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
4 | use ra_syntax::{ | 2 | use ra_syntax::{ |
5 | ast::{self, AstNode, AstToken}, | 3 | ast::{self, AstNode, AstToken}, |
@@ -9,8 +7,24 @@ use ra_syntax::{ | |||
9 | use crate::assist_ctx::AssistBuilder; | 7 | use crate::assist_ctx::AssistBuilder; |
10 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{Assist, AssistCtx, AssistId}; |
11 | 9 | ||
12 | pub(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 | // ``` | ||
26 | pub(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 | |||
3 | use format_buf::format; | 1 | use format_buf::format; |
4 | use hir::db::HirDatabase; | 2 | use hir::db::HirDatabase; |
5 | use ra_syntax::{ | 3 | use ra_syntax::{ |
@@ -14,7 +12,23 @@ use test_utils::tested_by; | |||
14 | 12 | ||
15 | use crate::{Assist, AssistCtx, AssistId}; | 13 | use crate::{Assist, AssistCtx, AssistId}; |
16 | 14 | ||
17 | pub(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 | // ``` | ||
31 | pub(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 | |||
3 | use crate::{Assist, AssistCtx, AssistId, TextRange, TextUnit}; | 1 | use crate::{Assist, AssistCtx, AssistId, TextRange, TextUnit}; |
4 | use hir::db::HirDatabase; | 2 | use hir::db::HirDatabase; |
5 | use ra_syntax::ast::{AstNode, MatchArm}; | 3 | use ra_syntax::ast::{AstNode, MatchArm}; |
6 | 4 | ||
7 | pub(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 | // ``` | ||
29 | pub(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 | |||
3 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
4 | use ra_syntax::{ | 2 | use 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 | ||
10 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{Assist, AssistCtx, AssistId}; |
11 | 9 | ||
12 | pub(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 | // ``` | ||
25 | pub(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 | ||
70 | fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { | 75 | fn 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 | |||
3 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
4 | use ra_syntax::{ | 2 | use ra_syntax::{ |
5 | ast, | 3 | ast, |
@@ -9,8 +7,33 @@ use ra_syntax::{ | |||
9 | 7 | ||
10 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{Assist, AssistCtx, AssistId}; |
11 | 9 | ||
12 | pub(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 | // ``` | ||
35 | pub(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 | ||
45 | pub(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 | // ``` | ||
92 | pub(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 | |||
3 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
4 | use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; | 2 | use ra_syntax::{ |
3 | SyntaxKind::{RAW_STRING, STRING}, | ||
4 | TextRange, TextUnit, | ||
5 | }; | ||
5 | use rustc_lexer; | 6 | use rustc_lexer; |
6 | 7 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{Assist, AssistCtx, AssistId}; |
8 | 9 | ||
9 | pub(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 | // ``` | ||
25 | pub(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 | |||
47 | fn 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 | |||
59 | fn 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 | ||
66 | pub(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 | // ``` | ||
70 | pub(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 | ||
86 | pub(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 | // ``` | ||
100 | pub(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 | ||
99 | pub(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 | // ``` | ||
124 | pub(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 | |||
145 | fn 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 | |||
157 | fn 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 | |||
3 | use crate::{Assist, AssistCtx, AssistId}; | ||
4 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
5 | use ra_syntax::{ | 2 | use ra_syntax::{ |
6 | ast::{self, AstNode}, | 3 | ast::{self, AstNode}, |
7 | TextUnit, T, | 4 | TextUnit, T, |
8 | }; | 5 | }; |
9 | 6 | ||
10 | pub(crate) fn remove_dbg(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 7 | use 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 | // ``` | ||
24 | pub(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(¯o_call, "dbg")? { | 27 | if !is_valid_macrocall(¯o_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 | |||
3 | use format_buf::format; | 1 | use format_buf::format; |
4 | use hir::db::HirDatabase; | 2 | use hir::db::HirDatabase; |
5 | use ra_fmt::extract_trivial_expression; | 3 | use ra_fmt::extract_trivial_expression; |
@@ -7,8 +5,34 @@ use ra_syntax::{ast, AstNode}; | |||
7 | 5 | ||
8 | use crate::{Assist, AssistCtx, AssistId}; | 6 | use crate::{Assist, AssistCtx, AssistId}; |
9 | 7 | ||
10 | pub(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 | // ``` | ||
34 | pub(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 | ||
31 | fn build_match_expr( | 53 | fn 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 | |||
3 | use std::iter::successors; | 1 | use std::iter::successors; |
4 | 2 | ||
5 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
@@ -7,8 +5,19 @@ use ra_syntax::{ast, AstNode, TextUnit, T}; | |||
7 | 5 | ||
8 | use crate::{Assist, AssistCtx, AssistId}; | 6 | use crate::{Assist, AssistCtx, AssistId}; |
9 | 7 | ||
10 | pub(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 | // ``` | ||
19 | pub(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 | |||
6 | mod generated; | ||
7 | |||
8 | use hir::mock::MockDatabase; | ||
9 | use ra_db::FileRange; | ||
10 | use test_utils::{assert_eq_text, extract_range_or_offset}; | ||
11 | |||
12 | fn 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 | |||
3 | use super::check; | ||
4 | |||
5 | #[test] | ||
6 | fn doctest_add_derive() { | ||
7 | check( | ||
8 | "add_derive", | ||
9 | r#####" | ||
10 | struct Point { | ||
11 | x: u32, | ||
12 | y: u32,<|> | ||
13 | } | ||
14 | "#####, | ||
15 | r#####" | ||
16 | #[derive()] | ||
17 | struct Point { | ||
18 | x: u32, | ||
19 | y: u32, | ||
20 | } | ||
21 | "#####, | ||
22 | ) | ||
23 | } | ||
24 | |||
25 | #[test] | ||
26 | fn doctest_add_explicit_type() { | ||
27 | check( | ||
28 | "add_explicit_type", | ||
29 | r#####" | ||
30 | fn main() { | ||
31 | let x<|> = 92; | ||
32 | } | ||
33 | "#####, | ||
34 | r#####" | ||
35 | fn main() { | ||
36 | let x: i32 = 92; | ||
37 | } | ||
38 | "#####, | ||
39 | ) | ||
40 | } | ||
41 | |||
42 | #[test] | ||
43 | fn doctest_add_hash() { | ||
44 | check( | ||
45 | "add_hash", | ||
46 | r#####" | ||
47 | fn main() { | ||
48 | r#"Hello,<|> World!"#; | ||
49 | } | ||
50 | "#####, | ||
51 | r#####" | ||
52 | fn main() { | ||
53 | r##"Hello, World!"##; | ||
54 | } | ||
55 | "#####, | ||
56 | ) | ||
57 | } | ||
58 | |||
59 | #[test] | ||
60 | fn doctest_add_impl() { | ||
61 | check( | ||
62 | "add_impl", | ||
63 | r#####" | ||
64 | struct Ctx<T: Clone> { | ||
65 | data: T,<|> | ||
66 | } | ||
67 | "#####, | ||
68 | r#####" | ||
69 | struct Ctx<T: Clone> { | ||
70 | data: T, | ||
71 | } | ||
72 | |||
73 | impl<T: Clone> Ctx<T> { | ||
74 | |||
75 | } | ||
76 | "#####, | ||
77 | ) | ||
78 | } | ||
79 | |||
80 | #[test] | ||
81 | fn doctest_add_impl_default_members() { | ||
82 | check( | ||
83 | "add_impl_default_members", | ||
84 | r#####" | ||
85 | trait T { | ||
86 | Type X; | ||
87 | fn foo(&self); | ||
88 | fn bar(&self) {} | ||
89 | } | ||
90 | |||
91 | impl T for () { | ||
92 | Type X = (); | ||
93 | fn foo(&self) {}<|> | ||
94 | |||
95 | } | ||
96 | "#####, | ||
97 | r#####" | ||
98 | trait T { | ||
99 | Type X; | ||
100 | fn foo(&self); | ||
101 | fn bar(&self) {} | ||
102 | } | ||
103 | |||
104 | impl T for () { | ||
105 | Type X = (); | ||
106 | fn foo(&self) {} | ||
107 | fn bar(&self) {} | ||
108 | |||
109 | } | ||
110 | "#####, | ||
111 | ) | ||
112 | } | ||
113 | |||
114 | #[test] | ||
115 | fn doctest_add_impl_missing_members() { | ||
116 | check( | ||
117 | "add_impl_missing_members", | ||
118 | r#####" | ||
119 | trait T { | ||
120 | Type X; | ||
121 | fn foo(&self); | ||
122 | fn bar(&self) {} | ||
123 | } | ||
124 | |||
125 | impl T for () {<|> | ||
126 | |||
127 | } | ||
128 | "#####, | ||
129 | r#####" | ||
130 | trait T { | ||
131 | Type X; | ||
132 | fn foo(&self); | ||
133 | fn bar(&self) {} | ||
134 | } | ||
135 | |||
136 | impl T for () { | ||
137 | fn foo(&self) { unimplemented!() } | ||
138 | |||
139 | } | ||
140 | "#####, | ||
141 | ) | ||
142 | } | ||
143 | |||
144 | #[test] | ||
145 | fn doctest_add_import() { | ||
146 | check( | ||
147 | "add_import", | ||
148 | r#####" | ||
149 | fn process(map: std::collections::<|>HashMap<String, String>) {} | ||
150 | "#####, | ||
151 | r#####" | ||
152 | use std::collections::HashMap; | ||
153 | |||
154 | fn process(map: HashMap<String, String>) {} | ||
155 | "#####, | ||
156 | ) | ||
157 | } | ||
158 | |||
159 | #[test] | ||
160 | fn doctest_apply_demorgan() { | ||
161 | check( | ||
162 | "apply_demorgan", | ||
163 | r#####" | ||
164 | fn main() { | ||
165 | if x != 4 ||<|> !y {} | ||
166 | } | ||
167 | "#####, | ||
168 | r#####" | ||
169 | fn main() { | ||
170 | if !(x == 4 && y) {} | ||
171 | } | ||
172 | "#####, | ||
173 | ) | ||
174 | } | ||
175 | |||
176 | #[test] | ||
177 | fn doctest_change_visibility() { | ||
178 | check( | ||
179 | "change_visibility", | ||
180 | r#####" | ||
181 | <|>fn frobnicate() {} | ||
182 | "#####, | ||
183 | r#####" | ||
184 | pub(crate) fn frobnicate() {} | ||
185 | "#####, | ||
186 | ) | ||
187 | } | ||
188 | |||
189 | #[test] | ||
190 | fn doctest_convert_to_guarded_return() { | ||
191 | check( | ||
192 | "convert_to_guarded_return", | ||
193 | r#####" | ||
194 | fn main() { | ||
195 | <|>if cond { | ||
196 | foo(); | ||
197 | bar(); | ||
198 | } | ||
199 | } | ||
200 | "#####, | ||
201 | r#####" | ||
202 | fn main() { | ||
203 | if !cond { | ||
204 | return; | ||
205 | } | ||
206 | foo(); | ||
207 | bar(); | ||
208 | } | ||
209 | "#####, | ||
210 | ) | ||
211 | } | ||
212 | |||
213 | #[test] | ||
214 | fn doctest_fill_match_arms() { | ||
215 | check( | ||
216 | "fill_match_arms", | ||
217 | r#####" | ||
218 | enum Action { Move { distance: u32 }, Stop } | ||
219 | |||
220 | fn handle(action: Action) { | ||
221 | match action { | ||
222 | <|> | ||
223 | } | ||
224 | } | ||
225 | "#####, | ||
226 | r#####" | ||
227 | enum Action { Move { distance: u32 }, Stop } | ||
228 | |||
229 | fn handle(action: Action) { | ||
230 | match action { | ||
231 | Action::Move { distance } => (), | ||
232 | Action::Stop => (), | ||
233 | } | ||
234 | } | ||
235 | "#####, | ||
236 | ) | ||
237 | } | ||
238 | |||
239 | #[test] | ||
240 | fn doctest_flip_binexpr() { | ||
241 | check( | ||
242 | "flip_binexpr", | ||
243 | r#####" | ||
244 | fn main() { | ||
245 | let _ = 90 +<|> 2; | ||
246 | } | ||
247 | "#####, | ||
248 | r#####" | ||
249 | fn main() { | ||
250 | let _ = 2 + 90; | ||
251 | } | ||
252 | "#####, | ||
253 | ) | ||
254 | } | ||
255 | |||
256 | #[test] | ||
257 | fn doctest_flip_comma() { | ||
258 | check( | ||
259 | "flip_comma", | ||
260 | r#####" | ||
261 | fn main() { | ||
262 | ((1, 2),<|> (3, 4)); | ||
263 | } | ||
264 | "#####, | ||
265 | r#####" | ||
266 | fn main() { | ||
267 | ((3, 4), (1, 2)); | ||
268 | } | ||
269 | "#####, | ||
270 | ) | ||
271 | } | ||
272 | |||
273 | #[test] | ||
274 | fn doctest_flip_trait_bound() { | ||
275 | check( | ||
276 | "flip_trait_bound", | ||
277 | r#####" | ||
278 | fn foo<T: Clone +<|> Copy>() { } | ||
279 | "#####, | ||
280 | r#####" | ||
281 | fn foo<T: Copy + Clone>() { } | ||
282 | "#####, | ||
283 | ) | ||
284 | } | ||
285 | |||
286 | #[test] | ||
287 | fn doctest_inline_local_variable() { | ||
288 | check( | ||
289 | "inline_local_variable", | ||
290 | r#####" | ||
291 | fn main() { | ||
292 | let x<|> = 1 + 2; | ||
293 | x * 4; | ||
294 | } | ||
295 | "#####, | ||
296 | r#####" | ||
297 | fn main() { | ||
298 | (1 + 2) * 4; | ||
299 | } | ||
300 | "#####, | ||
301 | ) | ||
302 | } | ||
303 | |||
304 | #[test] | ||
305 | fn doctest_introduce_variable() { | ||
306 | check( | ||
307 | "introduce_variable", | ||
308 | r#####" | ||
309 | fn main() { | ||
310 | <|>(1 + 2)<|> * 4; | ||
311 | } | ||
312 | "#####, | ||
313 | r#####" | ||
314 | fn main() { | ||
315 | let var_name = (1 + 2); | ||
316 | var_name * 4; | ||
317 | } | ||
318 | "#####, | ||
319 | ) | ||
320 | } | ||
321 | |||
322 | #[test] | ||
323 | fn doctest_make_raw_string() { | ||
324 | check( | ||
325 | "make_raw_string", | ||
326 | r#####" | ||
327 | fn main() { | ||
328 | "Hello,<|> World!"; | ||
329 | } | ||
330 | "#####, | ||
331 | r#####" | ||
332 | fn main() { | ||
333 | r#"Hello, World!"#; | ||
334 | } | ||
335 | "#####, | ||
336 | ) | ||
337 | } | ||
338 | |||
339 | #[test] | ||
340 | fn doctest_make_usual_string() { | ||
341 | check( | ||
342 | "make_usual_string", | ||
343 | r#####" | ||
344 | fn main() { | ||
345 | r#"Hello,<|> "World!""#; | ||
346 | } | ||
347 | "#####, | ||
348 | r#####" | ||
349 | fn main() { | ||
350 | "Hello, \"World!\""; | ||
351 | } | ||
352 | "#####, | ||
353 | ) | ||
354 | } | ||
355 | |||
356 | #[test] | ||
357 | fn doctest_merge_match_arms() { | ||
358 | check( | ||
359 | "merge_match_arms", | ||
360 | r#####" | ||
361 | enum Action { Move { distance: u32 }, Stop } | ||
362 | |||
363 | fn handle(action: Action) { | ||
364 | match action { | ||
365 | <|>Action::Move(..) => foo(), | ||
366 | Action::Stop => foo(), | ||
367 | } | ||
368 | } | ||
369 | "#####, | ||
370 | r#####" | ||
371 | enum Action { Move { distance: u32 }, Stop } | ||
372 | |||
373 | fn handle(action: Action) { | ||
374 | match action { | ||
375 | Action::Move(..) | Action::Stop => foo(), | ||
376 | } | ||
377 | } | ||
378 | "#####, | ||
379 | ) | ||
380 | } | ||
381 | |||
382 | #[test] | ||
383 | fn doctest_move_arm_cond_to_match_guard() { | ||
384 | check( | ||
385 | "move_arm_cond_to_match_guard", | ||
386 | r#####" | ||
387 | enum Action { Move { distance: u32 }, Stop } | ||
388 | |||
389 | fn handle(action: Action) { | ||
390 | match action { | ||
391 | Action::Move { distance } => <|>if distance > 10 { foo() }, | ||
392 | _ => (), | ||
393 | } | ||
394 | } | ||
395 | "#####, | ||
396 | r#####" | ||
397 | enum Action { Move { distance: u32 }, Stop } | ||
398 | |||
399 | fn handle(action: Action) { | ||
400 | match action { | ||
401 | Action::Move { distance } if distance > 10 => foo(), | ||
402 | _ => (), | ||
403 | } | ||
404 | } | ||
405 | "#####, | ||
406 | ) | ||
407 | } | ||
408 | |||
409 | #[test] | ||
410 | fn doctest_move_bounds_to_where_clause() { | ||
411 | check( | ||
412 | "move_bounds_to_where_clause", | ||
413 | r#####" | ||
414 | fn apply<T, U, <|>F: FnOnce(T) -> U>(f: F, x: T) -> U { | ||
415 | f(x) | ||
416 | } | ||
417 | "#####, | ||
418 | r#####" | ||
419 | fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U { | ||
420 | f(x) | ||
421 | } | ||
422 | "#####, | ||
423 | ) | ||
424 | } | ||
425 | |||
426 | #[test] | ||
427 | fn doctest_move_guard_to_arm_body() { | ||
428 | check( | ||
429 | "move_guard_to_arm_body", | ||
430 | r#####" | ||
431 | enum Action { Move { distance: u32 }, Stop } | ||
432 | |||
433 | fn handle(action: Action) { | ||
434 | match action { | ||
435 | Action::Move { distance } <|>if distance > 10 => foo(), | ||
436 | _ => (), | ||
437 | } | ||
438 | } | ||
439 | "#####, | ||
440 | r#####" | ||
441 | enum Action { Move { distance: u32 }, Stop } | ||
442 | |||
443 | fn handle(action: Action) { | ||
444 | match action { | ||
445 | Action::Move { distance } => if distance > 10 { foo() }, | ||
446 | _ => (), | ||
447 | } | ||
448 | } | ||
449 | "#####, | ||
450 | ) | ||
451 | } | ||
452 | |||
453 | #[test] | ||
454 | fn doctest_remove_dbg() { | ||
455 | check( | ||
456 | "remove_dbg", | ||
457 | r#####" | ||
458 | fn main() { | ||
459 | <|>dbg!(92); | ||
460 | } | ||
461 | "#####, | ||
462 | r#####" | ||
463 | fn main() { | ||
464 | 92; | ||
465 | } | ||
466 | "#####, | ||
467 | ) | ||
468 | } | ||
469 | |||
470 | #[test] | ||
471 | fn doctest_remove_hash() { | ||
472 | check( | ||
473 | "remove_hash", | ||
474 | r#####" | ||
475 | fn main() { | ||
476 | r#"Hello,<|> World!"#; | ||
477 | } | ||
478 | "#####, | ||
479 | r#####" | ||
480 | fn main() { | ||
481 | r"Hello, World!"; | ||
482 | } | ||
483 | "#####, | ||
484 | ) | ||
485 | } | ||
486 | |||
487 | #[test] | ||
488 | fn doctest_replace_if_let_with_match() { | ||
489 | check( | ||
490 | "replace_if_let_with_match", | ||
491 | r#####" | ||
492 | enum Action { Move { distance: u32 }, Stop } | ||
493 | |||
494 | fn handle(action: Action) { | ||
495 | <|>if let Action::Move { distance } = action { | ||
496 | foo(distance) | ||
497 | } else { | ||
498 | bar() | ||
499 | } | ||
500 | } | ||
501 | "#####, | ||
502 | r#####" | ||
503 | enum Action { Move { distance: u32 }, Stop } | ||
504 | |||
505 | fn handle(action: Action) { | ||
506 | match action { | ||
507 | Action::Move { distance } => foo(distance), | ||
508 | _ => bar(), | ||
509 | } | ||
510 | } | ||
511 | "#####, | ||
512 | ) | ||
513 | } | ||
514 | |||
515 | #[test] | ||
516 | fn doctest_split_import() { | ||
517 | check( | ||
518 | "split_import", | ||
519 | r#####" | ||
520 | use std::<|>collections::HashMap; | ||
521 | "#####, | ||
522 | r#####" | ||
523 | use 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 | ||
8 | mod assist_ctx; | 8 | mod assist_ctx; |
9 | mod marks; | 9 | mod marks; |
10 | #[cfg(test)] | ||
11 | mod doc_tests; | ||
10 | 12 | ||
11 | use hir::db::HirDatabase; | 13 | use hir::db::HirDatabase; |
12 | use itertools::Itertools; | ||
13 | use ra_db::FileRange; | 14 | use ra_db::FileRange; |
14 | use ra_syntax::{TextRange, TextUnit}; | 15 | use ra_syntax::{TextRange, TextUnit}; |
15 | use ra_text_edit::TextEdit; | 16 | use ra_text_edit::TextEdit; |
16 | 17 | ||
17 | pub(crate) use crate::assist_ctx::{Assist, AssistCtx}; | 18 | pub(crate) use crate::assist_ctx::{Assist, AssistCtx}; |
18 | pub use crate::assists::auto_import::auto_import_text_edit; | 19 | pub 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" } | |||
19 | ra_db = { path = "../ra_db" } | 19 | ra_db = { path = "../ra_db" } |
20 | mbe = { path = "../ra_mbe", package = "ra_mbe" } | 20 | mbe = { path = "../ra_mbe", package = "ra_mbe" } |
21 | tt = { path = "../ra_tt", package = "ra_tt" } | 21 | tt = { path = "../ra_tt", package = "ra_tt" } |
22 | hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" } | ||
23 | hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } | ||
22 | test_utils = { path = "../test_utils" } | 24 | test_utils = { path = "../test_utils" } |
23 | ra_prof = { path = "../ra_prof" } | 25 | ra_prof = { path = "../ra_prof" } |
24 | 26 | ||
25 | chalk-solve = { git = "https://github.com/rust-lang/chalk.git" } | 27 | chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" } |
26 | chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git" } | 28 | chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" } |
27 | chalk-ir = { git = "https://github.com/rust-lang/chalk.git" } | 29 | chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" } |
28 | lalrpop-intern = "0.15.1" | 30 | lalrpop-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 | ||
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | 5 | ||
6 | use hir_def::{type_ref::TypeRef, LocalEnumVariantId}; | ||
7 | use hir_expand::name::AsName; | ||
6 | use ra_arena::{impl_arena_id, Arena, RawId}; | 8 | use ra_arena::{impl_arena_id, Arena, RawId}; |
7 | use ra_syntax::ast::{self, NameOwner, StructKind, TypeAscriptionOwner}; | 9 | use ra_syntax::ast::{self, NameOwner, StructKind, TypeAscriptionOwner}; |
8 | 10 | ||
9 | use crate::{ | 11 | use 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 | ||
15 | impl Struct { | 16 | impl Struct { |
@@ -67,7 +68,7 @@ impl EnumVariant { | |||
67 | #[derive(Debug, Clone, PartialEq, Eq)] | 68 | #[derive(Debug, Clone, PartialEq, Eq)] |
68 | pub struct EnumData { | 69 | pub 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 | ||
73 | impl EnumData { | 74 | impl EnumData { |
@@ -84,10 +85,6 @@ impl EnumData { | |||
84 | } | 85 | } |
85 | } | 86 | } |
86 | 87 | ||
87 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
88 | pub(crate) struct EnumVariantId(RawId); | ||
89 | impl_arena_id!(EnumVariantId); | ||
90 | |||
91 | #[derive(Debug, Clone, PartialEq, Eq)] | 88 | #[derive(Debug, Clone, PartialEq, Eq)] |
92 | pub(crate) struct EnumVariantData { | 89 | pub(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 | ||
6 | use std::sync::Arc; | 6 | use std::sync::Arc; |
7 | 7 | ||
8 | use ra_db::{CrateId, Edition, FileId}; | 8 | use hir_def::{ |
9 | builtin_type::BuiltinType, | ||
10 | type_ref::{Mutability, TypeRef}, | ||
11 | CrateModuleId, LocalEnumVariantId, ModuleId, | ||
12 | }; | ||
13 | use hir_expand::name::{self, AsName}; | ||
14 | use ra_db::{CrateId, Edition}; | ||
9 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; | 15 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; |
10 | 16 | ||
11 | use crate::{ | 17 | use 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)] |
85 | pub struct Module { | 81 | pub 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)] | ||
91 | pub enum BuiltinType { | ||
92 | Char, | ||
93 | Bool, | ||
94 | Str, | ||
95 | Int(IntTy), | ||
96 | Float(FloatTy), | ||
97 | } | ||
98 | |||
99 | impl 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 | ||
151 | pub enum ModuleSource { | 111 | pub use hir_def::ModuleSource; |
152 | SourceFile(ast::SourceFile), | ||
153 | Module(ast::Module), | ||
154 | } | ||
155 | 112 | ||
156 | impl ModuleSource { | 113 | impl 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 | ||
177 | impl 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 | ||
341 | impl Struct { | 281 | impl 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 | ||
429 | impl Enum { | 369 | impl 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)] |
471 | pub struct EnumVariant { | 411 | pub 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 | ||
476 | impl EnumVariant { | 416 | impl 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 | ||
693 | impl Function { | 635 | impl 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 | ||
771 | impl Const { | 713 | impl 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 | ||
868 | impl Static { | 810 | impl 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 | ||
897 | impl Trait { | 839 | impl 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 | ||
999 | impl TypeAlias { | 939 | impl 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 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::ast::{self, AstNode}; |
4 | ast::{self, AstNode}, | ||
5 | SyntaxNode, | ||
6 | }; | ||
7 | 4 | ||
8 | use crate::{ | 5 | use 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)] | 12 | pub use hir_def::Source; |
16 | pub struct Source<T> { | ||
17 | pub file_id: HirFileId, | ||
18 | pub ast: T, | ||
19 | } | ||
20 | 13 | ||
21 | pub trait HasSource { | 14 | pub 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 | ||
26 | impl<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. |
37 | impl Module { | 21 | impl 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 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use ra_db::{salsa, SourceDatabase}; | 5 | use ra_db::salsa; |
6 | use ra_syntax::{ast, Parse, SmolStr, SyntaxNode}; | 6 | use ra_syntax::SmolStr; |
7 | 7 | ||
8 | use crate::{ | 8 | use 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. | 26 | pub 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. | 30 | pub use hir_expand::db::{ |
32 | #[salsa::query_group(InternDatabaseStorage)] | 31 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, |
33 | pub 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)] | ||
61 | pub 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)] |
89 | pub trait DefDatabase: InternDatabase + HirDebugDatabase { | 38 | pub 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 | ||
39 | impl 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 | |||
45 | pub trait HirDebugHelper: HirDatabase { | 39 | pub 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 | ||
7 | use std::{ops::Index, sync::Arc}; | 7 | use std::{ops::Index, sync::Arc}; |
8 | 8 | ||
9 | use hir_def::{ | ||
10 | path::GenericArgs, | ||
11 | type_ref::{Mutability, TypeRef}, | ||
12 | }; | ||
9 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | 13 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; |
10 | use ra_syntax::{ast, AstPtr}; | 14 | use ra_syntax::{ast, AstPtr}; |
11 | use rustc_hash::FxHashMap; | 15 | use rustc_hash::FxHashMap; |
12 | 16 | ||
13 | use crate::{ | 17 | use 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 | ||
3 | use hir_def::{path::GenericArgs, type_ref::TypeRef}; | ||
4 | use hir_expand::{ | ||
5 | hygiene::Hygiene, | ||
6 | name::{self, AsName, Name}, | ||
7 | }; | ||
3 | use ra_arena::Arena; | 8 | use ra_arena::Arena; |
4 | use ra_syntax::{ | 9 | use ra_syntax::{ |
5 | ast::{ | 10 | ast::{ |
@@ -12,11 +17,8 @@ use test_utils::tested_by; | |||
12 | 17 | ||
13 | use crate::{ | 18 | use 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 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_def::path::known; | ||
5 | use ra_syntax::ast; | 6 | use ra_syntax::ast; |
6 | use rustc_hash::FxHashSet; | 7 | use 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 | ||
3 | use ra_db::{FileId, FilePosition}; | 3 | use hir_expand::name::AsName; |
4 | use ra_syntax::{ | 4 | use ra_syntax::ast::{self, AstNode, NameOwner}; |
5 | algo::find_node_at_offset, | ||
6 | ast::{self, AstNode, NameOwner}, | ||
7 | SyntaxNode, | ||
8 | }; | ||
9 | 5 | ||
10 | use crate::{ | 6 | use 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 | ||
133 | impl 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 | |||
167 | impl Module { | 127 | impl 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 | ||
6 | use std::sync::Arc; | 6 | use std::sync::Arc; |
7 | 7 | ||
8 | use hir_def::{ | ||
9 | path::Path, | ||
10 | type_ref::{TypeBound, TypeRef}, | ||
11 | }; | ||
12 | use hir_expand::name::{self, AsName}; | ||
8 | use ra_syntax::ast::{self, DefaultTypeParamOwner, NameOwner, TypeBoundsOwner, TypeParamsOwner}; | 13 | use ra_syntax::ast::{self, DefaultTypeParamOwner, NameOwner, TypeBoundsOwner, TypeParamsOwner}; |
9 | 14 | ||
10 | use crate::{ | 15 | use 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 | |
3 | use 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 | ||
8 | use mbe::MacroRules; | 8 | use ra_db::salsa; |
9 | use ra_db::{salsa, FileId}; | 9 | |
10 | use ra_prof::profile; | 10 | pub use hir_def::{ |
11 | use ra_syntax::{ast, AstNode, Parse, SyntaxNode}; | 11 | AstItemDef, ConstId, EnumId, FunctionId, ItemLoc, LocationCtx, StaticId, StructId, TraitId, |
12 | 12 | TypeAliasId, | |
13 | use crate::{ | ||
14 | db::{AstDatabase, DefDatabase, InternDatabase}, | ||
15 | AstId, Crate, FileAstId, Module, Source, | ||
16 | }; | 13 | }; |
17 | 14 | pub 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)] | ||
38 | pub struct HirFileId(HirFileIdRepr); | ||
39 | |||
40 | impl 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)] | ||
99 | enum HirFileIdRepr { | ||
100 | File(FileId), | ||
101 | Macro(MacroFile), | ||
102 | } | ||
103 | |||
104 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
105 | pub struct MacroFile { | ||
106 | macro_call_id: MacroCallId, | ||
107 | macro_file_kind: MacroFileKind, | ||
108 | } | ||
109 | |||
110 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
111 | pub(crate) enum MacroFileKind { | ||
112 | Items, | ||
113 | Expr, | ||
114 | } | ||
115 | |||
116 | impl 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)] | ||
123 | pub struct MacroDefId { | ||
124 | pub(crate) ast_id: AstId<ast::MacroCall>, | ||
125 | pub(crate) krate: Crate, | ||
126 | } | ||
127 | |||
128 | pub(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 | |||
142 | pub(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 | |||
150 | pub(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(¯o_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 | ||
167 | macro_rules! impl_intern_key { | 16 | macro_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)] | ||
183 | pub struct MacroCallId(salsa::InternId); | ||
184 | impl_intern_key!(MacroCallId); | ||
185 | |||
186 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
187 | pub struct MacroCallLoc { | ||
188 | pub(crate) def: MacroDefId, | ||
189 | pub(crate) ast_id: AstId<ast::MacroCall>, | ||
190 | } | ||
191 | |||
192 | impl 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 | |||
203 | impl MacroCallLoc { | ||
204 | pub(crate) fn id(self, db: &impl InternDatabase) -> MacroCallId { | ||
205 | db.intern_macro(self) | ||
206 | } | ||
207 | } | ||
208 | |||
209 | #[derive(Debug)] | ||
210 | pub struct ItemLoc<N: AstNode> { | ||
211 | pub(crate) module: Module, | ||
212 | ast_id: AstId<N>, | ||
213 | } | ||
214 | |||
215 | impl<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 | } | ||
220 | impl<N: AstNode> Eq for ItemLoc<N> {} | ||
221 | impl<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 | |||
228 | impl<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)] | ||
235 | pub(crate) struct LocationCtx<DB> { | ||
236 | db: DB, | ||
237 | module: Module, | ||
238 | file_id: HirFileId, | ||
239 | } | ||
240 | |||
241 | impl<'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 | |||
247 | impl<'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 | |||
257 | pub(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)] | ||
282 | pub struct FunctionId(salsa::InternId); | ||
283 | impl_intern_key!(FunctionId); | ||
284 | |||
285 | impl 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)] | ||
295 | pub struct StructId(salsa::InternId); | ||
296 | impl_intern_key!(StructId); | ||
297 | impl 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)] | ||
307 | pub struct EnumId(salsa::InternId); | ||
308 | impl_intern_key!(EnumId); | ||
309 | impl 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)] | ||
319 | pub struct ConstId(salsa::InternId); | ||
320 | impl_intern_key!(ConstId); | ||
321 | impl 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)] | ||
331 | pub struct StaticId(salsa::InternId); | ||
332 | impl_intern_key!(StaticId); | ||
333 | impl 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)] | ||
343 | pub struct TraitId(salsa::InternId); | ||
344 | impl_intern_key!(TraitId); | ||
345 | impl 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)] | ||
355 | pub struct TypeAliasId(salsa::InternId); | ||
356 | impl_intern_key!(TypeAliasId); | ||
357 | impl 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 @@ | |||
3 | use rustc_hash::FxHashMap; | 3 | use rustc_hash::FxHashMap; |
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | 5 | ||
6 | use hir_def::{attr::Attr, type_ref::TypeRef}; | ||
7 | use hir_expand::hygiene::Hygiene; | ||
6 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | 8 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; |
7 | use ra_cfg::CfgOptions; | 9 | use ra_cfg::CfgOptions; |
8 | use ra_syntax::{ | 10 | use ra_syntax::{ |
@@ -11,7 +13,6 @@ use ra_syntax::{ | |||
11 | }; | 13 | }; |
12 | 14 | ||
13 | use crate::{ | 15 | use 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, ¯o_call, db); | 252 | let attrs = Attr::from_attrs_owner(¯o_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(¯o_call).with_file_id(file_id); | 260 | let ast_id = AstId::new(file_id, db.ast_id_map(file_id).ast_id(¯o_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 | ||
23 | impl LangItemTarget { | 23 | impl 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 | ||
29 | mod either; | ||
30 | pub mod debug; | 29 | pub mod debug; |
31 | 30 | ||
32 | pub mod db; | 31 | pub mod db; |
33 | #[macro_use] | 32 | #[macro_use] |
34 | pub mod mock; | 33 | pub mod mock; |
35 | mod path; | ||
36 | pub mod source_binder; | 34 | pub mod source_binder; |
37 | 35 | ||
38 | mod source_id; | ||
39 | mod ids; | 36 | mod ids; |
40 | mod name; | ||
41 | mod nameres; | 37 | mod nameres; |
42 | mod adt; | 38 | mod adt; |
43 | mod traits; | 39 | mod traits; |
44 | mod type_alias; | 40 | mod type_alias; |
45 | mod type_ref; | ||
46 | mod ty; | 41 | mod ty; |
47 | mod attr; | ||
48 | mod impl_block; | 42 | mod impl_block; |
49 | mod expr; | 43 | mod expr; |
50 | mod lang_item; | 44 | mod lang_item; |
@@ -60,37 +54,35 @@ pub mod from_source; | |||
60 | #[cfg(test)] | 54 | #[cfg(test)] |
61 | mod marks; | 55 | mod marks; |
62 | 56 | ||
63 | use crate::{ | 57 | use hir_expand::AstId; |
64 | ids::MacroFileKind, | 58 | |
65 | name::AsName, | 59 | use crate::{ids::MacroFileKind, resolve::Resolver}; |
66 | resolve::Resolver, | ||
67 | source_id::{AstId, FileAstId}, | ||
68 | }; | ||
69 | 60 | ||
70 | pub use self::{ | 61 | pub 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 | ||
90 | pub use self::code_model::{ | 83 | pub 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 | }; |
88 | pub 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 | ||
3 | test_utils::marks!( | 3 | test_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 | ||
50 | mod per_ns; | 50 | mod per_ns; |
51 | mod raw; | ||
52 | mod collector; | 51 | mod collector; |
53 | mod mod_resolution; | ||
54 | #[cfg(test)] | 52 | #[cfg(test)] |
55 | mod tests; | 53 | mod tests; |
56 | 54 | ||
57 | use std::sync::Arc; | 55 | use std::sync::Arc; |
58 | 56 | ||
57 | use hir_def::{builtin_type::BuiltinType, CrateModuleId}; | ||
59 | use once_cell::sync::Lazy; | 58 | use once_cell::sync::Lazy; |
60 | use ra_arena::{impl_arena_id, Arena, RawId}; | 59 | use ra_arena::Arena; |
61 | use ra_db::{Edition, FileId}; | 60 | use ra_db::{Edition, FileId}; |
62 | use ra_prof::profile; | 61 | use ra_prof::profile; |
63 | use ra_syntax::ast; | 62 | use 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 | ||
76 | pub(crate) use self::raw::{ImportSourceMap, RawItems}; | 74 | pub use self::per_ns::{Namespace, PerNs}; |
77 | 75 | ||
78 | pub use self::{ | 76 | pub 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)] | ||
120 | pub(crate) struct CrateModuleId(RawId); | ||
121 | impl_arena_id!(CrateModuleId); | ||
122 | |||
123 | #[derive(Default, Debug, PartialEq, Eq)] | 113 | #[derive(Default, Debug, PartialEq, Eq)] |
124 | pub(crate) struct ModuleData { | 114 | pub 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 | ||
3 | use hir_def::{ | ||
4 | attr::Attr, | ||
5 | nameres::{mod_resolution::ModDir, raw}, | ||
6 | }; | ||
7 | use hir_expand::name; | ||
3 | use ra_cfg::CfgOptions; | 8 | use ra_cfg::CfgOptions; |
4 | use ra_db::FileId; | 9 | use ra_db::FileId; |
5 | use ra_syntax::{ast, SmolStr}; | 10 | use ra_syntax::{ast, SmolStr}; |
@@ -7,13 +12,11 @@ use rustc_hash::FxHashMap; | |||
7 | use test_utils::tested_by; | 12 | use test_utils::tested_by; |
8 | 13 | ||
9 | use crate::{ | 14 | use 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 | ||
730 | fn is_macro_rules(path: &Path) -> bool { | 730 | fn 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] |
4 | fn name_res_works_for_broken_modules() { | 4 | fn 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. |
2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use hir_def::{ | ||
5 | builtin_type::BuiltinType, | ||
6 | path::{Path, PathKind}, | ||
7 | CrateModuleId, | ||
8 | }; | ||
9 | use hir_expand::name::{self, Name}; | ||
4 | use rustc_hash::FxHashSet; | 10 | use rustc_hash::FxHashSet; |
5 | 11 | ||
6 | use crate::{ | 12 | use 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". |
8 | use std::sync::Arc; | 8 | use std::sync::Arc; |
9 | 9 | ||
10 | use hir_def::path::known; | ||
11 | use hir_expand::name::AsName; | ||
10 | use ra_db::FileId; | 12 | use ra_db::FileId; |
11 | use ra_syntax::{ | 13 | use 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 | ||
34 | fn try_get_resolver_for_node( | 35 | fn 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 | ||
3 | use rustc_hash::FxHashMap; | ||
4 | use std::sync::Arc; | 3 | use std::sync::Arc; |
5 | 4 | ||
5 | use hir_expand::name::AsName; | ||
6 | |||
6 | use ra_syntax::ast::{self, NameOwner}; | 7 | use ra_syntax::ast::{self, NameOwner}; |
8 | use rustc_hash::FxHashMap; | ||
7 | 9 | ||
8 | use crate::{ | 10 | use 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; | |||
17 | use std::{fmt, iter, mem}; | 17 | use std::{fmt, iter, mem}; |
18 | 18 | ||
19 | use crate::{ | 19 | use 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 | }; |
23 | use display::{HirDisplay, HirFormatter}; | 23 | use 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 | ||
6 | use std::iter::successors; | 6 | use std::iter::successors; |
7 | 7 | ||
8 | use hir_expand::name; | ||
8 | use log::{info, warn}; | 9 | use log::{info, warn}; |
9 | 10 | ||
10 | use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk}; | 11 | use super::{traits::Solution, Canonical, Substs, Ty, TypeWalk}; |
11 | use crate::{db::HirDatabase, name, HasGenericParams, Resolver}; | 12 | use crate::{db::HirDatabase, HasGenericParams, Resolver}; |
12 | 13 | ||
13 | const AUTODEREF_RECURSION_LIMIT: usize = 10; | 14 | const 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; | |||
21 | use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; | 21 | use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; |
22 | use rustc_hash::FxHashMap; | 22 | use rustc_hash::FxHashMap; |
23 | 23 | ||
24 | use hir_def::{ | ||
25 | path::known, | ||
26 | type_ref::{Mutability, TypeRef}, | ||
27 | }; | ||
28 | use hir_expand::name; | ||
24 | use ra_arena::map::ArenaMap; | 29 | use ra_arena::map::ArenaMap; |
25 | use ra_prof::profile; | 30 | use ra_prof::profile; |
26 | use test_utils::tested_by; | 31 | use 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 | ||
21 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 20 | impl<'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 @@ | |||
3 | use std::iter::{repeat, repeat_with}; | 3 | use std::iter::{repeat, repeat_with}; |
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | 5 | ||
6 | use hir_def::path::{GenericArg, GenericArgs}; | ||
7 | use hir_expand::name; | ||
8 | |||
6 | use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; | 9 | use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; |
7 | use crate::{ | 10 | use 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 | ||
3 | use hir_def::path::PathSegment; | ||
4 | |||
3 | use super::{ExprOrPatId, InferenceContext, TraitRef}; | 5 | use super::{ExprOrPatId, InferenceContext, TraitRef}; |
4 | use crate::{ | 6 | use 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 @@ | |||
8 | use std::iter; | 8 | use std::iter; |
9 | use std::sync::Arc; | 9 | use std::sync::Arc; |
10 | 10 | ||
11 | use hir_def::{ | ||
12 | builtin_type::BuiltinType, | ||
13 | path::{GenericArg, PathSegment}, | ||
14 | type_ref::{TypeBound, TypeRef}, | ||
15 | }; | ||
16 | |||
11 | use super::{ | 17 | use 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 | ||
30 | impl Ty { | 37 | impl 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 @@ | |||
5 | use std::sync::Arc; | 5 | use std::sync::Arc; |
6 | 6 | ||
7 | use arrayvec::ArrayVec; | 7 | use arrayvec::ArrayVec; |
8 | use hir_def::CrateModuleId; | ||
8 | use rustc_hash::FxHashMap; | 9 | use rustc_hash::FxHashMap; |
9 | 10 | ||
10 | use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; | 11 | use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; |
11 | use crate::{ | 12 | use 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 | ||
3 | use std::fmt; | 3 | use std::fmt; |
4 | 4 | ||
5 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | 5 | pub use hir_def::builtin_type::{FloatBitness, IntBitness, Signedness}; |
6 | pub enum Signedness { | ||
7 | Signed, | ||
8 | Unsigned, | ||
9 | } | ||
10 | |||
11 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
12 | pub enum IntBitness { | ||
13 | Xsize, | ||
14 | X8, | ||
15 | X16, | ||
16 | X32, | ||
17 | X64, | ||
18 | X128, | ||
19 | } | ||
20 | |||
21 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
22 | pub 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)] |
28 | pub enum UncertainIntTy { | 8 | pub 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. |
2 | use std::sync::{Arc, Mutex}; | 2 | use std::sync::{Arc, Mutex}; |
3 | 3 | ||
4 | use chalk_ir::cast::Cast; | 4 | use chalk_ir::{cast::Cast, family::ChalkIr}; |
5 | use log::debug; | 5 | use log::debug; |
6 | use ra_db::salsa; | 6 | use ra_db::salsa; |
7 | use ra_prof::profile; | 7 | use 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 | ||
198 | fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution { | 198 | fn 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; | |||
4 | use log::debug; | 4 | use log::debug; |
5 | 5 | ||
6 | use chalk_ir::{ | 6 | use 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 | }; |
10 | use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; | 10 | use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum}; |
11 | 11 | ||
12 | use hir_expand::name; | ||
13 | |||
12 | use ra_db::salsa::{InternId, InternKey}; | 14 | use ra_db::salsa::{InternId, InternKey}; |
13 | 15 | ||
14 | use super::{Canonical, ChalkContext, Impl, Obligation}; | 16 | use super::{Canonical, ChalkContext, Impl, Obligation}; |
@@ -38,8 +40,8 @@ where | |||
38 | } | 40 | } |
39 | 41 | ||
40 | impl ToChalk for Ty { | 42 | impl 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 | ||
115 | impl ToChalk for Substs { | 128 | impl 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 | ||
134 | impl ToChalk for TraitRef { | 147 | impl 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 | ||
198 | impl ToChalk for GenericPredicate { | 211 | impl 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 | ||
232 | impl ToChalk for ProjectionTy { | 257 | impl 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 | ||
250 | impl ToChalk for super::ProjectionPredicate { | 278 | impl 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 | ||
265 | impl ToChalk for Obligation { | 293 | impl 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 | ||
298 | impl ToChalk for Arc<super::TraitEnvironment> { | 326 | impl 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 | ||
322 | impl<T: ToChalk> ToChalk for super::InEnvironment<T> { | 350 | impl<T: ToChalk> ToChalk for super::InEnvironment<T> |
351 | where | ||
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 | ||
749 | impl 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 | |||
755 | impl 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 | |||
761 | impl 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 | |||
767 | impl 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 | |||
773 | impl From<chalk_ir::StructId> for crate::ids::TypeCtorId { | 780 | impl 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 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_def::type_ref::TypeRef; | ||
6 | use hir_expand::name::{AsName, Name}; | ||
7 | |||
5 | use ra_syntax::ast::NameOwner; | 8 | use ra_syntax::ast::NameOwner; |
6 | 9 | ||
7 | use crate::{ | 10 | use 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] | ||
2 | edition = "2018" | ||
3 | name = "ra_hir_def" | ||
4 | version = "0.1.0" | ||
5 | authors = ["rust-analyzer developers"] | ||
6 | |||
7 | [dependencies] | ||
8 | log = "0.4.5" | ||
9 | once_cell = "1.0.1" | ||
10 | relative-path = "1.0.0" | ||
11 | rustc-hash = "1.0" | ||
12 | |||
13 | ra_arena = { path = "../ra_arena" } | ||
14 | ra_db = { path = "../ra_db" } | ||
15 | ra_syntax = { path = "../ra_syntax" } | ||
16 | ra_prof = { path = "../ra_prof" } | ||
17 | hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" } | ||
18 | test_utils = { path = "../test_utils" } | ||
19 | mbe = { path = "../ra_mbe", package = "ra_mbe" } | ||
20 | ra_cfg = { path = "../ra_cfg" } | ||
21 | tt = { 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 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_expand::hygiene::Hygiene; | ||
5 | use mbe::ast_to_token_tree; | 6 | use mbe::ast_to_token_tree; |
6 | use ra_cfg::CfgOptions; | 7 | use ra_cfg::CfgOptions; |
7 | use ra_syntax::{ | 8 | use ra_syntax::{ |
@@ -10,10 +11,10 @@ use ra_syntax::{ | |||
10 | }; | 11 | }; |
11 | use tt::Subtree; | 12 | use tt::Subtree; |
12 | 13 | ||
13 | use crate::{db::AstDatabase, path::Path, HirFileId, Source}; | 14 | use crate::path::Path; |
14 | 15 | ||
15 | #[derive(Debug, Clone, PartialEq, Eq)] | 16 | #[derive(Debug, Clone, PartialEq, Eq)] |
16 | pub(crate) struct Attr { | 17 | pub 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 | ||
27 | impl Attr { | 28 | impl 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 | |||
6 | use hir_expand::name::{self, Name}; | ||
7 | |||
8 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
9 | pub enum Signedness { | ||
10 | Signed, | ||
11 | Unsigned, | ||
12 | } | ||
13 | |||
14 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
15 | pub enum IntBitness { | ||
16 | Xsize, | ||
17 | X8, | ||
18 | X16, | ||
19 | X32, | ||
20 | X64, | ||
21 | X128, | ||
22 | } | ||
23 | |||
24 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] | ||
25 | pub enum FloatBitness { | ||
26 | X32, | ||
27 | X64, | ||
28 | } | ||
29 | |||
30 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
31 | pub enum BuiltinType { | ||
32 | Char, | ||
33 | Bool, | ||
34 | Str, | ||
35 | Int { signedness: Signedness, bitness: IntBitness }, | ||
36 | Float { bitness: FloatBitness }, | ||
37 | } | ||
38 | |||
39 | impl 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. | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use hir_expand::{db::AstDatabase, HirFileId}; | ||
5 | use ra_db::{salsa, SourceDatabase}; | ||
6 | use ra_syntax::ast; | ||
7 | |||
8 | use crate::nameres::raw::{ImportSourceMap, RawItems}; | ||
9 | |||
10 | #[salsa::query_group(InternDatabaseStorage)] | ||
11 | pub 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)] | ||
31 | pub 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 | |||
10 | pub mod db; | ||
11 | pub mod attr; | ||
12 | pub mod path; | ||
13 | pub mod type_ref; | ||
14 | pub mod builtin_type; | ||
15 | |||
16 | // FIXME: this should be private | ||
17 | pub mod nameres; | ||
18 | |||
19 | use std::hash::{Hash, Hasher}; | ||
20 | |||
21 | use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId}; | ||
22 | use ra_arena::{impl_arena_id, RawId}; | ||
23 | use ra_db::{salsa, CrateId, FileId}; | ||
24 | use ra_syntax::{ast, AstNode, SyntaxNode}; | ||
25 | |||
26 | use crate::{builtin_type::BuiltinType, db::InternDatabase}; | ||
27 | |||
28 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | ||
29 | pub struct Source<T> { | ||
30 | pub file_id: HirFileId, | ||
31 | pub ast: T, | ||
32 | } | ||
33 | |||
34 | pub enum ModuleSource { | ||
35 | SourceFile(ast::SourceFile), | ||
36 | Module(ast::Module), | ||
37 | } | ||
38 | |||
39 | impl 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 | |||
96 | impl<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)] | ||
106 | pub 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)] | ||
114 | pub struct CrateModuleId(RawId); | ||
115 | impl_arena_id!(CrateModuleId); | ||
116 | |||
117 | macro_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)] | ||
131 | pub struct ItemLoc<N: AstNode> { | ||
132 | pub(crate) module: ModuleId, | ||
133 | ast_id: AstId<N>, | ||
134 | } | ||
135 | |||
136 | impl<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 | } | ||
141 | impl<N: AstNode> Eq for ItemLoc<N> {} | ||
142 | impl<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 | |||
149 | impl<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)] | ||
156 | pub struct LocationCtx<DB> { | ||
157 | db: DB, | ||
158 | module: ModuleId, | ||
159 | file_id: HirFileId, | ||
160 | } | ||
161 | |||
162 | impl<'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 | |||
168 | impl<'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 | |||
178 | pub 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)] | ||
203 | pub struct FunctionId(salsa::InternId); | ||
204 | impl_intern_key!(FunctionId); | ||
205 | |||
206 | impl 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)] | ||
216 | pub struct StructId(salsa::InternId); | ||
217 | impl_intern_key!(StructId); | ||
218 | impl 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)] | ||
228 | pub struct UnionId(salsa::InternId); | ||
229 | impl_intern_key!(UnionId); | ||
230 | impl 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)] | ||
240 | pub struct EnumId(salsa::InternId); | ||
241 | impl_intern_key!(EnumId); | ||
242 | impl 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)] | ||
253 | pub struct EnumVariantId { | ||
254 | parent: EnumId, | ||
255 | local_id: LocalEnumVariantId, | ||
256 | } | ||
257 | |||
258 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
259 | pub struct LocalEnumVariantId(RawId); | ||
260 | impl_arena_id!(LocalEnumVariantId); | ||
261 | |||
262 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
263 | pub struct ConstId(salsa::InternId); | ||
264 | impl_intern_key!(ConstId); | ||
265 | impl 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)] | ||
275 | pub struct StaticId(salsa::InternId); | ||
276 | impl_intern_key!(StaticId); | ||
277 | impl 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)] | ||
287 | pub struct TraitId(salsa::InternId); | ||
288 | impl_intern_key!(TraitId); | ||
289 | impl 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)] | ||
299 | pub struct TypeAliasId(salsa::InternId); | ||
300 | impl_intern_key!(TypeAliasId); | ||
301 | impl 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 | |||
310 | macro_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)] | ||
331 | pub enum AdtId { | ||
332 | StructId(StructId), | ||
333 | UnionId(UnionId), | ||
334 | EnumId(EnumId), | ||
335 | } | ||
336 | impl_froms!(AdtId: StructId, UnionId, EnumId); | ||
337 | |||
338 | /// The defs which can be visible in the module. | ||
339 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
340 | pub 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 | } | ||
352 | impl_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 | ||
4 | pub mod raw; | ||
5 | pub 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. |
2 | use hir_expand::name::Name; | ||
2 | use ra_db::FileId; | 3 | use ra_db::FileId; |
3 | use ra_syntax::SmolStr; | 4 | use ra_syntax::SmolStr; |
4 | use relative_path::RelativePathBuf; | 5 | use relative_path::RelativePathBuf; |
5 | 6 | ||
6 | use crate::{db::DefDatabase, HirFileId, Name}; | 7 | use crate::{db::DefDatabase2, HirFileId}; |
7 | 8 | ||
8 | #[derive(Clone, Debug)] | 9 | #[derive(Clone, Debug)] |
9 | pub(super) struct ModDir { | 10 | pub 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 | ||
18 | impl ModDir { | 19 | impl 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 | ||
3 | use std::{ops::Index, sync::Arc}; | 3 | use std::{ops::Index, sync::Arc}; |
4 | 4 | ||
5 | use hir_expand::{ | ||
6 | ast_id_map::AstIdMap, | ||
7 | db::AstDatabase, | ||
8 | either::Either, | ||
9 | hygiene::Hygiene, | ||
10 | name::{AsName, Name}, | ||
11 | }; | ||
5 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | 12 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; |
6 | use ra_syntax::{ | 13 | use ra_syntax::{ |
7 | ast::{self, AttrsOwner, NameOwner}, | 14 | ast::{self, AttrsOwner, NameOwner}, |
8 | AstNode, AstPtr, SourceFile, | 15 | AstNode, AstPtr, SourceFile, |
9 | }; | 16 | }; |
10 | use test_utils::tested_by; | ||
11 | 17 | ||
12 | use crate::{ | 18 | use 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 { | |||
37 | type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>; | 39 | type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>; |