aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-11-27 15:29:40 +0000
committerJonas Schievink <[email protected]>2020-11-27 15:29:40 +0000
commitd171838d63907d004ab935d6564bfeb4238d5540 (patch)
tree5c8d1a42cedda2027a6214727e4ad7cd4ffc4fa9 /crates
parent0432aa0ed7be3f41d41928499abc688a956214cf (diff)
More accurately place proc-macro diagnostic
Diffstat (limited to 'crates')
-rw-r--r--crates/hir_def/src/diagnostics.rs5
-rw-r--r--crates/hir_def/src/nameres.rs41
-rw-r--r--crates/ide/src/diagnostics.rs10
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;
6use cfg::{CfgExpr, CfgOptions, DnfExpr}; 6use cfg::{CfgExpr, CfgOptions, DnfExpr};
7use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink}; 7use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink};
8use hir_expand::{HirFileId, InFile}; 8use hir_expand::{HirFileId, InFile};
9use syntax::{ast, AstPtr, SyntaxNodePtr}; 9use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
10 10
11use crate::{db::DefDatabase, DefWithBodyId}; 11use crate::{db::DefDatabase, DefWithBodyId};
12 12
@@ -137,6 +137,9 @@ impl Diagnostic for InactiveCode {
137pub struct UnresolvedProcMacro { 137pub 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))