aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r--crates/hir_def/src/body.rs20
-rw-r--r--crates/hir_def/src/body/tests.rs28
-rw-r--r--crates/hir_def/src/docs.rs22
-rw-r--r--crates/hir_def/src/lib.rs51
4 files changed, 89 insertions, 32 deletions
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 33eb5e78c..92bcc1705 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -120,18 +120,24 @@ impl Expander {
120 self.resolve_path_as_macro(db, &path) 120 self.resolve_path_as_macro(db, &path)
121 }; 121 };
122 122
123 let call_id = match macro_call.as_call_id(db, self.crate_def_map.krate, resolver) { 123 let mut err = None;
124 let call_id =
125 macro_call.as_call_id_with_errors(db, self.crate_def_map.krate, resolver, &mut |e| {
126 err.get_or_insert(e);
127 });
128 let call_id = match call_id {
124 Some(it) => it, 129 Some(it) => it,
125 None => { 130 None => {
126 // FIXME: this can mean other things too, but `as_call_id` doesn't provide enough 131 if err.is_none() {
127 // info. 132 eprintln!("no error despite `as_call_id_with_errors` returning `None`");
128 return ExpandResult::only_err(mbe::ExpandError::Other( 133 }
129 "failed to parse or resolve macro invocation".into(), 134 return ExpandResult { value: None, err };
130 ));
131 } 135 }
132 }; 136 };
133 137
134 let err = db.macro_expand_error(call_id); 138 if err.is_none() {
139 err = db.macro_expand_error(call_id);
140 }
135 141
136 let file_id = call_id.as_file(); 142 let file_id = call_id.as_file();
137 143
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index baf1179f1..6dba9817d 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -78,21 +78,41 @@ fn f() {
78fn macro_diag_builtin() { 78fn macro_diag_builtin() {
79 check_diagnostics( 79 check_diagnostics(
80 r#" 80 r#"
81#[rustc_builtin_macro]
82macro_rules! env {}
83
84#[rustc_builtin_macro]
85macro_rules! include {}
86
87#[rustc_builtin_macro]
88macro_rules! compile_error {}
89
90#[rustc_builtin_macro]
91macro_rules! format_args {
92 () => {}
93}
94
81fn f() { 95fn f() {
82 // Test a handful of built-in (eager) macros: 96 // Test a handful of built-in (eager) macros:
83 97
84 include!(invalid); 98 include!(invalid);
85 //^^^^^^^^^^^^^^^^^ failed to parse or resolve macro invocation 99 //^^^^^^^^^^^^^^^^^ could not convert tokens
86 include!("does not exist"); 100 include!("does not exist");
87 //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to parse or resolve macro invocation 101 //^^^^^^^^^^^^^^^^^^^^^^^^^^ could not convert tokens
88 102
89 env!(invalid); 103 env!(invalid);
90 //^^^^^^^^^^^^^ failed to parse or resolve macro invocation 104 //^^^^^^^^^^^^^ could not convert tokens
105
106 env!("OUT_DIR");
107 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix
108
109 compile_error!("compile_error works");
110 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works
91 111
92 // Lazy: 112 // Lazy:
93 113
94 format_args!(); 114 format_args!();
95 //^^^^^^^^^^^^^^ failed to parse or resolve macro invocation 115 //^^^^^^^^^^^^^^ no rule matches input tokens
96} 116}
97 "#, 117 "#,
98 ); 118 );
diff --git a/crates/hir_def/src/docs.rs b/crates/hir_def/src/docs.rs
index e9a02b11b..3e59a8f47 100644
--- a/crates/hir_def/src/docs.rs
+++ b/crates/hir_def/src/docs.rs
@@ -6,7 +6,8 @@
6use std::sync::Arc; 6use std::sync::Arc;
7 7
8use either::Either; 8use either::Either;
9use syntax::ast; 9use itertools::Itertools;
10use syntax::{ast, SmolStr};
10 11
11use crate::{ 12use crate::{
12 db::DefDatabase, 13 db::DefDatabase,
@@ -93,7 +94,7 @@ fn merge_doc_comments_and_attrs(
93) -> Option<String> { 94) -> Option<String> {
94 match (doc_comment_text, doc_attr_text) { 95 match (doc_comment_text, doc_attr_text) {
95 (Some(mut comment_text), Some(attr_text)) => { 96 (Some(mut comment_text), Some(attr_text)) => {
96 comment_text.push_str("\n\n"); 97 comment_text.push_str("\n");
97 comment_text.push_str(&attr_text); 98 comment_text.push_str(&attr_text);
98 Some(comment_text) 99 Some(comment_text)
99 } 100 }
@@ -105,17 +106,16 @@ fn merge_doc_comments_and_attrs(
105 106
106fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option<String> { 107fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option<String> {
107 let mut docs = String::new(); 108 let mut docs = String::new();
108 for attr in owner.attrs() { 109 owner
109 if let Some(("doc", value)) = 110 .attrs()
110 attr.as_simple_key_value().as_ref().map(|(k, v)| (k.as_str(), v.as_str())) 111 .filter_map(|attr| attr.as_simple_key_value().filter(|(key, _)| key == "doc"))
111 { 112 .map(|(_, value)| value)
112 docs.push_str(value); 113 .intersperse(SmolStr::new_inline("\n"))
113 docs.push_str("\n\n"); 114 // No FromIterator<SmolStr> for String
114 } 115 .for_each(|s| docs.push_str(s.as_str()));
115 }
116 if docs.is_empty() { 116 if docs.is_empty() {
117 None 117 None
118 } else { 118 } else {
119 Some(docs.trim_end_matches("\n\n").to_owned()) 119 Some(docs)
120 } 120 }
121} 121}
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 1b22d1eec..b41c5acb2 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -465,21 +465,37 @@ pub trait AsMacroCall {
465 db: &dyn db::DefDatabase, 465 db: &dyn db::DefDatabase,
466 krate: CrateId, 466 krate: CrateId,
467 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 467 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
468 ) -> Option<MacroCallId> {
469 self.as_call_id_with_errors(db, krate, resolver, &mut |_| ())
470 }
471
472 fn as_call_id_with_errors(
473 &self,
474 db: &dyn db::DefDatabase,
475 krate: CrateId,
476 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
477 error_sink: &mut dyn FnMut(mbe::ExpandError),
468 ) -> Option<MacroCallId>; 478 ) -> Option<MacroCallId>;
469} 479}
470 480
471impl AsMacroCall for InFile<&ast::MacroCall> { 481impl AsMacroCall for InFile<&ast::MacroCall> {
472 fn as_call_id( 482 fn as_call_id_with_errors(
473 &self, 483 &self,
474 db: &dyn db::DefDatabase, 484 db: &dyn db::DefDatabase,
475 krate: CrateId, 485 krate: CrateId,
476 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 486 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
487 error_sink: &mut dyn FnMut(mbe::ExpandError),
477 ) -> Option<MacroCallId> { 488 ) -> Option<MacroCallId> {
478 let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); 489 let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
479 let h = Hygiene::new(db.upcast(), self.file_id); 490 let h = Hygiene::new(db.upcast(), self.file_id);
480 let path = path::ModPath::from_src(self.value.path()?, &h)?; 491 let path = self.value.path().and_then(|path| path::ModPath::from_src(path, &h));
492
493 if path.is_none() {
494 error_sink(mbe::ExpandError::Other("malformed macro invocation".into()));
495 }
481 496
482 AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, krate, resolver) 497 AstIdWithPath::new(ast_id.file_id, ast_id.value, path?)
498 .as_call_id_with_errors(db, krate, resolver, error_sink)
483 } 499 }
484} 500}
485 501
@@ -497,22 +513,32 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
497} 513}
498 514
499impl AsMacroCall for AstIdWithPath<ast::MacroCall> { 515impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
500 fn as_call_id( 516 fn as_call_id_with_errors(
501 &self, 517 &self,
502 db: &dyn db::DefDatabase, 518 db: &dyn db::DefDatabase,
503 krate: CrateId, 519 krate: CrateId,
504 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 520 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
521 error_sink: &mut dyn FnMut(mbe::ExpandError),
505 ) -> Option<MacroCallId> { 522 ) -> Option<MacroCallId> {
506 let def: MacroDefId = resolver(self.path.clone())?; 523 let def: MacroDefId = resolver(self.path.clone()).or_else(|| {
524 error_sink(mbe::ExpandError::Other(format!("could not resolve macro `{}`", self.path)));
525 None
526 })?;
507 527
508 if let MacroDefKind::BuiltInEager(_) = def.kind { 528 if let MacroDefKind::BuiltInEager(_) = def.kind {
509 let macro_call = InFile::new(self.ast_id.file_id, self.ast_id.to_node(db.upcast())); 529 let macro_call = InFile::new(self.ast_id.file_id, self.ast_id.to_node(db.upcast()));
510 let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id); 530 let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id);
511 531
512 Some( 532 Some(
513 expand_eager_macro(db.upcast(), krate, macro_call, def, &|path: ast::Path| { 533 expand_eager_macro(
514 resolver(path::ModPath::from_src(path, &hygiene)?) 534 db.upcast(),
515 })? 535 krate,
536 macro_call,
537 def,
538 &|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?),
539 error_sink,
540 )
541 .ok()?
516 .into(), 542 .into(),
517 ) 543 )
518 } else { 544 } else {
@@ -522,13 +548,18 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
522} 548}
523 549
524impl AsMacroCall for AstIdWithPath<ast::Item> { 550impl AsMacroCall for AstIdWithPath<ast::Item> {
525 fn as_call_id( 551 fn as_call_id_with_errors(
526 &self, 552 &self,
527 db: &dyn db::DefDatabase, 553 db: &dyn db::DefDatabase,
528 krate: CrateId, 554 krate: CrateId,
529 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 555 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
556 error_sink: &mut dyn FnMut(mbe::ExpandError),
530 ) -> Option<MacroCallId> { 557 ) -> Option<MacroCallId> {
531 let def = resolver(self.path.clone())?; 558 let def: MacroDefId = resolver(self.path.clone()).or_else(|| {
559 error_sink(mbe::ExpandError::Other(format!("could not resolve macro `{}`", self.path)));
560 None
561 })?;
562
532 Some( 563 Some(
533 def.as_lazy_macro( 564 def.as_lazy_macro(
534 db.upcast(), 565 db.upcast(),