diff options
author | Aleksey Kladov <[email protected]> | 2021-02-28 11:12:11 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-02-28 11:29:10 +0000 |
commit | 05729fd3c4aa542d162b54e7352c0d4bade62684 (patch) | |
tree | 5e0c37057750cc897031a02ec4860462a4cea9ef /crates/hir_def/src | |
parent | c412d5f8d13cd55dc1873fb55e742a317c7846a8 (diff) |
For unresolved macros, hightlight only the last segment
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r-- | crates/hir_def/src/body.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/diagnostics.rs | 28 | ||||
-rw-r--r-- | crates/hir_def/src/lib.rs | 114 | ||||
-rw-r--r-- | crates/hir_def/src/nameres.rs | 14 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 81 |
5 files changed, 147 insertions, 92 deletions
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 9a432f7d1..ff4b4a0cf 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs | |||
@@ -123,7 +123,7 @@ impl Expander { | |||
123 | Some(it) => it, | 123 | Some(it) => it, |
124 | None => { | 124 | None => { |
125 | if err.is_none() { | 125 | if err.is_none() { |
126 | eprintln!("no error despite `as_call_id_with_errors` returning `None`"); | 126 | log::warn!("no error despite `as_call_id_with_errors` returning `None`"); |
127 | } | 127 | } |
128 | return ExpandResult { value: None, err }; | 128 | return ExpandResult { value: None, err }; |
129 | } | 129 | } |
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs index ab3f059ce..ac7474f63 100644 --- a/crates/hir_def/src/diagnostics.rs +++ b/crates/hir_def/src/diagnostics.rs | |||
@@ -95,6 +95,34 @@ impl Diagnostic for UnresolvedImport { | |||
95 | } | 95 | } |
96 | } | 96 | } |
97 | 97 | ||
98 | // Diagnostic: unresolved-macro-call | ||
99 | // | ||
100 | // This diagnostic is triggered if rust-analyzer is unable to resolove path to a | ||
101 | // macro in a macro invocation. | ||
102 | #[derive(Debug)] | ||
103 | pub struct UnresolvedMacroCall { | ||
104 | pub file: HirFileId, | ||
105 | pub node: AstPtr<ast::MacroCall>, | ||
106 | } | ||
107 | |||
108 | impl Diagnostic for UnresolvedMacroCall { | ||
109 | fn code(&self) -> DiagnosticCode { | ||
110 | DiagnosticCode("unresolved-macro-call") | ||
111 | } | ||
112 | fn message(&self) -> String { | ||
113 | "unresolved macro call".to_string() | ||
114 | } | ||
115 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
116 | InFile::new(self.file, self.node.clone().into()) | ||
117 | } | ||
118 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
119 | self | ||
120 | } | ||
121 | fn is_experimental(&self) -> bool { | ||
122 | true | ||
123 | } | ||
124 | } | ||
125 | |||
98 | // Diagnostic: inactive-code | 126 | // Diagnostic: inactive-code |
99 | // | 127 | // |
100 | // This diagnostic is shown for code with inactive `#[cfg]` attributes. | 128 | // This diagnostic is shown for code with inactive `#[cfg]` attributes. |
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index b50923747..6802bc250 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -57,8 +57,10 @@ use std::{ | |||
57 | 57 | ||
58 | use base_db::{impl_intern_key, salsa, CrateId}; | 58 | use base_db::{impl_intern_key, salsa, CrateId}; |
59 | use hir_expand::{ | 59 | use hir_expand::{ |
60 | ast_id_map::FileAstId, eager::expand_eager_macro, hygiene::Hygiene, AstId, HirFileId, InFile, | 60 | ast_id_map::FileAstId, |
61 | MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, | 61 | eager::{expand_eager_macro, ErrorEmitted}, |
62 | hygiene::Hygiene, | ||
63 | AstId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, | ||
62 | }; | 64 | }; |
63 | use la_arena::Idx; | 65 | use la_arena::Idx; |
64 | use nameres::DefMap; | 66 | use nameres::DefMap; |
@@ -592,8 +594,15 @@ impl AsMacroCall for InFile<&ast::MacroCall> { | |||
592 | error_sink(mbe::ExpandError::Other("malformed macro invocation".into())); | 594 | error_sink(mbe::ExpandError::Other("malformed macro invocation".into())); |
593 | } | 595 | } |
594 | 596 | ||
595 | AstIdWithPath::new(ast_id.file_id, ast_id.value, path?) | 597 | macro_call_as_call_id( |
596 | .as_call_id_with_errors(db, krate, resolver, error_sink) | 598 | &AstIdWithPath::new(ast_id.file_id, ast_id.value, path?), |
599 | db, | ||
600 | krate, | ||
601 | resolver, | ||
602 | error_sink, | ||
603 | ) | ||
604 | .ok()? | ||
605 | .ok() | ||
597 | } | 606 | } |
598 | } | 607 | } |
599 | 608 | ||
@@ -610,61 +619,50 @@ impl<T: ast::AstNode> AstIdWithPath<T> { | |||
610 | } | 619 | } |
611 | } | 620 | } |
612 | 621 | ||
613 | impl AsMacroCall for AstIdWithPath<ast::MacroCall> { | 622 | struct UnresolvedMacro; |
614 | fn as_call_id_with_errors( | 623 | |
615 | &self, | 624 | fn macro_call_as_call_id( |
616 | db: &dyn db::DefDatabase, | 625 | call: &AstIdWithPath<ast::MacroCall>, |
617 | krate: CrateId, | 626 | db: &dyn db::DefDatabase, |
618 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 627 | krate: CrateId, |
619 | error_sink: &mut dyn FnMut(mbe::ExpandError), | 628 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
620 | ) -> Option<MacroCallId> { | 629 | error_sink: &mut dyn FnMut(mbe::ExpandError), |
621 | let def: MacroDefId = resolver(self.path.clone()).or_else(|| { | 630 | ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { |
622 | error_sink(mbe::ExpandError::Other(format!("could not resolve macro `{}`", self.path))); | 631 | let def: MacroDefId = resolver(call.path.clone()).ok_or(UnresolvedMacro)?; |
623 | None | 632 | |
624 | })?; | 633 | let res = if let MacroDefKind::BuiltInEager(_) = def.kind { |
625 | 634 | let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast())); | |
626 | if let MacroDefKind::BuiltInEager(_) = def.kind { | 635 | let hygiene = Hygiene::new(db.upcast(), call.ast_id.file_id); |
627 | let macro_call = InFile::new(self.ast_id.file_id, self.ast_id.to_node(db.upcast())); | 636 | |
628 | let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id); | 637 | expand_eager_macro( |
629 | 638 | db.upcast(), | |
630 | Some( | 639 | krate, |
631 | expand_eager_macro( | 640 | macro_call, |
632 | db.upcast(), | 641 | def, |
633 | krate, | 642 | &|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?), |
634 | macro_call, | 643 | error_sink, |
635 | def, | 644 | ) |
636 | &|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?), | 645 | .map(MacroCallId::from) |
637 | error_sink, | 646 | } else { |
638 | ) | 647 | Ok(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(call.ast_id)).into()) |
639 | .ok()? | 648 | }; |
640 | .into(), | 649 | Ok(res) |
641 | ) | ||
642 | } else { | ||
643 | Some(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(self.ast_id)).into()) | ||
644 | } | ||
645 | } | ||
646 | } | 650 | } |
647 | 651 | ||
648 | impl AsMacroCall for AstIdWithPath<ast::Item> { | 652 | fn item_attr_as_call_id( |
649 | fn as_call_id_with_errors( | 653 | item_attr: &AstIdWithPath<ast::Item>, |
650 | &self, | 654 | db: &dyn db::DefDatabase, |
651 | db: &dyn db::DefDatabase, | 655 | krate: CrateId, |
652 | krate: CrateId, | 656 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
653 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 657 | ) -> Result<MacroCallId, UnresolvedMacro> { |
654 | error_sink: &mut dyn FnMut(mbe::ExpandError), | 658 | let def: MacroDefId = resolver(item_attr.path.clone()).ok_or(UnresolvedMacro)?; |
655 | ) -> Option<MacroCallId> { | 659 | let last_segment = item_attr.path.segments().last().ok_or(UnresolvedMacro)?; |
656 | let def: MacroDefId = resolver(self.path.clone()).or_else(|| { | 660 | let res = def |
657 | error_sink(mbe::ExpandError::Other(format!("could not resolve macro `{}`", self.path))); | 661 | .as_lazy_macro( |
658 | None | 662 | db.upcast(), |
659 | })?; | 663 | krate, |
660 | 664 | MacroCallKind::Attr(item_attr.ast_id, last_segment.to_string()), | |
661 | Some( | ||
662 | def.as_lazy_macro( | ||
663 | db.upcast(), | ||
664 | krate, | ||
665 | MacroCallKind::Attr(self.ast_id, self.path.segments().last()?.to_string()), | ||
666 | ) | ||
667 | .into(), | ||
668 | ) | 665 | ) |
669 | } | 666 | .into(); |
667 | Ok(res) | ||
670 | } | 668 | } |
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index f92232eb3..6a3456f2e 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -417,6 +417,8 @@ mod diagnostics { | |||
417 | 417 | ||
418 | UnresolvedProcMacro { ast: MacroCallKind }, | 418 | UnresolvedProcMacro { ast: MacroCallKind }, |
419 | 419 | ||
420 | UnresolvedMacroCall { ast: AstId<ast::MacroCall> }, | ||
421 | |||
420 | MacroError { ast: MacroCallKind, message: String }, | 422 | MacroError { ast: MacroCallKind, message: String }, |
421 | } | 423 | } |
422 | 424 | ||
@@ -477,6 +479,13 @@ mod diagnostics { | |||
477 | Self { in_module: container, kind: DiagnosticKind::MacroError { ast, message } } | 479 | Self { in_module: container, kind: DiagnosticKind::MacroError { ast, message } } |
478 | } | 480 | } |
479 | 481 | ||
482 | pub(super) fn unresolved_macro_call( | ||
483 | container: LocalModuleId, | ||
484 | ast: AstId<ast::MacroCall>, | ||
485 | ) -> Self { | ||
486 | Self { in_module: container, kind: DiagnosticKind::UnresolvedMacroCall { ast } } | ||
487 | } | ||
488 | |||
480 | pub(super) fn add_to( | 489 | pub(super) fn add_to( |
481 | &self, | 490 | &self, |
482 | db: &dyn DefDatabase, | 491 | db: &dyn DefDatabase, |
@@ -589,6 +598,11 @@ mod diagnostics { | |||
589 | }); | 598 | }); |
590 | } | 599 | } |
591 | 600 | ||
601 | DiagnosticKind::UnresolvedMacroCall { ast } => { | ||
602 | let node = ast.to_node(db.upcast()); | ||
603 | sink.push(UnresolvedMacroCall { file: ast.file_id, node: AstPtr::new(&node) }); | ||
604 | } | ||
605 | |||
592 | DiagnosticKind::MacroError { ast, message } => { | 606 | DiagnosticKind::MacroError { ast, message } => { |
593 | let (file, ast) = match ast { | 607 | let (file, ast) = match ast { |
594 | MacroCallKind::FnLike(ast) => { | 608 | MacroCallKind::FnLike(ast) => { |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 9996a0807..e51d89b43 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -13,7 +13,7 @@ use hir_expand::{ | |||
13 | builtin_macro::find_builtin_macro, | 13 | builtin_macro::find_builtin_macro, |
14 | name::{AsName, Name}, | 14 | name::{AsName, Name}, |
15 | proc_macro::ProcMacroExpander, | 15 | proc_macro::ProcMacroExpander, |
16 | HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, | 16 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, |
17 | }; | 17 | }; |
18 | use hir_expand::{InFile, MacroCallLoc}; | 18 | use hir_expand::{InFile, MacroCallLoc}; |
19 | use rustc_hash::{FxHashMap, FxHashSet}; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -24,11 +24,13 @@ use tt::{Leaf, TokenTree}; | |||
24 | use crate::{ | 24 | use crate::{ |
25 | attr::Attrs, | 25 | attr::Attrs, |
26 | db::DefDatabase, | 26 | db::DefDatabase, |
27 | item_attr_as_call_id, | ||
27 | item_scope::{ImportType, PerNsGlobImports}, | 28 | item_scope::{ImportType, PerNsGlobImports}, |
28 | item_tree::{ | 29 | item_tree::{ |
29 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroRules, Mod, ModItem, ModKind, | 30 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroRules, Mod, ModItem, ModKind, |
30 | StructDefKind, | 31 | StructDefKind, |
31 | }, | 32 | }, |
33 | macro_call_as_call_id, | ||
32 | nameres::{ | 34 | nameres::{ |
33 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, | 35 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, |
34 | BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode, | 36 | BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode, |
@@ -36,9 +38,9 @@ use crate::{ | |||
36 | path::{ImportAlias, ModPath, PathKind}, | 38 | path::{ImportAlias, ModPath, PathKind}, |
37 | per_ns::PerNs, | 39 | per_ns::PerNs, |
38 | visibility::{RawVisibility, Visibility}, | 40 | visibility::{RawVisibility, Visibility}, |
39 | AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId, | 41 | AdtId, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, |
40 | FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc, | 42 | ImplLoc, Intern, LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, |
41 | TypeAliasLoc, UnionLoc, | 43 | UnionLoc, UnresolvedMacro, |
42 | }; | 44 | }; |
43 | 45 | ||
44 | const GLOB_RECURSION_LIMIT: usize = 100; | 46 | const GLOB_RECURSION_LIMIT: usize = 100; |
@@ -790,8 +792,11 @@ impl DefCollector<'_> { | |||
790 | return false; | 792 | return false; |
791 | } | 793 | } |
792 | 794 | ||
793 | if let Some(call_id) = | 795 | match macro_call_as_call_id( |
794 | directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| { | 796 | &directive.ast_id, |
797 | self.db, | ||
798 | self.def_map.krate, | ||
799 | |path| { | ||
795 | let resolved_res = self.def_map.resolve_path_fp_with_macro( | 800 | let resolved_res = self.def_map.resolve_path_fp_with_macro( |
796 | self.db, | 801 | self.db, |
797 | ResolveMode::Other, | 802 | ResolveMode::Other, |
@@ -800,24 +805,29 @@ impl DefCollector<'_> { | |||
800 | BuiltinShadowMode::Module, | 805 | BuiltinShadowMode::Module, |
801 | ); | 806 | ); |
802 | resolved_res.resolved_def.take_macros() | 807 | resolved_res.resolved_def.take_macros() |
803 | }) | 808 | }, |
804 | { | 809 | &mut |_err| (), |
805 | resolved.push((directive.module_id, call_id, directive.depth)); | 810 | ) { |
806 | res = ReachedFixedPoint::No; | 811 | Ok(Ok(call_id)) => { |
807 | return false; | 812 | resolved.push((directive.module_id, call_id, directive.depth)); |
813 | res = ReachedFixedPoint::No; | ||
814 | return false; | ||
815 | } | ||
816 | Err(UnresolvedMacro) | Ok(Err(_)) => {} | ||
808 | } | 817 | } |
809 | 818 | ||
810 | true | 819 | true |
811 | }); | 820 | }); |
812 | attribute_macros.retain(|directive| { | 821 | attribute_macros.retain(|directive| { |
813 | if let Some(call_id) = | 822 | match item_attr_as_call_id(&directive.ast_id, self.db, self.def_map.krate, |path| { |
814 | directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| { | 823 | self.resolve_attribute_macro(&directive, &path) |
815 | self.resolve_attribute_macro(&directive, &path) | 824 | }) { |
816 | }) | 825 | Ok(call_id) => { |
817 | { | 826 | resolved.push((directive.module_id, call_id, 0)); |
818 | resolved.push((directive.module_id, call_id, 0)); | 827 | res = ReachedFixedPoint::No; |
819 | res = ReachedFixedPoint::No; | 828 | return false; |
820 | return false; | 829 | } |
830 | Err(UnresolvedMacro) => (), | ||
821 | } | 831 | } |
822 | 832 | ||
823 | true | 833 | true |
@@ -902,7 +912,8 @@ impl DefCollector<'_> { | |||
902 | 912 | ||
903 | for directive in &self.unexpanded_macros { | 913 | for directive in &self.unexpanded_macros { |
904 | let mut error = None; | 914 | let mut error = None; |
905 | directive.ast_id.as_call_id_with_errors( | 915 | match macro_call_as_call_id( |
916 | &directive.ast_id, | ||
906 | self.db, | 917 | self.db, |
907 | self.def_map.krate, | 918 | self.def_map.krate, |
908 | |path| { | 919 | |path| { |
@@ -918,15 +929,15 @@ impl DefCollector<'_> { | |||
918 | &mut |e| { | 929 | &mut |e| { |
919 | error.get_or_insert(e); | 930 | error.get_or_insert(e); |
920 | }, | 931 | }, |
921 | ); | 932 | ) { |
922 | 933 | Ok(_) => (), | |
923 | if let Some(err) = error { | 934 | Err(UnresolvedMacro) => { |
924 | self.def_map.diagnostics.push(DefDiagnostic::macro_error( | 935 | self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( |
925 | directive.module_id, | 936 | directive.module_id, |
926 | MacroCallKind::FnLike(directive.ast_id.ast_id), | 937 | directive.ast_id.ast_id, |
927 | err.to_string(), | 938 | )); |
928 | )); | 939 | } |
929 | } | 940 | }; |
930 | } | 941 | } |
931 | 942 | ||
932 | // Emit diagnostics for all remaining unresolved imports. | 943 | // Emit diagnostics for all remaining unresolved imports. |
@@ -1446,8 +1457,11 @@ impl ModCollector<'_, '_> { | |||
1446 | let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); | 1457 | let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); |
1447 | 1458 | ||
1448 | // Case 1: try to resolve in legacy scope and expand macro_rules | 1459 | // Case 1: try to resolve in legacy scope and expand macro_rules |
1449 | if let Some(macro_call_id) = | 1460 | if let Ok(Ok(macro_call_id)) = macro_call_as_call_id( |
1450 | ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| { | 1461 | &ast_id, |
1462 | self.def_collector.db, | ||
1463 | self.def_collector.def_map.krate, | ||
1464 | |path| { | ||
1451 | path.as_ident().and_then(|name| { | 1465 | path.as_ident().and_then(|name| { |
1452 | self.def_collector.def_map.with_ancestor_maps( | 1466 | self.def_collector.def_map.with_ancestor_maps( |
1453 | self.def_collector.db, | 1467 | self.def_collector.db, |
@@ -1455,8 +1469,9 @@ impl ModCollector<'_, '_> { | |||
1455 | &mut |map, module| map[module].scope.get_legacy_macro(&name), | 1469 | &mut |map, module| map[module].scope.get_legacy_macro(&name), |
1456 | ) | 1470 | ) |
1457 | }) | 1471 | }) |
1458 | }) | 1472 | }, |
1459 | { | 1473 | &mut |_err| (), |
1474 | ) { | ||
1460 | self.def_collector.unexpanded_macros.push(MacroDirective { | 1475 | self.def_collector.unexpanded_macros.push(MacroDirective { |
1461 | module_id: self.module_id, | 1476 | module_id: self.module_id, |
1462 | ast_id, | 1477 | ast_id, |