diff options
author | Jonas Schievink <[email protected]> | 2020-11-27 15:29:40 +0000 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2020-11-27 15:29:40 +0000 |
commit | d171838d63907d004ab935d6564bfeb4238d5540 (patch) | |
tree | 5c8d1a42cedda2027a6214727e4ad7cd4ffc4fa9 /crates | |
parent | 0432aa0ed7be3f41d41928499abc688a956214cf (diff) |
More accurately place proc-macro diagnostic
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir_def/src/diagnostics.rs | 5 | ||||
-rw-r--r-- | crates/hir_def/src/nameres.rs | 41 | ||||
-rw-r--r-- | crates/ide/src/diagnostics.rs | 10 |
3 files changed, 48 insertions, 8 deletions
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs index dd06e3f20..c71266dc0 100644 --- a/crates/hir_def/src/diagnostics.rs +++ b/crates/hir_def/src/diagnostics.rs | |||
@@ -6,7 +6,7 @@ use stdx::format_to; | |||
6 | use cfg::{CfgExpr, CfgOptions, DnfExpr}; | 6 | use cfg::{CfgExpr, CfgOptions, DnfExpr}; |
7 | use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink}; | 7 | use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink}; |
8 | use hir_expand::{HirFileId, InFile}; | 8 | use hir_expand::{HirFileId, InFile}; |
9 | use syntax::{ast, AstPtr, SyntaxNodePtr}; | 9 | use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; |
10 | 10 | ||
11 | use crate::{db::DefDatabase, DefWithBodyId}; | 11 | use crate::{db::DefDatabase, DefWithBodyId}; |
12 | 12 | ||
@@ -137,6 +137,9 @@ impl Diagnostic for InactiveCode { | |||
137 | pub struct UnresolvedProcMacro { | 137 | pub struct UnresolvedProcMacro { |
138 | pub file: HirFileId, | 138 | pub file: HirFileId, |
139 | pub node: SyntaxNodePtr, | 139 | pub node: SyntaxNodePtr, |
140 | /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange` | ||
141 | /// to use instead. | ||
142 | pub precise_location: Option<TextRange>, | ||
140 | pub macro_name: Option<String>, | 143 | pub macro_name: Option<String>, |
141 | } | 144 | } |
142 | 145 | ||
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 3d65a46bf..ffd0381d4 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -287,7 +287,8 @@ mod diagnostics { | |||
287 | use hir_expand::diagnostics::DiagnosticSink; | 287 | use hir_expand::diagnostics::DiagnosticSink; |
288 | use hir_expand::hygiene::Hygiene; | 288 | use hir_expand::hygiene::Hygiene; |
289 | use hir_expand::{InFile, MacroCallKind}; | 289 | use hir_expand::{InFile, MacroCallKind}; |
290 | use syntax::{ast, AstPtr, SyntaxNodePtr}; | 290 | use syntax::ast::AttrsOwner; |
291 | use syntax::{ast, AstNode, AstPtr, SyntaxKind, SyntaxNodePtr}; | ||
291 | 292 | ||
292 | use crate::path::ModPath; | 293 | use crate::path::ModPath; |
293 | use crate::{db::DefDatabase, diagnostics::*, nameres::LocalModuleId, AstId}; | 294 | use crate::{db::DefDatabase, diagnostics::*, nameres::LocalModuleId, AstId}; |
@@ -425,6 +426,7 @@ mod diagnostics { | |||
425 | } | 426 | } |
426 | 427 | ||
427 | DiagnosticKind::UnresolvedProcMacro { ast } => { | 428 | DiagnosticKind::UnresolvedProcMacro { ast } => { |
429 | let mut precise_location = None; | ||
428 | let (file, ast, name) = match ast { | 430 | let (file, ast, name) = match ast { |
429 | MacroCallKind::FnLike(ast) => { | 431 | MacroCallKind::FnLike(ast) => { |
430 | let node = ast.to_node(db.upcast()); | 432 | let node = ast.to_node(db.upcast()); |
@@ -432,14 +434,47 @@ mod diagnostics { | |||
432 | } | 434 | } |
433 | MacroCallKind::Attr(ast, name) => { | 435 | MacroCallKind::Attr(ast, name) => { |
434 | let node = ast.to_node(db.upcast()); | 436 | let node = ast.to_node(db.upcast()); |
437 | |||
438 | // Compute the precise location of the macro name's token in the derive | ||
439 | // list. | ||
440 | // FIXME: This does not handle paths to the macro, but neither does the | ||
441 | // rest of r-a. | ||
442 | let derive_attrs = | ||
443 | node.attrs().filter_map(|attr| match attr.as_simple_call() { | ||
444 | Some((name, args)) if name == "derive" => Some(args), | ||
445 | _ => None, | ||
446 | }); | ||
447 | 'outer: for attr in derive_attrs { | ||
448 | let tokens = | ||
449 | attr.syntax().children_with_tokens().filter_map(|elem| { | ||
450 | match elem { | ||
451 | syntax::NodeOrToken::Node(_) => None, | ||
452 | syntax::NodeOrToken::Token(tok) => Some(tok), | ||
453 | } | ||
454 | }); | ||
455 | for token in tokens { | ||
456 | if token.kind() == SyntaxKind::IDENT | ||
457 | && token.to_string() == *name | ||
458 | { | ||
459 | precise_location = Some(token.text_range()); | ||
460 | break 'outer; | ||
461 | } | ||
462 | } | ||
463 | } | ||
464 | |||
435 | ( | 465 | ( |
436 | ast.file_id, | 466 | ast.file_id, |
437 | SyntaxNodePtr::from(AstPtr::new(&node)), | 467 | SyntaxNodePtr::from(AstPtr::new(&node)), |
438 | Some(name.to_string()), | 468 | Some(name.clone()), |
439 | ) | 469 | ) |
440 | } | 470 | } |
441 | }; | 471 | }; |
442 | sink.push(UnresolvedProcMacro { file, node: ast, macro_name: name }); | 472 | sink.push(UnresolvedProcMacro { |
473 | file, | ||
474 | node: ast, | ||
475 | precise_location, | ||
476 | macro_name: name, | ||
477 | }); | ||
443 | } | 478 | } |
444 | 479 | ||
445 | DiagnosticKind::MacroError { ast, message } => { | 480 | DiagnosticKind::MacroError { ast, message } => { |
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 8b4ceb9a1..9d3d88289 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -143,11 +143,13 @@ pub(crate) fn diagnostics( | |||
143 | ); | 143 | ); |
144 | }) | 144 | }) |
145 | .on::<hir::diagnostics::UnresolvedProcMacro, _>(|d| { | 145 | .on::<hir::diagnostics::UnresolvedProcMacro, _>(|d| { |
146 | // Use more accurate position if available. | ||
147 | let display_range = | ||
148 | d.precise_location.unwrap_or_else(|| sema.diagnostics_display_range(d).range); | ||
149 | |||
146 | // FIXME: it would be nice to tell the user whether proc macros are currently disabled | 150 | // FIXME: it would be nice to tell the user whether proc macros are currently disabled |
147 | res.borrow_mut().push( | 151 | res.borrow_mut() |
148 | Diagnostic::hint(sema.diagnostics_display_range(d).range, d.message()) | 152 | .push(Diagnostic::hint(display_range, d.message()).with_code(Some(d.code()))); |
149 | .with_code(Some(d.code())), | ||
150 | ); | ||
151 | }) | 153 | }) |
152 | // Only collect experimental diagnostics when they're enabled. | 154 | // Only collect experimental diagnostics when they're enabled. |
153 | .filter(|diag| !(diag.is_experimental() && config.disable_experimental)) | 155 | .filter(|diag| !(diag.is_experimental() && config.disable_experimental)) |