aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/body/lower.rs8
-rw-r--r--crates/hir_def/src/body/tests.rs2
-rw-r--r--crates/hir_def/src/diagnostics.rs5
-rw-r--r--crates/hir_def/src/find_path.rs23
-rw-r--r--crates/hir_def/src/lib.rs29
-rw-r--r--crates/hir_def/src/nameres.rs13
-rw-r--r--crates/hir_def/src/nameres/collector.rs9
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs8
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs4
-rw-r--r--crates/hir_def/src/test_db.rs51
-rw-r--r--crates/hir_def/src/visibility.rs10
11 files changed, 139 insertions, 23 deletions
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index ed07d6928..c0b0b7841 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -568,9 +568,13 @@ impl ExprCollector<'_> {
568 568
569 let res = match res { 569 let res = match res {
570 Ok(res) => res, 570 Ok(res) => res,
571 Err(UnresolvedMacro) => { 571 Err(UnresolvedMacro { path }) => {
572 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall( 572 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall(
573 UnresolvedMacroCall { file: outer_file, node: syntax_ptr.cast().unwrap() }, 573 UnresolvedMacroCall {
574 file: outer_file,
575 node: syntax_ptr.cast().unwrap(),
576 path,
577 },
574 )); 578 ));
575 collector(self, None); 579 collector(self, None);
576 return; 580 return;
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index c1d3e998f..63f5fe88d 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -180,7 +180,7 @@ fn unresolved_macro_diag() {
180 r#" 180 r#"
181fn f() { 181fn f() {
182 m!(); 182 m!();
183 //^^^^ unresolved macro call 183 //^^^^ unresolved macro `m!`
184} 184}
185 "#, 185 "#,
186 ); 186 );
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs
index 97abf8653..a71ae2668 100644
--- a/crates/hir_def/src/diagnostics.rs
+++ b/crates/hir_def/src/diagnostics.rs
@@ -8,7 +8,7 @@ use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink};
8use hir_expand::{HirFileId, InFile}; 8use hir_expand::{HirFileId, InFile};
9use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; 9use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
10 10
11use crate::{db::DefDatabase, DefWithBodyId}; 11use crate::{db::DefDatabase, path::ModPath, DefWithBodyId};
12 12
13pub fn validate_body(db: &dyn DefDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) { 13pub fn validate_body(db: &dyn DefDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) {
14 let source_map = db.body_with_source_map(owner).1; 14 let source_map = db.body_with_source_map(owner).1;
@@ -103,6 +103,7 @@ impl Diagnostic for UnresolvedImport {
103pub struct UnresolvedMacroCall { 103pub struct UnresolvedMacroCall {
104 pub file: HirFileId, 104 pub file: HirFileId,
105 pub node: AstPtr<ast::MacroCall>, 105 pub node: AstPtr<ast::MacroCall>,
106 pub path: ModPath,
106} 107}
107 108
108impl Diagnostic for UnresolvedMacroCall { 109impl Diagnostic for UnresolvedMacroCall {
@@ -110,7 +111,7 @@ impl Diagnostic for UnresolvedMacroCall {
110 DiagnosticCode("unresolved-macro-call") 111 DiagnosticCode("unresolved-macro-call")
111 } 112 }
112 fn message(&self) -> String { 113 fn message(&self) -> String {
113 "unresolved macro call".to_string() 114 format!("unresolved macro `{}!`", self.path)
114 } 115 }
115 fn display_source(&self) -> InFile<SyntaxNodePtr> { 116 fn display_source(&self) -> InFile<SyntaxNodePtr> {
116 InFile::new(self.file, self.node.clone().into()) 117 InFile::new(self.file, self.node.clone().into())
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index 41da3bc2d..2c4bbe585 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -955,6 +955,29 @@ fn main() {
955 } 955 }
956 956
957 #[test] 957 #[test]
958 fn from_inside_module() {
959 // This worked correctly, but the test suite logic was broken.
960 cov_mark::check!(submodule_in_testdb);
961 check_found_path(
962 r#"
963mod baz {
964 pub struct Foo {}
965}
966
967mod bar {
968 fn bar() {
969 $0
970 }
971}
972 "#,
973 "crate::baz::Foo",
974 "crate::baz::Foo",
975 "crate::baz::Foo",
976 "crate::baz::Foo",
977 )
978 }
979
980 #[test]
958 fn recursive_pub_mod_reexport() { 981 fn recursive_pub_mod_reexport() {
959 cov_mark::check!(recursive_imports); 982 cov_mark::check!(recursive_imports);
960 check_found_path( 983 check_found_path(
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index ffee05500..5ac1670b5 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -66,6 +66,7 @@ use hir_expand::{
66}; 66};
67use la_arena::Idx; 67use la_arena::Idx;
68use nameres::DefMap; 68use nameres::DefMap;
69use path::ModPath;
69use syntax::ast; 70use syntax::ast;
70 71
71use crate::builtin_type::BuiltinType; 72use crate::builtin_type::BuiltinType;
@@ -107,6 +108,18 @@ impl ModuleId {
107 pub fn containing_module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> { 108 pub fn containing_module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> {
108 self.def_map(db).containing_module(self.local_id) 109 self.def_map(db).containing_module(self.local_id)
109 } 110 }
111
112 /// Returns `true` if this module represents a block expression.
113 ///
114 /// Returns `false` if this module is a submodule *inside* a block expression
115 /// (eg. `m` in `{ mod m {} }`).
116 pub fn is_block_root(&self, db: &dyn db::DefDatabase) -> bool {
117 if self.block.is_none() {
118 return false;
119 }
120
121 self.def_map(db)[self.local_id].parent.is_none()
122 }
110} 123}
111 124
112/// An ID of a module, **local** to a specific crate 125/// An ID of a module, **local** to a specific crate
@@ -675,7 +688,9 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
675 } 688 }
676} 689}
677 690
678pub struct UnresolvedMacro; 691pub struct UnresolvedMacro {
692 pub path: ModPath,
693}
679 694
680fn macro_call_as_call_id( 695fn macro_call_as_call_id(
681 call: &AstIdWithPath<ast::MacroCall>, 696 call: &AstIdWithPath<ast::MacroCall>,
@@ -684,7 +699,8 @@ fn macro_call_as_call_id(
684 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 699 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
685 error_sink: &mut dyn FnMut(mbe::ExpandError), 700 error_sink: &mut dyn FnMut(mbe::ExpandError),
686) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { 701) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
687 let def: MacroDefId = resolver(call.path.clone()).ok_or(UnresolvedMacro)?; 702 let def: MacroDefId =
703 resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
688 704
689 let res = if let MacroDefKind::BuiltInEager(..) = def.kind { 705 let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
690 let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast())); 706 let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast()));
@@ -714,8 +730,13 @@ fn derive_macro_as_call_id(
714 krate: CrateId, 730 krate: CrateId,
715 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 731 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
716) -> Result<MacroCallId, UnresolvedMacro> { 732) -> Result<MacroCallId, UnresolvedMacro> {
717 let def: MacroDefId = resolver(item_attr.path.clone()).ok_or(UnresolvedMacro)?; 733 let def: MacroDefId = resolver(item_attr.path.clone())
718 let last_segment = item_attr.path.segments().last().ok_or(UnresolvedMacro)?; 734 .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
735 let last_segment = item_attr
736 .path
737 .segments()
738 .last()
739 .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
719 let res = def 740 let res = def
720 .as_lazy_macro( 741 .as_lazy_macro(
721 db.upcast(), 742 db.upcast(),
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 9e181751c..542f190a1 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -481,7 +481,7 @@ mod diagnostics {
481 481
482 UnresolvedProcMacro { ast: MacroCallKind }, 482 UnresolvedProcMacro { ast: MacroCallKind },
483 483
484 UnresolvedMacroCall { ast: AstId<ast::MacroCall> }, 484 UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath },
485 485
486 MacroError { ast: MacroCallKind, message: String }, 486 MacroError { ast: MacroCallKind, message: String },
487 } 487 }
@@ -546,8 +546,9 @@ mod diagnostics {
546 pub(super) fn unresolved_macro_call( 546 pub(super) fn unresolved_macro_call(
547 container: LocalModuleId, 547 container: LocalModuleId,
548 ast: AstId<ast::MacroCall>, 548 ast: AstId<ast::MacroCall>,
549 path: ModPath,
549 ) -> Self { 550 ) -> Self {
550 Self { in_module: container, kind: DiagnosticKind::UnresolvedMacroCall { ast } } 551 Self { in_module: container, kind: DiagnosticKind::UnresolvedMacroCall { ast, path } }
551 } 552 }
552 553
553 pub(super) fn add_to( 554 pub(super) fn add_to(
@@ -662,9 +663,13 @@ mod diagnostics {
662 }); 663 });
663 } 664 }
664 665
665 DiagnosticKind::UnresolvedMacroCall { ast } => { 666 DiagnosticKind::UnresolvedMacroCall { ast, path } => {
666 let node = ast.to_node(db.upcast()); 667 let node = ast.to_node(db.upcast());
667 sink.push(UnresolvedMacroCall { file: ast.file_id, node: AstPtr::new(&node) }); 668 sink.push(UnresolvedMacroCall {
669 file: ast.file_id,
670 node: AstPtr::new(&node),
671 path: path.clone(),
672 });
668 } 673 }
669 674
670 DiagnosticKind::MacroError { ast, message } => { 675 DiagnosticKind::MacroError { ast, message } => {
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index fb4ddff5e..05ceb1efb 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -829,7 +829,7 @@ impl DefCollector<'_> {
829 res = ReachedFixedPoint::No; 829 res = ReachedFixedPoint::No;
830 return false; 830 return false;
831 } 831 }
832 Err(UnresolvedMacro) | Ok(Err(_)) => {} 832 Err(UnresolvedMacro { .. }) | Ok(Err(_)) => {}
833 } 833 }
834 } 834 }
835 MacroDirectiveKind::Derive { ast_id, derive_attr } => { 835 MacroDirectiveKind::Derive { ast_id, derive_attr } => {
@@ -845,7 +845,7 @@ impl DefCollector<'_> {
845 res = ReachedFixedPoint::No; 845 res = ReachedFixedPoint::No;
846 return false; 846 return false;
847 } 847 }
848 Err(UnresolvedMacro) => (), 848 Err(UnresolvedMacro { .. }) => (),
849 } 849 }
850 } 850 }
851 } 851 }
@@ -943,10 +943,11 @@ impl DefCollector<'_> {
943 &mut |_| (), 943 &mut |_| (),
944 ) { 944 ) {
945 Ok(_) => (), 945 Ok(_) => (),
946 Err(UnresolvedMacro) => { 946 Err(UnresolvedMacro { path }) => {
947 self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( 947 self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
948 directive.module_id, 948 directive.module_id,
949 ast_id.ast_id, 949 ast_id.ast_id,
950 path,
950 )); 951 ));
951 } 952 }
952 }, 953 },
@@ -1530,7 +1531,7 @@ impl ModCollector<'_, '_> {
1530 )); 1531 ));
1531 return; 1532 return;
1532 } 1533 }
1533 Err(UnresolvedMacro) => (), 1534 Err(UnresolvedMacro { .. }) => (),
1534 } 1535 }
1535 1536
1536 // Case 2: resolve in module scope, expand during name resolution. 1537 // Case 2: resolve in module scope, expand during name resolution.
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index ccc9f22eb..c984148c3 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -387,7 +387,13 @@ impl DefMap {
387 .get_legacy_macro(name) 387 .get_legacy_macro(name)
388 .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public)); 388 .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public));
389 let from_scope = self[module].scope.get(name); 389 let from_scope = self[module].scope.get(name);
390 let from_builtin = BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none); 390 let from_builtin = match self.block {
391 Some(_) => {
392 // Only resolve to builtins in the root `DefMap`.
393 PerNs::none()
394 }
395 None => BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none),
396 };
391 let from_scope_or_builtin = match shadow { 397 let from_scope_or_builtin = match shadow {
392 BuiltinShadowMode::Module => from_scope.or(from_builtin), 398 BuiltinShadowMode::Module => from_scope.or(from_builtin),
393 BuiltinShadowMode::Other => { 399 BuiltinShadowMode::Other => {
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index 1ac88fc89..543975e07 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -170,7 +170,7 @@ fn unresolved_legacy_scope_macro() {
170 170
171 m!(); 171 m!();
172 m2!(); 172 m2!();
173 //^^^^^^ unresolved macro call 173 //^^^^^^ unresolved macro `self::m2!`
174 "#, 174 "#,
175 ); 175 );
176} 176}
@@ -187,7 +187,7 @@ fn unresolved_module_scope_macro() {
187 187
188 self::m!(); 188 self::m!();
189 self::m2!(); 189 self::m2!();
190 //^^^^^^^^^^^^ unresolved macro call 190 //^^^^^^^^^^^^ unresolved macro `self::m2!`
191 "#, 191 "#,
192 ); 192 );
193} 193}
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs
index dd36106f8..8fa703a57 100644
--- a/crates/hir_def/src/test_db.rs
+++ b/crates/hir_def/src/test_db.rs
@@ -15,7 +15,12 @@ use rustc_hash::FxHashSet;
15use syntax::{algo, ast, AstNode, TextRange, TextSize}; 15use syntax::{algo, ast, AstNode, TextRange, TextSize};
16use test_utils::extract_annotations; 16use test_utils::extract_annotations;
17 17
18use crate::{db::DefDatabase, nameres::DefMap, src::HasSource, Lookup, ModuleDefId, ModuleId}; 18use crate::{
19 db::DefDatabase,
20 nameres::{DefMap, ModuleSource},
21 src::HasSource,
22 LocalModuleId, Lookup, ModuleDefId, ModuleId,
23};
19 24
20#[salsa::database( 25#[salsa::database(
21 base_db::SourceDatabaseExtStorage, 26 base_db::SourceDatabaseExtStorage,
@@ -87,10 +92,11 @@ impl TestDB {
87 pub(crate) fn module_at_position(&self, position: FilePosition) -> ModuleId { 92 pub(crate) fn module_at_position(&self, position: FilePosition) -> ModuleId {
88 let file_module = self.module_for_file(position.file_id); 93 let file_module = self.module_for_file(position.file_id);
89 let mut def_map = file_module.def_map(self); 94 let mut def_map = file_module.def_map(self);
95 let module = self.mod_at_position(&def_map, position);
90 96
91 def_map = match self.block_at_position(&def_map, position) { 97 def_map = match self.block_at_position(&def_map, position) {
92 Some(it) => it, 98 Some(it) => it,
93 None => return file_module, 99 None => return def_map.module_id(module),
94 }; 100 };
95 loop { 101 loop {
96 let new_map = self.block_at_position(&def_map, position); 102 let new_map = self.block_at_position(&def_map, position);
@@ -106,6 +112,47 @@ impl TestDB {
106 } 112 }
107 } 113 }
108 114
115 /// Finds the smallest/innermost module in `def_map` containing `position`.
116 fn mod_at_position(&self, def_map: &DefMap, position: FilePosition) -> LocalModuleId {
117 let mut size = None;
118 let mut res = def_map.root();
119 for (module, data) in def_map.modules() {
120 let src = data.definition_source(self);
121 if src.file_id != position.file_id.into() {
122 continue;
123 }
124
125 let range = match src.value {
126 ModuleSource::SourceFile(it) => it.syntax().text_range(),
127 ModuleSource::Module(it) => it.syntax().text_range(),
128 ModuleSource::BlockExpr(it) => it.syntax().text_range(),
129 };
130
131 if !range.contains(position.offset) {
132 continue;
133 }
134
135 let new_size = match size {
136 None => range.len(),
137 Some(size) => {
138 if range.len() < size {
139 range.len()
140 } else {
141 size
142 }
143 }
144 };
145
146 if size != Some(new_size) {
147 cov_mark::hit!(submodule_in_testdb);
148 size = Some(new_size);
149 res = module;
150 }
151 }
152
153 res
154 }
155
109 fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<Arc<DefMap>> { 156 fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<Arc<DefMap>> {
110 // Find the smallest (innermost) function in `def_map` containing the cursor. 157 // Find the smallest (innermost) function in `def_map` containing the cursor.
111 let mut size = None; 158 let mut size = None;
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs
index 9908cd926..d4b7c9970 100644
--- a/crates/hir_def/src/visibility.rs
+++ b/crates/hir_def/src/visibility.rs
@@ -123,11 +123,19 @@ impl Visibility {
123 def_map: &DefMap, 123 def_map: &DefMap,
124 mut from_module: crate::LocalModuleId, 124 mut from_module: crate::LocalModuleId,
125 ) -> bool { 125 ) -> bool {
126 let to_module = match self { 126 let mut to_module = match self {
127 Visibility::Module(m) => m, 127 Visibility::Module(m) => m,
128 Visibility::Public => return true, 128 Visibility::Public => return true,
129 }; 129 };
130 130
131 // `to_module` might be the root module of a block expression. Those have the same
132 // visibility as the containing module (even though no items are directly nameable from
133 // there, getting this right is important for method resolution).
134 // In that case, we adjust the visibility of `to_module` to point to the containing module.
135 if to_module.is_block_root(db) {
136 to_module = to_module.containing_module(db).unwrap();
137 }
138
131 // from_module needs to be a descendant of to_module 139 // from_module needs to be a descendant of to_module
132 let mut def_map = def_map; 140 let mut def_map = def_map;
133 let mut parent_arc; 141 let mut parent_arc;