Skip to content

Commit 0262c9b

Browse files
bors[bot]matklad
andauthored
Merge #4010
4010: Fix handling of ranges in diagnostics r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
2 parents bd6b532 + 146f6f5 commit 0262c9b

File tree

8 files changed

+83
-17
lines changed

8 files changed

+83
-17
lines changed

crates/ra_hir/src/semantics.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
2020

2121
use crate::{
2222
db::HirDatabase,
23+
diagnostics::Diagnostic,
2324
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
2425
source_analyzer::{resolve_hir_path, SourceAnalyzer},
2526
AssocItem, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, Name,
@@ -126,6 +127,13 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
126127
original_range(self.db, node.as_ref())
127128
}
128129

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+
129137
pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
130138
let node = self.find_file(node);
131139
node.ancestors_with_macros(self.db).map(|it| it.value)

crates/ra_hir_def/src/body.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ pub struct BodySourceMap {
210210
expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
211211
pat_map: FxHashMap<PatSource, PatId>,
212212
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>>>,
214214
expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
215215
}
216216

@@ -303,7 +303,7 @@ impl BodySourceMap {
303303
self.pat_map.get(&src).cloned()
304304
}
305305

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>> {
307307
self.field_map[&(expr, field)].clone()
308308
}
309309
}

crates/ra_hir_def/src/body/lower.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,8 @@ impl ExprCollector<'_> {
320320

321321
let res = self.alloc_expr(record_lit, syntax_ptr);
322322
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);
324325
}
325326
res
326327
}

crates/ra_hir_def/src/diagnostics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ impl Diagnostic for UnresolvedModule {
2020
"unresolved module".to_string()
2121
}
2222
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())
2424
}
2525
fn as_any(&self) -> &(dyn Any + Send + 'static) {
2626
self

crates/ra_hir_expand/src/diagnostics.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,13 @@
1616
1717
use std::{any::Any, fmt};
1818

19-
use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange};
19+
use ra_syntax::{SyntaxNode, SyntaxNodePtr};
2020

2121
use crate::{db::AstDatabase, InFile};
2222

2323
pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
2424
fn message(&self) -> String;
2525
fn source(&self) -> InFile<SyntaxNodePtr>;
26-
fn highlight_range(&self) -> TextRange {
27-
self.source().value.range()
28-
}
2926
fn as_any(&self) -> &(dyn Any + Send + 'static);
3027
}
3128

crates/ra_hir_ty/src/diagnostics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ impl Diagnostic for NoSuchField {
2121
}
2222

2323
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())
2525
}
2626

2727
fn as_any(&self) -> &(dyn Any + Send + 'static) {

crates/ra_hir_ty/src/infer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -682,10 +682,10 @@ mod diagnostics {
682682
) {
683683
match self {
684684
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());
686686
let (_, source_map) = db.body_with_source_map(owner.into());
687687
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 })
689689
}
690690
}
691691
}

crates/ra_ide/src/diagnostics.rs

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
26
37
use std::cell::RefCell;
48

@@ -46,7 +50,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
4650
let mut sink = DiagnosticSink::new(|d| {
4751
res.borrow_mut().push(Diagnostic {
4852
message: d.message(),
49-
range: d.highlight_range(),
53+
range: sema.diagnostics_range(d).range,
5054
severity: Severity::Error,
5155
fix: None,
5256
})
@@ -62,7 +66,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
6266
let create_file = FileSystemEdit::CreateFile { source_root, path };
6367
let fix = SourceChange::file_system_edit("create module", create_file);
6468
res.borrow_mut().push(Diagnostic {
65-
range: d.highlight_range(),
69+
range: sema.diagnostics_range(d).range,
6670
message: d.message(),
6771
severity: Severity::Error,
6872
fix: Some(fix),
@@ -95,15 +99,15 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
9599
};
96100

97101
res.borrow_mut().push(Diagnostic {
98-
range: d.highlight_range(),
102+
range: sema.diagnostics_range(d).range,
99103
message: d.message(),
100104
severity: Severity::Error,
101105
fix,
102106
})
103107
})
104108
.on::<hir::diagnostics::MissingMatchArms, _>(|d| {
105109
res.borrow_mut().push(Diagnostic {
106-
range: d.highlight_range(),
110+
range: sema.diagnostics_range(d).range,
107111
message: d.message(),
108112
severity: Severity::Error,
109113
fix: None,
@@ -115,7 +119,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
115119
let edit = TextEdit::replace(node.syntax().text_range(), replacement);
116120
let fix = SourceChange::source_file_edit_from("wrap with ok", file_id, edit);
117121
res.borrow_mut().push(Diagnostic {
118-
range: d.highlight_range(),
122+
range: sema.diagnostics_range(d).range,
119123
message: d.message(),
120124
severity: Severity::Error,
121125
fix: Some(fix),
@@ -621,6 +625,62 @@ mod tests {
621625
"###);
622626
}
623627

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+
624684
#[test]
625685
fn test_check_unnecessary_braces_in_use_statement() {
626686
check_not_applicable(

0 commit comments

Comments
 (0)