diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/semantics.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir_def/src/diagnostics.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_expand/src/diagnostics.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide/src/diagnostics.rs | 72 |
8 files changed, 83 insertions, 17 deletions
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 2707e422d..0b477f0e9 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -20,6 +20,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
20 | 20 | ||
21 | use crate::{ | 21 | use crate::{ |
22 | db::HirDatabase, | 22 | db::HirDatabase, |
23 | diagnostics::Diagnostic, | ||
23 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 24 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
24 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, | 25 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, |
25 | AssocItem, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, Name, | 26 | AssocItem, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, Name, |
@@ -126,6 +127,13 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
126 | original_range(self.db, node.as_ref()) | 127 | original_range(self.db, node.as_ref()) |
127 | } | 128 | } |
128 | 129 | ||
130 | pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { | ||
131 | let src = diagnostics.source(); | ||
132 | let root = self.db.parse_or_expand(src.file_id).unwrap(); | ||
133 | let node = src.value.to_node(&root); | ||
134 | original_range(self.db, src.with_value(&node)) | ||
135 | } | ||
136 | |||
129 | pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { | 137 | pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { |
130 | let node = self.find_file(node); | 138 | let node = self.find_file(node); |
131 | node.ancestors_with_macros(self.db).map(|it| it.value) | 139 | node.ancestors_with_macros(self.db).map(|it| it.value) |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index eafaf48c1..3b169440a 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -210,7 +210,7 @@ pub struct BodySourceMap { | |||
210 | expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>, | 210 | expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>, |
211 | pat_map: FxHashMap<PatSource, PatId>, | 211 | pat_map: FxHashMap<PatSource, PatId>, |
212 | pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>, | 212 | pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>, |
213 | field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, | 213 | field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordField>>>, |
214 | expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>, | 214 | expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>, |
215 | } | 215 | } |
216 | 216 | ||
@@ -303,7 +303,7 @@ impl BodySourceMap { | |||
303 | self.pat_map.get(&src).cloned() | 303 | self.pat_map.get(&src).cloned() |
304 | } | 304 | } |
305 | 305 | ||
306 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { | 306 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordField>> { |
307 | self.field_map[&(expr, field)].clone() | 307 | self.field_map[&(expr, field)].clone() |
308 | } | 308 | } |
309 | } | 309 | } |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 79abe55ce..10a1ba714 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -320,7 +320,8 @@ impl ExprCollector<'_> { | |||
320 | 320 | ||
321 | let res = self.alloc_expr(record_lit, syntax_ptr); | 321 | let res = self.alloc_expr(record_lit, syntax_ptr); |
322 | for (i, ptr) in field_ptrs.into_iter().enumerate() { | 322 | for (i, ptr) in field_ptrs.into_iter().enumerate() { |
323 | self.source_map.field_map.insert((res, i), ptr); | 323 | let src = self.expander.to_source(ptr); |
324 | self.source_map.field_map.insert((res, i), src); | ||
324 | } | 325 | } |
325 | res | 326 | res |
326 | } | 327 | } |
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs index cfa0f2f76..510c5e064 100644 --- a/crates/ra_hir_def/src/diagnostics.rs +++ b/crates/ra_hir_def/src/diagnostics.rs | |||
@@ -20,7 +20,7 @@ impl Diagnostic for UnresolvedModule { | |||
20 | "unresolved module".to_string() | 20 | "unresolved module".to_string() |
21 | } | 21 | } |
22 | fn source(&self) -> InFile<SyntaxNodePtr> { | 22 | fn source(&self) -> InFile<SyntaxNodePtr> { |
23 | InFile { file_id: self.file, value: self.decl.clone().into() } | 23 | InFile::new(self.file, self.decl.clone().into()) |
24 | } | 24 | } |
25 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 25 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
26 | self | 26 | self |
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs index 108c1e38c..99209c6e8 100644 --- a/crates/ra_hir_expand/src/diagnostics.rs +++ b/crates/ra_hir_expand/src/diagnostics.rs | |||
@@ -16,16 +16,13 @@ | |||
16 | 16 | ||
17 | use std::{any::Any, fmt}; | 17 | use std::{any::Any, fmt}; |
18 | 18 | ||
19 | use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange}; | 19 | use ra_syntax::{SyntaxNode, SyntaxNodePtr}; |
20 | 20 | ||
21 | use crate::{db::AstDatabase, InFile}; | 21 | use crate::{db::AstDatabase, InFile}; |
22 | 22 | ||
23 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { | 23 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { |
24 | fn message(&self) -> String; | 24 | fn message(&self) -> String; |
25 | fn source(&self) -> InFile<SyntaxNodePtr>; | 25 | fn source(&self) -> InFile<SyntaxNodePtr>; |
26 | fn highlight_range(&self) -> TextRange { | ||
27 | self.source().value.range() | ||
28 | } | ||
29 | fn as_any(&self) -> &(dyn Any + Send + 'static); | 26 | fn as_any(&self) -> &(dyn Any + Send + 'static); |
30 | } | 27 | } |
31 | 28 | ||
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 927896d6f..c8fd54861 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs | |||
@@ -21,7 +21,7 @@ impl Diagnostic for NoSuchField { | |||
21 | } | 21 | } |
22 | 22 | ||
23 | fn source(&self) -> InFile<SyntaxNodePtr> { | 23 | fn source(&self) -> InFile<SyntaxNodePtr> { |
24 | InFile { file_id: self.file, value: self.field.clone().into() } | 24 | InFile::new(self.file, self.field.clone().into()) |
25 | } | 25 | } |
26 | 26 | ||
27 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 27 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 246b0e9be..b6d9b3438 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -682,10 +682,10 @@ mod diagnostics { | |||
682 | ) { | 682 | ) { |
683 | match self { | 683 | match self { |
684 | InferenceDiagnostic::NoSuchField { expr, field } => { | 684 | InferenceDiagnostic::NoSuchField { expr, field } => { |
685 | let file = owner.lookup(db.upcast()).source(db.upcast()).file_id; | 685 | let source = owner.lookup(db.upcast()).source(db.upcast()); |
686 | let (_, source_map) = db.body_with_source_map(owner.into()); | 686 | let (_, source_map) = db.body_with_source_map(owner.into()); |
687 | let field = source_map.field_syntax(*expr, *field); | 687 | let field = source_map.field_syntax(*expr, *field); |
688 | sink.push(NoSuchField { file, field }) | 688 | sink.push(NoSuchField { file: source.file_id, field: field.value }) |
689 | } | 689 | } |
690 | } | 690 | } |
691 | } | 691 | } |
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 901ad104c..e7e201709 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs | |||
@@ -1,4 +1,8 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! Collects diagnostics & fixits for a single file. |
2 | //! | ||
3 | //! The tricky bit here is that diagnostics are produced by hir in terms of | ||
4 | //! macro-expanded files, but we need to present them to the users in terms of | ||
5 | //! original files. So we need to map the ranges. | ||
2 | 6 | ||
3 | use std::cell::RefCell; | 7 | use std::cell::RefCell; |
4 | 8 | ||
@@ -46,7 +50,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
46 | let mut sink = DiagnosticSink::new(|d| { | 50 | let mut sink = DiagnosticSink::new(|d| { |
47 | res.borrow_mut().push(Diagnostic { | 51 | res.borrow_mut().push(Diagnostic { |
48 | message: d.message(), | 52 | message: d.message(), |
49 | range: d.highlight_range(), | 53 | range: sema.diagnostics_range(d).range, |
50 | severity: Severity::Error, | 54 | severity: Severity::Error, |
51 | fix: None, | 55 | fix: None, |
52 | }) | 56 | }) |
@@ -62,7 +66,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
62 | let create_file = FileSystemEdit::CreateFile { source_root, path }; | 66 | let create_file = FileSystemEdit::CreateFile { source_root, path }; |
63 | let fix = SourceChange::file_system_edit("create module", create_file); | 67 | let fix = SourceChange::file_system_edit("create module", create_file); |
64 | res.borrow_mut().push(Diagnostic { | 68 | res.borrow_mut().push(Diagnostic { |
65 | range: d.highlight_range(), | 69 | range: sema.diagnostics_range(d).range, |
66 | message: d.message(), | 70 | message: d.message(), |
67 | severity: Severity::Error, | 71 | severity: Severity::Error, |
68 | fix: Some(fix), | 72 | fix: Some(fix), |
@@ -95,7 +99,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
95 | }; | 99 | }; |
96 | 100 | ||
97 | res.borrow_mut().push(Diagnostic { | 101 | res.borrow_mut().push(Diagnostic { |
98 | range: d.highlight_range(), | 102 | range: sema.diagnostics_range(d).range, |
99 | message: d.message(), | 103 | message: d.message(), |
100 | severity: Severity::Error, | 104 | severity: Severity::Error, |
101 | fix, | 105 | fix, |
@@ -103,7 +107,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
103 | }) | 107 | }) |
104 | .on::<hir::diagnostics::MissingMatchArms, _>(|d| { | 108 | .on::<hir::diagnostics::MissingMatchArms, _>(|d| { |
105 | res.borrow_mut().push(Diagnostic { | 109 | res.borrow_mut().push(Diagnostic { |
106 | range: d.highlight_range(), | 110 | range: sema.diagnostics_range(d).range, |
107 | message: d.message(), | 111 | message: d.message(), |
108 | severity: Severity::Error, | 112 | severity: Severity::Error, |
109 | fix: None, | 113 | fix: None, |
@@ -115,7 +119,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
115 | let edit = TextEdit::replace(node.syntax().text_range(), replacement); | 119 | let edit = TextEdit::replace(node.syntax().text_range(), replacement); |
116 | let fix = SourceChange::source_file_edit_from("wrap with ok", file_id, edit); | 120 | let fix = SourceChange::source_file_edit_from("wrap with ok", file_id, edit); |
117 | res.borrow_mut().push(Diagnostic { | 121 | res.borrow_mut().push(Diagnostic { |
118 | range: d.highlight_range(), | 122 | range: sema.diagnostics_range(d).range, |
119 | message: d.message(), | 123 | message: d.message(), |
120 | severity: Severity::Error, | 124 | severity: Severity::Error, |
121 | fix: Some(fix), | 125 | fix: Some(fix), |
@@ -622,6 +626,62 @@ mod tests { | |||
622 | } | 626 | } |
623 | 627 | ||
624 | #[test] | 628 | #[test] |
629 | fn range_mapping_out_of_macros() { | ||
630 | let (analysis, file_id) = single_file( | ||
631 | r" | ||
632 | fn some() {} | ||
633 | fn items() {} | ||
634 | fn here() {} | ||
635 | |||
636 | macro_rules! id { | ||
637 | ($($tt:tt)*) => { $($tt)*}; | ||
638 | } | ||
639 | |||
640 | fn main() { | ||
641 | let _x = id![Foo { a: 42 }]; | ||
642 | } | ||
643 | |||
644 | pub struct Foo { | ||
645 | pub a: i32, | ||
646 | pub b: i32, | ||
647 | } | ||
648 | ", | ||
649 | ); | ||
650 | let diagnostics = analysis.diagnostics(file_id).unwrap(); | ||
651 | assert_debug_snapshot!(diagnostics, @r###" | ||
652 | [ | ||
653 | Diagnostic { | ||
654 | message: "Missing structure fields:\n- b", | ||
655 | range: [224; 233), | ||
656 | fix: Some( | ||
657 | SourceChange { | ||
658 | label: "fill struct fields", | ||
659 | source_file_edits: [ | ||
660 | SourceFileEdit { | ||
661 | file_id: FileId( | ||
662 | 1, | ||
663 | ), | ||
664 | edit: TextEdit { | ||
665 | atoms: [ | ||
666 | AtomTextEdit { | ||
667 | delete: [3; 9), | ||
668 | insert: "{a:42, b: ()}", | ||
669 | }, | ||
670 | ], | ||
671 | }, | ||
672 | }, | ||
673 | ], | ||
674 | file_system_edits: [], | ||
675 | cursor_position: None, | ||
676 | }, | ||
677 | ), | ||
678 | severity: Error, | ||
679 | }, | ||
680 | ] | ||
681 | "###); | ||
682 | } | ||
683 | |||
684 | #[test] | ||
625 | fn test_check_unnecessary_braces_in_use_statement() { | 685 | fn test_check_unnecessary_braces_in_use_statement() { |
626 | check_not_applicable( | 686 | check_not_applicable( |
627 | " | 687 | " |