aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/lib.rs5
-rw-r--r--crates/ra_assists/src/raw_string.rs370
-rw-r--r--crates/ra_hir/src/code_model.rs2
-rw-r--r--crates/ra_hir/src/from_source.rs211
-rw-r--r--crates/ra_hir/src/lib.rs3
-rw-r--r--crates/ra_hir/src/mock.rs6
-rw-r--r--crates/ra_hir/src/nameres/tests/incremental.rs12
-rw-r--r--crates/ra_hir/src/source_binder.rs124
-rw-r--r--crates/ra_ide_api/src/completion/completion_context.rs7
-rw-r--r--crates/ra_ide_api/src/diagnostics.rs10
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs5
-rw-r--r--crates/ra_ide_api/src/impls.rs25
-rw-r--r--crates/ra_ide_api/src/lib.rs10
-rw-r--r--crates/ra_ide_api/src/parent_module.rs16
-rw-r--r--crates/ra_ide_api/src/references.rs7
-rw-r--r--crates/ra_ide_api/src/runnables.rs4
-rw-r--r--crates/ra_parser/src/grammar.rs14
-rw-r--r--crates/ra_parser/src/grammar/attributes.rs4
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs20
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs32
-rw-r--r--crates/ra_parser/src/grammar/items.rs18
-rw-r--r--crates/ra_parser/src/grammar/items/consts.rs2
-rw-r--r--crates/ra_parser/src/grammar/items/nominal.rs12
-rw-r--r--crates/ra_parser/src/grammar/items/traits.rs8
-rw-r--r--crates/ra_parser/src/grammar/items/use_item.rs6
-rw-r--r--crates/ra_parser/src/grammar/params.rs2
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs14
-rw-r--r--crates/ra_parser/src/grammar/type_args.rs2
-rw-r--r--crates/ra_parser/src/grammar/type_params.rs18
-rw-r--r--crates/ra_parser/src/grammar/types.rs22
-rw-r--r--docs/user/features.md56
31 files changed, 821 insertions, 226 deletions
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 66cf32524..756acf415 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -96,6 +96,7 @@ mod fill_match_arms;
96mod merge_match_arms; 96mod merge_match_arms;
97mod introduce_variable; 97mod introduce_variable;
98mod inline_local_variable; 98mod inline_local_variable;
99mod raw_string;
99mod replace_if_let_with_match; 100mod replace_if_let_with_match;
100mod split_import; 101mod split_import;
101mod remove_dbg; 102mod remove_dbg;
@@ -125,6 +126,10 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis
125 move_guard::move_guard_to_arm_body, 126 move_guard::move_guard_to_arm_body,
126 move_guard::move_arm_cond_to_match_guard, 127 move_guard::move_arm_cond_to_match_guard,
127 move_bounds::move_bounds_to_where_clause, 128 move_bounds::move_bounds_to_where_clause,
129 raw_string::add_hash,
130 raw_string::make_raw_string,
131 raw_string::make_usual_string,
132 raw_string::remove_hash,
128 ] 133 ]
129} 134}
130 135
diff --git a/crates/ra_assists/src/raw_string.rs b/crates/ra_assists/src/raw_string.rs
new file mode 100644
index 000000000..e00267060
--- /dev/null
+++ b/crates/ra_assists/src/raw_string.rs
@@ -0,0 +1,370 @@
1use hir::db::HirDatabase;
2use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit};
3
4use crate::{Assist, AssistCtx, AssistId};
5
6pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
7 let literal = ctx.node_at_offset::<Literal>()?;
8 if literal.token().kind() != ra_syntax::SyntaxKind::STRING {
9 return None;
10 }
11 ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| {
12 edit.target(literal.syntax().text_range());
13 edit.insert(literal.syntax().text_range().start(), "r");
14 });
15 ctx.build()
16}
17
18fn find_usual_string_range(s: &str) -> Option<TextRange> {
19 Some(TextRange::from_to(
20 TextUnit::from(s.find('"')? as u32),
21 TextUnit::from(s.rfind('"')? as u32),
22 ))
23}
24
25pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
26 let literal = ctx.node_at_offset::<Literal>()?;
27 if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING {
28 return None;
29 }
30 let token = literal.token();
31 let text = token.text().as_str();
32 let usual_string_range = find_usual_string_range(text)?;
33 ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| {
34 edit.target(literal.syntax().text_range());
35 // parse inside string to escape `"`
36 let start_of_inside = usual_string_range.start().to_usize() + 1;
37 let end_of_inside = usual_string_range.end().to_usize();
38 let inside_str = &text[start_of_inside..end_of_inside];
39 let escaped = inside_str.escape_default().to_string();
40 edit.replace(literal.syntax().text_range(), format!("\"{}\"", escaped));
41 });
42 ctx.build()
43}
44
45pub(crate) fn add_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
46 let literal = ctx.node_at_offset::<Literal>()?;
47 if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING {
48 return None;
49 }
50 ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| {
51 edit.target(literal.syntax().text_range());
52 edit.insert(literal.syntax().text_range().start() + TextUnit::of_char('r'), "#");
53 edit.insert(literal.syntax().text_range().end(), "#");
54 });
55 ctx.build()
56}
57
58pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
59 let literal = ctx.node_at_offset::<Literal>()?;
60 if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING {
61 return None;
62 }
63 let token = literal.token();
64 let text = token.text().as_str();
65 if text.starts_with("r\"") {
66 // no hash to remove
67 return None;
68 }
69 ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| {
70 edit.target(literal.syntax().text_range());
71 let result = &text[2..text.len() - 1];
72 let result = if result.starts_with("\"") {
73 // no more hash, escape
74 let internal_str = &result[1..result.len() - 1];
75 format!("\"{}\"", internal_str.escape_default().to_string())
76 } else {
77 result.to_owned()
78 };
79 edit.replace(literal.syntax().text_range(), format!("r{}", result));
80 });
81 ctx.build()
82}
83
84#[cfg(test)]
85mod test {
86 use super::*;
87 use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target};
88
89 #[test]
90 fn make_raw_string_target() {
91 check_assist_target(
92 make_raw_string,
93 r#"
94 fn f() {
95 let s = <|>"random string";
96 }
97 "#,
98 r#""random string""#,
99 );
100 }
101
102 #[test]
103 fn make_raw_string_works() {
104 check_assist(
105 make_raw_string,
106 r#"
107 fn f() {
108 let s = <|>"random string";
109 }
110 "#,
111 r#"
112 fn f() {
113 let s = <|>r"random string";
114 }
115 "#,
116 )
117 }
118
119 #[test]
120 fn make_raw_string_with_escaped_works() {
121 check_assist(
122 make_raw_string,
123 r#"
124 fn f() {
125 let s = <|>"random\nstring";
126 }
127 "#,
128 r#"
129 fn f() {
130 let s = <|>r"random\nstring";
131 }
132 "#,
133 )
134 }
135
136 #[test]
137 fn make_raw_string_not_works() {
138 check_assist_not_applicable(
139 make_raw_string,
140 r#"
141 fn f() {
142 let s = <|>r"random string";
143 }
144 "#,
145 );
146 }
147
148 #[test]
149 fn add_hash_target() {
150 check_assist_target(
151 add_hash,
152 r#"
153 fn f() {
154 let s = <|>r"random string";
155 }
156 "#,
157 r#"r"random string""#,
158 );
159 }
160
161 #[test]
162 fn add_hash_works() {
163 check_assist(
164 add_hash,
165 r#"
166 fn f() {
167 let s = <|>r"random string";
168 }
169 "#,
170 r##"
171 fn f() {
172 let s = <|>r#"random string"#;
173 }
174 "##,
175 )
176 }
177
178 #[test]
179 fn add_more_hash_works() {
180 check_assist(
181 add_hash,
182 r##"
183 fn f() {
184 let s = <|>r#"random"string"#;
185 }
186 "##,
187 r###"
188 fn f() {
189 let s = <|>r##"random"string"##;
190 }
191 "###,
192 )
193 }
194
195 #[test]
196 fn add_hash_not_works() {
197 check_assist_not_applicable(
198 add_hash,
199 r#"
200 fn f() {
201 let s = <|>"random string";
202 }
203 "#,
204 );
205 }
206
207 #[test]
208 fn remove_hash_target() {
209 check_assist_target(
210 remove_hash,
211 r##"
212 fn f() {
213 let s = <|>r#"random string"#;
214 }
215 "##,
216 r##"r#"random string"#"##,
217 );
218 }
219
220 #[test]
221 fn remove_hash_works() {
222 check_assist(
223 remove_hash,
224 r##"
225 fn f() {
226 let s = <|>r#"random string"#;
227 }
228 "##,
229 r#"
230 fn f() {
231 let s = <|>r"random string";
232 }
233 "#,
234 )
235 }
236
237 #[test]
238 fn remove_hash_with_quote_works() {
239 check_assist(
240 remove_hash,
241 r##"
242 fn f() {
243 let s = <|>r#"random"str"ing"#;
244 }
245 "##,
246 r#"
247 fn f() {
248 let s = <|>r"random\"str\"ing";
249 }
250 "#,
251 )
252 }
253
254 #[test]
255 fn remove_more_hash_works() {
256 check_assist(
257 remove_hash,
258 r###"
259 fn f() {
260 let s = <|>r##"random string"##;
261 }
262 "###,
263 r##"
264 fn f() {
265 let s = <|>r#"random string"#;
266 }
267 "##,
268 )
269 }
270
271 #[test]
272 fn remove_hash_not_works() {
273 check_assist_not_applicable(
274 remove_hash,
275 r#"
276 fn f() {
277 let s = <|>"random string";
278 }
279 "#,
280 );
281 }
282
283 #[test]
284 fn remove_hash_no_hash_not_works() {
285 check_assist_not_applicable(
286 remove_hash,
287 r#"
288 fn f() {
289 let s = <|>r"random string";
290 }
291 "#,
292 );
293 }
294
295 #[test]
296 fn make_usual_string_target() {
297 check_assist_target(
298 make_usual_string,
299 r##"
300 fn f() {
301 let s = <|>r#"random string"#;
302 }
303 "##,
304 r##"r#"random string"#"##,
305 );
306 }
307
308 #[test]
309 fn make_usual_string_works() {
310 check_assist(
311 make_usual_string,
312 r##"
313 fn f() {
314 let s = <|>r#"random string"#;
315 }
316 "##,
317 r#"
318 fn f() {
319 let s = <|>"random string";
320 }
321 "#,
322 )
323 }
324
325 #[test]
326 fn make_usual_string_with_quote_works() {
327 check_assist(
328 make_usual_string,
329 r##"
330 fn f() {
331 let s = <|>r#"random"str"ing"#;
332 }
333 "##,
334 r#"
335 fn f() {
336 let s = <|>"random\"str\"ing";
337 }
338 "#,
339 )
340 }
341
342 #[test]
343 fn make_usual_string_more_hash_works() {
344 check_assist(
345 make_usual_string,
346 r###"
347 fn f() {
348 let s = <|>r##"random string"##;
349 }
350 "###,
351 r##"
352 fn f() {
353 let s = <|>"random string";
354 }
355 "##,
356 )
357 }
358
359 #[test]
360 fn make_usual_string_not_works() {
361 check_assist_not_applicable(
362 make_usual_string,
363 r#"
364 fn f() {
365 let s = <|>"random string";
366 }
367 "#,
368 );
369 }
370}
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 706d24c32..28002f740 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -313,7 +313,7 @@ pub struct StructField {
313 pub(crate) id: StructFieldId, 313 pub(crate) id: StructFieldId,
314} 314}
315 315
316#[derive(Debug)] 316#[derive(Debug, PartialEq, Eq)]
317pub enum FieldSource { 317pub enum FieldSource {
318 Named(ast::RecordFieldDef), 318 Named(ast::RecordFieldDef),
319 Pos(ast::TupleFieldDef), 319 Pos(ast::TupleFieldDef),
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
new file mode 100644
index 000000000..c6ad85fc7
--- /dev/null
+++ b/crates/ra_hir/src/from_source.rs
@@ -0,0 +1,211 @@
1use ra_db::{FileId, FilePosition};
2use ra_syntax::{
3 algo::find_node_at_offset,
4 ast::{self, AstNode, NameOwner},
5 SyntaxNode,
6};
7
8use crate::{
9 db::{AstDatabase, DefDatabase, HirDatabase},
10 ids::{AstItemDef, LocationCtx},
11 name::AsName,
12 Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module,
13 ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef,
14};
15
16pub trait FromSource: Sized {
17 type Ast;
18 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self>;
19}
20
21impl FromSource for Struct {
22 type Ast = ast::StructDef;
23 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
24 let id = from_source(db, src)?;
25 Some(Struct { id })
26 }
27}
28impl FromSource for Union {
29 type Ast = ast::StructDef;
30 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
31 let id = from_source(db, src)?;
32 Some(Union { id })
33 }
34}
35impl FromSource for Enum {
36 type Ast = ast::EnumDef;
37 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
38 let id = from_source(db, src)?;
39 Some(Enum { id })
40 }
41}
42impl FromSource for Trait {
43 type Ast = ast::TraitDef;
44 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
45 let id = from_source(db, src)?;
46 Some(Trait { id })
47 }
48}
49impl FromSource for Function {
50 type Ast = ast::FnDef;
51 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
52 let id = from_source(db, src)?;
53 Some(Function { id })
54 }
55}
56impl FromSource for Const {
57 type Ast = ast::ConstDef;
58 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
59 let id = from_source(db, src)?;
60 Some(Const { id })
61 }
62}
63impl FromSource for Static {
64 type Ast = ast::StaticDef;
65 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
66 let id = from_source(db, src)?;
67 Some(Static { id })
68 }
69}
70impl FromSource for TypeAlias {
71 type Ast = ast::TypeAliasDef;
72 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
73 let id = from_source(db, src)?;
74 Some(TypeAlias { id })
75 }
76}
77// FIXME: add impl FromSource for MacroDef
78
79impl FromSource for ImplBlock {
80 type Ast = ast::ImplBlock;
81 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
82 let module_src = crate::ModuleSource::from_child_node(
83 db,
84 src.file_id.original_file(db),
85 &src.ast.syntax(),
86 );
87 let module = Module::from_definition(db, Source { file_id: src.file_id, ast: module_src })?;
88 let impls = module.impl_blocks(db);
89 impls.into_iter().find(|b| b.source(db) == src)
90 }
91}
92
93impl FromSource for EnumVariant {
94 type Ast = ast::EnumVariant;
95 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
96 let parent_enum = src.ast.parent_enum();
97 let src_enum = Source { file_id: src.file_id, ast: parent_enum };
98 let variants = Enum::from_source(db, src_enum)?.variants(db);
99 variants.into_iter().find(|v| v.source(db) == src)
100 }
101}
102
103impl FromSource for StructField {
104 type Ast = FieldSource;
105 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
106 let variant_def: VariantDef = match src.ast {
107 FieldSource::Named(ref field) => {
108 let ast = field.syntax().ancestors().find_map(ast::StructDef::cast)?;
109 let src = Source { file_id: src.file_id, ast };
110 let def = Struct::from_source(db, src)?;
111 VariantDef::from(def)
112 }
113 FieldSource::Pos(ref field) => {
114 let ast = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?;
115 let src = Source { file_id: src.file_id, ast };
116 let def = EnumVariant::from_source(db, src)?;
117 VariantDef::from(def)
118 }
119 };
120 variant_def
121 .variant_data(db)
122 .fields()
123 .into_iter()
124 .flat_map(|it| it.iter())
125 .map(|(id, _)| StructField { parent: variant_def.clone(), id })
126 .find(|f| f.source(db) == src)
127 }
128}
129
130// FIXME: simplify it
131impl ModuleSource {
132 pub fn from_position(
133 db: &(impl DefDatabase + AstDatabase),
134 position: FilePosition,
135 ) -> ModuleSource {
136 let parse = db.parse(position.file_id);
137 match &find_node_at_offset::<ast::Module>(parse.tree().syntax(), position.offset) {
138 Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()),
139 _ => {
140 let source_file = parse.tree().to_owned();
141 ModuleSource::SourceFile(source_file)
142 }
143 }
144 }
145
146 pub fn from_child_node(
147 db: &(impl DefDatabase + AstDatabase),
148 file_id: FileId,
149 child: &SyntaxNode,
150 ) -> ModuleSource {
151 if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) {
152 ModuleSource::Module(m.clone())
153 } else {
154 let source_file = db.parse(file_id).tree().to_owned();
155 ModuleSource::SourceFile(source_file)
156 }
157 }
158
159 pub fn from_file_id(db: &(impl DefDatabase + AstDatabase), file_id: FileId) -> ModuleSource {
160 let source_file = db.parse(file_id).tree().to_owned();
161 ModuleSource::SourceFile(source_file)
162 }
163}
164
165impl Module {
166 pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> {
167 let src_parent = Source {
168 file_id: src.file_id,
169 ast: ModuleSource::new(db, Some(src.file_id.original_file(db)), None),
170 };
171 let parent_module = Module::from_definition(db, src_parent)?;
172 let child_name = src.ast.name()?;
173 parent_module.child(db, &child_name.as_name())
174 }
175
176 pub fn from_definition(
177 db: &(impl DefDatabase + AstDatabase),
178 src: Source<ModuleSource>,
179 ) -> Option<Self> {
180 let decl_id = match src.ast {
181 ModuleSource::Module(ref module) => {
182 assert!(!module.has_semi());
183 let ast_id_map = db.ast_id_map(src.file_id);
184 let item_id = ast_id_map.ast_id(module).with_file_id(src.file_id);
185 Some(item_id)
186 }
187 ModuleSource::SourceFile(_) => None,
188 };
189
190 let source_root_id = db.file_source_root(src.file_id.original_file(db));
191 db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map(
192 |krate| {
193 let def_map = db.crate_def_map(krate);
194 let module_id = def_map.find_module_by_source(src.file_id, decl_id)?;
195 Some(Module { krate, module_id })
196 },
197 )
198 }
199}
200
201fn from_source<N, DEF>(db: &(impl DefDatabase + AstDatabase), src: Source<N>) -> Option<DEF>
202where
203 N: AstNode,
204 DEF: AstItemDef<N>,
205{
206 let module_src =
207 crate::ModuleSource::from_child_node(db, src.file_id.original_file(db), &src.ast.syntax());
208 let module = Module::from_definition(db, Source { file_id: src.file_id, ast: module_src })?;
209 let ctx = LocationCtx::new(db, module, src.file_id);
210 Some(DEF::from_ast(ctx, &src.ast))
211}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index e7a576aa0..a9de9fb6b 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -53,6 +53,8 @@ pub mod diagnostics;
53 53
54mod code_model; 54mod code_model;
55 55
56pub mod from_source;
57
56#[cfg(test)] 58#[cfg(test)]
57mod marks; 59mod marks;
58 60
@@ -67,6 +69,7 @@ pub use self::{
67 adt::VariantDef, 69 adt::VariantDef,
68 either::Either, 70 either::Either,
69 expr::ExprScopes, 71 expr::ExprScopes,
72 from_source::FromSource,
70 generics::{GenericParam, GenericParams, HasGenericParams}, 73 generics::{GenericParam, GenericParams, HasGenericParams},
71 ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, 74 ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile},
72 impl_block::ImplBlock, 75 impl_block::ImplBlock,
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 8dcea5071..cb405091e 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -93,7 +93,11 @@ impl MockDatabase {
93 let mut files: Vec<FileId> = self.files.values().copied().collect(); 93 let mut files: Vec<FileId> = self.files.values().copied().collect();
94 files.sort(); 94 files.sort();
95 for file in files { 95 for file in files {
96 let module = crate::source_binder::module_from_file_id(self, file).unwrap(); 96 let src = crate::Source {
97 file_id: file.into(),
98 ast: crate::ModuleSource::new(self, Some(file), None),
99 };
100 let module = crate::Module::from_definition(self, src).unwrap();
97 module.diagnostics( 101 module.diagnostics(
98 self, 102 self,
99 &mut DiagnosticSink::new(|d| { 103 &mut DiagnosticSink::new(|d| {
diff --git a/crates/ra_hir/src/nameres/tests/incremental.rs b/crates/ra_hir/src/nameres/tests/incremental.rs
index bc721f6e0..c41862a0b 100644
--- a/crates/ra_hir/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir/src/nameres/tests/incremental.rs
@@ -114,7 +114,11 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
114 ); 114 );
115 { 115 {
116 let events = db.log_executed(|| { 116 let events = db.log_executed(|| {
117 let module = crate::source_binder::module_from_file_id(&db, pos.file_id).unwrap(); 117 let src = crate::Source {
118 file_id: pos.file_id.into(),
119 ast: crate::ModuleSource::new(&db, Some(pos.file_id), None),
120 };
121 let module = crate::Module::from_definition(&db, src).unwrap();
118 let decls = module.declarations(&db); 122 let decls = module.declarations(&db);
119 assert_eq!(decls.len(), 18); 123 assert_eq!(decls.len(), 18);
120 }); 124 });
@@ -124,7 +128,11 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
124 128
125 { 129 {
126 let events = db.log_executed(|| { 130 let events = db.log_executed(|| {
127 let module = crate::source_binder::module_from_file_id(&db, pos.file_id).unwrap(); 131 let src = crate::Source {
132 file_id: pos.file_id.into(),
133 ast: crate::ModuleSource::new(&db, Some(pos.file_id), None),
134 };
135 let module = crate::Module::from_definition(&db, src).unwrap();
128 let decls = module.declarations(&db); 136 let decls = module.declarations(&db);
129 assert_eq!(decls.len(), 18); 137 assert_eq!(decls.len(), 18);
130 }); 138 });
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 4d895f0a1..296acc364 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -7,10 +7,9 @@
7/// purely for "IDE needs". 7/// purely for "IDE needs".
8use std::sync::Arc; 8use std::sync::Arc;
9 9
10use ra_db::{FileId, FilePosition}; 10use ra_db::FileId;
11use ra_syntax::{ 11use ra_syntax::{
12 algo::find_node_at_offset, 12 ast::{self, AstNode},
13 ast::{self, AstNode, NameOwner},
14 AstPtr, 13 AstPtr,
15 SyntaxKind::*, 14 SyntaxKind::*,
16 SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, 15 SyntaxNode, SyntaxNodePtr, TextRange, TextUnit,
@@ -28,119 +27,28 @@ use crate::{
28 path::known, 27 path::known,
29 resolve::{ScopeDef, TypeNs, ValueNs}, 28 resolve::{ScopeDef, TypeNs, ValueNs},
30 ty::method_resolution::implements_trait, 29 ty::method_resolution::implements_trait,
31 AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef, 30 AsName, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, MacroDef,
32 Module, Name, Path, Resolver, Static, Struct, Trait, Ty, 31 Module, Name, Path, Resolver, Static, Struct, Ty,
33}; 32};
34 33
35/// Locates the module by `FileId`. Picks topmost module in the file.
36pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Option<Module> {
37 module_from_source(db, file_id.into(), None)
38}
39
40/// Locates the child module by `mod child;` declaration.
41pub fn module_from_declaration(
42 db: &impl HirDatabase,
43 file_id: FileId,
44 decl: ast::Module,
45) -> Option<Module> {
46 let parent_module = module_from_file_id(db, file_id);
47 let child_name = decl.name();
48 match (parent_module, child_name) {
49 (Some(parent_module), Some(child_name)) => parent_module.child(db, &child_name.as_name()),
50 _ => None,
51 }
52}
53
54/// Locates the module by position in the source code.
55pub fn module_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Module> {
56 let parse = db.parse(position.file_id);
57 match &find_node_at_offset::<ast::Module>(parse.tree().syntax(), position.offset) {
58 Some(m) if !m.has_semi() => module_from_inline(db, position.file_id, m.clone()),
59 _ => module_from_file_id(db, position.file_id),
60 }
61}
62
63fn module_from_inline(
64 db: &impl HirDatabase,
65 file_id: FileId,
66 module: ast::Module,
67) -> Option<Module> {
68 assert!(!module.has_semi());
69 let file_id = file_id.into();
70 let ast_id_map = db.ast_id_map(file_id);
71 let item_id = ast_id_map.ast_id(&module).with_file_id(file_id);
72 module_from_source(db, file_id, Some(item_id))
73}
74
75/// Locates the module by child syntax element within the module
76pub fn module_from_child_node(
77 db: &impl HirDatabase,
78 file_id: FileId,
79 child: &SyntaxNode,
80) -> Option<Module> {
81 if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) {
82 module_from_inline(db, file_id, m)
83 } else {
84 module_from_file_id(db, file_id)
85 }
86}
87
88fn module_from_source(
89 db: &impl HirDatabase,
90 file_id: HirFileId,
91 decl_id: Option<AstId<ast::Module>>,
92) -> Option<Module> {
93 let source_root_id = db.file_source_root(file_id.as_original_file());
94 db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map(
95 |krate| {
96 let def_map = db.crate_def_map(krate);
97 let module_id = def_map.find_module_by_source(file_id, decl_id)?;
98 Some(Module { krate, module_id })
99 },
100 )
101}
102
103pub fn struct_from_module(
104 db: &impl HirDatabase,
105 module: Module,
106 struct_def: &ast::StructDef,
107) -> Struct {
108 let file_id = module.definition_source(db).file_id;
109 let ctx = LocationCtx::new(db, module, file_id);
110 Struct { id: ctx.to_def(struct_def) }
111}
112
113pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum {
114 let file_id = module.definition_source(db).file_id;
115 let ctx = LocationCtx::new(db, module, file_id);
116 Enum { id: ctx.to_def(enum_def) }
117}
118
119pub fn trait_from_module(
120 db: &impl HirDatabase,
121 module: Module,
122 trait_def: &ast::TraitDef,
123) -> Trait {
124 let file_id = module.definition_source(db).file_id;
125 let ctx = LocationCtx::new(db, module, file_id);
126 Trait { id: ctx.to_def(trait_def) }
127}
128
129fn try_get_resolver_for_node( 34fn try_get_resolver_for_node(
130 db: &impl HirDatabase, 35 db: &impl HirDatabase,
131 file_id: FileId, 36 file_id: FileId,
132 node: &SyntaxNode, 37 node: &SyntaxNode,
133) -> Option<Resolver> { 38) -> Option<Resolver> {
134 if let Some(module) = ast::Module::cast(node.clone()) { 39 if let Some(module) = ast::Module::cast(node.clone()) {
135 Some(module_from_declaration(db, file_id, module)?.resolver(db)) 40 let src = crate::Source { file_id: file_id.into(), ast: module };
136 } else if let Some(_) = ast::SourceFile::cast(node.clone()) { 41 Some(crate::Module::from_declaration(db, src)?.resolver(db))
137 Some(module_from_source(db, file_id.into(), None)?.resolver(db)) 42 } else if let Some(file) = ast::SourceFile::cast(node.clone()) {
43 let src =
44 crate::Source { file_id: file_id.into(), ast: crate::ModuleSource::SourceFile(file) };
45 Some(crate::Module::from_definition(db, src)?.resolver(db))
138 } else if let Some(s) = ast::StructDef::cast(node.clone()) { 46 } else if let Some(s) = ast::StructDef::cast(node.clone()) {
139 let module = module_from_child_node(db, file_id, s.syntax())?; 47 let src = crate::Source { file_id: file_id.into(), ast: s };
140 Some(struct_from_module(db, module, &s).resolver(db)) 48 Some(Struct::from_source(db, src)?.resolver(db))
141 } else if let Some(e) = ast::EnumDef::cast(node.clone()) { 49 } else if let Some(e) = ast::EnumDef::cast(node.clone()) {
142 let module = module_from_child_node(db, file_id, e.syntax())?; 50 let src = crate::Source { file_id: file_id.into(), ast: e };
143 Some(enum_from_module(db, module, &e).resolver(db)) 51 Some(Enum::from_source(db, src)?.resolver(db))
144 } else if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF { 52 } else if node.kind() == FN_DEF || node.kind() == CONST_DEF || node.kind() == STATIC_DEF {
145 Some(def_with_body_from_child_node(db, file_id, node)?.resolver(db)) 53 Some(def_with_body_from_child_node(db, file_id, node)?.resolver(db))
146 } else { 54 } else {
@@ -154,8 +62,10 @@ fn def_with_body_from_child_node(
154 file_id: FileId, 62 file_id: FileId,
155 node: &SyntaxNode, 63 node: &SyntaxNode,
156) -> Option<DefWithBody> { 64) -> Option<DefWithBody> {
157 let module = module_from_child_node(db, file_id, node)?; 65 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 })?;
158 let ctx = LocationCtx::new(db, module, file_id.into()); 67 let ctx = LocationCtx::new(db, module, file_id.into());
68
159 node.ancestors().find_map(|node| { 69 node.ancestors().find_map(|node| {
160 if let Some(def) = ast::FnDef::cast(node.clone()) { 70 if let Some(def) = ast::FnDef::cast(node.clone()) {
161 return Some(Function { id: ctx.to_def(&def) }.into()); 71 return Some(Function { id: ctx.to_def(&def) }.into());
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs
index 7139947b3..59bd3689b 100644
--- a/crates/ra_ide_api/src/completion/completion_context.rs
+++ b/crates/ra_ide_api/src/completion/completion_context.rs
@@ -1,4 +1,3 @@
1use hir::source_binder;
2use ra_syntax::{ 1use ra_syntax::{
3 algo::{find_covering_element, find_node_at_offset}, 2 algo::{find_covering_element, find_node_at_offset},
4 ast, AstNode, Parse, SourceFile, 3 ast, AstNode, Parse, SourceFile,
@@ -47,7 +46,11 @@ impl<'a> CompletionContext<'a> {
47 original_parse: &'a Parse<ast::SourceFile>, 46 original_parse: &'a Parse<ast::SourceFile>,
48 position: FilePosition, 47 position: FilePosition,
49 ) -> Option<CompletionContext<'a>> { 48 ) -> Option<CompletionContext<'a>> {
50 let module = source_binder::module_from_position(db, position); 49 let src = hir::ModuleSource::from_position(db, position);
50 let module = hir::Module::from_definition(
51 db,
52 hir::Source { file_id: position.file_id.into(), ast: src },
53 );
51 let token = 54 let token =
52 original_parse.tree().syntax().token_at_offset(position.offset).left_biased()?; 55 original_parse.tree().syntax().token_at_offset(position.offset).left_biased()?;
53 let analyzer = 56 let analyzer =
diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs
index c448aa8c5..1ae152e5b 100644
--- a/crates/ra_ide_api/src/diagnostics.rs
+++ b/crates/ra_ide_api/src/diagnostics.rs
@@ -1,9 +1,6 @@
1use std::cell::RefCell; 1use std::cell::RefCell;
2 2
3use hir::{ 3use hir::diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSink};
4 diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSink},
5 source_binder,
6};
7use itertools::Itertools; 4use itertools::Itertools;
8use ra_assists::ast_editor::{AstBuilder, AstEditor}; 5use ra_assists::ast_editor::{AstBuilder, AstEditor};
9use ra_db::SourceDatabase; 6use ra_db::SourceDatabase;
@@ -89,7 +86,10 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
89 fix: Some(fix), 86 fix: Some(fix),
90 }) 87 })
91 }); 88 });
92 if let Some(m) = source_binder::module_from_file_id(db, file_id) { 89 let source_file = db.parse(file_id).tree().to_owned();
90 let src =
91 hir::Source { file_id: file_id.into(), ast: hir::ModuleSource::SourceFile(source_file) };
92 if let Some(m) = hir::Module::from_definition(db, src) {
93 m.diagnostics(db, &mut sink); 93 m.diagnostics(db, &mut sink);
94 }; 94 };
95 drop(sink); 95 drop(sink);
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 503dcacff..bc8863dad 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -96,9 +96,8 @@ pub(crate) fn name_definition(
96 96
97 if let Some(module) = ast::Module::cast(parent.clone()) { 97 if let Some(module) = ast::Module::cast(parent.clone()) {
98 if module.has_semi() { 98 if module.has_semi() {
99 if let Some(child_module) = 99 let src = hir::Source { file_id: file_id.into(), ast: module };
100 hir::source_binder::module_from_declaration(db, file_id, module) 100 if let Some(child_module) = hir::Module::from_declaration(db, src) {
101 {
102 let nav = NavigationTarget::from_module(db, child_module); 101 let nav = NavigationTarget::from_module(db, child_module);
103 return Some(vec![nav]); 102 return Some(vec![nav]);
104 } 103 }
diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs
index c5620dd52..f57f9a21b 100644
--- a/crates/ra_ide_api/src/impls.rs
+++ b/crates/ra_ide_api/src/impls.rs
@@ -1,4 +1,4 @@
1use hir::{db::HirDatabase, source_binder, ApplicationTy, Ty, TypeCtor}; 1use hir::{db::HirDatabase, ApplicationTy, FromSource, Ty, TypeCtor};
2use ra_db::SourceDatabase; 2use ra_db::SourceDatabase;
3use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; 3use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
4 4
@@ -11,17 +11,21 @@ pub(crate) fn goto_implementation(
11 let parse = db.parse(position.file_id); 11 let parse = db.parse(position.file_id);
12 let syntax = parse.tree().syntax().clone(); 12 let syntax = parse.tree().syntax().clone();
13 13
14 let module = source_binder::module_from_position(db, position)?; 14 let src = hir::ModuleSource::from_position(db, position);
15 let module = hir::Module::from_definition(
16 db,
17 hir::Source { file_id: position.file_id.into(), ast: src },
18 )?;
15 19
16 if let Some(nominal_def) = find_node_at_offset::<ast::NominalDef>(&syntax, position.offset) { 20 if let Some(nominal_def) = find_node_at_offset::<ast::NominalDef>(&syntax, position.offset) {
17 return Some(RangeInfo::new( 21 return Some(RangeInfo::new(
18 nominal_def.syntax().text_range(), 22 nominal_def.syntax().text_range(),
19 impls_for_def(db, &nominal_def, module)?, 23 impls_for_def(db, position, &nominal_def, module)?,
20 )); 24 ));
21 } else if let Some(trait_def) = find_node_at_offset::<ast::TraitDef>(&syntax, position.offset) { 25 } else if let Some(trait_def) = find_node_at_offset::<ast::TraitDef>(&syntax, position.offset) {
22 return Some(RangeInfo::new( 26 return Some(RangeInfo::new(
23 trait_def.syntax().text_range(), 27 trait_def.syntax().text_range(),
24 impls_for_trait(db, &trait_def, module)?, 28 impls_for_trait(db, position, &trait_def, module)?,
25 )); 29 ));
26 } 30 }
27 31
@@ -30,14 +34,19 @@ pub(crate) fn goto_implementation(
30 34
31fn impls_for_def( 35fn impls_for_def(
32 db: &RootDatabase, 36 db: &RootDatabase,
37 position: FilePosition,
33 node: &ast::NominalDef, 38 node: &ast::NominalDef,
34 module: hir::Module, 39 module: hir::Module,
35) -> Option<Vec<NavigationTarget>> { 40) -> Option<Vec<NavigationTarget>> {
36 let ty = match node { 41 let ty = match node {
37 ast::NominalDef::StructDef(def) => { 42 ast::NominalDef::StructDef(def) => {
38 source_binder::struct_from_module(db, module, &def).ty(db) 43 let src = hir::Source { file_id: position.file_id.into(), ast: def.clone() };
44 hir::Struct::from_source(db, src)?.ty(db)
45 }
46 ast::NominalDef::EnumDef(def) => {
47 let src = hir::Source { file_id: position.file_id.into(), ast: def.clone() };
48 hir::Enum::from_source(db, src)?.ty(db)
39 } 49 }
40 ast::NominalDef::EnumDef(def) => source_binder::enum_from_module(db, module, &def).ty(db),
41 }; 50 };
42 51
43 let krate = module.krate(db)?; 52 let krate = module.krate(db)?;
@@ -54,10 +63,12 @@ fn impls_for_def(
54 63
55fn impls_for_trait( 64fn impls_for_trait(
56 db: &RootDatabase, 65 db: &RootDatabase,
66 position: FilePosition,
57 node: &ast::TraitDef, 67 node: &ast::TraitDef,
58 module: hir::Module, 68 module: hir::Module,
59) -> Option<Vec<NavigationTarget>> { 69) -> Option<Vec<NavigationTarget>> {
60 let tr = source_binder::trait_from_module(db, module, node); 70 let src = hir::Source { file_id: position.file_id.into(), ast: node.clone() };
71 let tr = hir::Trait::from_source(db, src)?;
61 72
62 let krate = module.krate(db)?; 73 let krate = module.krate(db)?;
63 let impls = db.impls_in_crate(krate); 74 let impls = db.impls_in_crate(krate);
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index e90fbd428..412dc4d71 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -223,6 +223,7 @@ impl Query {
223 } 223 }
224} 224}
225 225
226/// Info associated with a text range.
226#[derive(Debug)] 227#[derive(Debug)]
227pub struct RangeInfo<T> { 228pub struct RangeInfo<T> {
228 pub range: TextRange, 229 pub range: TextRange,
@@ -235,6 +236,8 @@ impl<T> RangeInfo<T> {
235 } 236 }
236} 237}
237 238
239/// Contains information about a call site. Specifically the
240/// `FunctionSignature`and current parameter.
238#[derive(Debug)] 241#[derive(Debug)]
239pub struct CallInfo { 242pub struct CallInfo {
240 pub signature: FunctionSignature, 243 pub signature: FunctionSignature,
@@ -325,11 +328,12 @@ impl Analysis {
325 (host.analysis(), file_id) 328 (host.analysis(), file_id)
326 } 329 }
327 330
331 /// Features for Analysis.
328 pub fn feature_flags(&self) -> &FeatureFlags { 332 pub fn feature_flags(&self) -> &FeatureFlags {
329 &self.db.feature_flags 333 &self.db.feature_flags
330 } 334 }
331 335
332 /// Debug info about the current state of the analysis 336 /// Debug info about the current state of the analysis.
333 pub fn status(&self) -> Cancelable<String> { 337 pub fn status(&self) -> Cancelable<String> {
334 self.with_db(|db| status::status(&*db)) 338 self.with_db(|db| status::status(&*db))
335 } 339 }
@@ -440,6 +444,7 @@ impl Analysis {
440 }) 444 })
441 } 445 }
442 446
447 /// Returns the definitions from the symbol at `position`.
443 pub fn goto_definition( 448 pub fn goto_definition(
444 &self, 449 &self,
445 position: FilePosition, 450 position: FilePosition,
@@ -447,6 +452,7 @@ impl Analysis {
447 self.with_db(|db| goto_definition::goto_definition(db, position)) 452 self.with_db(|db| goto_definition::goto_definition(db, position))
448 } 453 }
449 454
455 /// Returns the impls from the symbol at `position`.
450 pub fn goto_implementation( 456 pub fn goto_implementation(
451 &self, 457 &self,
452 position: FilePosition, 458 position: FilePosition,
@@ -454,6 +460,7 @@ impl Analysis {
454 self.with_db(|db| impls::goto_implementation(db, position)) 460 self.with_db(|db| impls::goto_implementation(db, position))
455 } 461 }
456 462
463 /// Returns the type definitions for the symbol at `position`.
457 pub fn goto_type_definition( 464 pub fn goto_type_definition(
458 &self, 465 &self,
459 position: FilePosition, 466 position: FilePosition,
@@ -540,6 +547,7 @@ impl Analysis {
540 self.with_db(|db| references::rename(db, position, new_name)) 547 self.with_db(|db| references::rename(db, position, new_name))
541 } 548 }
542 549
550 /// Performs an operation on that may be Canceled.
543 fn with_db<F: FnOnce(&db::RootDatabase) -> T + std::panic::UnwindSafe, T>( 551 fn with_db<F: FnOnce(&db::RootDatabase) -> T + std::panic::UnwindSafe, T>(
544 &self, 552 &self,
545 f: F, 553 f: F,
diff --git a/crates/ra_ide_api/src/parent_module.rs b/crates/ra_ide_api/src/parent_module.rs
index 7d5f9ea2c..3668da8d7 100644
--- a/crates/ra_ide_api/src/parent_module.rs
+++ b/crates/ra_ide_api/src/parent_module.rs
@@ -5,7 +5,11 @@ use crate::{db::RootDatabase, NavigationTarget};
5/// This returns `Vec` because a module may be included from several places. We 5/// This returns `Vec` because a module may be included from several places. We
6/// don't handle this case yet though, so the Vec has length at most one. 6/// don't handle this case yet though, so the Vec has length at most one.
7pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { 7pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> {
8 let module = match hir::source_binder::module_from_position(db, position) { 8 let src = hir::ModuleSource::from_position(db, position);
9 let module = match hir::Module::from_definition(
10 db,
11 hir::Source { file_id: position.file_id.into(), ast: src },
12 ) {
9 None => return Vec::new(), 13 None => return Vec::new(),
10 Some(it) => it, 14 Some(it) => it,
11 }; 15 };
@@ -15,10 +19,12 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
15 19
16/// Returns `Vec` for the same reason as `parent_module` 20/// Returns `Vec` for the same reason as `parent_module`
17pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> { 21pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
18 let module = match hir::source_binder::module_from_file_id(db, file_id) { 22 let src = hir::ModuleSource::from_file_id(db, file_id);
19 Some(it) => it, 23 let module =
20 None => return Vec::new(), 24 match hir::Module::from_definition(db, hir::Source { file_id: file_id.into(), ast: src }) {
21 }; 25 Some(it) => it,
26 None => return Vec::new(),
27 };
22 let krate = match module.krate(db) { 28 let krate = match module.krate(db) {
23 Some(it) => it, 29 Some(it) => it,
24 None => return Vec::new(), 30 None => return Vec::new(),
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index 5f1f0efc3..acca71f2a 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -1,4 +1,4 @@
1use hir::{source_binder, Either, ModuleSource}; 1use hir::{Either, ModuleSource};
2use ra_db::SourceDatabase; 2use ra_db::SourceDatabase;
3use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode}; 3use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode};
4use relative_path::{RelativePath, RelativePathBuf}; 4use relative_path::{RelativePath, RelativePathBuf};
@@ -135,9 +135,8 @@ fn rename_mod(
135) -> Option<SourceChange> { 135) -> Option<SourceChange> {
136 let mut source_file_edits = Vec::new(); 136 let mut source_file_edits = Vec::new();
137 let mut file_system_edits = Vec::new(); 137 let mut file_system_edits = Vec::new();
138 if let Some(module) = 138 let module_src = hir::Source { file_id: position.file_id.into(), ast: ast_module.clone() };
139 source_binder::module_from_declaration(db, position.file_id, ast_module.clone()) 139 if let Some(module) = hir::Module::from_declaration(db, module_src) {
140 {
141 let src = module.definition_source(db); 140 let src = module.definition_source(db);
142 let file_id = src.file_id.as_original_file(); 141 let file_id = src.file_id.as_original_file();
143 match src.ast { 142 match src.ast {
diff --git a/crates/ra_ide_api/src/runnables.rs b/crates/ra_ide_api/src/runnables.rs
index 9d84b3d08..095ca56c4 100644
--- a/crates/ra_ide_api/src/runnables.rs
+++ b/crates/ra_ide_api/src/runnables.rs
@@ -63,7 +63,9 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Opti
63 return None; 63 return None;
64 } 64 }
65 let range = module.syntax().text_range(); 65 let range = module.syntax().text_range();
66 let module = hir::source_binder::module_from_child_node(db, file_id, module.syntax())?; 66 let src = hir::ModuleSource::from_child_node(db, file_id, &module.syntax());
67 let module =
68 hir::Module::from_definition(db, hir::Source { file_id: file_id.into(), ast: src })?;
67 69
68 let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::"); 70 let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::");
69 Some(Runnable { range, kind: RunnableKind::TestMod { path } }) 71 Some(Runnable { range, kind: RunnableKind::TestMod { path } })
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index 0158f9b8a..e2355aff9 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -212,7 +212,7 @@ fn opt_visibility(p: &mut Parser) -> bool {
212 // fn foo() { crate::foo(); } 212 // fn foo() { crate::foo(); }
213 T![crate] if !p.nth_at(1, T![::]) => { 213 T![crate] if !p.nth_at(1, T![::]) => {
214 let m = p.start(); 214 let m = p.start();
215 p.bump_any(); 215 p.bump(T![crate]);
216 m.complete(p, VISIBILITY); 216 m.complete(p, VISIBILITY);
217 } 217 }
218 _ => return false, 218 _ => return false,
@@ -223,7 +223,7 @@ fn opt_visibility(p: &mut Parser) -> bool {
223fn opt_alias(p: &mut Parser) { 223fn opt_alias(p: &mut Parser) {
224 if p.at(T![as]) { 224 if p.at(T![as]) {
225 let m = p.start(); 225 let m = p.start();
226 p.bump_any(); 226 p.bump(T![as]);
227 if !p.eat(T![_]) { 227 if !p.eat(T![_]) {
228 name(p); 228 name(p);
229 } 229 }
@@ -234,7 +234,7 @@ fn opt_alias(p: &mut Parser) {
234fn abi(p: &mut Parser) { 234fn abi(p: &mut Parser) {
235 assert!(p.at(T![extern])); 235 assert!(p.at(T![extern]));
236 let abi = p.start(); 236 let abi = p.start();
237 p.bump_any(); 237 p.bump(T![extern]);
238 match p.current() { 238 match p.current() {
239 STRING | RAW_STRING => p.bump_any(), 239 STRING | RAW_STRING => p.bump_any(),
240 _ => (), 240 _ => (),
@@ -257,7 +257,7 @@ fn opt_fn_ret_type(p: &mut Parser) -> bool {
257fn name_r(p: &mut Parser, recovery: TokenSet) { 257fn name_r(p: &mut Parser, recovery: TokenSet) {
258 if p.at(IDENT) { 258 if p.at(IDENT) {
259 let m = p.start(); 259 let m = p.start();
260 p.bump_any(); 260 p.bump(IDENT);
261 m.complete(p, NAME); 261 m.complete(p, NAME);
262 } else { 262 } else {
263 p.err_recover("expected a name", recovery); 263 p.err_recover("expected a name", recovery);
@@ -271,11 +271,11 @@ fn name(p: &mut Parser) {
271fn name_ref(p: &mut Parser) { 271fn name_ref(p: &mut Parser) {
272 if p.at(IDENT) { 272 if p.at(IDENT) {
273 let m = p.start(); 273 let m = p.start();
274 p.bump_any(); 274 p.bump(IDENT);
275 m.complete(p, NAME_REF); 275 m.complete(p, NAME_REF);
276 } else if p.at(T![self]) { 276 } else if p.at(T![self]) {
277 let m = p.start(); 277 let m = p.start();
278 p.bump_any(); 278 p.bump(T![self]);
279 m.complete(p, T![self]); 279 m.complete(p, T![self]);
280 } else { 280 } else {
281 p.err_and_bump("expected identifier"); 281 p.err_and_bump("expected identifier");
@@ -296,7 +296,7 @@ fn error_block(p: &mut Parser, message: &str) {
296 assert!(p.at(T!['{'])); 296 assert!(p.at(T!['{']));
297 let m = p.start(); 297 let m = p.start();
298 p.error(message); 298 p.error(message);
299 p.bump_any(); 299 p.bump(T!['{']);
300 expressions::expr_block_contents(p); 300 expressions::expr_block_contents(p);
301 p.eat(T!['}']); 301 p.eat(T!['}']);
302 m.complete(p, ERROR); 302 m.complete(p, ERROR);
diff --git a/crates/ra_parser/src/grammar/attributes.rs b/crates/ra_parser/src/grammar/attributes.rs
index 81a363a57..1cfd301b5 100644
--- a/crates/ra_parser/src/grammar/attributes.rs
+++ b/crates/ra_parser/src/grammar/attributes.rs
@@ -15,11 +15,11 @@ pub(super) fn outer_attributes(p: &mut Parser) {
15fn attribute(p: &mut Parser, inner: bool) { 15fn attribute(p: &mut Parser, inner: bool) {
16 let attr = p.start(); 16 let attr = p.start();
17 assert!(p.at(T![#])); 17 assert!(p.at(T![#]));
18 p.bump_any(); 18 p.bump(T![#]);
19 19
20 if inner { 20 if inner {
21 assert!(p.at(T![!])); 21 assert!(p.at(T![!]));
22 p.bump_any(); 22 p.bump(T![!]);
23 } 23 }
24 24
25 if p.at(T!['[']) { 25 if p.at(T!['[']) {
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index 1dd9a586c..80b085280 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -43,7 +43,7 @@ pub(crate) fn block(p: &mut Parser) {
43pub(crate) fn naked_block(p: &mut Parser) { 43pub(crate) fn naked_block(p: &mut Parser) {
44 assert!(p.at(T!['{'])); 44 assert!(p.at(T!['{']));
45 let m = p.start(); 45 let m = p.start();
46 p.bump_any(); 46 p.bump(T!['{']);
47 expr_block_contents(p); 47 expr_block_contents(p);
48 p.expect(T!['}']); 48 p.expect(T!['}']);
49 m.complete(p, BLOCK); 49 m.complete(p, BLOCK);
@@ -150,7 +150,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) {
150 // } 150 // }
151 fn let_stmt(p: &mut Parser, m: Marker, with_semi: StmtWithSemi) { 151 fn let_stmt(p: &mut Parser, m: Marker, with_semi: StmtWithSemi) {
152 assert!(p.at(T![let])); 152 assert!(p.at(T![let]));
153 p.bump_any(); 153 p.bump(T![let]);
154 patterns::pattern(p); 154 patterns::pattern(p);
155 if p.at(T![:]) { 155 if p.at(T![:]) {
156 types::ascription(p); 156 types::ascription(p);
@@ -195,7 +195,7 @@ pub(crate) fn expr_block_contents(p: &mut Parser) {
195 // } 195 // }
196 196
197 if p.at(T![;]) { 197 if p.at(T![;]) {
198 p.bump_any(); 198 p.bump(T![;]);
199 continue; 199 continue;
200 } 200 }
201 201
@@ -297,7 +297,7 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)>
297 // } 297 // }
298 T![&] => { 298 T![&] => {
299 m = p.start(); 299 m = p.start();
300 p.bump_any(); 300 p.bump(T![&]);
301 p.eat(T![mut]); 301 p.eat(T![mut]);
302 REF_EXPR 302 REF_EXPR
303 } 303 }
@@ -438,7 +438,7 @@ fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
438fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { 438fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
439 assert!(p.at(T!['['])); 439 assert!(p.at(T!['[']));
440 let m = lhs.precede(p); 440 let m = lhs.precede(p);
441 p.bump_any(); 441 p.bump(T!['[']);
442 expr(p); 442 expr(p);
443 p.expect(T![']']); 443 p.expect(T![']']);
444 m.complete(p, INDEX_EXPR) 444 m.complete(p, INDEX_EXPR)
@@ -478,7 +478,7 @@ fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
478fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { 478fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
479 assert!(p.at(T![.])); 479 assert!(p.at(T![.]));
480 let m = lhs.precede(p); 480 let m = lhs.precede(p);
481 p.bump_any(); 481 p.bump(T![.]);
482 if p.at(IDENT) || p.at(INT_NUMBER) { 482 if p.at(IDENT) || p.at(INT_NUMBER) {
483 name_ref_or_index(p) 483 name_ref_or_index(p)
484 } else if p.at(FLOAT_NUMBER) { 484 } else if p.at(FLOAT_NUMBER) {
@@ -497,7 +497,7 @@ fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
497fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { 497fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
498 assert!(p.at(T![?])); 498 assert!(p.at(T![?]));
499 let m = lhs.precede(p); 499 let m = lhs.precede(p);
500 p.bump_any(); 500 p.bump(T![?]);
501 m.complete(p, TRY_EXPR) 501 m.complete(p, TRY_EXPR)
502} 502}
503 503
@@ -511,7 +511,7 @@ fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
511fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { 511fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
512 assert!(p.at(T![as])); 512 assert!(p.at(T![as]));
513 let m = lhs.precede(p); 513 let m = lhs.precede(p);
514 p.bump_any(); 514 p.bump(T![as]);
515 // Use type_no_bounds(), because cast expressions are not 515 // Use type_no_bounds(), because cast expressions are not
516 // allowed to have bounds. 516 // allowed to have bounds.
517 types::type_no_bounds(p); 517 types::type_no_bounds(p);
@@ -521,7 +521,7 @@ fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
521fn arg_list(p: &mut Parser) { 521fn arg_list(p: &mut Parser) {
522 assert!(p.at(T!['('])); 522 assert!(p.at(T!['(']));
523 let m = p.start(); 523 let m = p.start();
524 p.bump_any(); 524 p.bump(T!['(']);
525 while !p.at(T![')']) && !p.at(EOF) { 525 while !p.at(T![')']) && !p.at(EOF) {
526 if !p.at_ts(EXPR_FIRST) { 526 if !p.at_ts(EXPR_FIRST) {
527 p.error("expected expression"); 527 p.error("expected expression");
@@ -570,7 +570,7 @@ fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) {
570pub(crate) fn record_field_list(p: &mut Parser) { 570pub(crate) fn record_field_list(p: &mut Parser) {
571 assert!(p.at(T!['{'])); 571 assert!(p.at(T!['{']));
572 let m = p.start(); 572 let m = p.start();
573 p.bump_any(); 573 p.bump(T!['{']);
574 while !p.at(EOF) && !p.at(T!['}']) { 574 while !p.at(EOF) && !p.at(T!['}']) {
575 match p.current() { 575 match p.current() {
576 // test record_literal_field_with_attr 576 // test record_literal_field_with_attr
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index 6e295fbf9..6c7fdc2cd 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -101,14 +101,14 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
101 } 101 }
102 T![async] if la == T!['{'] || (la == T![move] && p.nth(2) == T!['{']) => { 102 T![async] if la == T!['{'] || (la == T![move] && p.nth(2) == T!['{']) => {
103 let m = p.start(); 103 let m = p.start();
104 p.bump_any(); 104 p.bump(T![async]);
105 p.eat(T![move]); 105 p.eat(T![move]);
106 block_expr(p, Some(m)) 106 block_expr(p, Some(m))
107 } 107 }
108 T![match] => match_expr(p), 108 T![match] => match_expr(p),
109 T![unsafe] if la == T!['{'] => { 109 T![unsafe] if la == T!['{'] => {
110 let m = p.start(); 110 let m = p.start();
111 p.bump_any(); 111 p.bump(T![unsafe]);
112 block_expr(p, Some(m)) 112 block_expr(p, Some(m))
113 } 113 }
114 T!['{'] => { 114 T!['{'] => {
@@ -180,7 +180,7 @@ fn tuple_expr(p: &mut Parser) -> CompletedMarker {
180fn array_expr(p: &mut Parser) -> CompletedMarker { 180fn array_expr(p: &mut Parser) -> CompletedMarker {
181 assert!(p.at(T!['['])); 181 assert!(p.at(T!['[']));
182 let m = p.start(); 182 let m = p.start();
183 p.bump_any(); 183 p.bump(T!['[']);
184 if p.eat(T![']']) { 184 if p.eat(T![']']) {
185 return m.complete(p, ARRAY_EXPR); 185 return m.complete(p, ARRAY_EXPR);
186 } 186 }
@@ -262,11 +262,11 @@ fn lambda_expr(p: &mut Parser) -> CompletedMarker {
262fn if_expr(p: &mut Parser) -> CompletedMarker { 262fn if_expr(p: &mut Parser) -> CompletedMarker {
263 assert!(p.at(T![if])); 263 assert!(p.at(T![if]));
264 let m = p.start(); 264 let m = p.start();
265 p.bump_any(); 265 p.bump(T![if]);
266 cond(p); 266 cond(p);
267 block(p); 267 block(p);
268 if p.at(T![else]) { 268 if p.at(T![else]) {
269 p.bump_any(); 269 p.bump(T![else]);
270 if p.at(T![if]) { 270 if p.at(T![if]) {
271 if_expr(p); 271 if_expr(p);
272 } else { 272 } else {
@@ -285,7 +285,7 @@ fn if_expr(p: &mut Parser) -> CompletedMarker {
285fn label(p: &mut Parser) { 285fn label(p: &mut Parser) {
286 assert!(p.at(LIFETIME) && p.nth(1) == T![:]); 286 assert!(p.at(LIFETIME) && p.nth(1) == T![:]);
287 let m = p.start(); 287 let m = p.start();
288 p.bump_any(); 288 p.bump(LIFETIME);
289 p.bump_any(); 289 p.bump_any();
290 m.complete(p, LABEL); 290 m.complete(p, LABEL);
291} 291}
@@ -297,7 +297,7 @@ fn label(p: &mut Parser) {
297fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { 297fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
298 assert!(p.at(T![loop])); 298 assert!(p.at(T![loop]));
299 let m = m.unwrap_or_else(|| p.start()); 299 let m = m.unwrap_or_else(|| p.start());
300 p.bump_any(); 300 p.bump(T![loop]);
301 block(p); 301 block(p);
302 m.complete(p, LOOP_EXPR) 302 m.complete(p, LOOP_EXPR)
303} 303}
@@ -310,7 +310,7 @@ fn loop_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
310fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { 310fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
311 assert!(p.at(T![while])); 311 assert!(p.at(T![while]));
312 let m = m.unwrap_or_else(|| p.start()); 312 let m = m.unwrap_or_else(|| p.start());
313 p.bump_any(); 313 p.bump(T![while]);
314 cond(p); 314 cond(p);
315 block(p); 315 block(p);
316 m.complete(p, WHILE_EXPR) 316 m.complete(p, WHILE_EXPR)
@@ -323,7 +323,7 @@ fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
323fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { 323fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
324 assert!(p.at(T![for])); 324 assert!(p.at(T![for]));
325 let m = m.unwrap_or_else(|| p.start()); 325 let m = m.unwrap_or_else(|| p.start());
326 p.bump_any(); 326 p.bump(T![for]);
327 patterns::pattern(p); 327 patterns::pattern(p);
328 p.expect(T![in]); 328 p.expect(T![in]);
329 expr_no_struct(p); 329 expr_no_struct(p);
@@ -357,7 +357,7 @@ fn cond(p: &mut Parser) {
357fn match_expr(p: &mut Parser) -> CompletedMarker { 357fn match_expr(p: &mut Parser) -> CompletedMarker {
358 assert!(p.at(T![match])); 358 assert!(p.at(T![match]));
359 let m = p.start(); 359 let m = p.start();
360 p.bump_any(); 360 p.bump(T![match]);
361 expr_no_struct(p); 361 expr_no_struct(p);
362 if p.at(T!['{']) { 362 if p.at(T!['{']) {
363 match_arm_list(p); 363 match_arm_list(p);
@@ -453,7 +453,7 @@ fn match_arm(p: &mut Parser) -> BlockLike {
453fn match_guard(p: &mut Parser) -> CompletedMarker { 453fn match_guard(p: &mut Parser) -> CompletedMarker {
454 assert!(p.at(T![if])); 454 assert!(p.at(T![if]));
455 let m = p.start(); 455 let m = p.start();
456 p.bump_any(); 456 p.bump(T![if]);
457 expr(p); 457 expr(p);
458 m.complete(p, MATCH_GUARD) 458 m.complete(p, MATCH_GUARD)
459} 459}
@@ -479,7 +479,7 @@ pub(super) fn block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
479fn return_expr(p: &mut Parser) -> CompletedMarker { 479fn return_expr(p: &mut Parser) -> CompletedMarker {
480 assert!(p.at(T![return])); 480 assert!(p.at(T![return]));
481 let m = p.start(); 481 let m = p.start();
482 p.bump_any(); 482 p.bump(T![return]);
483 if p.at_ts(EXPR_FIRST) { 483 if p.at_ts(EXPR_FIRST) {
484 expr(p); 484 expr(p);
485 } 485 }
@@ -496,7 +496,7 @@ fn return_expr(p: &mut Parser) -> CompletedMarker {
496fn continue_expr(p: &mut Parser) -> CompletedMarker { 496fn continue_expr(p: &mut Parser) -> CompletedMarker {
497 assert!(p.at(T![continue])); 497 assert!(p.at(T![continue]));
498 let m = p.start(); 498 let m = p.start();
499 p.bump_any(); 499 p.bump(T![continue]);
500 p.eat(LIFETIME); 500 p.eat(LIFETIME);
501 m.complete(p, CONTINUE_EXPR) 501 m.complete(p, CONTINUE_EXPR)
502} 502}
@@ -513,7 +513,7 @@ fn continue_expr(p: &mut Parser) -> CompletedMarker {
513fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker { 513fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
514 assert!(p.at(T![break])); 514 assert!(p.at(T![break]));
515 let m = p.start(); 515 let m = p.start();
516 p.bump_any(); 516 p.bump(T![break]);
517 p.eat(LIFETIME); 517 p.eat(LIFETIME);
518 // test break_ambiguity 518 // test break_ambiguity
519 // fn foo(){ 519 // fn foo(){
@@ -535,7 +535,7 @@ fn break_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
535fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { 535fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
536 assert!(p.at(T![try])); 536 assert!(p.at(T![try]));
537 let m = m.unwrap_or_else(|| p.start()); 537 let m = m.unwrap_or_else(|| p.start());
538 p.bump_any(); 538 p.bump(T![try]);
539 block(p); 539 block(p);
540 m.complete(p, TRY_EXPR) 540 m.complete(p, TRY_EXPR)
541} 541}
@@ -549,7 +549,7 @@ fn try_block_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
549fn box_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker { 549fn box_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
550 assert!(p.at(T![box])); 550 assert!(p.at(T![box]));
551 let m = m.unwrap_or_else(|| p.start()); 551 let m = m.unwrap_or_else(|| p.start());
552 p.bump_any(); 552 p.bump(T![box]);
553 if p.at_ts(EXPR_FIRST) { 553 if p.at_ts(EXPR_FIRST) {
554 expr(p); 554 expr(p);
555 } 555 }
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs
index 4dd80d443..4c67a5c2e 100644
--- a/crates/ra_parser/src/grammar/items.rs
+++ b/crates/ra_parser/src/grammar/items.rs
@@ -64,7 +64,7 @@ pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemF
64 } else if p.at(T!['}']) && !stop_on_r_curly { 64 } else if p.at(T!['}']) && !stop_on_r_curly {
65 let e = p.start(); 65 let e = p.start();
66 p.error("unmatched `}`"); 66 p.error("unmatched `}`");
67 p.bump_any(); 67 p.bump(T!['}']);
68 e.complete(p, ERROR); 68 e.complete(p, ERROR);
69 } else if !p.at(EOF) && !p.at(T!['}']) { 69 } else if !p.at(EOF) && !p.at(T!['}']) {
70 p.err_and_bump("expected an item"); 70 p.err_and_bump("expected an item");
@@ -276,9 +276,9 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
276 276
277fn extern_crate_item(p: &mut Parser, m: Marker) { 277fn extern_crate_item(p: &mut Parser, m: Marker) {
278 assert!(p.at(T![extern])); 278 assert!(p.at(T![extern]));
279 p.bump_any(); 279 p.bump(T![extern]);
280 assert!(p.at(T![crate])); 280 assert!(p.at(T![crate]));
281 p.bump_any(); 281 p.bump(T![crate]);
282 name_ref(p); 282 name_ref(p);
283 opt_alias(p); 283 opt_alias(p);
284 p.expect(T![;]); 284 p.expect(T![;]);
@@ -288,7 +288,7 @@ fn extern_crate_item(p: &mut Parser, m: Marker) {
288pub(crate) fn extern_item_list(p: &mut Parser) { 288pub(crate) fn extern_item_list(p: &mut Parser) {
289 assert!(p.at(T!['{'])); 289 assert!(p.at(T!['{']));
290 let m = p.start(); 290 let m = p.start();
291 p.bump_any(); 291 p.bump(T!['{']);
292 mod_contents(p, true); 292 mod_contents(p, true);
293 p.expect(T!['}']); 293 p.expect(T!['}']);
294 m.complete(p, EXTERN_ITEM_LIST); 294 m.complete(p, EXTERN_ITEM_LIST);
@@ -296,7 +296,7 @@ pub(crate) fn extern_item_list(p: &mut Parser) {
296 296
297fn fn_def(p: &mut Parser, flavor: ItemFlavor) { 297fn fn_def(p: &mut Parser, flavor: ItemFlavor) {
298 assert!(p.at(T![fn])); 298 assert!(p.at(T![fn]));
299 p.bump_any(); 299 p.bump(T![fn]);
300 300
301 name_r(p, ITEM_RECOVERY_SET); 301 name_r(p, ITEM_RECOVERY_SET);
302 // test function_type_params 302 // test function_type_params
@@ -323,7 +323,7 @@ fn fn_def(p: &mut Parser, flavor: ItemFlavor) {
323 // test fn_decl 323 // test fn_decl
324 // trait T { fn foo(); } 324 // trait T { fn foo(); }
325 if p.at(T![;]) { 325 if p.at(T![;]) {
326 p.bump_any(); 326 p.bump(T![;]);
327 } else { 327 } else {
328 expressions::block(p) 328 expressions::block(p)
329 } 329 }
@@ -333,7 +333,7 @@ fn fn_def(p: &mut Parser, flavor: ItemFlavor) {
333// type Foo = Bar; 333// type Foo = Bar;
334fn type_def(p: &mut Parser, m: Marker) { 334fn type_def(p: &mut Parser, m: Marker) {
335 assert!(p.at(T![type])); 335 assert!(p.at(T![type]));
336 p.bump_any(); 336 p.bump(T![type]);
337 337
338 name(p); 338 name(p);
339 339
@@ -357,7 +357,7 @@ fn type_def(p: &mut Parser, m: Marker) {
357 357
358pub(crate) fn mod_item(p: &mut Parser, m: Marker) { 358pub(crate) fn mod_item(p: &mut Parser, m: Marker) {
359 assert!(p.at(T![mod])); 359 assert!(p.at(T![mod]));
360 p.bump_any(); 360 p.bump(T![mod]);
361 361
362 name(p); 362 name(p);
363 if p.at(T!['{']) { 363 if p.at(T!['{']) {
@@ -371,7 +371,7 @@ pub(crate) fn mod_item(p: &mut Parser, m: Marker) {
371pub(crate) fn mod_item_list(p: &mut Parser) { 371pub(crate) fn mod_item_list(p: &mut Parser) {
372 assert!(p.at(T!['{'])); 372 assert!(p.at(T!['{']));
373 let m = p.start(); 373 let m = p.start();
374 p.bump_any(); 374 p.bump(T!['{']);
375 mod_contents(p, true); 375 mod_contents(p, true);
376 p.expect(T!['}']); 376 p.expect(T!['}']);
377 m.complete(p, ITEM_LIST); 377 m.complete(p, ITEM_LIST);
diff --git a/crates/ra_parser/src/grammar/items/consts.rs b/crates/ra_parser/src/grammar/items/consts.rs
index 63e0e6e0c..310260689 100644
--- a/crates/ra_parser/src/grammar/items/consts.rs
+++ b/crates/ra_parser/src/grammar/items/consts.rs
@@ -10,7 +10,7 @@ pub(super) fn const_def(p: &mut Parser, m: Marker) {
10 10
11fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) { 11fn const_or_static(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) {
12 assert!(p.at(kw)); 12 assert!(p.at(kw));
13 p.bump_any(); 13 p.bump(kw);
14 p.eat(T![mut]); // FIXME: validator to forbid const mut 14 p.eat(T![mut]); // FIXME: validator to forbid const mut
15 15
16 // Allow `_` in place of an identifier in a `const`. 16 // Allow `_` in place of an identifier in a `const`.
diff --git a/crates/ra_parser/src/grammar/items/nominal.rs b/crates/ra_parser/src/grammar/items/nominal.rs
index 460acd65e..bede3b692 100644
--- a/crates/ra_parser/src/grammar/items/nominal.rs
+++ b/crates/ra_parser/src/grammar/items/nominal.rs
@@ -11,7 +11,7 @@ pub(super) fn struct_def(p: &mut Parser, m: Marker, kind: SyntaxKind) {
11 type_params::opt_where_clause(p); 11 type_params::opt_where_clause(p);
12 match p.current() { 12 match p.current() {
13 T![;] => { 13 T![;] => {
14 p.bump_any(); 14 p.bump(T![;]);
15 } 15 }
16 T!['{'] => record_field_def_list(p), 16 T!['{'] => record_field_def_list(p),
17 _ => { 17 _ => {
@@ -21,7 +21,7 @@ pub(super) fn struct_def(p: &mut Parser, m: Marker, kind: SyntaxKind) {
21 } 21 }
22 } 22 }
23 T![;] if kind == T![struct] => { 23 T![;] if kind == T![struct] => {
24 p.bump_any(); 24 p.bump(T![;]);
25 } 25 }
26 T!['{'] => record_field_def_list(p), 26 T!['{'] => record_field_def_list(p),
27 T!['('] if kind == T![struct] => { 27 T!['('] if kind == T![struct] => {
@@ -44,7 +44,7 @@ pub(super) fn struct_def(p: &mut Parser, m: Marker, kind: SyntaxKind) {
44 44
45pub(super) fn enum_def(p: &mut Parser, m: Marker) { 45pub(super) fn enum_def(p: &mut Parser, m: Marker) {
46 assert!(p.at(T![enum])); 46 assert!(p.at(T![enum]));
47 p.bump_any(); 47 p.bump(T![enum]);
48 name_r(p, ITEM_RECOVERY_SET); 48 name_r(p, ITEM_RECOVERY_SET);
49 type_params::opt_type_param_list(p); 49 type_params::opt_type_param_list(p);
50 type_params::opt_where_clause(p); 50 type_params::opt_where_clause(p);
@@ -59,7 +59,7 @@ pub(super) fn enum_def(p: &mut Parser, m: Marker) {
59pub(crate) fn enum_variant_list(p: &mut Parser) { 59pub(crate) fn enum_variant_list(p: &mut Parser) {
60 assert!(p.at(T!['{'])); 60 assert!(p.at(T!['{']));
61 let m = p.start(); 61 let m = p.start();
62 p.bump_any(); 62 p.bump(T!['{']);
63 while !p.at(EOF) && !p.at(T!['}']) { 63 while !p.at(EOF) && !p.at(T!['}']) {
64 if p.at(T!['{']) { 64 if p.at(T!['{']) {
65 error_block(p, "expected enum variant"); 65 error_block(p, "expected enum variant");
@@ -73,7 +73,7 @@ pub(crate) fn enum_variant_list(p: &mut Parser) {
73 T!['{'] => record_field_def_list(p), 73 T!['{'] => record_field_def_list(p),
74 T!['('] => tuple_field_def_list(p), 74 T!['('] => tuple_field_def_list(p),
75 T![=] => { 75 T![=] => {
76 p.bump_any(); 76 p.bump(T![=]);
77 expressions::expr(p); 77 expressions::expr(p);
78 } 78 }
79 _ => (), 79 _ => (),
@@ -94,7 +94,7 @@ pub(crate) fn enum_variant_list(p: &mut Parser) {
94pub(crate) fn record_field_def_list(p: &mut Parser) { 94pub(crate) fn record_field_def_list(p: &mut Parser) {
95 assert!(p.at(T!['{'])); 95 assert!(p.at(T!['{']));
96 let m = p.start(); 96 let m = p.start();
97 p.bump_any(); 97 p.bump(T!['{']);
98 while !p.at(T!['}']) && !p.at(EOF) { 98 while !p.at(T!['}']) && !p.at(EOF) {
99 if p.at(T!['{']) { 99 if p.at(T!['{']) {
100 error_block(p, "expected field"); 100 error_block(p, "expected field");
diff --git a/crates/ra_parser/src/grammar/items/traits.rs b/crates/ra_parser/src/grammar/items/traits.rs
index b49221a4b..3742fd197 100644
--- a/crates/ra_parser/src/grammar/items/traits.rs
+++ b/crates/ra_parser/src/grammar/items/traits.rs
@@ -5,7 +5,7 @@ use super::*;
5// trait X<U: Debug + Display>: Hash + Clone where U: Copy {} 5// trait X<U: Debug + Display>: Hash + Clone where U: Copy {}
6pub(super) fn trait_def(p: &mut Parser) { 6pub(super) fn trait_def(p: &mut Parser) {
7 assert!(p.at(T![trait])); 7 assert!(p.at(T![trait]));
8 p.bump_any(); 8 p.bump(T![trait]);
9 name_r(p, ITEM_RECOVERY_SET); 9 name_r(p, ITEM_RECOVERY_SET);
10 type_params::opt_type_param_list(p); 10 type_params::opt_type_param_list(p);
11 if p.at(T![:]) { 11 if p.at(T![:]) {
@@ -29,7 +29,7 @@ pub(super) fn trait_def(p: &mut Parser) {
29pub(crate) fn trait_item_list(p: &mut Parser) { 29pub(crate) fn trait_item_list(p: &mut Parser) {
30 assert!(p.at(T!['{'])); 30 assert!(p.at(T!['{']));
31 let m = p.start(); 31 let m = p.start();
32 p.bump_any(); 32 p.bump(T!['{']);
33 while !p.at(EOF) && !p.at(T!['}']) { 33 while !p.at(EOF) && !p.at(T!['}']) {
34 if p.at(T!['{']) { 34 if p.at(T!['{']) {
35 error_block(p, "expected an item"); 35 error_block(p, "expected an item");
@@ -45,7 +45,7 @@ pub(crate) fn trait_item_list(p: &mut Parser) {
45// impl Foo {} 45// impl Foo {}
46pub(super) fn impl_block(p: &mut Parser) { 46pub(super) fn impl_block(p: &mut Parser) {
47 assert!(p.at(T![impl])); 47 assert!(p.at(T![impl]));
48 p.bump_any(); 48 p.bump(T![impl]);
49 if choose_type_params_over_qpath(p) { 49 if choose_type_params_over_qpath(p) {
50 type_params::opt_type_param_list(p); 50 type_params::opt_type_param_list(p);
51 } 51 }
@@ -78,7 +78,7 @@ pub(super) fn impl_block(p: &mut Parser) {
78pub(crate) fn impl_item_list(p: &mut Parser) { 78pub(crate) fn impl_item_list(p: &mut Parser) {
79 assert!(p.at(T!['{'])); 79 assert!(p.at(T!['{']));
80 let m = p.start(); 80 let m = p.start();
81 p.bump_any(); 81 p.bump(T!['{']);
82 // test impl_inner_attributes 82 // test impl_inner_attributes
83 // enum F{} 83 // enum F{}
84 // impl F { 84 // impl F {
diff --git a/crates/ra_parser/src/grammar/items/use_item.rs b/crates/ra_parser/src/grammar/items/use_item.rs
index f28f522b8..2af2ad315 100644
--- a/crates/ra_parser/src/grammar/items/use_item.rs
+++ b/crates/ra_parser/src/grammar/items/use_item.rs
@@ -2,7 +2,7 @@ use super::*;
2 2
3pub(super) fn use_item(p: &mut Parser, m: Marker) { 3pub(super) fn use_item(p: &mut Parser, m: Marker) {
4 assert!(p.at(T![use])); 4 assert!(p.at(T![use]));
5 p.bump_any(); 5 p.bump(T![use]);
6 use_tree(p); 6 use_tree(p);
7 p.expect(T![;]); 7 p.expect(T![;]);
8 m.complete(p, USE_ITEM); 8 m.complete(p, USE_ITEM);
@@ -84,7 +84,7 @@ fn use_tree(p: &mut Parser) {
84 p.bump(T![::]); 84 p.bump(T![::]);
85 match p.current() { 85 match p.current() {
86 T![*] => { 86 T![*] => {
87 p.bump_any(); 87 p.bump(T![*]);
88 } 88 }
89 // test use_tree_list_after_path 89 // test use_tree_list_after_path
90 // use crate::{Item}; 90 // use crate::{Item};
@@ -114,7 +114,7 @@ fn use_tree(p: &mut Parser) {
114pub(crate) fn use_tree_list(p: &mut Parser) { 114pub(crate) fn use_tree_list(p: &mut Parser) {
115 assert!(p.at(T!['{'])); 115 assert!(p.at(T!['{']));
116 let m = p.start(); 116 let m = p.start();
117 p.bump_any(); 117 p.bump(T!['{']);
118 while !p.at(EOF) && !p.at(T!['}']) { 118 while !p.at(EOF) && !p.at(T!['}']) {
119 use_tree(p); 119 use_tree(p);
120 if !p.at(T!['}']) { 120 if !p.at(T!['}']) {
diff --git a/crates/ra_parser/src/grammar/params.rs b/crates/ra_parser/src/grammar/params.rs
index 5893b22fd..efc329243 100644
--- a/crates/ra_parser/src/grammar/params.rs
+++ b/crates/ra_parser/src/grammar/params.rs
@@ -39,7 +39,7 @@ fn list_(p: &mut Parser, flavor: Flavor) {
39 let (bra, ket) = if flavor.type_required() { (T!['('], T![')']) } else { (T![|], T![|]) }; 39 let (bra, ket) = if flavor.type_required() { (T!['('], T![')']) } else { (T![|], T![|]) };
40 assert!(p.at(bra)); 40 assert!(p.at(bra));
41 let m = p.start(); 41 let m = p.start();
42 p.bump_any(); 42 p.bump(bra);
43 if flavor.type_required() { 43 if flavor.type_required() {
44 // test self_param_outer_attr 44 // test self_param_outer_attr
45 // fn f(#[must_use] self) {} 45 // fn f(#[must_use] self) {}
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs
index 919b0f37d..a4ffd6960 100644
--- a/crates/ra_parser/src/grammar/patterns.rs
+++ b/crates/ra_parser/src/grammar/patterns.rs
@@ -106,7 +106,7 @@ fn literal_pat(p: &mut Parser) -> CompletedMarker {
106 assert!(is_literal_pat_start(p)); 106 assert!(is_literal_pat_start(p));
107 let m = p.start(); 107 let m = p.start();
108 if p.at(T![-]) { 108 if p.at(T![-]) {
109 p.bump_any(); 109 p.bump(T![-]);
110 } 110 }
111 expressions::literal(p); 111 expressions::literal(p);
112 m.complete(p, LITERAL_PAT) 112 m.complete(p, LITERAL_PAT)
@@ -146,7 +146,7 @@ fn path_pat(p: &mut Parser) -> CompletedMarker {
146// } 146// }
147fn tuple_pat_fields(p: &mut Parser) { 147fn tuple_pat_fields(p: &mut Parser) {
148 assert!(p.at(T!['('])); 148 assert!(p.at(T!['(']));
149 p.bump_any(); 149 p.bump(T!['(']);
150 pat_list(p, T![')']); 150 pat_list(p, T![')']);
151 p.expect(T![')']); 151 p.expect(T![')']);
152} 152}
@@ -161,7 +161,7 @@ fn tuple_pat_fields(p: &mut Parser) {
161fn record_field_pat_list(p: &mut Parser) { 161fn record_field_pat_list(p: &mut Parser) {
162 assert!(p.at(T!['{'])); 162 assert!(p.at(T!['{']));
163 let m = p.start(); 163 let m = p.start();
164 p.bump_any(); 164 p.bump(T!['{']);
165 while !p.at(EOF) && !p.at(T!['}']) { 165 while !p.at(EOF) && !p.at(T!['}']) {
166 match p.current() { 166 match p.current() {
167 // A trailing `..` is *not* treated as a DOT_DOT_PAT. 167 // A trailing `..` is *not* treated as a DOT_DOT_PAT.
@@ -200,7 +200,7 @@ fn record_field_pat(p: &mut Parser) {
200fn placeholder_pat(p: &mut Parser) -> CompletedMarker { 200fn placeholder_pat(p: &mut Parser) -> CompletedMarker {
201 assert!(p.at(T![_])); 201 assert!(p.at(T![_]));
202 let m = p.start(); 202 let m = p.start();
203 p.bump_any(); 203 p.bump(T![_]);
204 m.complete(p, PLACEHOLDER_PAT) 204 m.complete(p, PLACEHOLDER_PAT)
205} 205}
206 206
@@ -245,7 +245,7 @@ fn dot_dot_pat(p: &mut Parser) -> CompletedMarker {
245fn ref_pat(p: &mut Parser) -> CompletedMarker { 245fn ref_pat(p: &mut Parser) -> CompletedMarker {
246 assert!(p.at(T![&])); 246 assert!(p.at(T![&]));
247 let m = p.start(); 247 let m = p.start();
248 p.bump_any(); 248 p.bump(T![&]);
249 p.eat(T![mut]); 249 p.eat(T![mut]);
250 pattern(p); 250 pattern(p);
251 m.complete(p, REF_PAT) 251 m.complete(p, REF_PAT)
@@ -269,7 +269,7 @@ fn tuple_pat(p: &mut Parser) -> CompletedMarker {
269fn slice_pat(p: &mut Parser) -> CompletedMarker { 269fn slice_pat(p: &mut Parser) -> CompletedMarker {
270 assert!(p.at(T!['['])); 270 assert!(p.at(T!['[']));
271 let m = p.start(); 271 let m = p.start();
272 p.bump_any(); 272 p.bump(T!['[']);
273 pat_list(p, T![']']); 273 pat_list(p, T![']']);
274 p.expect(T![']']); 274 p.expect(T![']']);
275 m.complete(p, SLICE_PAT) 275 m.complete(p, SLICE_PAT)
@@ -318,7 +318,7 @@ fn bind_pat(p: &mut Parser, with_at: bool) -> CompletedMarker {
318fn box_pat(p: &mut Parser) -> CompletedMarker { 318fn box_pat(p: &mut Parser) -> CompletedMarker {
319 assert!(p.at(T![box])); 319 assert!(p.at(T![box]));
320 let m = p.start(); 320 let m = p.start();
321 p.bump_any(); 321 p.bump(T![box]);
322 pattern(p); 322 pattern(p);
323 m.complete(p, BOX_PAT) 323 m.complete(p, BOX_PAT)
324} 324}
diff --git a/crates/ra_parser/src/grammar/type_args.rs b/crates/ra_parser/src/grammar/type_args.rs
index edc7d4ff2..8e97fe03c 100644
--- a/crates/ra_parser/src/grammar/type_args.rs
+++ b/crates/ra_parser/src/grammar/type_args.rs
@@ -29,7 +29,7 @@ fn type_arg(p: &mut Parser) {
29 let m = p.start(); 29 let m = p.start();
30 match p.current() { 30 match p.current() {
31 LIFETIME => { 31 LIFETIME => {
32 p.bump_any(); 32 p.bump(LIFETIME);
33 m.complete(p, LIFETIME_ARG); 33 m.complete(p, LIFETIME_ARG);
34 } 34 }
35 // test associated_type_bounds 35 // test associated_type_bounds
diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs
index 31d709d81..7071c70ea 100644
--- a/crates/ra_parser/src/grammar/type_params.rs
+++ b/crates/ra_parser/src/grammar/type_params.rs
@@ -10,7 +10,7 @@ pub(super) fn opt_type_param_list(p: &mut Parser) {
10fn type_param_list(p: &mut Parser) { 10fn type_param_list(p: &mut Parser) {
11 assert!(p.at(T![<])); 11 assert!(p.at(T![<]));
12 let m = p.start(); 12 let m = p.start();
13 p.bump_any(); 13 p.bump(T![<]);
14 14
15 while !p.at(EOF) && !p.at(T![>]) { 15 while !p.at(EOF) && !p.at(T![>]) {
16 let m = p.start(); 16 let m = p.start();
@@ -38,7 +38,7 @@ fn type_param_list(p: &mut Parser) {
38 38
39fn lifetime_param(p: &mut Parser, m: Marker) { 39fn lifetime_param(p: &mut Parser, m: Marker) {
40 assert!(p.at(LIFETIME)); 40 assert!(p.at(LIFETIME));
41 p.bump_any(); 41 p.bump(LIFETIME);
42 if p.at(T![:]) { 42 if p.at(T![:]) {
43 lifetime_bounds(p); 43 lifetime_bounds(p);
44 } 44 }
@@ -54,7 +54,7 @@ fn type_param(p: &mut Parser, m: Marker) {
54 // test type_param_default 54 // test type_param_default
55 // struct S<T = i32>; 55 // struct S<T = i32>;
56 if p.at(T![=]) { 56 if p.at(T![=]) {
57 p.bump_any(); 57 p.bump(T![=]);
58 types::type_(p) 58 types::type_(p)
59 } 59 }
60 m.complete(p, TYPE_PARAM); 60 m.complete(p, TYPE_PARAM);
@@ -64,15 +64,15 @@ fn type_param(p: &mut Parser, m: Marker) {
64// struct S<T: 'a + ?Sized + (Copy)>; 64// struct S<T: 'a + ?Sized + (Copy)>;
65pub(super) fn bounds(p: &mut Parser) { 65pub(super) fn bounds(p: &mut Parser) {
66 assert!(p.at(T![:])); 66 assert!(p.at(T![:]));
67 p.bump_any(); 67 p.bump(T![:]);
68 bounds_without_colon(p); 68 bounds_without_colon(p);
69} 69}
70 70
71fn lifetime_bounds(p: &mut Parser) { 71fn lifetime_bounds(p: &mut Parser) {
72 assert!(p.at(T![:])); 72 assert!(p.at(T![:]));
73 p.bump_any(); 73 p.bump(T![:]);
74 while p.at(LIFETIME) { 74 while p.at(LIFETIME) {
75 p.bump_any(); 75 p.bump(LIFETIME);
76 if !p.eat(T![+]) { 76 if !p.eat(T![+]) {
77 break; 77 break;
78 } 78 }
@@ -99,7 +99,7 @@ fn type_bound(p: &mut Parser) -> bool {
99 let has_paren = p.eat(T!['(']); 99 let has_paren = p.eat(T!['(']);
100 p.eat(T![?]); 100 p.eat(T![?]);
101 match p.current() { 101 match p.current() {
102 LIFETIME => p.bump_any(), 102 LIFETIME => p.bump(LIFETIME),
103 T![for] => types::for_type(p), 103 T![for] => types::for_type(p),
104 _ if paths::is_use_path_start(p) => types::path_type_(p, false), 104 _ if paths::is_use_path_start(p) => types::path_type_(p, false),
105 _ => { 105 _ => {
@@ -128,7 +128,7 @@ pub(super) fn opt_where_clause(p: &mut Parser) {
128 return; 128 return;
129 } 129 }
130 let m = p.start(); 130 let m = p.start();
131 p.bump_any(); 131 p.bump(T![where]);
132 132
133 while is_where_predicate(p) { 133 while is_where_predicate(p) {
134 where_predicate(p); 134 where_predicate(p);
@@ -166,7 +166,7 @@ fn where_predicate(p: &mut Parser) {
166 let m = p.start(); 166 let m = p.start();
167 match p.current() { 167 match p.current() {
168 LIFETIME => { 168 LIFETIME => {
169 p.bump_any(); 169 p.bump(LIFETIME);
170 if p.at(T![:]) { 170 if p.at(T![:]) {
171 bounds(p); 171 bounds(p);
172 } else { 172 } else {
diff --git a/crates/ra_parser/src/grammar/types.rs b/crates/ra_parser/src/grammar/types.rs
index a5a5b6d73..4e3522d48 100644
--- a/crates/ra_parser/src/grammar/types.rs
+++ b/crates/ra_parser/src/grammar/types.rs
@@ -44,7 +44,7 @@ pub(super) fn ascription(p: &mut Parser) {
44fn paren_or_tuple_type(p: &mut Parser) { 44fn paren_or_tuple_type(p: &mut Parser) {
45 assert!(p.at(T!['('])); 45 assert!(p.at(T!['(']));
46 let m = p.start(); 46 let m = p.start();
47 p.bump_any(); 47 p.bump(T!['(']);
48 let mut n_types: u32 = 0; 48 let mut n_types: u32 = 0;
49 let mut trailing_comma: bool = false; 49 let mut trailing_comma: bool = false;
50 while !p.at(EOF) && !p.at(T![')']) { 50 while !p.at(EOF) && !p.at(T![')']) {
@@ -79,14 +79,14 @@ fn paren_or_tuple_type(p: &mut Parser) {
79fn never_type(p: &mut Parser) { 79fn never_type(p: &mut Parser) {
80 assert!(p.at(T![!])); 80 assert!(p.at(T![!]));
81 let m = p.start(); 81 let m = p.start();
82 p.bump_any(); 82 p.bump(T![!]);
83 m.complete(p, NEVER_TYPE); 83 m.complete(p, NEVER_TYPE);
84} 84}
85 85
86fn pointer_type(p: &mut Parser) { 86fn pointer_type(p: &mut Parser) {
87 assert!(p.at(T![*])); 87 assert!(p.at(T![*]));
88 let m = p.start(); 88 let m = p.start();
89 p.bump_any(); 89 p.bump(T![*]);
90 90
91 match p.current() { 91 match p.current() {
92 // test pointer_type_mut 92 // test pointer_type_mut
@@ -110,21 +110,21 @@ fn pointer_type(p: &mut Parser) {
110fn array_or_slice_type(p: &mut Parser) { 110fn array_or_slice_type(p: &mut Parser) {
111 assert!(p.at(T!['['])); 111 assert!(p.at(T!['[']));
112 let m = p.start(); 112 let m = p.start();
113 p.bump_any(); 113 p.bump(T!['[']);
114 114
115 type_(p); 115 type_(p);
116 let kind = match p.current() { 116 let kind = match p.current() {
117 // test slice_type 117 // test slice_type
118 // type T = [()]; 118 // type T = [()];
119 T![']'] => { 119 T![']'] => {
120 p.bump_any(); 120 p.bump(T![']']);
121 SLICE_TYPE 121 SLICE_TYPE
122 } 122 }
123 123
124 // test array_type 124 // test array_type
125 // type T = [(); 92]; 125 // type T = [(); 92];
126 T![;] => { 126 T![;] => {
127 p.bump_any(); 127 p.bump(T![;]);
128 expressions::expr(p); 128 expressions::expr(p);
129 p.expect(T![']']); 129 p.expect(T![']']);
130 ARRAY_TYPE 130 ARRAY_TYPE
@@ -146,7 +146,7 @@ fn array_or_slice_type(p: &mut Parser) {
146fn reference_type(p: &mut Parser) { 146fn reference_type(p: &mut Parser) {
147 assert!(p.at(T![&])); 147 assert!(p.at(T![&]));
148 let m = p.start(); 148 let m = p.start();
149 p.bump_any(); 149 p.bump(T![&]);
150 p.eat(LIFETIME); 150 p.eat(LIFETIME);
151 p.eat(T![mut]); 151 p.eat(T![mut]);
152 type_no_bounds(p); 152 type_no_bounds(p);
@@ -158,7 +158,7 @@ fn reference_type(p: &mut Parser) {
158fn placeholder_type(p: &mut Parser) { 158fn placeholder_type(p: &mut Parser) {
159 assert!(p.at(T![_])); 159 assert!(p.at(T![_]));
160 let m = p.start(); 160 let m = p.start();
161 p.bump_any(); 161 p.bump(T![_]);
162 m.complete(p, PLACEHOLDER_TYPE); 162 m.complete(p, PLACEHOLDER_TYPE);
163} 163}
164 164
@@ -193,7 +193,7 @@ fn fn_pointer_type(p: &mut Parser) {
193 193
194pub(super) fn for_binder(p: &mut Parser) { 194pub(super) fn for_binder(p: &mut Parser) {
195 assert!(p.at(T![for])); 195 assert!(p.at(T![for]));
196 p.bump_any(); 196 p.bump(T![for]);
197 if p.at(T![<]) { 197 if p.at(T![<]) {
198 type_params::opt_type_param_list(p); 198 type_params::opt_type_param_list(p);
199 } else { 199 } else {
@@ -224,7 +224,7 @@ pub(super) fn for_type(p: &mut Parser) {
224fn impl_trait_type(p: &mut Parser) { 224fn impl_trait_type(p: &mut Parser) {
225 assert!(p.at(T![impl])); 225 assert!(p.at(T![impl]));
226 let m = p.start(); 226 let m = p.start();
227 p.bump_any(); 227 p.bump(T![impl]);
228 type_params::bounds_without_colon(p); 228 type_params::bounds_without_colon(p);
229 m.complete(p, IMPL_TRAIT_TYPE); 229 m.complete(p, IMPL_TRAIT_TYPE);
230} 230}
@@ -234,7 +234,7 @@ fn impl_trait_type(p: &mut Parser) {
234fn dyn_trait_type(p: &mut Parser) { 234fn dyn_trait_type(p: &mut Parser) {
235 assert!(p.at(T![dyn ])); 235 assert!(p.at(T![dyn ]));
236 let m = p.start(); 236 let m = p.start();
237 p.bump_any(); 237 p.bump(T![dyn ]);
238 type_params::bounds_without_colon(p); 238 type_params::bounds_without_colon(p);
239 m.complete(p, DYN_TRAIT_TYPE); 239 m.complete(p, DYN_TRAIT_TYPE);
240} 240}
diff --git a/docs/user/features.md b/docs/user/features.md
index 1034a5117..93e565315 100644
--- a/docs/user/features.md
+++ b/docs/user/features.md
@@ -445,6 +445,62 @@ fn foo<T: u32, F: FnOnce(T) -> T>() {}
445fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {} 445fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {}
446``` 446```
447 447
448- Make raw string
449
450```rust
451// before:
452fn f() {
453 let s = <|>"abcd";
454}
455
456// after:
457fn f() {
458 let s = <|>r"abcd";
459}
460```
461
462- Make usual string
463
464```rust
465// before:
466fn f() {
467 let s = <|>r#"abcd"#;
468}
469
470// after:
471fn f() {
472 let s = <|>"abcd";
473}
474```
475
476- Add hash
477
478```rust
479// before:
480fn f() {
481 let s = <|>r"abcd";
482}
483
484// after:
485fn f() {
486 let s = <|>r#"abcd"#;
487}
488```
489
490- Remove hash
491
492```rust
493// before:
494fn f() {
495 let s = <|>r#"abcd"#;
496}
497
498// after:
499fn f() {
500 let s = <|>r"abcd";
501}
502```
503
448### Magic Completions 504### Magic Completions
449 505
450In addition to usual reference completion, rust-analyzer provides some ✨magic✨ 506In addition to usual reference completion, rust-analyzer provides some ✨magic✨