aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src')
-rw-r--r--crates/ra_ide_api/src/completion.rs8
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_record_literal.rs (renamed from crates/ra_ide_api/src/completion/complete_struct_literal.rs)14
-rw-r--r--crates/ra_ide_api/src/completion/complete_record_pattern.rs (renamed from crates/ra_ide_api/src/completion/complete_struct_pattern.rs)10
-rw-r--r--crates/ra_ide_api/src/completion/completion_context.rs16
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs2
-rw-r--r--crates/ra_ide_api/src/diagnostics.rs233
-rw-r--r--crates/ra_ide_api/src/display/navigation_target.rs4
-rw-r--r--crates/ra_ide_api/src/display/short_label.rs2
-rw-r--r--crates/ra_ide_api/src/display/structure.rs4
-rw-r--r--crates/ra_ide_api/src/extend_selection.rs8
-rw-r--r--crates/ra_ide_api/src/folding_ranges.rs10
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs12
-rw-r--r--crates/ra_ide_api/src/hover.rs2
-rw-r--r--crates/ra_ide_api/src/inlay_hints.rs10
-rw-r--r--crates/ra_ide_api/src/marks.rs2
-rw-r--r--crates/ra_ide_api/src/name_ref_kind.rs8
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs2
18 files changed, 284 insertions, 65 deletions
diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs
index a6b68be75..a4f080adc 100644
--- a/crates/ra_ide_api/src/completion.rs
+++ b/crates/ra_ide_api/src/completion.rs
@@ -3,8 +3,8 @@ mod completion_context;
3mod presentation; 3mod presentation;
4 4
5mod complete_dot; 5mod complete_dot;
6mod complete_struct_literal; 6mod complete_record_literal;
7mod complete_struct_pattern; 7mod complete_record_pattern;
8mod complete_pattern; 8mod complete_pattern;
9mod complete_fn_param; 9mod complete_fn_param;
10mod complete_keyword; 10mod complete_keyword;
@@ -65,8 +65,8 @@ pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Opti
65 complete_path::complete_path(&mut acc, &ctx); 65 complete_path::complete_path(&mut acc, &ctx);
66 complete_scope::complete_scope(&mut acc, &ctx); 66 complete_scope::complete_scope(&mut acc, &ctx);
67 complete_dot::complete_dot(&mut acc, &ctx); 67 complete_dot::complete_dot(&mut acc, &ctx);
68 complete_struct_literal::complete_struct_literal(&mut acc, &ctx); 68 complete_record_literal::complete_record_literal(&mut acc, &ctx);
69 complete_struct_pattern::complete_struct_pattern(&mut acc, &ctx); 69 complete_record_pattern::complete_record_pattern(&mut acc, &ctx);
70 complete_pattern::complete_pattern(&mut acc, &ctx); 70 complete_pattern::complete_pattern(&mut acc, &ctx);
71 complete_postfix::complete_postfix(&mut acc, &ctx); 71 complete_postfix::complete_postfix(&mut acc, &ctx);
72 Some(acc) 72 Some(acc)
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index d43ff2eec..27256f879 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -45,7 +45,7 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
45 // FIXME unions 45 // FIXME unions
46 TypeCtor::Tuple { .. } => { 46 TypeCtor::Tuple { .. } => {
47 for (i, ty) in a_ty.parameters.iter().enumerate() { 47 for (i, ty) in a_ty.parameters.iter().enumerate() {
48 acc.add_pos_field(ctx, i, ty); 48 acc.add_tuple_field(ctx, i, ty);
49 } 49 }
50 } 50 }
51 _ => {} 51 _ => {}
diff --git a/crates/ra_ide_api/src/completion/complete_struct_literal.rs b/crates/ra_ide_api/src/completion/complete_record_literal.rs
index 6aa41f498..6b929a8ac 100644
--- a/crates/ra_ide_api/src/completion/complete_struct_literal.rs
+++ b/crates/ra_ide_api/src/completion/complete_record_literal.rs
@@ -3,11 +3,11 @@ use hir::Substs;
3use crate::completion::{CompletionContext, Completions}; 3use crate::completion::{CompletionContext, Completions};
4 4
5/// Complete fields in fields literals. 5/// Complete fields in fields literals.
6pub(super) fn complete_struct_literal(acc: &mut Completions, ctx: &CompletionContext) { 6pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionContext) {
7 let (ty, variant) = match ctx.struct_lit_syntax.as_ref().and_then(|it| { 7 let (ty, variant) = match ctx.record_lit_syntax.as_ref().and_then(|it| {
8 Some(( 8 Some((
9 ctx.analyzer.type_of(ctx.db, &it.clone().into())?, 9 ctx.analyzer.type_of(ctx.db, &it.clone().into())?,
10 ctx.analyzer.resolve_struct_literal(it)?, 10 ctx.analyzer.resolve_record_literal(it)?,
11 )) 11 ))
12 }) { 12 }) {
13 Some(it) => it, 13 Some(it) => it,
@@ -30,7 +30,7 @@ mod tests {
30 } 30 }
31 31
32 #[test] 32 #[test]
33 fn test_struct_literal_field() { 33 fn test_record_literal_field() {
34 let completions = complete( 34 let completions = complete(
35 r" 35 r"
36 struct A { the_field: u32 } 36 struct A { the_field: u32 }
@@ -54,7 +54,7 @@ mod tests {
54 } 54 }
55 55
56 #[test] 56 #[test]
57 fn test_struct_literal_enum_variant() { 57 fn test_record_literal_enum_variant() {
58 let completions = complete( 58 let completions = complete(
59 r" 59 r"
60 enum E { 60 enum E {
@@ -80,7 +80,7 @@ mod tests {
80 } 80 }
81 81
82 #[test] 82 #[test]
83 fn test_struct_literal_two_structs() { 83 fn test_record_literal_two_structs() {
84 let completions = complete( 84 let completions = complete(
85 r" 85 r"
86 struct A { a: u32 } 86 struct A { a: u32 }
@@ -106,7 +106,7 @@ mod tests {
106 } 106 }
107 107
108 #[test] 108 #[test]
109 fn test_struct_literal_generic_struct() { 109 fn test_record_literal_generic_struct() {
110 let completions = complete( 110 let completions = complete(
111 r" 111 r"
112 struct A<T> { a: T } 112 struct A<T> { a: T }
diff --git a/crates/ra_ide_api/src/completion/complete_struct_pattern.rs b/crates/ra_ide_api/src/completion/complete_record_pattern.rs
index d0dde5930..8c8b47ea4 100644
--- a/crates/ra_ide_api/src/completion/complete_struct_pattern.rs
+++ b/crates/ra_ide_api/src/completion/complete_record_pattern.rs
@@ -2,11 +2,11 @@ use hir::Substs;
2 2
3use crate::completion::{CompletionContext, Completions}; 3use crate::completion::{CompletionContext, Completions};
4 4
5pub(super) fn complete_struct_pattern(acc: &mut Completions, ctx: &CompletionContext) { 5pub(super) fn complete_record_pattern(acc: &mut Completions, ctx: &CompletionContext) {
6 let (ty, variant) = match ctx.struct_lit_pat.as_ref().and_then(|it| { 6 let (ty, variant) = match ctx.record_lit_pat.as_ref().and_then(|it| {
7 Some(( 7 Some((
8 ctx.analyzer.type_of_pat(ctx.db, &it.clone().into())?, 8 ctx.analyzer.type_of_pat(ctx.db, &it.clone().into())?,
9 ctx.analyzer.resolve_struct_pattern(it)?, 9 ctx.analyzer.resolve_record_pattern(it)?,
10 )) 10 ))
11 }) { 11 }) {
12 Some(it) => it, 12 Some(it) => it,
@@ -29,7 +29,7 @@ mod tests {
29 } 29 }
30 30
31 #[test] 31 #[test]
32 fn test_struct_pattern_field() { 32 fn test_record_pattern_field() {
33 let completions = complete( 33 let completions = complete(
34 r" 34 r"
35 struct S { foo: u32 } 35 struct S { foo: u32 }
@@ -56,7 +56,7 @@ mod tests {
56 } 56 }
57 57
58 #[test] 58 #[test]
59 fn test_struct_pattern_enum_variant() { 59 fn test_record_pattern_enum_variant() {
60 let completions = complete( 60 let completions = complete(
61 r" 61 r"
62 enum E { 62 enum E {
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs
index dfaa9ce69..7139947b3 100644
--- a/crates/ra_ide_api/src/completion/completion_context.rs
+++ b/crates/ra_ide_api/src/completion/completion_context.rs
@@ -20,8 +20,8 @@ pub(crate) struct CompletionContext<'a> {
20 pub(super) module: Option<hir::Module>, 20 pub(super) module: Option<hir::Module>,
21 pub(super) function_syntax: Option<ast::FnDef>, 21 pub(super) function_syntax: Option<ast::FnDef>,
22 pub(super) use_item_syntax: Option<ast::UseItem>, 22 pub(super) use_item_syntax: Option<ast::UseItem>,
23 pub(super) struct_lit_syntax: Option<ast::StructLit>, 23 pub(super) record_lit_syntax: Option<ast::RecordLit>,
24 pub(super) struct_lit_pat: Option<ast::StructPat>, 24 pub(super) record_lit_pat: Option<ast::RecordPat>,
25 pub(super) is_param: bool, 25 pub(super) is_param: bool,
26 /// If a name-binding or reference to a const in a pattern. 26 /// If a name-binding or reference to a const in a pattern.
27 /// Irrefutable patterns (like let) are excluded. 27 /// Irrefutable patterns (like let) are excluded.
@@ -60,8 +60,8 @@ impl<'a> CompletionContext<'a> {
60 module, 60 module,
61 function_syntax: None, 61 function_syntax: None,
62 use_item_syntax: None, 62 use_item_syntax: None,
63 struct_lit_syntax: None, 63 record_lit_syntax: None,
64 struct_lit_pat: None, 64 record_lit_pat: None,
65 is_param: false, 65 is_param: false,
66 is_pat_binding: false, 66 is_pat_binding: false,
67 is_trivial_path: false, 67 is_trivial_path: false,
@@ -120,8 +120,8 @@ impl<'a> CompletionContext<'a> {
120 self.is_param = true; 120 self.is_param = true;
121 return; 121 return;
122 } 122 }
123 if name.syntax().ancestors().find_map(ast::FieldPatList::cast).is_some() { 123 if name.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() {
124 self.struct_lit_pat = 124 self.record_lit_pat =
125 find_node_at_offset(original_parse.tree().syntax(), self.offset); 125 find_node_at_offset(original_parse.tree().syntax(), self.offset);
126 } 126 }
127 } 127 }
@@ -129,8 +129,8 @@ impl<'a> CompletionContext<'a> {
129 129
130 fn classify_name_ref(&mut self, original_file: SourceFile, name_ref: ast::NameRef) { 130 fn classify_name_ref(&mut self, original_file: SourceFile, name_ref: ast::NameRef) {
131 let name_range = name_ref.syntax().text_range(); 131 let name_range = name_ref.syntax().text_range();
132 if name_ref.syntax().parent().and_then(ast::NamedField::cast).is_some() { 132 if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() {
133 self.struct_lit_syntax = find_node_at_offset(original_file.syntax(), self.offset); 133 self.record_lit_syntax = find_node_at_offset(original_file.syntax(), self.offset);
134 } 134 }
135 135
136 let top_node = name_ref 136 let top_node = name_ref
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index 2b3f98482..147ceda0c 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -28,7 +28,7 @@ impl Completions {
28 .add_to(self); 28 .add_to(self);
29 } 29 }
30 30
31 pub(crate) fn add_pos_field(&mut self, ctx: &CompletionContext, field: usize, ty: &hir::Ty) { 31 pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &hir::Ty) {
32 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string()) 32 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string())
33 .kind(CompletionItemKind::Field) 33 .kind(CompletionItemKind::Field)
34 .detail(ty.display(ctx.db).to_string()) 34 .detail(ty.display(ctx.db).to_string())
diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs
index 98b840b26..1a4882824 100644
--- a/crates/ra_ide_api/src/diagnostics.rs
+++ b/crates/ra_ide_api/src/diagnostics.rs
@@ -9,7 +9,7 @@ use ra_assists::ast_editor::{AstBuilder, AstEditor};
9use ra_db::SourceDatabase; 9use ra_db::SourceDatabase;
10use ra_prof::profile; 10use ra_prof::profile;
11use ra_syntax::{ 11use ra_syntax::{
12 ast::{self, AstNode, NamedField}, 12 ast::{self, AstNode, RecordField},
13 Location, SyntaxNode, TextRange, T, 13 Location, SyntaxNode, TextRange, T,
14}; 14};
15use ra_text_edit::{TextEdit, TextEditBuilder}; 15use ra_text_edit::{TextEdit, TextEditBuilder};
@@ -62,7 +62,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
62 let node = d.ast(db); 62 let node = d.ast(db);
63 let mut ast_editor = AstEditor::new(node); 63 let mut ast_editor = AstEditor::new(node);
64 for f in d.missed_fields.iter() { 64 for f in d.missed_fields.iter() {
65 ast_editor.append_field(&AstBuilder::<NamedField>::from_name(f)); 65 ast_editor.append_field(&AstBuilder::<RecordField>::from_name(f));
66 } 66 }
67 67
68 let mut builder = TextEditBuilder::default(); 68 let mut builder = TextEditBuilder::default();
@@ -75,6 +75,19 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
75 severity: Severity::Error, 75 severity: Severity::Error,
76 fix: Some(fix), 76 fix: Some(fix),
77 }) 77 })
78 })
79 .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| {
80 let node = d.ast(db);
81 let mut builder = TextEditBuilder::default();
82 let replacement = format!("Ok({})", node.syntax());
83 builder.replace(node.syntax().text_range(), replacement);
84 let fix = SourceChange::source_file_edit_from("wrap with ok", file_id, builder.finish());
85 res.borrow_mut().push(Diagnostic {
86 range: d.highlight_range(),
87 message: d.message(),
88 severity: Severity::Error,
89 fix: Some(fix),
90 })
78 }); 91 });
79 if let Some(m) = source_binder::module_from_file_id(db, file_id) { 92 if let Some(m) = source_binder::module_from_file_id(db, file_id) {
80 m.diagnostics(db, &mut sink); 93 m.diagnostics(db, &mut sink);
@@ -141,20 +154,20 @@ fn check_struct_shorthand_initialization(
141 file_id: FileId, 154 file_id: FileId,
142 node: &SyntaxNode, 155 node: &SyntaxNode,
143) -> Option<()> { 156) -> Option<()> {
144 let struct_lit = ast::StructLit::cast(node.clone())?; 157 let record_lit = ast::RecordLit::cast(node.clone())?;
145 let named_field_list = struct_lit.named_field_list()?; 158 let record_field_list = record_lit.record_field_list()?;
146 for named_field in named_field_list.fields() { 159 for record_field in record_field_list.fields() {
147 if let (Some(name_ref), Some(expr)) = (named_field.name_ref(), named_field.expr()) { 160 if let (Some(name_ref), Some(expr)) = (record_field.name_ref(), record_field.expr()) {
148 let field_name = name_ref.syntax().text().to_string(); 161 let field_name = name_ref.syntax().text().to_string();
149 let field_expr = expr.syntax().text().to_string(); 162 let field_expr = expr.syntax().text().to_string();
150 if field_name == field_expr { 163 if field_name == field_expr {
151 let mut edit_builder = TextEditBuilder::default(); 164 let mut edit_builder = TextEditBuilder::default();
152 edit_builder.delete(named_field.syntax().text_range()); 165 edit_builder.delete(record_field.syntax().text_range());
153 edit_builder.insert(named_field.syntax().text_range().start(), field_name); 166 edit_builder.insert(record_field.syntax().text_range().start(), field_name);
154 let edit = edit_builder.finish(); 167 let edit = edit_builder.finish();
155 168
156 acc.push(Diagnostic { 169 acc.push(Diagnostic {
157 range: named_field.syntax().text_range(), 170 range: record_field.syntax().text_range(),
158 message: "Shorthand struct initialization".to_string(), 171 message: "Shorthand struct initialization".to_string(),
159 severity: Severity::WeakWarning, 172 severity: Severity::WeakWarning,
160 fix: Some(SourceChange::source_file_edit( 173 fix: Some(SourceChange::source_file_edit(
@@ -171,10 +184,11 @@ fn check_struct_shorthand_initialization(
171#[cfg(test)] 184#[cfg(test)]
172mod tests { 185mod tests {
173 use insta::assert_debug_snapshot_matches; 186 use insta::assert_debug_snapshot_matches;
187 use join_to_string::join;
174 use ra_syntax::SourceFile; 188 use ra_syntax::SourceFile;
175 use test_utils::assert_eq_text; 189 use test_utils::assert_eq_text;
176 190
177 use crate::mock_analysis::single_file; 191 use crate::mock_analysis::{analysis_and_position, single_file};
178 192
179 use super::*; 193 use super::*;
180 194
@@ -203,6 +217,48 @@ mod tests {
203 assert_eq_text!(after, &actual); 217 assert_eq_text!(after, &actual);
204 } 218 }
205 219
220 /// Takes a multi-file input fixture with annotated cursor positions,
221 /// and checks that:
222 /// * a diagnostic is produced
223 /// * this diagnostic touches the input cursor position
224 /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied
225 fn check_apply_diagnostic_fix_from_position(fixture: &str, after: &str) {
226 let (analysis, file_position) = analysis_and_position(fixture);
227 let diagnostic = analysis.diagnostics(file_position.file_id).unwrap().pop().unwrap();
228 let mut fix = diagnostic.fix.unwrap();
229 let edit = fix.source_file_edits.pop().unwrap().edit;
230 let target_file_contents = analysis.file_text(file_position.file_id).unwrap();
231 let actual = edit.apply(&target_file_contents);
232
233 // Strip indent and empty lines from `after`, to match the behaviour of
234 // `parse_fixture` called from `analysis_and_position`.
235 let margin = fixture
236 .lines()
237 .filter(|it| it.trim_start().starts_with("//-"))
238 .map(|it| it.len() - it.trim_start().len())
239 .next()
240 .expect("empty fixture");
241 let after = join(after.lines().filter_map(|line| {
242 if line.len() > margin {
243 Some(&line[margin..])
244 } else {
245 None
246 }
247 }))
248 .separator("\n")
249 .suffix("\n")
250 .to_string();
251
252 assert_eq_text!(&after, &actual);
253 assert!(
254 diagnostic.range.start() <= file_position.offset
255 && diagnostic.range.end() >= file_position.offset,
256 "diagnostic range {} does not touch cursor position {}",
257 diagnostic.range,
258 file_position.offset
259 );
260 }
261
206 fn check_apply_diagnostic_fix(before: &str, after: &str) { 262 fn check_apply_diagnostic_fix(before: &str, after: &str) {
207 let (analysis, file_id) = single_file(before); 263 let (analysis, file_id) = single_file(before);
208 let diagnostic = analysis.diagnostics(file_id).unwrap().pop().unwrap(); 264 let diagnostic = analysis.diagnostics(file_id).unwrap().pop().unwrap();
@@ -212,6 +268,14 @@ mod tests {
212 assert_eq_text!(after, &actual); 268 assert_eq_text!(after, &actual);
213 } 269 }
214 270
271 /// Takes a multi-file input fixture with annotated cursor position and checks that no diagnostics
272 /// apply to the file containing the cursor.
273 fn check_no_diagnostic_for_target_file(fixture: &str) {
274 let (analysis, file_position) = analysis_and_position(fixture);
275 let diagnostics = analysis.diagnostics(file_position.file_id).unwrap();
276 assert_eq!(diagnostics.len(), 0);
277 }
278
215 fn check_no_diagnostic(content: &str) { 279 fn check_no_diagnostic(content: &str) {
216 let (analysis, file_id) = single_file(content); 280 let (analysis, file_id) = single_file(content);
217 let diagnostics = analysis.diagnostics(file_id).unwrap(); 281 let diagnostics = analysis.diagnostics(file_id).unwrap();
@@ -219,6 +283,155 @@ mod tests {
219 } 283 }
220 284
221 #[test] 285 #[test]
286 fn test_wrap_return_type() {
287 let before = r#"
288 //- /main.rs
289 use std::{string::String, result::Result::{self, Ok, Err}};
290
291 fn div(x: i32, y: i32) -> Result<i32, String> {
292 if y == 0 {
293 return Err("div by zero".into());
294 }
295 x / y<|>
296 }
297
298 //- /std/lib.rs
299 pub mod string {
300 pub struct String { }
301 }
302 pub mod result {
303 pub enum Result<T, E> { Ok(T), Err(E) }
304 }
305 "#;
306 let after = r#"
307 use std::{string::String, result::Result::{self, Ok, Err}};
308
309 fn div(x: i32, y: i32) -> Result<i32, String> {
310 if y == 0 {
311 return Err("div by zero".into());
312 }
313 Ok(x / y)
314 }
315 "#;
316 check_apply_diagnostic_fix_from_position(before, after);
317 }
318
319 #[test]
320 fn test_wrap_return_type_handles_generic_functions() {
321 let before = r#"
322 //- /main.rs
323 use std::result::Result::{self, Ok, Err};
324
325 fn div<T>(x: T) -> Result<T, i32> {
326 if x == 0 {
327 return Err(7);
328 }
329 <|>x
330 }
331
332 //- /std/lib.rs
333 pub mod result {
334 pub enum Result<T, E> { Ok(T), Err(E) }
335 }
336 "#;
337 let after = r#"
338 use std::result::Result::{self, Ok, Err};
339
340 fn div<T>(x: T) -> Result<T, i32> {
341 if x == 0 {
342 return Err(7);
343 }
344 Ok(x)
345 }
346 "#;
347 check_apply_diagnostic_fix_from_position(before, after);
348 }
349
350 #[test]
351 fn test_wrap_return_type_handles_type_aliases() {
352 let before = r#"
353 //- /main.rs
354 use std::{string::String, result::Result::{self, Ok, Err}};
355
356 type MyResult<T> = Result<T, String>;
357
358 fn div(x: i32, y: i32) -> MyResult<i32> {
359 if y == 0 {
360 return Err("div by zero".into());
361 }
362 x <|>/ y
363 }
364
365 //- /std/lib.rs
366 pub mod string {
367 pub struct String { }
368 }
369 pub mod result {
370 pub enum Result<T, E> { Ok(T), Err(E) }
371 }
372 "#;
373 let after = r#"
374 use std::{string::String, result::Result::{self, Ok, Err}};
375
376 type MyResult<T> = Result<T, String>;
377 fn div(x: i32, y: i32) -> MyResult<i32> {
378 if y == 0 {
379 return Err("div by zero".into());
380 }
381 Ok(x / y)
382 }
383 "#;
384 check_apply_diagnostic_fix_from_position(before, after);
385 }
386
387 #[test]
388 fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() {
389 let content = r#"
390 //- /main.rs
391 use std::{string::String, result::Result::{self, Ok, Err}};
392
393 fn foo() -> Result<String, i32> {
394 0<|>
395 }
396
397 //- /std/lib.rs
398 pub mod string {
399 pub struct String { }
400 }
401 pub mod result {
402 pub enum Result<T, E> { Ok(T), Err(E) }
403 }
404 "#;
405 check_no_diagnostic_for_target_file(content);
406 }
407
408 #[test]
409 fn test_wrap_return_type_not_applicable_when_return_type_is_not_result() {
410 let content = r#"
411 //- /main.rs
412 use std::{string::String, result::Result::{self, Ok, Err}};
413
414 enum SomeOtherEnum {
415 Ok(i32),
416 Err(String),
417 }
418
419 fn foo() -> SomeOtherEnum {
420 0<|>
421 }
422
423 //- /std/lib.rs
424 pub mod string {
425 pub struct String { }
426 }
427 pub mod result {
428 pub enum Result<T, E> { Ok(T), Err(E) }
429 }
430 "#;
431 check_no_diagnostic_for_target_file(content);
432 }
433
434 #[test]
222 fn test_fill_struct_fields_empty() { 435 fn test_fill_struct_fields_empty() {
223 let before = r" 436 let before = r"
224 struct TestStruct { 437 struct TestStruct {
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs
index 84fabdb9e..c85214bb3 100644
--- a/crates/ra_ide_api/src/display/navigation_target.rs
+++ b/crates/ra_ide_api/src/display/navigation_target.rs
@@ -314,7 +314,7 @@ pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option
314 .visit(|it: ast::TypeAliasDef| it.doc_comment_text()) 314 .visit(|it: ast::TypeAliasDef| it.doc_comment_text())
315 .visit(|it: ast::ConstDef| it.doc_comment_text()) 315 .visit(|it: ast::ConstDef| it.doc_comment_text())
316 .visit(|it: ast::StaticDef| it.doc_comment_text()) 316 .visit(|it: ast::StaticDef| it.doc_comment_text())
317 .visit(|it: ast::NamedFieldDef| it.doc_comment_text()) 317 .visit(|it: ast::RecordFieldDef| it.doc_comment_text())
318 .visit(|it: ast::EnumVariant| it.doc_comment_text()) 318 .visit(|it: ast::EnumVariant| it.doc_comment_text())
319 .visit(|it: ast::MacroCall| it.doc_comment_text()) 319 .visit(|it: ast::MacroCall| it.doc_comment_text())
320 .accept(&node)? 320 .accept(&node)?
@@ -336,7 +336,7 @@ pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) ->
336 .visit(|node: ast::TypeAliasDef| node.short_label()) 336 .visit(|node: ast::TypeAliasDef| node.short_label())
337 .visit(|node: ast::ConstDef| node.short_label()) 337 .visit(|node: ast::ConstDef| node.short_label())
338 .visit(|node: ast::StaticDef| node.short_label()) 338 .visit(|node: ast::StaticDef| node.short_label())
339 .visit(|node: ast::NamedFieldDef| node.short_label()) 339 .visit(|node: ast::RecordFieldDef| node.short_label())
340 .visit(|node: ast::EnumVariant| node.short_label()) 340 .visit(|node: ast::EnumVariant| node.short_label())
341 .accept(&node)? 341 .accept(&node)?
342} 342}
diff --git a/crates/ra_ide_api/src/display/short_label.rs b/crates/ra_ide_api/src/display/short_label.rs
index 825a033ee..b16d504e1 100644
--- a/crates/ra_ide_api/src/display/short_label.rs
+++ b/crates/ra_ide_api/src/display/short_label.rs
@@ -53,7 +53,7 @@ impl ShortLabel for ast::StaticDef {
53 } 53 }
54} 54}
55 55
56impl ShortLabel for ast::NamedFieldDef { 56impl ShortLabel for ast::RecordFieldDef {
57 fn short_label(&self) -> Option<String> { 57 fn short_label(&self) -> Option<String> {
58 short_label_from_ascribed_node(self, "") 58 short_label_from_ascribed_node(self, "")
59 } 59 }
diff --git a/crates/ra_ide_api/src/display/structure.rs b/crates/ra_ide_api/src/display/structure.rs
index b026dfa59..a2025ed59 100644
--- a/crates/ra_ide_api/src/display/structure.rs
+++ b/crates/ra_ide_api/src/display/structure.rs
@@ -124,7 +124,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
124 let ty = td.type_ref(); 124 let ty = td.type_ref();
125 decl_with_type_ref(td, ty) 125 decl_with_type_ref(td, ty)
126 }) 126 })
127 .visit(decl_with_ascription::<ast::NamedFieldDef>) 127 .visit(decl_with_ascription::<ast::RecordFieldDef>)
128 .visit(decl_with_ascription::<ast::ConstDef>) 128 .visit(decl_with_ascription::<ast::ConstDef>)
129 .visit(decl_with_ascription::<ast::StaticDef>) 129 .visit(decl_with_ascription::<ast::StaticDef>)
130 .visit(|im: ast::ImplBlock| { 130 .visit(|im: ast::ImplBlock| {
@@ -222,7 +222,7 @@ fn very_obsolete() {}
222 label: "x", 222 label: "x",
223 navigation_range: [18; 19), 223 navigation_range: [18; 19),
224 node_range: [18; 24), 224 node_range: [18; 24),
225 kind: NAMED_FIELD_DEF, 225 kind: RECORD_FIELD_DEF,
226 detail: Some( 226 detail: Some(
227 "i32", 227 "i32",
228 ), 228 ),
diff --git a/crates/ra_ide_api/src/extend_selection.rs b/crates/ra_ide_api/src/extend_selection.rs
index edbf622c1..e990eb0d1 100644
--- a/crates/ra_ide_api/src/extend_selection.rs
+++ b/crates/ra_ide_api/src/extend_selection.rs
@@ -18,11 +18,11 @@ pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRang
18fn try_extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange> { 18fn try_extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange> {
19 let string_kinds = [COMMENT, STRING, RAW_STRING, BYTE_STRING, RAW_BYTE_STRING]; 19 let string_kinds = [COMMENT, STRING, RAW_STRING, BYTE_STRING, RAW_BYTE_STRING];
20 let list_kinds = [ 20 let list_kinds = [
21 FIELD_PAT_LIST, 21 RECORD_FIELD_PAT_LIST,
22 MATCH_ARM_LIST, 22 MATCH_ARM_LIST,
23 NAMED_FIELD_DEF_LIST, 23 RECORD_FIELD_DEF_LIST,
24 POS_FIELD_DEF_LIST, 24 TUPLE_FIELD_DEF_LIST,
25 NAMED_FIELD_LIST, 25 RECORD_FIELD_LIST,
26 ENUM_VARIANT_LIST, 26 ENUM_VARIANT_LIST,
27 USE_TREE_LIST, 27 USE_TREE_LIST,
28 TYPE_PARAM_LIST, 28 TYPE_PARAM_LIST,
diff --git a/crates/ra_ide_api/src/folding_ranges.rs b/crates/ra_ide_api/src/folding_ranges.rs
index e60ae8cf6..3ab6c195e 100644
--- a/crates/ra_ide_api/src/folding_ranges.rs
+++ b/crates/ra_ide_api/src/folding_ranges.rs
@@ -81,8 +81,14 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
81 match kind { 81 match kind {
82 COMMENT => Some(FoldKind::Comment), 82 COMMENT => Some(FoldKind::Comment),
83 USE_ITEM => Some(FoldKind::Imports), 83 USE_ITEM => Some(FoldKind::Imports),
84 NAMED_FIELD_DEF_LIST | FIELD_PAT_LIST | ITEM_LIST | EXTERN_ITEM_LIST | USE_TREE_LIST 84 RECORD_FIELD_DEF_LIST
85 | BLOCK | ENUM_VARIANT_LIST | TOKEN_TREE => Some(FoldKind::Block), 85 | RECORD_FIELD_PAT_LIST
86 | ITEM_LIST
87 | EXTERN_ITEM_LIST
88 | USE_TREE_LIST
89 | BLOCK
90 | ENUM_VARIANT_LIST
91 | TOKEN_TREE => Some(FoldKind::Block),
86 _ => None, 92 _ => None,
87 } 93 }
88} 94}
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index ddd55a9c1..28529a2de 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -178,7 +178,7 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget>
178 node.short_label(), 178 node.short_label(),
179 ) 179 )
180 }) 180 })
181 .visit(|node: ast::NamedFieldDef| { 181 .visit(|node: ast::RecordFieldDef| {
182 NavigationTarget::from_named( 182 NavigationTarget::from_named(
183 file_id, 183 file_id,
184 &node, 184 &node,
@@ -344,13 +344,13 @@ mod tests {
344 foo.spam<|>; 344 foo.spam<|>;
345 } 345 }
346 ", 346 ",
347 "spam NAMED_FIELD_DEF FileId(1) [17; 26) [17; 21)", 347 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)",
348 ); 348 );
349 } 349 }
350 350
351 #[test] 351 #[test]
352 fn goto_definition_works_for_named_fields() { 352 fn goto_definition_works_for_record_fields() {
353 covers!(goto_definition_works_for_named_fields); 353 covers!(goto_definition_works_for_record_fields);
354 check_goto( 354 check_goto(
355 " 355 "
356 //- /lib.rs 356 //- /lib.rs
@@ -364,7 +364,7 @@ mod tests {
364 } 364 }
365 } 365 }
366 ", 366 ",
367 "spam NAMED_FIELD_DEF FileId(1) [17; 26) [17; 21)", 367 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)",
368 ); 368 );
369 } 369 }
370 #[test] 370 #[test]
@@ -473,7 +473,7 @@ mod tests {
473 field<|>: string, 473 field<|>: string,
474 } 474 }
475 "#, 475 "#,
476 "field NAMED_FIELD_DEF FileId(1) [17; 30) [17; 22)", 476 "field RECORD_FIELD_DEF FileId(1) [17; 30) [17; 22)",
477 ); 477 );
478 478
479 check_goto( 479 check_goto(
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 2a5ac7821..1981e62d3 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -197,7 +197,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
197 .visit(|node: ast::TraitDef| { 197 .visit(|node: ast::TraitDef| {
198 hover_text(node.doc_comment_text(), node.short_label()) 198 hover_text(node.doc_comment_text(), node.short_label())
199 }) 199 })
200 .visit(|node: ast::NamedFieldDef| { 200 .visit(|node: ast::RecordFieldDef| {
201 hover_text(node.doc_comment_text(), node.short_label()) 201 hover_text(node.doc_comment_text(), node.short_label())
202 }) 202 })
203 .visit(|node: ast::Module| hover_text(node.doc_comment_text(), node.short_label())) 203 .visit(|node: ast::Module| hover_text(node.doc_comment_text(), node.short_label()))
diff --git a/crates/ra_ide_api/src/inlay_hints.rs b/crates/ra_ide_api/src/inlay_hints.rs
index 735f3166c..61ccb74b6 100644
--- a/crates/ra_ide_api/src/inlay_hints.rs
+++ b/crates/ra_ide_api/src/inlay_hints.rs
@@ -125,13 +125,13 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
125 pats_to_process.push_back(arg_pat); 125 pats_to_process.push_back(arg_pat);
126 } 126 }
127 } 127 }
128 ast::Pat::StructPat(struct_pat) => { 128 ast::Pat::RecordPat(record_pat) => {
129 if let Some(pat_list) = struct_pat.field_pat_list() { 129 if let Some(pat_list) = record_pat.record_field_pat_list() {
130 pats_to_process.extend( 130 pats_to_process.extend(
131 pat_list 131 pat_list
132 .field_pats() 132 .record_field_pats()
133 .filter_map(|field_pat| { 133 .filter_map(|record_field_pat| {
134 field_pat 134 record_field_pat
135 .pat() 135 .pat()
136 .filter(|pat| pat.syntax().kind() != SyntaxKind::BIND_PAT) 136 .filter(|pat| pat.syntax().kind() != SyntaxKind::BIND_PAT)
137 }) 137 })
diff --git a/crates/ra_ide_api/src/marks.rs b/crates/ra_ide_api/src/marks.rs
index 9cb991de5..c3752cc54 100644
--- a/crates/ra_ide_api/src/marks.rs
+++ b/crates/ra_ide_api/src/marks.rs
@@ -3,7 +3,7 @@ test_utils::marks!(
3 goto_definition_works_for_macros 3 goto_definition_works_for_macros
4 goto_definition_works_for_methods 4 goto_definition_works_for_methods
5 goto_definition_works_for_fields 5 goto_definition_works_for_fields
6 goto_definition_works_for_named_fields 6 goto_definition_works_for_record_fields
7 call_info_bad_offset 7 call_info_bad_offset
8 dont_complete_current_use 8 dont_complete_current_use
9 dont_complete_primitive_in_use 9 dont_complete_primitive_in_use
diff --git a/crates/ra_ide_api/src/name_ref_kind.rs b/crates/ra_ide_api/src/name_ref_kind.rs
index f7db6c826..34a8bcc36 100644
--- a/crates/ra_ide_api/src/name_ref_kind.rs
+++ b/crates/ra_ide_api/src/name_ref_kind.rs
@@ -54,12 +54,12 @@ pub(crate) fn classify_name_ref(
54 } 54 }
55 55
56 // It could also be a named field 56 // It could also be a named field
57 if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::NamedField::cast) { 57 if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::RecordField::cast) {
58 tested_by!(goto_definition_works_for_named_fields); 58 tested_by!(goto_definition_works_for_record_fields);
59 59
60 let struct_lit = field_expr.syntax().ancestors().find_map(ast::StructLit::cast); 60 let record_lit = field_expr.syntax().ancestors().find_map(ast::RecordLit::cast);
61 61
62 if let Some(ty) = struct_lit.and_then(|lit| analyzer.type_of(db, &lit.into())) { 62 if let Some(ty) = record_lit.and_then(|lit| analyzer.type_of(db, &lit.into())) {
63 if let Some((hir::AdtDef::Struct(s), _)) = ty.as_adt() { 63 if let Some((hir::AdtDef::Struct(s), _)) = ty.as_adt() {
64 let hir_path = hir::Path::from_name_ref(name_ref); 64 let hir_path = hir::Path::from_name_ref(name_ref);
65 let hir_name = hir_path.as_ident().unwrap(); 65 let hir_name = hir_path.as_ident().unwrap();
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs
index 448acffc8..06ccf0728 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -165,7 +165,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
165 TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => { 165 TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => {
166 "type" 166 "type"
167 } 167 }
168 NAMED_FIELD_DEF => "field", 168 RECORD_FIELD_DEF => "field",
169 _ => "function", 169 _ => "function",
170 }) 170 })
171 .unwrap_or("function") 171 .unwrap_or("function")