diff options
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r-- | crates/hir_def/src/body.rs | 20 | ||||
-rw-r--r-- | crates/hir_def/src/body/tests.rs | 28 | ||||
-rw-r--r-- | crates/hir_def/src/docs.rs | 22 | ||||
-rw-r--r-- | crates/hir_def/src/lib.rs | 51 |
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() { | |||
78 | fn macro_diag_builtin() { | 78 | fn macro_diag_builtin() { |
79 | check_diagnostics( | 79 | check_diagnostics( |
80 | r#" | 80 | r#" |
81 | #[rustc_builtin_macro] | ||
82 | macro_rules! env {} | ||
83 | |||
84 | #[rustc_builtin_macro] | ||
85 | macro_rules! include {} | ||
86 | |||
87 | #[rustc_builtin_macro] | ||
88 | macro_rules! compile_error {} | ||
89 | |||
90 | #[rustc_builtin_macro] | ||
91 | macro_rules! format_args { | ||
92 | () => {} | ||
93 | } | ||
94 | |||
81 | fn f() { | 95 | fn 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 @@ | |||
6 | use std::sync::Arc; | 6 | use std::sync::Arc; |
7 | 7 | ||
8 | use either::Either; | 8 | use either::Either; |
9 | use syntax::ast; | 9 | use itertools::Itertools; |
10 | use syntax::{ast, SmolStr}; | ||
10 | 11 | ||
11 | use crate::{ | 12 | use 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 | ||
106 | fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option<String> { | 107 | fn 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 | ||
471 | impl AsMacroCall for InFile<&ast::MacroCall> { | 481 | impl 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 | ||
499 | impl AsMacroCall for AstIdWithPath<ast::MacroCall> { | 515 | impl 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 | ||
524 | impl AsMacroCall for AstIdWithPath<ast::Item> { | 550 | impl 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(), |