aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/semantics.rs8
-rw-r--r--crates/ra_hir_def/src/body.rs4
-rw-r--r--crates/ra_hir_def/src/body/lower.rs3
-rw-r--r--crates/ra_hir_def/src/diagnostics.rs2
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs5
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs2
-rw-r--r--crates/ra_hir_ty/src/infer.rs4
-rw-r--r--crates/ra_ide/src/diagnostics.rs72
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
21use crate::{ 21use 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
17use std::{any::Any, fmt}; 17use std::{any::Any, fmt};
18 18
19use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange}; 19use ra_syntax::{SyntaxNode, SyntaxNodePtr};
20 20
21use crate::{db::AstDatabase, InFile}; 21use crate::{db::AstDatabase, InFile};
22 22
23pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { 23pub 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
3use std::cell::RefCell; 7use 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 "