Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
4010: Fix handling of ranges in diagnostics r=matklad a=matklad

bors r+
🤖

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
  • Loading branch information
bors[bot] and matklad committed Apr 17, 2020
2 parents bd6b532 + 146f6f5 commit 0262c9b
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 17 deletions.
8 changes: 8 additions & 0 deletions crates/ra_hir/src/semantics.rs
Expand Up @@ -20,6 +20,7 @@ use rustc_hash::{FxHashMap, FxHashSet};

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

pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange {
let src = diagnostics.source();
let root = self.db.parse_or_expand(src.file_id).unwrap();
let node = src.value.to_node(&root);
original_range(self.db, src.with_value(&node))
}

pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
let node = self.find_file(node);
node.ancestors_with_macros(self.db).map(|it| it.value)
Expand Down
4 changes: 2 additions & 2 deletions crates/ra_hir_def/src/body.rs
Expand Up @@ -210,7 +210,7 @@ pub struct BodySourceMap {
expr_map_back: ArenaMap<ExprId, Result<ExprSource, SyntheticSyntax>>,
pat_map: FxHashMap<PatSource, PatId>,
pat_map_back: ArenaMap<PatId, Result<PatSource, SyntheticSyntax>>,
field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>,
field_map: FxHashMap<(ExprId, usize), InFile<AstPtr<ast::RecordField>>>,
expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
}

Expand Down Expand Up @@ -303,7 +303,7 @@ impl BodySourceMap {
self.pat_map.get(&src).cloned()
}

pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> {
pub fn field_syntax(&self, expr: ExprId, field: usize) -> InFile<AstPtr<ast::RecordField>> {
self.field_map[&(expr, field)].clone()
}
}
3 changes: 2 additions & 1 deletion crates/ra_hir_def/src/body/lower.rs
Expand Up @@ -320,7 +320,8 @@ impl ExprCollector<'_> {

let res = self.alloc_expr(record_lit, syntax_ptr);
for (i, ptr) in field_ptrs.into_iter().enumerate() {
self.source_map.field_map.insert((res, i), ptr);
let src = self.expander.to_source(ptr);
self.source_map.field_map.insert((res, i), src);
}
res
}
Expand Down
2 changes: 1 addition & 1 deletion crates/ra_hir_def/src/diagnostics.rs
Expand Up @@ -20,7 +20,7 @@ impl Diagnostic for UnresolvedModule {
"unresolved module".to_string()
}
fn source(&self) -> InFile<SyntaxNodePtr> {
InFile { file_id: self.file, value: self.decl.clone().into() }
InFile::new(self.file, self.decl.clone().into())
}
fn as_any(&self) -> &(dyn Any + Send + 'static) {
self
Expand Down
5 changes: 1 addition & 4 deletions crates/ra_hir_expand/src/diagnostics.rs
Expand Up @@ -16,16 +16,13 @@

use std::{any::Any, fmt};

use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange};
use ra_syntax::{SyntaxNode, SyntaxNodePtr};

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

pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
fn message(&self) -> String;
fn source(&self) -> InFile<SyntaxNodePtr>;
fn highlight_range(&self) -> TextRange {
self.source().value.range()
}
fn as_any(&self) -> &(dyn Any + Send + 'static);
}

Expand Down
2 changes: 1 addition & 1 deletion crates/ra_hir_ty/src/diagnostics.rs
Expand Up @@ -21,7 +21,7 @@ impl Diagnostic for NoSuchField {
}

fn source(&self) -> InFile<SyntaxNodePtr> {
InFile { file_id: self.file, value: self.field.clone().into() }
InFile::new(self.file, self.field.clone().into())
}

fn as_any(&self) -> &(dyn Any + Send + 'static) {
Expand Down
4 changes: 2 additions & 2 deletions crates/ra_hir_ty/src/infer.rs
Expand Up @@ -682,10 +682,10 @@ mod diagnostics {
) {
match self {
InferenceDiagnostic::NoSuchField { expr, field } => {
let file = owner.lookup(db.upcast()).source(db.upcast()).file_id;
let source = owner.lookup(db.upcast()).source(db.upcast());
let (_, source_map) = db.body_with_source_map(owner.into());
let field = source_map.field_syntax(*expr, *field);
sink.push(NoSuchField { file, field })
sink.push(NoSuchField { file: source.file_id, field: field.value })
}
}
}
Expand Down
72 changes: 66 additions & 6 deletions crates/ra_ide/src/diagnostics.rs
@@ -1,4 +1,8 @@
//! FIXME: write short doc here
//! Collects diagnostics & fixits for a single file.
//!
//! The tricky bit here is that diagnostics are produced by hir in terms of
//! macro-expanded files, but we need to present them to the users in terms of
//! original files. So we need to map the ranges.

use std::cell::RefCell;

Expand Down Expand Up @@ -46,7 +50,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
let mut sink = DiagnosticSink::new(|d| {
res.borrow_mut().push(Diagnostic {
message: d.message(),
range: d.highlight_range(),
range: sema.diagnostics_range(d).range,
severity: Severity::Error,
fix: None,
})
Expand All @@ -62,7 +66,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
let create_file = FileSystemEdit::CreateFile { source_root, path };
let fix = SourceChange::file_system_edit("create module", create_file);
res.borrow_mut().push(Diagnostic {
range: d.highlight_range(),
range: sema.diagnostics_range(d).range,
message: d.message(),
severity: Severity::Error,
fix: Some(fix),
Expand Down Expand Up @@ -95,15 +99,15 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
};

res.borrow_mut().push(Diagnostic {
range: d.highlight_range(),
range: sema.diagnostics_range(d).range,
message: d.message(),
severity: Severity::Error,
fix,
})
})
.on::<hir::diagnostics::MissingMatchArms, _>(|d| {
res.borrow_mut().push(Diagnostic {
range: d.highlight_range(),
range: sema.diagnostics_range(d).range,
message: d.message(),
severity: Severity::Error,
fix: None,
Expand All @@ -115,7 +119,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
let edit = TextEdit::replace(node.syntax().text_range(), replacement);
let fix = SourceChange::source_file_edit_from("wrap with ok", file_id, edit);
res.borrow_mut().push(Diagnostic {
range: d.highlight_range(),
range: sema.diagnostics_range(d).range,
message: d.message(),
severity: Severity::Error,
fix: Some(fix),
Expand Down Expand Up @@ -621,6 +625,62 @@ mod tests {
"###);
}

#[test]
fn range_mapping_out_of_macros() {
let (analysis, file_id) = single_file(
r"
fn some() {}
fn items() {}
fn here() {}
macro_rules! id {
($($tt:tt)*) => { $($tt)*};
}
fn main() {
let _x = id![Foo { a: 42 }];
}
pub struct Foo {
pub a: i32,
pub b: i32,
}
",
);
let diagnostics = analysis.diagnostics(file_id).unwrap();
assert_debug_snapshot!(diagnostics, @r###"
[
Diagnostic {
message: "Missing structure fields:\n- b",
range: [224; 233),
fix: Some(
SourceChange {
label: "fill struct fields",
source_file_edits: [
SourceFileEdit {
file_id: FileId(
1,
),
edit: TextEdit {
atoms: [
AtomTextEdit {
delete: [3; 9),
insert: "{a:42, b: ()}",
},
],
},
},
],
file_system_edits: [],
cursor_position: None,
},
),
severity: Error,
},
]
"###);
}

#[test]
fn test_check_unnecessary_braces_in_use_statement() {
check_not_applicable(
Expand Down

0 comments on commit 0262c9b

Please sign in to comment.