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/attr.rs32
-rw-r--r--crates/hir_def/src/body/lower.rs8
-rw-r--r--crates/hir_def/src/body/scope.rs2
-rw-r--r--crates/hir_def/src/body/tests.rs149
-rw-r--r--crates/hir_def/src/body/tests/block.rs10
-rw-r--r--crates/hir_def/src/builtin_attr.rs38
-rw-r--r--crates/hir_def/src/child_by_source.rs4
-rw-r--r--crates/hir_def/src/data.rs17
-rw-r--r--crates/hir_def/src/db.rs3
-rw-r--r--crates/hir_def/src/generics.rs4
-rw-r--r--crates/hir_def/src/import_map.rs169
-rw-r--r--crates/hir_def/src/item_scope.rs19
-rw-r--r--crates/hir_def/src/item_tree/lower.rs17
-rw-r--r--crates/hir_def/src/item_tree/pretty.rs2
-rw-r--r--crates/hir_def/src/item_tree/tests.rs38
-rw-r--r--crates/hir_def/src/keys.rs3
-rw-r--r--crates/hir_def/src/lang_item.rs1
-rw-r--r--crates/hir_def/src/lib.rs86
-rw-r--r--crates/hir_def/src/nameres/collector.rs82
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs12
-rw-r--r--crates/hir_def/src/nameres/tests.rs1
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs229
-rw-r--r--crates/hir_def/src/path/lower.rs4
-rw-r--r--crates/hir_def/src/per_ns.rs2
-rw-r--r--crates/hir_def/src/resolver.rs10
-rw-r--r--crates/hir_def/src/test_db.rs161
-rw-r--r--crates/hir_def/src/type_ref.rs16
27 files changed, 413 insertions, 706 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 385ba8c80..d07adb084 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -36,6 +36,10 @@ use crate::{
36pub struct Documentation(String); 36pub struct Documentation(String);
37 37
38impl Documentation { 38impl Documentation {
39 pub fn new(s: String) -> Self {
40 Documentation(s)
41 }
42
39 pub fn as_str(&self) -> &str { 43 pub fn as_str(&self) -> &str {
40 &self.0 44 &self.0
41 } 45 }
@@ -102,7 +106,9 @@ impl RawAttrs {
102 ) -> Self { 106 ) -> Self {
103 let entries = collect_attrs(owner) 107 let entries = collect_attrs(owner)
104 .flat_map(|(id, attr)| match attr { 108 .flat_map(|(id, attr)| match attr {
105 Either::Left(attr) => Attr::from_src(db, attr, hygiene, id), 109 Either::Left(attr) => {
110 attr.meta().and_then(|meta| Attr::from_src(db, meta, hygiene, id))
111 }
106 Either::Right(comment) => comment.doc_comment().map(|doc| Attr { 112 Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
107 id, 113 id,
108 input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))), 114 input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))),
@@ -168,10 +174,9 @@ impl RawAttrs {
168 let index = attr.id; 174 let index = attr.id;
169 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { 175 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| {
170 let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; 176 let tree = Subtree { delimiter: None, token_trees: attr.to_vec() };
171 let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?;
172 // FIXME hygiene 177 // FIXME hygiene
173 let hygiene = Hygiene::new_unhygienic(); 178 let hygiene = Hygiene::new_unhygienic();
174 Attr::from_src(db, attr, &hygiene, index) 179 Attr::from_tt(db, &tree, &hygiene, index)
175 }); 180 });
176 181
177 let cfg_options = &crate_graph[krate].cfg_options; 182 let cfg_options = &crate_graph[krate].cfg_options;
@@ -578,13 +583,13 @@ impl AttrSourceMap {
578 .get(id.ast_index as usize) 583 .get(id.ast_index as usize)
579 .unwrap_or_else(|| panic!("cannot find doc comment at index {:?}", id)) 584 .unwrap_or_else(|| panic!("cannot find doc comment at index {:?}", id))
580 .clone() 585 .clone()
581 .map(|attr| Either::Right(attr)) 586 .map(Either::Right)
582 } else { 587 } else {
583 self.attrs 588 self.attrs
584 .get(id.ast_index as usize) 589 .get(id.ast_index as usize)
585 .unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", id)) 590 .unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", id))
586 .clone() 591 .clone()
587 .map(|attr| Either::Left(attr)) 592 .map(Either::Left)
588 } 593 }
589 } 594 }
590} 595}
@@ -601,7 +606,7 @@ pub struct DocsRangeMap {
601impl DocsRangeMap { 606impl DocsRangeMap {
602 pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> { 607 pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
603 let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?; 608 let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?;
604 let (line_docs_range, idx, original_line_src_range) = self.mapping[found].clone(); 609 let (line_docs_range, idx, original_line_src_range) = self.mapping[found];
605 if !line_docs_range.contains_range(range) { 610 if !line_docs_range.contains_range(range) {
606 return None; 611 return None;
607 } 612 }
@@ -660,7 +665,7 @@ impl fmt::Display for AttrInput {
660impl Attr { 665impl Attr {
661 fn from_src( 666 fn from_src(
662 db: &dyn DefDatabase, 667 db: &dyn DefDatabase,
663 ast: ast::Attr, 668 ast: ast::Meta,
664 hygiene: &Hygiene, 669 hygiene: &Hygiene,
665 id: AttrId, 670 id: AttrId,
666 ) -> Option<Attr> { 671 ) -> Option<Attr> {
@@ -679,6 +684,19 @@ impl Attr {
679 Some(Attr { id, path, input }) 684 Some(Attr { id, path, input })
680 } 685 }
681 686
687 fn from_tt(
688 db: &dyn DefDatabase,
689 tt: &tt::Subtree,
690 hygiene: &Hygiene,
691 id: AttrId,
692 ) -> Option<Attr> {
693 let (parse, _) =
694 mbe::token_tree_to_syntax_node(tt, hir_expand::FragmentKind::MetaItem).ok()?;
695 let ast = ast::Meta::cast(parse.syntax_node())?;
696
697 Self::from_src(db, ast, hygiene, id)
698 }
699
682 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths 700 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths
683 /// to derive macros. 701 /// to derive macros.
684 /// 702 ///
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index da1fdac33..bed4c4994 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -1000,18 +1000,18 @@ impl From<ast::LiteralKind> for Literal {
1000 // FIXME: these should have actual values filled in, but unsure on perf impact 1000 // FIXME: these should have actual values filled in, but unsure on perf impact
1001 LiteralKind::IntNumber(lit) => { 1001 LiteralKind::IntNumber(lit) => {
1002 if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) { 1002 if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
1003 return Literal::Float(Default::default(), builtin); 1003 Literal::Float(Default::default(), builtin)
1004 } else if let builtin @ Some(_) = 1004 } else if let builtin @ Some(_) =
1005 lit.suffix().and_then(|it| BuiltinInt::from_suffix(&it)) 1005 lit.suffix().and_then(|it| BuiltinInt::from_suffix(it))
1006 { 1006 {
1007 Literal::Int(lit.value().unwrap_or(0) as i128, builtin) 1007 Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
1008 } else { 1008 } else {
1009 let builtin = lit.suffix().and_then(|it| BuiltinUint::from_suffix(&it)); 1009 let builtin = lit.suffix().and_then(|it| BuiltinUint::from_suffix(it));
1010 Literal::Uint(lit.value().unwrap_or(0), builtin) 1010 Literal::Uint(lit.value().unwrap_or(0), builtin)
1011 } 1011 }
1012 } 1012 }
1013 LiteralKind::FloatNumber(lit) => { 1013 LiteralKind::FloatNumber(lit) => {
1014 let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it)); 1014 let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(it));
1015 Literal::Float(Default::default(), ty) 1015 Literal::Float(Default::default(), ty)
1016 } 1016 }
1017 LiteralKind::ByteString(bs) => { 1017 LiteralKind::ByteString(bs) => {
diff --git a/crates/hir_def/src/body/scope.rs b/crates/hir_def/src/body/scope.rs
index 6764de3a7..58a1fc81c 100644
--- a/crates/hir_def/src/body/scope.rs
+++ b/crates/hir_def/src/body/scope.rs
@@ -198,7 +198,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
198 } 198 }
199 Expr::Lambda { args, body: body_expr, .. } => { 199 Expr::Lambda { args, body: body_expr, .. } => {
200 let scope = scopes.new_scope(scope); 200 let scope = scopes.new_scope(scope);
201 scopes.add_params_bindings(body, scope, &args); 201 scopes.add_params_bindings(body, scope, args);
202 compute_expr_scopes(*body_expr, body, scopes, scope); 202 compute_expr_scopes(*body_expr, body, scopes, scope);
203 } 203 }
204 Expr::Match { expr, arms } => { 204 Expr::Match { expr, arms } => {
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index d4fae05a6..27d837d47 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -3,7 +3,7 @@ mod block;
3use base_db::{fixture::WithFixture, SourceDatabase}; 3use base_db::{fixture::WithFixture, SourceDatabase};
4use expect_test::Expect; 4use expect_test::Expect;
5 5
6use crate::{test_db::TestDB, ModuleDefId}; 6use crate::ModuleDefId;
7 7
8use super::*; 8use super::*;
9 9
@@ -28,11 +28,6 @@ fn lower(ra_fixture: &str) -> Arc<Body> {
28 db.body(fn_def.unwrap().into()) 28 db.body(fn_def.unwrap().into())
29} 29}
30 30
31fn check_diagnostics(ra_fixture: &str) {
32 let db: TestDB = TestDB::with_files(ra_fixture);
33 db.check_diagnostics();
34}
35
36fn block_def_map_at(ra_fixture: &str) -> String { 31fn block_def_map_at(ra_fixture: &str) -> String {
37 let (db, position) = crate::test_db::TestDB::with_position(ra_fixture); 32 let (db, position) = crate::test_db::TestDB::with_position(ra_fixture);
38 33
@@ -57,7 +52,7 @@ fn check_at(ra_fixture: &str, expect: Expect) {
57fn your_stack_belongs_to_me() { 52fn your_stack_belongs_to_me() {
58 cov_mark::check!(your_stack_belongs_to_me); 53 cov_mark::check!(your_stack_belongs_to_me);
59 lower( 54 lower(
60 " 55 r#"
61macro_rules! n_nuple { 56macro_rules! n_nuple {
62 ($e:tt) => (); 57 ($e:tt) => ();
63 ($($rest:tt)*) => {{ 58 ($($rest:tt)*) => {{
@@ -65,7 +60,7 @@ macro_rules! n_nuple {
65 }}; 60 }};
66} 61}
67fn main() { n_nuple!(1,2,3); } 62fn main() { n_nuple!(1,2,3); }
68", 63"#,
69 ); 64 );
70} 65}
71 66
@@ -73,7 +68,7 @@ fn main() { n_nuple!(1,2,3); }
73fn macro_resolve() { 68fn macro_resolve() {
74 // Regression test for a path resolution bug introduced with inner item handling. 69 // Regression test for a path resolution bug introduced with inner item handling.
75 lower( 70 lower(
76 r" 71 r#"
77macro_rules! vec { 72macro_rules! vec {
78 () => { () }; 73 () => { () };
79 ($elem:expr; $n:expr) => { () }; 74 ($elem:expr; $n:expr) => { () };
@@ -84,140 +79,6 @@ mod m {
84 let _ = vec![FileSet::default(); self.len()]; 79 let _ = vec![FileSet::default(); self.len()];
85 } 80 }
86} 81}
87 ", 82"#,
88 );
89}
90
91#[test]
92fn cfg_diagnostics() {
93 check_diagnostics(
94 r"
95fn f() {
96 // The three g̶e̶n̶d̶e̶r̶s̶ statements:
97
98 #[cfg(a)] fn f() {} // Item statement
99 //^^^^^^^^^^^^^^^^^^^ InactiveCode
100 #[cfg(a)] {} // Expression statement
101 //^^^^^^^^^^^^ InactiveCode
102 #[cfg(a)] let x = 0; // let statement
103 //^^^^^^^^^^^^^^^^^^^^ InactiveCode
104
105 abc(#[cfg(a)] 0);
106 //^^^^^^^^^^^ InactiveCode
107 let x = Struct {
108 #[cfg(a)] f: 0,
109 //^^^^^^^^^^^^^^ InactiveCode
110 };
111 match () {
112 () => (),
113 #[cfg(a)] () => (),
114 //^^^^^^^^^^^^^^^^^^ InactiveCode
115 }
116
117 #[cfg(a)] 0 // Trailing expression of block
118 //^^^^^^^^^^^ InactiveCode
119}
120 ",
121 );
122}
123
124#[test]
125fn macro_diag_builtin() {
126 check_diagnostics(
127 r#"
128#[rustc_builtin_macro]
129macro_rules! env {}
130
131#[rustc_builtin_macro]
132macro_rules! include {}
133
134#[rustc_builtin_macro]
135macro_rules! compile_error {}
136
137#[rustc_builtin_macro]
138macro_rules! format_args {
139 () => {}
140}
141
142fn f() {
143 // Test a handful of built-in (eager) macros:
144
145 include!(invalid);
146 //^^^^^^^^^^^^^^^^^ could not convert tokens
147 include!("does not exist");
148 //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist`
149
150 env!(invalid);
151 //^^^^^^^^^^^^^ could not convert tokens
152
153 env!("OUT_DIR");
154 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
155
156 compile_error!("compile_error works");
157 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works
158
159 // Lazy:
160
161 format_args!();
162 //^^^^^^^^^^^^^^ no rule matches input tokens
163}
164 "#,
165 );
166}
167
168#[test]
169fn macro_rules_diag() {
170 check_diagnostics(
171 r#"
172macro_rules! m {
173 () => {};
174}
175fn f() {
176 m!();
177
178 m!(hi);
179 //^^^^^^ leftover tokens
180}
181 "#,
182 ); 83 );
183} 84}
184
185#[test]
186fn unresolved_macro_diag() {
187 check_diagnostics(
188 r#"
189fn f() {
190 m!();
191 //^^^^ UnresolvedMacroCall
192}
193 "#,
194 );
195}
196
197#[test]
198fn dollar_crate_in_builtin_macro() {
199 check_diagnostics(
200 r#"
201#[macro_export]
202#[rustc_builtin_macro]
203macro_rules! format_args {}
204
205#[macro_export]
206macro_rules! arg {
207 () => {}
208}
209
210#[macro_export]
211macro_rules! outer {
212 () => {
213 $crate::format_args!( "", $crate::arg!(1) )
214 };
215}
216
217fn f() {
218 outer!();
219 //^^^^^^^^ leftover tokens
220}
221 "#,
222 )
223}
diff --git a/crates/hir_def/src/body/tests/block.rs b/crates/hir_def/src/body/tests/block.rs
index bc3d0f138..15c10d053 100644
--- a/crates/hir_def/src/body/tests/block.rs
+++ b/crates/hir_def/src/body/tests/block.rs
@@ -163,14 +163,14 @@ fn legacy_macro_items() {
163 // correctly. 163 // correctly.
164 check_at( 164 check_at(
165 r#" 165 r#"
166macro_rules! hit { 166macro_rules! mark {
167 () => { 167 () => {
168 struct Hit {} 168 struct Hit {}
169 } 169 }
170} 170}
171 171
172fn f() { 172fn f() {
173 hit!(); 173 mark!();
174 $0 174 $0
175} 175}
176"#, 176"#,
@@ -193,20 +193,20 @@ use core::cov_mark;
193 193
194fn f() { 194fn f() {
195 fn nested() { 195 fn nested() {
196 cov_mark::hit!(Hit); 196 cov_mark::mark!(Hit);
197 $0 197 $0
198 } 198 }
199} 199}
200//- /core.rs crate:core 200//- /core.rs crate:core
201pub mod cov_mark { 201pub mod cov_mark {
202 #[macro_export] 202 #[macro_export]
203 macro_rules! _hit { 203 macro_rules! _mark {
204 ($name:ident) => { 204 ($name:ident) => {
205 struct $name {} 205 struct $name {}
206 } 206 }
207 } 207 }
208 208
209 pub use crate::_hit as hit; 209 pub use crate::_mark as mark;
210} 210}
211"#, 211"#,
212 expect![[r#" 212 expect![[r#"
diff --git a/crates/hir_def/src/builtin_attr.rs b/crates/hir_def/src/builtin_attr.rs
index d5d7f0f47..39c7f84f7 100644
--- a/crates/hir_def/src/builtin_attr.rs
+++ b/crates/hir_def/src/builtin_attr.rs
@@ -2,7 +2,7 @@
2//! 2//!
3//! The actual definitions were copied from rustc's `compiler/rustc_feature/src/builtin_attrs.rs`. 3//! The actual definitions were copied from rustc's `compiler/rustc_feature/src/builtin_attrs.rs`.
4//! 4//!
5//! It was last synchronized with upstream commit 2225ee1b62ff089917434aefd9b2bf509cfa087f. 5//! It was last synchronized with upstream commit 835150e70288535bc57bb624792229b9dc94991d.
6//! 6//!
7//! The macros were adjusted to only expand to the attribute name, since that is all we need to do 7//! The macros were adjusted to only expand to the attribute name, since that is all we need to do
8//! name resolution, and `BUILTIN_ATTRIBUTES` is almost entirely unchanged from the original, to 8//! name resolution, and `BUILTIN_ATTRIBUTES` is almost entirely unchanged from the original, to
@@ -58,7 +58,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
58 ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")), 58 ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")),
59 59
60 // Macros: 60 // Macros:
61 ungated!(derive, Normal, template!(List: "Trait1, Trait2, ...")),
62 ungated!(automatically_derived, Normal, template!(Word)), 61 ungated!(automatically_derived, Normal, template!(Word)),
63 // FIXME(#14407) 62 // FIXME(#14407)
64 ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")), 63 ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")),
@@ -98,8 +97,8 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
98 template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#), 97 template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#),
99 ), 98 ),
100 ungated!(link_name, AssumedUsed, template!(NameValueStr: "name")), 99 ungated!(link_name, AssumedUsed, template!(NameValueStr: "name")),
101 ungated!(no_link, Normal, template!(Word)), 100 ungated!(no_link, AssumedUsed, template!(Word)),
102 ungated!(repr, Normal, template!(List: "C")), 101 ungated!(repr, AssumedUsed, template!(List: "C")),
103 ungated!(export_name, AssumedUsed, template!(NameValueStr: "name")), 102 ungated!(export_name, AssumedUsed, template!(NameValueStr: "name")),
104 ungated!(link_section, AssumedUsed, template!(NameValueStr: "name")), 103 ungated!(link_section, AssumedUsed, template!(NameValueStr: "name")),
105 ungated!(no_mangle, AssumedUsed, template!(Word)), 104 ungated!(no_mangle, AssumedUsed, template!(Word)),
@@ -112,6 +111,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
112 const_eval_limit, CrateLevel, template!(NameValueStr: "N"), const_eval_limit, 111 const_eval_limit, CrateLevel, template!(NameValueStr: "N"), const_eval_limit,
113 experimental!(const_eval_limit) 112 experimental!(const_eval_limit)
114 ), 113 ),
114 gated!(
115 move_size_limit, CrateLevel, template!(NameValueStr: "N"), large_assignments,
116 experimental!(move_size_limit)
117 ),
115 118
116 // Entry point: 119 // Entry point:
117 ungated!(main, Normal, template!(Word)), 120 ungated!(main, Normal, template!(Word)),
@@ -140,6 +143,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
140 template!(List: "address, memory, thread"), 143 template!(List: "address, memory, thread"),
141 experimental!(no_sanitize) 144 experimental!(no_sanitize)
142 ), 145 ),
146 gated!(no_coverage, AssumedUsed, template!(Word), experimental!(no_coverage)),
143 147
144 // FIXME: #14408 assume docs are used since rustdoc looks at them. 148 // FIXME: #14408 assume docs are used since rustdoc looks at them.
145 ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")), 149 ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")),
@@ -151,11 +155,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
151 // Linking: 155 // Linking:
152 gated!(naked, AssumedUsed, template!(Word), naked_functions, experimental!(naked)), 156 gated!(naked, AssumedUsed, template!(Word), naked_functions, experimental!(naked)),
153 gated!( 157 gated!(
154 link_args, Normal, template!(NameValueStr: "args"),
155 "the `link_args` attribute is experimental and not portable across platforms, \
156 it is recommended to use `#[link(name = \"foo\")] instead",
157 ),
158 gated!(
159 link_ordinal, AssumedUsed, template!(List: "ordinal"), raw_dylib, 158 link_ordinal, AssumedUsed, template!(List: "ordinal"), raw_dylib,
160 experimental!(link_ordinal) 159 experimental!(link_ordinal)
161 ), 160 ),
@@ -172,7 +171,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
172 "custom test frameworks are an unstable feature", 171 "custom test frameworks are an unstable feature",
173 ), 172 ),
174 // RFC #1268 173 // RFC #1268
175 gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)), 174 gated!(marker, AssumedUsed, template!(Word), marker_trait_attr, experimental!(marker)),
176 gated!( 175 gated!(
177 thread_local, AssumedUsed, template!(Word), 176 thread_local, AssumedUsed, template!(Word),
178 "`#[thread_local]` is an experimental feature, and does not currently handle destructors", 177 "`#[thread_local]` is an experimental feature, and does not currently handle destructors",
@@ -291,7 +290,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
291 // Internal attributes, Macro related: 290 // Internal attributes, Macro related:
292 // ========================================================================== 291 // ==========================================================================
293 292
294 rustc_attr!(rustc_builtin_macro, AssumedUsed, template!(Word), IMPL_DETAIL), 293 rustc_attr!(rustc_builtin_macro, AssumedUsed, template!(Word, NameValueStr: "name"), IMPL_DETAIL),
295 rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE), 294 rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE),
296 rustc_attr!( 295 rustc_attr!(
297 rustc_macro_transparency, AssumedUsed, 296 rustc_macro_transparency, AssumedUsed,
@@ -319,7 +318,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
319 // ========================================================================== 318 // ==========================================================================
320 319
321 rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL), 320 rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL),
322 rustc_attr!(rustc_args_required_const, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE), 321 rustc_attr!(rustc_legacy_const_generics, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE),
323 322
324 // ========================================================================== 323 // ==========================================================================
325 // Internal attributes, Layout related: 324 // Internal attributes, Layout related:
@@ -380,6 +379,15 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
380 rustc_specialization_trait, Normal, template!(Word), 379 rustc_specialization_trait, Normal, template!(Word),
381 "the `#[rustc_specialization_trait]` attribute is used to check specializations" 380 "the `#[rustc_specialization_trait]` attribute is used to check specializations"
382 ), 381 ),
382 rustc_attr!(
383 rustc_main, Normal, template!(Word),
384 "the `#[rustc_main]` attribute is used internally to specify test entry point function",
385 ),
386 rustc_attr!(
387 rustc_skip_array_during_method_dispatch, Normal, template!(Word),
388 "the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
389 from method dispatch when the receiver is an array, for compatibility in editions < 2021."
390 ),
383 391
384 // ========================================================================== 392 // ==========================================================================
385 // Internal attributes, Testing: 393 // Internal attributes, Testing:
@@ -387,6 +395,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
387 395
388 rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)), 396 rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)),
389 rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)), 397 rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)),
398 rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word)),
390 rustc_attr!(TEST, rustc_variance, Normal, template!(Word)), 399 rustc_attr!(TEST, rustc_variance, Normal, template!(Word)),
391 rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")), 400 rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
392 rustc_attr!(TEST, rustc_regions, Normal, template!(Word)), 401 rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
@@ -395,13 +404,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
395 template!(Word, List: "delay_span_bug_from_inside_query") 404 template!(Word, List: "delay_span_bug_from_inside_query")
396 ), 405 ),
397 rustc_attr!(TEST, rustc_dump_user_substs, AssumedUsed, template!(Word)), 406 rustc_attr!(TEST, rustc_dump_user_substs, AssumedUsed, template!(Word)),
407 rustc_attr!(TEST, rustc_evaluate_where_clauses, AssumedUsed, template!(Word)),
398 rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")), 408 rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")),
399 rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")), 409 rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")),
400 rustc_attr!( 410 rustc_attr!(
401 TEST, rustc_dirty, AssumedUsed,
402 template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
403 ),
404 rustc_attr!(
405 TEST, rustc_clean, AssumedUsed, 411 TEST, rustc_clean, AssumedUsed,
406 template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), 412 template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
407 ), 413 ),
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index f2e809ca9..f22383e22 100644
--- a/crates/hir_def/src/child_by_source.rs
+++ b/crates/hir_def/src/child_by_source.rs
@@ -85,6 +85,10 @@ impl ChildBySource for ItemScope {
85 res[keys::CONST].insert(src, konst); 85 res[keys::CONST].insert(src, konst);
86 }); 86 });
87 self.impls().for_each(|imp| add_impl(db, res, imp)); 87 self.impls().for_each(|imp| add_impl(db, res, imp));
88 self.attr_macro_invocs().for_each(|(ast_id, call_id)| {
89 let item = ast_id.with_value(ast_id.to_node(db.upcast()));
90 res[keys::ATTR_MACRO].insert(item, call_id);
91 });
88 92
89 fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) { 93 fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) {
90 match item { 94 match item {
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index d2bb381be..52cb7777b 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -143,6 +143,10 @@ pub struct TraitData {
143 pub is_auto: bool, 143 pub is_auto: bool,
144 pub is_unsafe: bool, 144 pub is_unsafe: bool,
145 pub visibility: RawVisibility, 145 pub visibility: RawVisibility,
146 /// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore
147 /// method calls to this trait's methods when the receiver is an array and the crate edition is
148 /// 2015 or 2018.
149 pub skip_array_during_method_dispatch: bool,
146} 150}
147 151
148impl TraitData { 152impl TraitData {
@@ -157,6 +161,10 @@ impl TraitData {
157 let container = AssocContainerId::TraitId(tr); 161 let container = AssocContainerId::TraitId(tr);
158 let visibility = item_tree[tr_def.visibility].clone(); 162 let visibility = item_tree[tr_def.visibility].clone();
159 let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id); 163 let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id);
164 let skip_array_during_method_dispatch = item_tree
165 .attrs(db, tr_loc.container.krate(), ModItem::from(tr_loc.id.value).into())
166 .by_key("rustc_skip_array_during_method_dispatch")
167 .exists();
160 168
161 let items = collect_items( 169 let items = collect_items(
162 db, 170 db,
@@ -168,7 +176,14 @@ impl TraitData {
168 100, 176 100,
169 ); 177 );
170 178
171 Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility }) 179 Arc::new(TraitData {
180 name,
181 items,
182 is_auto,
183 is_unsafe,
184 visibility,
185 skip_array_during_method_dispatch,
186 })
172 } 187 }
173 188
174 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { 189 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs
index 7eadc8e0d..c977971cd 100644
--- a/crates/hir_def/src/db.rs
+++ b/crates/hir_def/src/db.rs
@@ -51,6 +51,9 @@ pub trait InternDatabase: SourceDatabase {
51 51
52#[salsa::query_group(DefDatabaseStorage)] 52#[salsa::query_group(DefDatabaseStorage)]
53pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { 53pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
54 #[salsa::input]
55 fn enable_proc_attr_macros(&self) -> bool;
56
54 #[salsa::invoke(ItemTree::file_item_tree_query)] 57 #[salsa::invoke(ItemTree::file_item_tree_query)]
55 fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>; 58 fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>;
56 59
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 44d22b918..6933f6e3c 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -280,7 +280,7 @@ impl GenericParams {
280 sm.type_params.insert(param_id, Either::Right(type_param.clone())); 280 sm.type_params.insert(param_id, Either::Right(type_param.clone()));
281 281
282 let type_ref = TypeRef::Path(name.into()); 282 let type_ref = TypeRef::Path(name.into());
283 self.fill_bounds(&lower_ctx, &type_param, Either::Left(type_ref)); 283 self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref));
284 } 284 }
285 for lifetime_param in params.lifetime_params() { 285 for lifetime_param in params.lifetime_params() {
286 let name = 286 let name =
@@ -289,7 +289,7 @@ impl GenericParams {
289 let param_id = self.lifetimes.alloc(param); 289 let param_id = self.lifetimes.alloc(param);
290 sm.lifetime_params.insert(param_id, lifetime_param.clone()); 290 sm.lifetime_params.insert(param_id, lifetime_param.clone());
291 let lifetime_ref = LifetimeRef::new_name(name); 291 let lifetime_ref = LifetimeRef::new_name(name);
292 self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); 292 self.fill_bounds(lower_ctx, &lifetime_param, Either::Right(lifetime_ref));
293 } 293 }
294 for const_param in params.const_params() { 294 for const_param in params.const_params() {
295 let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); 295 let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index 960cabb5f..404e3e153 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -1,6 +1,6 @@
1//! A map of all publicly exported items in a crate. 1//! A map of all publicly exported items in a crate.
2 2
3use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc}; 3use std::{fmt, hash::BuildHasherDefault, sync::Arc};
4 4
5use base_db::CrateId; 5use base_db::CrateId;
6use fst::{self, Streamer}; 6use fst::{self, Streamer};
@@ -69,81 +69,11 @@ pub struct ImportMap {
69impl ImportMap { 69impl ImportMap {
70 pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { 70 pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
71 let _p = profile::span("import_map_query"); 71 let _p = profile::span("import_map_query");
72 let def_map = db.crate_def_map(krate);
73 let mut import_map = Self::default();
74
75 // We look only into modules that are public(ly reexported), starting with the crate root.
76 let empty = ImportPath { segments: vec![] };
77 let root = def_map.module_id(def_map.root());
78 let mut worklist = vec![(root, empty)];
79 while let Some((module, mod_path)) = worklist.pop() {
80 let ext_def_map;
81 let mod_data = if module.krate == krate {
82 &def_map[module.local_id]
83 } else {
84 // The crate might reexport a module defined in another crate.
85 ext_def_map = module.def_map(db);
86 &ext_def_map[module.local_id]
87 };
88
89 let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| {
90 let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public);
91 if per_ns.is_none() {
92 None
93 } else {
94 Some((name, per_ns))
95 }
96 });
97
98 for (name, per_ns) in visible_items {
99 let mk_path = || {
100 let mut path = mod_path.clone();
101 path.segments.push(name.clone());
102 path
103 };
104
105 for item in per_ns.iter_items() {
106 let path = mk_path();
107 let path_len = path.len();
108 let import_info =
109 ImportInfo { path, container: module, is_trait_assoc_item: false };
110
111 if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
112 import_map.collect_trait_assoc_items(
113 db,
114 tr,
115 matches!(item, ItemInNs::Types(_)),
116 &import_info,
117 );
118 }
119 72
120 match import_map.map.entry(item) { 73 let mut import_map = collect_import_map(db, krate);
121 Entry::Vacant(entry) => {
122 entry.insert(import_info);
123 }
124 Entry::Occupied(mut entry) => {
125 // If the new path is shorter, prefer that one.
126 if path_len < entry.get().path.len() {
127 *entry.get_mut() = import_info;
128 } else {
129 continue;
130 }
131 }
132 }
133
134 // If we've just added a path to a module, descend into it. We might traverse
135 // modules multiple times, but only if the new path to it is shorter than the
136 // first (else we `continue` above).
137 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
138 worklist.push((mod_id, mk_path()));
139 }
140 }
141 }
142 }
143 74
144 let mut importables = import_map.map.iter().collect::<Vec<_>>(); 75 let mut importables = import_map.map.iter().collect::<Vec<_>>();
145 76 importables.sort_by_cached_key(|(_, import_info)| fst_path(&import_info.path));
146 importables.sort_by(cmp);
147 77
148 // Build the FST, taking care not to insert duplicate values. 78 // Build the FST, taking care not to insert duplicate values.
149 79
@@ -151,13 +81,13 @@ impl ImportMap {
151 let mut last_batch_start = 0; 81 let mut last_batch_start = 0;
152 82
153 for idx in 0..importables.len() { 83 for idx in 0..importables.len() {
154 if let Some(next_item) = importables.get(idx + 1) { 84 let key = fst_path(&importables[last_batch_start].1.path);
155 if cmp(&importables[last_batch_start], next_item) == Ordering::Equal { 85 if let Some((_, next_import_info)) = importables.get(idx + 1) {
86 if key == fst_path(&next_import_info.path) {
156 continue; 87 continue;
157 } 88 }
158 } 89 }
159 90
160 let key = fst_path(&importables[last_batch_start].1.path);
161 builder.insert(key, last_batch_start as u64).unwrap(); 91 builder.insert(key, last_batch_start as u64).unwrap();
162 92
163 last_batch_start = idx + 1; 93 last_batch_start = idx + 1;
@@ -185,6 +115,7 @@ impl ImportMap {
185 is_type_in_ns: bool, 115 is_type_in_ns: bool,
186 original_import_info: &ImportInfo, 116 original_import_info: &ImportInfo,
187 ) { 117 ) {
118 let _p = profile::span("collect_trait_assoc_items");
188 for (assoc_item_name, item) in &db.trait_data(tr).items { 119 for (assoc_item_name, item) in &db.trait_data(tr).items {
189 let module_def_id = match item { 120 let module_def_id = match item {
190 AssocItemId::FunctionId(f) => ModuleDefId::from(*f), 121 AssocItemId::FunctionId(f) => ModuleDefId::from(*f),
@@ -210,6 +141,84 @@ impl ImportMap {
210 } 141 }
211} 142}
212 143
144fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMap {
145 let _p = profile::span("collect_import_map");
146
147 let def_map = db.crate_def_map(krate);
148 let mut import_map = ImportMap::default();
149
150 // We look only into modules that are public(ly reexported), starting with the crate root.
151 let empty = ImportPath { segments: vec![] };
152 let root = def_map.module_id(def_map.root());
153 let mut worklist = vec![(root, empty)];
154 while let Some((module, mod_path)) = worklist.pop() {
155 let ext_def_map;
156 let mod_data = if module.krate == krate {
157 &def_map[module.local_id]
158 } else {
159 // The crate might reexport a module defined in another crate.
160 ext_def_map = module.def_map(db);
161 &ext_def_map[module.local_id]
162 };
163
164 let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| {
165 let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public);
166 if per_ns.is_none() {
167 None
168 } else {
169 Some((name, per_ns))
170 }
171 });
172
173 for (name, per_ns) in visible_items {
174 let mk_path = || {
175 let mut path = mod_path.clone();
176 path.segments.push(name.clone());
177 path
178 };
179
180 for item in per_ns.iter_items() {
181 let path = mk_path();
182 let path_len = path.len();
183 let import_info =
184 ImportInfo { path, container: module, is_trait_assoc_item: false };
185
186 if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() {
187 import_map.collect_trait_assoc_items(
188 db,
189 tr,
190 matches!(item, ItemInNs::Types(_)),
191 &import_info,
192 );
193 }
194
195 match import_map.map.entry(item) {
196 Entry::Vacant(entry) => {
197 entry.insert(import_info);
198 }
199 Entry::Occupied(mut entry) => {
200 // If the new path is shorter, prefer that one.
201 if path_len < entry.get().path.len() {
202 *entry.get_mut() = import_info;
203 } else {
204 continue;
205 }
206 }
207 }
208
209 // If we've just added a path to a module, descend into it. We might traverse
210 // modules multiple times, but only if the new path to it is shorter than the
211 // first (else we `continue` above).
212 if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
213 worklist.push((mod_id, mk_path()));
214 }
215 }
216 }
217 }
218
219 import_map
220}
221
213impl PartialEq for ImportMap { 222impl PartialEq for ImportMap {
214 fn eq(&self, other: &Self) -> bool { 223 fn eq(&self, other: &Self) -> bool {
215 // `fst` and `importables` are built from `map`, so we don't need to compare them. 224 // `fst` and `importables` are built from `map`, so we don't need to compare them.
@@ -240,17 +249,12 @@ impl fmt::Debug for ImportMap {
240} 249}
241 250
242fn fst_path(path: &ImportPath) -> String { 251fn fst_path(path: &ImportPath) -> String {
252 let _p = profile::span("fst_path");
243 let mut s = path.to_string(); 253 let mut s = path.to_string();
244 s.make_ascii_lowercase(); 254 s.make_ascii_lowercase();
245 s 255 s
246} 256}
247 257
248fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering {
249 let lhs_str = fst_path(&lhs.path);
250 let rhs_str = fst_path(&rhs.path);
251 lhs_str.cmp(&rhs_str)
252}
253
254#[derive(Debug, Eq, PartialEq, Hash)] 258#[derive(Debug, Eq, PartialEq, Hash)]
255pub enum ImportKind { 259pub enum ImportKind {
256 Module, 260 Module,
@@ -338,6 +342,7 @@ impl Query {
338 } 342 }
339 343
340 fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool { 344 fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool {
345 let _p = profile::span("import_map::Query::import_matches");
341 if import.is_trait_assoc_item { 346 if import.is_trait_assoc_item {
342 if self.exclude_import_kinds.contains(&ImportKind::AssociatedItem) { 347 if self.exclude_import_kinds.contains(&ImportKind::AssociatedItem) {
343 return false; 348 return false;
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index 9014468ea..08407ebfa 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -4,11 +4,11 @@
4use std::collections::hash_map::Entry; 4use std::collections::hash_map::Entry;
5 5
6use base_db::CrateId; 6use base_db::CrateId;
7use hir_expand::name::Name; 7use hir_expand::{name::Name, AstId, MacroCallId, MacroDefKind};
8use hir_expand::MacroDefKind;
9use once_cell::sync::Lazy; 8use once_cell::sync::Lazy;
10use rustc_hash::{FxHashMap, FxHashSet}; 9use rustc_hash::{FxHashMap, FxHashSet};
11use stdx::format_to; 10use stdx::format_to;
11use syntax::ast;
12 12
13use crate::{ 13use crate::{
14 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, ImplId, 14 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, ImplId,
@@ -53,12 +53,13 @@ pub struct ItemScope {
53 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will 53 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
54 // be all resolved to the last one defined if shadowing happens. 54 // be all resolved to the last one defined if shadowing happens.
55 legacy_macros: FxHashMap<Name, MacroDefId>, 55 legacy_macros: FxHashMap<Name, MacroDefId>,
56 attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
56} 57}
57 58
58pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { 59pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
59 BuiltinType::ALL 60 BuiltinType::ALL
60 .iter() 61 .iter()
61 .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public))) 62 .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public)))
62 .collect() 63 .collect()
63}); 64});
64 65
@@ -169,6 +170,16 @@ impl ItemScope {
169 self.legacy_macros.insert(name, mac); 170 self.legacy_macros.insert(name, mac);
170 } 171 }
171 172
173 pub(crate) fn add_attr_macro_invoc(&mut self, item: AstId<ast::Item>, call: MacroCallId) {
174 self.attr_macros.insert(item, call);
175 }
176
177 pub(crate) fn attr_macro_invocs(
178 &self,
179 ) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
180 self.attr_macros.iter().map(|(k, v)| (*k, *v))
181 }
182
172 pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> { 183 pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
173 self.unnamed_trait_imports.get(&tr).copied() 184 self.unnamed_trait_imports.get(&tr).copied()
174 } 185 }
@@ -307,6 +318,7 @@ impl ItemScope {
307 unnamed_consts, 318 unnamed_consts,
308 unnamed_trait_imports, 319 unnamed_trait_imports,
309 legacy_macros, 320 legacy_macros,
321 attr_macros,
310 } = self; 322 } = self;
311 types.shrink_to_fit(); 323 types.shrink_to_fit();
312 values.shrink_to_fit(); 324 values.shrink_to_fit();
@@ -317,6 +329,7 @@ impl ItemScope {
317 unnamed_consts.shrink_to_fit(); 329 unnamed_consts.shrink_to_fit();
318 unnamed_trait_imports.shrink_to_fit(); 330 unnamed_trait_imports.shrink_to_fit();
319 legacy_macros.shrink_to_fit(); 331 legacy_macros.shrink_to_fit();
332 attr_macros.shrink_to_fit();
320 } 333 }
321} 334}
322 335
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 6208facd5..3f90bda74 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -130,7 +130,7 @@ impl<'a> Ctx<'a> {
130 ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(), 130 ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(),
131 }; 131 };
132 132
133 self.add_attrs(item.into(), attrs.clone()); 133 self.add_attrs(item.into(), attrs);
134 134
135 Some(item) 135 Some(item)
136 } 136 }
@@ -276,10 +276,11 @@ impl<'a> Ctx<'a> {
276 let visibility = self.lower_visibility(enum_); 276 let visibility = self.lower_visibility(enum_);
277 let name = enum_.name()?.as_name(); 277 let name = enum_.name()?.as_name();
278 let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); 278 let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_);
279 let variants = match &enum_.variant_list() { 279 let variants =
280 Some(variant_list) => self.lower_variants(variant_list), 280 self.with_inherited_visibility(visibility, |this| match &enum_.variant_list() {
281 None => IdRange::new(self.next_variant_idx()..self.next_variant_idx()), 281 Some(variant_list) => this.lower_variants(variant_list),
282 }; 282 None => IdRange::new(this.next_variant_idx()..this.next_variant_idx()),
283 });
283 let ast_id = self.source_ast_id_map.ast_id(enum_); 284 let ast_id = self.source_ast_id_map.ast_id(enum_);
284 let res = Enum { name, visibility, generic_params, variants, ast_id }; 285 let res = Enum { name, visibility, generic_params, variants, ast_id };
285 Some(id(self.data().enums.alloc(res))) 286 Some(id(self.data().enums.alloc(res)))
@@ -822,7 +823,7 @@ fn is_intrinsic_fn_unsafe(name: &Name) -> bool {
822 known::type_name, 823 known::type_name,
823 known::variant_count, 824 known::variant_count,
824 ] 825 ]
825 .contains(&name) 826 .contains(name)
826} 827}
827 828
828fn lower_abi(abi: ast::Abi) -> Interned<str> { 829fn lower_abi(abi: ast::Abi) -> Interned<str> {
@@ -854,7 +855,7 @@ impl UseTreeLowering<'_> {
854 // E.g. `use something::{inner}` (prefix is `None`, path is `something`) 855 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
855 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) 856 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
856 Some(path) => { 857 Some(path) => {
857 match ModPath::from_src(self.db, path, &self.hygiene) { 858 match ModPath::from_src(self.db, path, self.hygiene) {
858 Some(it) => Some(it), 859 Some(it) => Some(it),
859 None => return None, // FIXME: report errors somewhere 860 None => return None, // FIXME: report errors somewhere
860 } 861 }
@@ -873,7 +874,7 @@ impl UseTreeLowering<'_> {
873 } else { 874 } else {
874 let is_glob = tree.star_token().is_some(); 875 let is_glob = tree.star_token().is_some();
875 let path = match tree.path() { 876 let path = match tree.path() {
876 Some(path) => Some(ModPath::from_src(self.db, path, &self.hygiene)?), 877 Some(path) => Some(ModPath::from_src(self.db, path, self.hygiene)?),
877 None => None, 878 None => None,
878 }; 879 };
879 let alias = tree.rename().map(|a| { 880 let alias = tree.rename().map(|a| {
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index cc9944a22..b1e1b70d0 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -426,7 +426,7 @@ impl<'a> Printer<'a> {
426 w!(self, " {{"); 426 w!(self, " {{");
427 self.indented(|this| { 427 self.indented(|this| {
428 for item in &**items { 428 for item in &**items {
429 this.print_mod_item((*item).into()); 429 this.print_mod_item(*item);
430 } 430 }
431 }); 431 });
432 wln!(self, "}}"); 432 wln!(self, "}}");
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index b362add5c..57686dc6e 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -359,3 +359,41 @@ trait Tr<'a, T: 'a>: Super {}
359 "#]], 359 "#]],
360 ) 360 )
361} 361}
362
363#[test]
364fn inherit_visibility() {
365 check(
366 r#"
367pub(crate) enum En {
368 Var1(u8),
369 Var2 {
370 fld: u8,
371 },
372}
373
374pub(crate) trait Tr {
375 fn f();
376 fn method(&self) {}
377}
378 "#,
379 expect![[r#"
380 pub(crate) enum En {
381 Var1(
382 pub(crate) 0: u8,
383 ),
384 Var2 {
385 pub(crate) fld: u8,
386 },
387 }
388
389 pub(crate) trait Tr<Self> {
390 pub(crate) fn f() -> ();
391
392 // flags = 0x3
393 pub(crate) fn method(
394 _: &Self,
395 ) -> ();
396 }
397 "#]],
398 )
399}
diff --git a/crates/hir_def/src/keys.rs b/crates/hir_def/src/keys.rs
index 89b3ed868..688cd9fcf 100644
--- a/crates/hir_def/src/keys.rs
+++ b/crates/hir_def/src/keys.rs
@@ -2,7 +2,7 @@
2 2
3use std::marker::PhantomData; 3use std::marker::PhantomData;
4 4
5use hir_expand::{InFile, MacroDefId}; 5use hir_expand::{InFile, MacroCallId, MacroDefId};
6use rustc_hash::FxHashMap; 6use rustc_hash::FxHashMap;
7use syntax::{ast, AstNode, AstPtr}; 7use syntax::{ast, AstNode, AstPtr};
8 8
@@ -32,6 +32,7 @@ pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new();
32pub const CONST_PARAM: Key<ast::ConstParam, ConstParamId> = Key::new(); 32pub const CONST_PARAM: Key<ast::ConstParam, ConstParamId> = Key::new();
33 33
34pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new(); 34pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new();
35pub const ATTR_MACRO: Key<ast::Item, MacroCallId> = Key::new();
35 36
36/// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are 37/// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are
37/// equal if they point to exactly the same object. 38/// equal if they point to exactly the same object.
diff --git a/crates/hir_def/src/lang_item.rs b/crates/hir_def/src/lang_item.rs
index 9e90f745c..3a45cbfa1 100644
--- a/crates/hir_def/src/lang_item.rs
+++ b/crates/hir_def/src/lang_item.rs
@@ -141,6 +141,7 @@ impl LangItems {
141 ) where 141 ) where
142 T: Into<AttrDefId> + Copy, 142 T: Into<AttrDefId> + Copy,
143 { 143 {
144 let _p = profile::span("collect_lang_item");
144 if let Some(lang_item_name) = lang_attr(db, item) { 145 if let Some(lang_item_name) = lang_attr(db, item) {
145 self.items.entry(lang_item_name).or_insert_with(|| constructor(item)); 146 self.items.entry(lang_item_name).or_insert_with(|| constructor(item));
146 } 147 }
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 9aa95720a..bb174aec8 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -55,6 +55,7 @@ use std::{
55 sync::Arc, 55 sync::Arc,
56}; 56};
57 57
58use attr::Attr;
58use base_db::{impl_intern_key, salsa, CrateId}; 59use base_db::{impl_intern_key, salsa, CrateId};
59use hir_expand::{ 60use hir_expand::{
60 ast_id_map::FileAstId, 61 ast_id_map::FileAstId,
@@ -111,6 +112,10 @@ impl ModuleId {
111 self.def_map(db).containing_module(self.local_id) 112 self.def_map(db).containing_module(self.local_id)
112 } 113 }
113 114
115 pub fn containing_block(&self) -> Option<BlockId> {
116 self.block
117 }
118
114 /// Returns `true` if this module represents a block expression. 119 /// Returns `true` if this module represents a block expression.
115 /// 120 ///
116 /// Returns `false` if this module is a submodule *inside* a block expression 121 /// Returns `false` if this module is a submodule *inside* a block expression
@@ -580,6 +585,18 @@ impl HasModule for GenericDefId {
580 } 585 }
581} 586}
582 587
588impl HasModule for TypeAliasId {
589 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
590 self.lookup(db).module(db)
591 }
592}
593
594impl HasModule for TraitId {
595 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
596 self.lookup(db).container
597 }
598}
599
583impl HasModule for StaticLoc { 600impl HasModule for StaticLoc {
584 fn module(&self, _db: &dyn db::DefDatabase) -> ModuleId { 601 fn module(&self, _db: &dyn db::DefDatabase) -> ModuleId {
585 self.container 602 self.container
@@ -730,13 +747,11 @@ fn macro_call_as_call_id(
730 ) 747 )
731 .map(MacroCallId::from) 748 .map(MacroCallId::from)
732 } else { 749 } else {
733 Ok(def 750 Ok(def.as_lazy_macro(
734 .as_lazy_macro( 751 db.upcast(),
735 db.upcast(), 752 krate,
736 krate, 753 MacroCallKind::FnLike { ast_id: call.ast_id, fragment },
737 MacroCallKind::FnLike { ast_id: call.ast_id, fragment }, 754 ))
738 )
739 .into())
740 }; 755 };
741 Ok(res) 756 Ok(res)
742} 757}
@@ -755,16 +770,51 @@ fn derive_macro_as_call_id(
755 .segments() 770 .segments()
756 .last() 771 .last()
757 .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?; 772 .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
758 let res = def 773 let res = def.as_lazy_macro(
759 .as_lazy_macro( 774 db.upcast(),
760 db.upcast(), 775 krate,
761 krate, 776 MacroCallKind::Derive {
762 MacroCallKind::Derive { 777 ast_id: item_attr.ast_id,
763 ast_id: item_attr.ast_id, 778 derive_name: last_segment.to_string(),
764 derive_name: last_segment.to_string(), 779 derive_attr_index: derive_attr.ast_index,
765 derive_attr_index: derive_attr.ast_index, 780 },
766 }, 781 );
767 ) 782 Ok(res)
768 .into(); 783}
784
785fn attr_macro_as_call_id(
786 item_attr: &AstIdWithPath<ast::Item>,
787 macro_attr: &Attr,
788 db: &dyn db::DefDatabase,
789 krate: CrateId,
790 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
791) -> Result<MacroCallId, UnresolvedMacro> {
792 let def: MacroDefId = resolver(item_attr.path.clone())
793 .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
794 let last_segment = item_attr
795 .path
796 .segments()
797 .last()
798 .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
799 let mut arg = match &macro_attr.input {
800 Some(input) => match &**input {
801 attr::AttrInput::Literal(_) => tt::Subtree::default(),
802 attr::AttrInput::TokenTree(tt) => tt.clone(),
803 },
804 None => tt::Subtree::default(),
805 };
806 // The parentheses are always disposed here.
807 arg.delimiter = None;
808
809 let res = def.as_lazy_macro(
810 db.upcast(),
811 krate,
812 MacroCallKind::Attr {
813 ast_id: item_attr.ast_id,
814 attr_name: last_segment.to_string(),
815 attr_args: arg,
816 invoc_attr_index: macro_attr.id.ast_index,
817 },
818 );
769 Ok(res) 819 Ok(res)
770} 820}
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 6b41921ae..6fab58f15 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -9,6 +9,7 @@ use base_db::{CrateId, Edition, FileId, ProcMacroId};
9use cfg::{CfgExpr, CfgOptions}; 9use cfg::{CfgExpr, CfgOptions};
10use hir_expand::{ 10use hir_expand::{
11 ast_id_map::FileAstId, 11 ast_id_map::FileAstId,
12 builtin_attr::find_builtin_attr,
12 builtin_derive::find_builtin_derive, 13 builtin_derive::find_builtin_derive,
13 builtin_macro::find_builtin_macro, 14 builtin_macro::find_builtin_macro,
14 name::{name, AsName, Name}, 15 name::{name, AsName, Name},
@@ -23,7 +24,7 @@ use syntax::ast;
23 24
24use crate::{ 25use crate::{
25 attr::{Attr, AttrId, AttrInput, Attrs}, 26 attr::{Attr, AttrId, AttrInput, Attrs},
26 builtin_attr, 27 attr_macro_as_call_id, builtin_attr,
27 db::DefDatabase, 28 db::DefDatabase,
28 derive_macro_as_call_id, 29 derive_macro_as_call_id,
29 intern::Interned, 30 intern::Interned,
@@ -223,7 +224,7 @@ struct MacroDirective {
223enum MacroDirectiveKind { 224enum MacroDirectiveKind {
224 FnLike { ast_id: AstIdWithPath<ast::MacroCall>, fragment: FragmentKind }, 225 FnLike { ast_id: AstIdWithPath<ast::MacroCall>, fragment: FragmentKind },
225 Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId }, 226 Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId },
226 Attr { ast_id: AstIdWithPath<ast::Item>, attr: AttrId, mod_item: ModItem }, 227 Attr { ast_id: AstIdWithPath<ast::Item>, attr: Attr, mod_item: ModItem },
227} 228}
228 229
229struct DefData<'a> { 230struct DefData<'a> {
@@ -419,7 +420,7 @@ impl DefCollector<'_> {
419 let mut unresolved_macros = std::mem::replace(&mut self.unresolved_macros, Vec::new()); 420 let mut unresolved_macros = std::mem::replace(&mut self.unresolved_macros, Vec::new());
420 let pos = unresolved_macros.iter().position(|directive| { 421 let pos = unresolved_macros.iter().position(|directive| {
421 if let MacroDirectiveKind::Attr { ast_id, mod_item, attr } = &directive.kind { 422 if let MacroDirectiveKind::Attr { ast_id, mod_item, attr } = &directive.kind {
422 self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), *attr); 423 self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), attr.id);
423 424
424 let file_id = ast_id.ast_id.file_id; 425 let file_id = ast_id.ast_id.file_id;
425 let item_tree = self.db.file_item_tree(file_id); 426 let item_tree = self.db.file_item_tree(file_id);
@@ -499,7 +500,7 @@ impl DefCollector<'_> {
499 let (per_ns, _) = self.def_map.resolve_path( 500 let (per_ns, _) = self.def_map.resolve_path(
500 self.db, 501 self.db,
501 self.def_map.root, 502 self.def_map.root,
502 &path, 503 path,
503 BuiltinShadowMode::Other, 504 BuiltinShadowMode::Other,
504 ); 505 );
505 506
@@ -721,7 +722,7 @@ impl DefCollector<'_> {
721 if import.is_extern_crate { 722 if import.is_extern_crate {
722 let res = self.def_map.resolve_name_in_extern_prelude( 723 let res = self.def_map.resolve_name_in_extern_prelude(
723 self.db, 724 self.db,
724 &import 725 import
725 .path 726 .path
726 .as_ident() 727 .as_ident()
727 .expect("extern crate should have been desugared to one-element path"), 728 .expect("extern crate should have been desugared to one-element path"),
@@ -1050,7 +1051,7 @@ impl DefCollector<'_> {
1050 let file_id = ast_id.ast_id.file_id; 1051 let file_id = ast_id.ast_id.file_id;
1051 let item_tree = self.db.file_item_tree(file_id); 1052 let item_tree = self.db.file_item_tree(file_id);
1052 let mod_dir = self.mod_dirs[&directive.module_id].clone(); 1053 let mod_dir = self.mod_dirs[&directive.module_id].clone();
1053 self.skip_attrs.insert(InFile::new(file_id, *mod_item), *attr); 1054 self.skip_attrs.insert(InFile::new(file_id, *mod_item), attr.id);
1054 ModCollector { 1055 ModCollector {
1055 def_collector: &mut *self, 1056 def_collector: &mut *self,
1056 macro_depth: directive.depth, 1057 macro_depth: directive.depth,
@@ -1062,13 +1063,67 @@ impl DefCollector<'_> {
1062 .collect(&[*mod_item]); 1063 .collect(&[*mod_item]);
1063 1064
1064 // Remove the original directive since we resolved it. 1065 // Remove the original directive since we resolved it.
1066 res = ReachedFixedPoint::No;
1065 return false; 1067 return false;
1066 } 1068 }
1067 } 1069 }
1068 } 1070 }
1069 1071
1072 if !self.db.enable_proc_attr_macros() {
1073 return true;
1074 }
1075
1070 // Not resolved to a derive helper, so try to resolve as a macro. 1076 // Not resolved to a derive helper, so try to resolve as a macro.
1071 // FIXME: not yet :) 1077 match attr_macro_as_call_id(
1078 ast_id,
1079 attr,
1080 self.db,
1081 self.def_map.krate,
1082 &resolver,
1083 ) {
1084 Ok(call_id) => {
1085 let loc: MacroCallLoc = self.db.lookup_intern_macro(call_id);
1086 if let MacroDefKind::ProcMacro(exp, ..) = &loc.def.kind {
1087 if exp.is_dummy() {
1088 // Proc macros that cannot be expanded are treated as not
1089 // resolved, in order to fall back later.
1090 self.def_map.diagnostics.push(
1091 DefDiagnostic::unresolved_proc_macro(
1092 directive.module_id,
1093 loc.kind,
1094 ),
1095 );
1096
1097 let file_id = ast_id.ast_id.file_id;
1098 let item_tree = self.db.file_item_tree(file_id);
1099 let mod_dir = self.mod_dirs[&directive.module_id].clone();
1100 self.skip_attrs
1101 .insert(InFile::new(file_id, *mod_item), attr.id);
1102 ModCollector {
1103 def_collector: &mut *self,
1104 macro_depth: directive.depth,
1105 module_id: directive.module_id,
1106 file_id,
1107 item_tree: &item_tree,
1108 mod_dir,
1109 }
1110 .collect(&[*mod_item]);
1111
1112 // Remove the macro directive.
1113 return false;
1114 }
1115 }
1116
1117 self.def_map.modules[directive.module_id]
1118 .scope
1119 .add_attr_macro_invoc(ast_id.ast_id, call_id);
1120
1121 resolved.push((directive.module_id, call_id, directive.depth));
1122 res = ReachedFixedPoint::No;
1123 return false;
1124 }
1125 Err(UnresolvedMacro { .. }) => (),
1126 }
1072 } 1127 }
1073 } 1128 }
1074 1129
@@ -1296,7 +1351,7 @@ impl ModCollector<'_, '_> {
1296 let imports = Import::from_use( 1351 let imports = Import::from_use(
1297 self.def_collector.db, 1352 self.def_collector.db,
1298 krate, 1353 krate,
1299 &self.item_tree, 1354 self.item_tree,
1300 ItemTreeId::new(self.file_id, import_id), 1355 ItemTreeId::new(self.file_id, import_id),
1301 ); 1356 );
1302 self.def_collector.unresolved_imports.extend(imports.into_iter().map( 1357 self.def_collector.unresolved_imports.extend(imports.into_iter().map(
@@ -1313,7 +1368,7 @@ impl ModCollector<'_, '_> {
1313 import: Import::from_extern_crate( 1368 import: Import::from_extern_crate(
1314 self.def_collector.db, 1369 self.def_collector.db,
1315 krate, 1370 krate,
1316 &self.item_tree, 1371 self.item_tree,
1317 ItemTreeId::new(self.file_id, import_id), 1372 ItemTreeId::new(self.file_id, import_id),
1318 ), 1373 ),
1319 status: PartialResolvedImport::Unresolved, 1374 status: PartialResolvedImport::Unresolved,
@@ -1628,7 +1683,7 @@ impl ModCollector<'_, '_> {
1628 self.def_collector.unresolved_macros.push(MacroDirective { 1683 self.def_collector.unresolved_macros.push(MacroDirective {
1629 module_id: self.module_id, 1684 module_id: self.module_id,
1630 depth: self.macro_depth + 1, 1685 depth: self.macro_depth + 1,
1631 kind: MacroDirectiveKind::Attr { ast_id, attr: attr.id, mod_item }, 1686 kind: MacroDirectiveKind::Attr { ast_id, attr: attr.clone(), mod_item },
1632 }); 1687 });
1633 1688
1634 return Err(()); 1689 return Err(());
@@ -1782,7 +1837,8 @@ impl ModCollector<'_, '_> {
1782 let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); 1837 let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
1783 if attrs.by_key("rustc_builtin_macro").exists() { 1838 if attrs.by_key("rustc_builtin_macro").exists() {
1784 let macro_id = find_builtin_macro(&mac.name, krate, ast_id) 1839 let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
1785 .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); 1840 .or_else(|| find_builtin_derive(&mac.name, krate, ast_id))
1841 .or_else(|| find_builtin_attr(&mac.name, krate, ast_id));
1786 1842
1787 match macro_id { 1843 match macro_id {
1788 Some(macro_id) => { 1844 Some(macro_id) => {
@@ -1833,7 +1889,7 @@ impl ModCollector<'_, '_> {
1833 self.def_collector.def_map.with_ancestor_maps( 1889 self.def_collector.def_map.with_ancestor_maps(
1834 self.def_collector.db, 1890 self.def_collector.db,
1835 self.module_id, 1891 self.module_id,
1836 &mut |map, module| map[module].scope.get_legacy_macro(&name), 1892 &mut |map, module| map[module].scope.get_legacy_macro(name),
1837 ) 1893 )
1838 }) 1894 })
1839 }, 1895 },
@@ -1937,7 +1993,7 @@ mod tests {
1937 } 1993 }
1938 1994
1939 fn do_resolve(code: &str) -> DefMap { 1995 fn do_resolve(code: &str) -> DefMap {
1940 let (db, _file_id) = TestDB::with_single_file(&code); 1996 let (db, _file_id) = TestDB::with_single_file(code);
1941 let krate = db.test_crate(); 1997 let krate = db.test_crate();
1942 1998
1943 let edition = db.crate_graph()[krate].edition; 1999 let edition = db.crate_graph()[krate].edition;
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index c984148c3..629bc7952 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -93,7 +93,7 @@ impl DefMap {
93 let mut vis = match visibility { 93 let mut vis = match visibility {
94 RawVisibility::Module(path) => { 94 RawVisibility::Module(path) => {
95 let (result, remaining) = 95 let (result, remaining) =
96 self.resolve_path(db, original_module, &path, BuiltinShadowMode::Module); 96 self.resolve_path(db, original_module, path, BuiltinShadowMode::Module);
97 if remaining.is_some() { 97 if remaining.is_some() {
98 return None; 98 return None;
99 } 99 }
@@ -205,7 +205,7 @@ impl DefMap {
205 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 205 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
206 }; 206 };
207 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 207 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
208 self.resolve_name_in_crate_root_or_extern_prelude(db, &segment) 208 self.resolve_name_in_crate_root_or_extern_prelude(db, segment)
209 } 209 }
210 PathKind::Plain => { 210 PathKind::Plain => {
211 let (_, segment) = match segments.next() { 211 let (_, segment) = match segments.next() {
@@ -222,7 +222,7 @@ impl DefMap {
222 if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module }; 222 if path.segments().len() == 1 { shadow } else { BuiltinShadowMode::Module };
223 223
224 log::debug!("resolving {:?} in module", segment); 224 log::debug!("resolving {:?} in module", segment);
225 self.resolve_name_in_module(db, original_module, &segment, prefer_module) 225 self.resolve_name_in_module(db, original_module, segment, prefer_module)
226 } 226 }
227 PathKind::Super(lvl) => { 227 PathKind::Super(lvl) => {
228 let mut module = original_module; 228 let mut module = original_module;
@@ -269,7 +269,7 @@ impl DefMap {
269 Some((_, segment)) => segment, 269 Some((_, segment)) => segment,
270 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 270 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
271 }; 271 };
272 if let Some(def) = self.extern_prelude.get(&segment) { 272 if let Some(def) = self.extern_prelude.get(segment) {
273 log::debug!("absolute path {:?} resolved to crate {:?}", path, def); 273 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
274 PerNs::types(*def, Visibility::Public) 274 PerNs::types(*def, Visibility::Public)
275 } else { 275 } else {
@@ -319,13 +319,13 @@ impl DefMap {
319 }; 319 };
320 320
321 // Since it is a qualified path here, it should not contains legacy macros 321 // Since it is a qualified path here, it should not contains legacy macros
322 module_data.scope.get(&segment) 322 module_data.scope.get(segment)
323 } 323 }
324 ModuleDefId::AdtId(AdtId::EnumId(e)) => { 324 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
325 // enum variant 325 // enum variant
326 cov_mark::hit!(can_import_enum_variant); 326 cov_mark::hit!(can_import_enum_variant);
327 let enum_data = db.enum_data(e); 327 let enum_data = db.enum_data(e);
328 match enum_data.variant(&segment) { 328 match enum_data.variant(segment) {
329 Some(local_id) => { 329 Some(local_id) => {
330 let variant = EnumVariantId { parent: e, local_id }; 330 let variant = EnumVariantId { parent: e, local_id };
331 match &*enum_data.variants[local_id].variant_data { 331 match &*enum_data.variants[local_id].variant_data {
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index 58c01354a..cf43f2a96 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -2,7 +2,6 @@ mod globs;
2mod incremental; 2mod incremental;
3mod macros; 3mod macros;
4mod mod_resolution; 4mod mod_resolution;
5mod diagnostics;
6mod primitives; 5mod primitives;
7 6
8use std::sync::Arc; 7use std::sync::Arc;
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
deleted file mode 100644
index ec6670952..000000000
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ /dev/null
@@ -1,229 +0,0 @@
1use base_db::fixture::WithFixture;
2
3use crate::test_db::TestDB;
4
5fn check_diagnostics(ra_fixture: &str) {
6 let db: TestDB = TestDB::with_files(ra_fixture);
7 db.check_diagnostics();
8}
9
10fn check_no_diagnostics(ra_fixture: &str) {
11 let db: TestDB = TestDB::with_files(ra_fixture);
12 db.check_no_diagnostics();
13}
14
15#[test]
16fn unresolved_import() {
17 check_diagnostics(
18 r"
19 use does_exist;
20 use does_not_exist;
21 //^^^^^^^^^^^^^^^^^^^ UnresolvedImport
22
23 mod does_exist {}
24 ",
25 );
26}
27
28#[test]
29fn unresolved_extern_crate() {
30 check_diagnostics(
31 r"
32 //- /main.rs crate:main deps:core
33 extern crate core;
34 extern crate doesnotexist;
35 //^^^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedExternCrate
36 //- /lib.rs crate:core
37 ",
38 );
39}
40
41#[test]
42fn extern_crate_self_as() {
43 cov_mark::check!(extern_crate_self_as);
44 check_diagnostics(
45 r"
46 //- /lib.rs
47 extern crate doesnotexist;
48 //^^^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedExternCrate
49 // Should not error.
50 extern crate self as foo;
51 struct Foo;
52 use foo::Foo as Bar;
53 ",
54 );
55}
56
57#[test]
58fn dedup_unresolved_import_from_unresolved_crate() {
59 check_diagnostics(
60 r"
61 //- /main.rs crate:main
62 mod a {
63 extern crate doesnotexist;
64 //^^^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedExternCrate
65
66 // Should not error, since we already errored for the missing crate.
67 use doesnotexist::{self, bla, *};
68
69 use crate::doesnotexist;
70 //^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedImport
71 }
72
73 mod m {
74 use super::doesnotexist;
75 //^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedImport
76 }
77 ",
78 );
79}
80
81#[test]
82fn unresolved_module() {
83 check_diagnostics(
84 r"
85 //- /lib.rs
86 mod foo;
87 mod bar;
88 //^^^^^^^^ UnresolvedModule
89 mod baz {}
90 //- /foo.rs
91 ",
92 );
93}
94
95#[test]
96fn inactive_item() {
97 // Additional tests in `cfg` crate. This only tests disabled cfgs.
98
99 check_diagnostics(
100 r#"
101 //- /lib.rs
102 #[cfg(no)] pub fn f() {}
103 //^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
104
105 #[cfg(no)] #[cfg(no2)] mod m;
106 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
107
108 #[cfg(all(not(a), b))] enum E {}
109 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
110
111 #[cfg(feature = "std")] use std;
112 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
113 "#,
114 );
115}
116
117/// Tests that `cfg` attributes behind `cfg_attr` is handled properly.
118#[test]
119fn inactive_via_cfg_attr() {
120 cov_mark::check!(cfg_attr_active);
121 check_diagnostics(
122 r#"
123 //- /lib.rs
124 #[cfg_attr(not(never), cfg(no))] fn f() {}
125 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
126
127 #[cfg_attr(not(never), cfg(not(no)))] fn f() {}
128
129 #[cfg_attr(never, cfg(no))] fn g() {}
130
131 #[cfg_attr(not(never), inline, cfg(no))] fn h() {}
132 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
133 "#,
134 );
135}
136
137#[test]
138fn unresolved_legacy_scope_macro() {
139 check_diagnostics(
140 r#"
141 //- /lib.rs
142 macro_rules! m { () => {} }
143
144 m!();
145 m2!();
146 //^^^^^^ UnresolvedMacroCall
147 "#,
148 );
149}
150
151#[test]
152fn unresolved_module_scope_macro() {
153 check_diagnostics(
154 r#"
155 //- /lib.rs
156 mod mac {
157 #[macro_export]
158 macro_rules! m { () => {} }
159 }
160
161 self::m!();
162 self::m2!();
163 //^^^^^^^^^^^^ UnresolvedMacroCall
164 "#,
165 );
166}
167
168#[test]
169fn builtin_macro_fails_expansion() {
170 check_diagnostics(
171 r#"
172 //- /lib.rs
173 #[rustc_builtin_macro]
174 macro_rules! include { () => {} }
175
176 include!("doesntexist");
177 //^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist`
178 "#,
179 );
180}
181
182#[test]
183fn include_macro_should_allow_empty_content() {
184 check_no_diagnostics(
185 r#"
186 //- /lib.rs
187 #[rustc_builtin_macro]
188 macro_rules! include { () => {} }
189
190 include!("bar.rs");
191 //- /bar.rs
192 // empty
193 "#,
194 );
195}
196
197#[test]
198fn good_out_dir_diagnostic() {
199 check_diagnostics(
200 r#"
201 #[rustc_builtin_macro]
202 macro_rules! include { () => {} }
203 #[rustc_builtin_macro]
204 macro_rules! env { () => {} }
205 #[rustc_builtin_macro]
206 macro_rules! concat { () => {} }
207
208 include!(concat!(env!("OUT_DIR"), "/out.rs"));
209 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
210 "#,
211 );
212}
213
214#[test]
215fn register_attr_and_tool() {
216 cov_mark::check!(register_attr);
217 cov_mark::check!(register_tool);
218 check_no_diagnostics(
219 r#"
220#![register_tool(tool)]
221#![register_attr(attr)]
222
223#[tool::path]
224#[attr]
225struct S;
226 "#,
227 );
228 // NB: we don't currently emit diagnostics here
229}
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index f6220aa92..27345d07c 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -208,13 +208,13 @@ fn lower_generic_args_from_fn_path(
208 let params = params?; 208 let params = params?;
209 let mut param_types = Vec::new(); 209 let mut param_types = Vec::new();
210 for param in params.params() { 210 for param in params.params() {
211 let type_ref = TypeRef::from_ast_opt(&ctx, param.ty()); 211 let type_ref = TypeRef::from_ast_opt(ctx, param.ty());
212 param_types.push(type_ref); 212 param_types.push(type_ref);
213 } 213 }
214 let arg = GenericArg::Type(TypeRef::Tuple(param_types)); 214 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
215 args.push(arg); 215 args.push(arg);
216 if let Some(ret_type) = ret_type { 216 if let Some(ret_type) = ret_type {
217 let type_ref = TypeRef::from_ast_opt(&ctx, ret_type.ty()); 217 let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty());
218 bindings.push(AssociatedTypeBinding { 218 bindings.push(AssociatedTypeBinding {
219 name: name![Output], 219 name: name![Output],
220 type_ref: Some(type_ref), 220 type_ref: Some(type_ref),
diff --git a/crates/hir_def/src/per_ns.rs b/crates/hir_def/src/per_ns.rs
index a594afce6..a9f13cb82 100644
--- a/crates/hir_def/src/per_ns.rs
+++ b/crates/hir_def/src/per_ns.rs
@@ -62,6 +62,7 @@ impl PerNs {
62 } 62 }
63 63
64 pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs { 64 pub fn filter_visibility(self, mut f: impl FnMut(Visibility) -> bool) -> PerNs {
65 let _p = profile::span("PerNs::filter_visibility");
65 PerNs { 66 PerNs {
66 types: self.types.filter(|(_, v)| f(*v)), 67 types: self.types.filter(|(_, v)| f(*v)),
67 values: self.values.filter(|(_, v)| f(*v)), 68 values: self.values.filter(|(_, v)| f(*v)),
@@ -86,6 +87,7 @@ impl PerNs {
86 } 87 }
87 88
88 pub fn iter_items(self) -> impl Iterator<Item = ItemInNs> { 89 pub fn iter_items(self) -> impl Iterator<Item = ItemInNs> {
90 let _p = profile::span("PerNs::iter_items");
89 self.types 91 self.types
90 .map(|it| ItemInNs::Types(it.0)) 92 .map(|it| ItemInNs::Types(it.0))
91 .into_iter() 93 .into_iter()
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index fb8a6f260..d4681fa3e 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -133,7 +133,7 @@ impl Resolver {
133 Some(it) => it, 133 Some(it) => it,
134 None => return PerNs::none(), 134 None => return PerNs::none(),
135 }; 135 };
136 let (module_res, segment_index) = item_map.resolve_path(db, module, &path, shadow); 136 let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
137 if segment_index.is_some() { 137 if segment_index.is_some() {
138 return PerNs::none(); 138 return PerNs::none();
139 } 139 }
@@ -150,7 +150,7 @@ impl Resolver {
150 path: &ModPath, 150 path: &ModPath,
151 ) -> Option<TraitId> { 151 ) -> Option<TraitId> {
152 let (item_map, module) = self.module_scope()?; 152 let (item_map, module) = self.module_scope()?;
153 let (module_res, ..) = item_map.resolve_path(db, module, &path, BuiltinShadowMode::Module); 153 let (module_res, ..) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module);
154 match module_res.take_types()? { 154 match module_res.take_types()? {
155 ModuleDefId::TraitId(it) => Some(it), 155 ModuleDefId::TraitId(it) => Some(it),
156 _ => None, 156 _ => None,
@@ -325,7 +325,7 @@ impl Resolver {
325 path: &ModPath, 325 path: &ModPath,
326 ) -> Option<MacroDefId> { 326 ) -> Option<MacroDefId> {
327 let (item_map, module) = self.module_scope()?; 327 let (item_map, module) = self.module_scope()?;
328 item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros() 328 item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
329 } 329 }
330 330
331 pub fn process_all_names(&self, db: &dyn DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) { 331 pub fn process_all_names(&self, db: &dyn DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) {
@@ -561,7 +561,7 @@ impl ModuleItemMap {
561 path: &ModPath, 561 path: &ModPath,
562 ) -> Option<ResolveValueResult> { 562 ) -> Option<ResolveValueResult> {
563 let (module_def, idx) = 563 let (module_def, idx) =
564 self.def_map.resolve_path_locally(db, self.module_id, &path, BuiltinShadowMode::Other); 564 self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
565 match idx { 565 match idx {
566 None => { 566 None => {
567 let value = to_value_ns(module_def)?; 567 let value = to_value_ns(module_def)?;
@@ -591,7 +591,7 @@ impl ModuleItemMap {
591 path: &ModPath, 591 path: &ModPath,
592 ) -> Option<(TypeNs, Option<usize>)> { 592 ) -> Option<(TypeNs, Option<usize>)> {
593 let (module_def, idx) = 593 let (module_def, idx) =
594 self.def_map.resolve_path_locally(db, self.module_id, &path, BuiltinShadowMode::Other); 594 self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other);
595 let res = to_type_ns(module_def)?; 595 let res = to_type_ns(module_def)?;
596 Some((res, idx)) 596 Some((res, idx))
597 } 597 }
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs
index e840fe5e8..2635b556e 100644
--- a/crates/hir_def/src/test_db.rs
+++ b/crates/hir_def/src/test_db.rs
@@ -6,19 +6,16 @@ use std::{
6}; 6};
7 7
8use base_db::{ 8use base_db::{
9 salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition, FileRange, Upcast, 9 salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition,
10 SourceDatabase, Upcast,
10}; 11};
11use base_db::{AnchoredPath, SourceDatabase};
12use hir_expand::{db::AstDatabase, InFile}; 12use hir_expand::{db::AstDatabase, InFile};
13use rustc_hash::FxHashMap;
14use rustc_hash::FxHashSet; 13use rustc_hash::FxHashSet;
15use syntax::{algo, ast, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize}; 14use syntax::{algo, ast, AstNode};
16use test_utils::extract_annotations;
17 15
18use crate::{ 16use crate::{
19 body::BodyDiagnostic,
20 db::DefDatabase, 17 db::DefDatabase,
21 nameres::{diagnostics::DefDiagnosticKind, DefMap, ModuleSource}, 18 nameres::{DefMap, ModuleSource},
22 src::HasSource, 19 src::HasSource,
23 LocalModuleId, Lookup, ModuleDefId, ModuleId, 20 LocalModuleId, Lookup, ModuleDefId, ModuleId,
24}; 21};
@@ -30,12 +27,19 @@ use crate::{
30 crate::db::InternDatabaseStorage, 27 crate::db::InternDatabaseStorage,
31 crate::db::DefDatabaseStorage 28 crate::db::DefDatabaseStorage
32)] 29)]
33#[derive(Default)]
34pub(crate) struct TestDB { 30pub(crate) struct TestDB {
35 storage: salsa::Storage<TestDB>, 31 storage: salsa::Storage<TestDB>,
36 events: Mutex<Option<Vec<salsa::Event>>>, 32 events: Mutex<Option<Vec<salsa::Event>>>,
37} 33}
38 34
35impl Default for TestDB {
36 fn default() -> Self {
37 let mut this = Self { storage: Default::default(), events: Default::default() };
38 this.set_enable_proc_attr_macros(true);
39 this
40 }
41}
42
39impl Upcast<dyn AstDatabase> for TestDB { 43impl Upcast<dyn AstDatabase> for TestDB {
40 fn upcast(&self) -> &(dyn AstDatabase + 'static) { 44 fn upcast(&self) -> &(dyn AstDatabase + 'static) {
41 &*self 45 &*self
@@ -238,145 +242,4 @@ impl TestDB {
238 }) 242 })
239 .collect() 243 .collect()
240 } 244 }
241
242 pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
243 let mut files = Vec::new();
244 let crate_graph = self.crate_graph();
245 for krate in crate_graph.iter() {
246 let crate_def_map = self.crate_def_map(krate);
247 for (module_id, _) in crate_def_map.modules() {
248 let file_id = crate_def_map[module_id].origin.file_id();
249 files.extend(file_id)
250 }
251 }
252 assert!(!files.is_empty());
253 files
254 .into_iter()
255 .filter_map(|file_id| {
256 let text = self.file_text(file_id);
257 let annotations = extract_annotations(&text);
258 if annotations.is_empty() {
259 return None;
260 }
261 Some((file_id, annotations))
262 })
263 .collect()
264 }
265
266 pub(crate) fn diagnostics(&self, cb: &mut dyn FnMut(FileRange, String)) {
267 let crate_graph = self.crate_graph();
268 for krate in crate_graph.iter() {
269 let crate_def_map = self.crate_def_map(krate);
270
271 for diag in crate_def_map.diagnostics() {
272 let (node, message): (InFile<SyntaxNode>, &str) = match &diag.kind {
273 DefDiagnosticKind::UnresolvedModule { ast, .. } => {
274 let node = ast.to_node(self.upcast());
275 (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedModule")
276 }
277 DefDiagnosticKind::UnresolvedExternCrate { ast, .. } => {
278 let node = ast.to_node(self.upcast());
279 (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedExternCrate")
280 }
281 DefDiagnosticKind::UnresolvedImport { id, .. } => {
282 let item_tree = id.item_tree(self.upcast());
283 let import = &item_tree[id.value];
284 let node = InFile::new(id.file_id(), import.ast_id).to_node(self.upcast());
285 (InFile::new(id.file_id(), node.syntax().clone()), "UnresolvedImport")
286 }
287 DefDiagnosticKind::UnconfiguredCode { ast, .. } => {
288 let node = ast.to_node(self.upcast());
289 (InFile::new(ast.file_id, node.syntax().clone()), "UnconfiguredCode")
290 }
291 DefDiagnosticKind::UnresolvedProcMacro { ast, .. } => {
292 (ast.to_node(self.upcast()), "UnresolvedProcMacro")
293 }
294 DefDiagnosticKind::UnresolvedMacroCall { ast, .. } => {
295 let node = ast.to_node(self.upcast());
296 (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedMacroCall")
297 }
298 DefDiagnosticKind::MacroError { ast, message } => {
299 (ast.to_node(self.upcast()), message.as_str())
300 }
301 DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
302 let node = ast.to_node(self.upcast());
303 (
304 InFile::new(ast.file_id, node.syntax().clone()),
305 "UnimplementedBuiltinMacro",
306 )
307 }
308 };
309
310 let frange = node.as_ref().original_file_range(self);
311 cb(frange, message.to_string())
312 }
313
314 for (_module_id, module) in crate_def_map.modules() {
315 for decl in module.scope.declarations() {
316 if let ModuleDefId::FunctionId(it) = decl {
317 let source_map = self.body_with_source_map(it.into()).1;
318 for diag in source_map.diagnostics() {
319 let (ptr, message): (InFile<SyntaxNodePtr>, &str) = match diag {
320 BodyDiagnostic::InactiveCode { node, .. } => {
321 (node.clone().map(|it| it.into()), "InactiveCode")
322 }
323 BodyDiagnostic::MacroError { node, message } => {
324 (node.clone().map(|it| it.into()), message.as_str())
325 }
326 BodyDiagnostic::UnresolvedProcMacro { node } => {
327 (node.clone().map(|it| it.into()), "UnresolvedProcMacro")
328 }
329 BodyDiagnostic::UnresolvedMacroCall { node, .. } => {
330 (node.clone().map(|it| it.into()), "UnresolvedMacroCall")
331 }
332 };
333
334 let root = self.parse_or_expand(ptr.file_id).unwrap();
335 let node = ptr.map(|ptr| ptr.to_node(&root));
336 let frange = node.as_ref().original_file_range(self);
337 cb(frange, message.to_string())
338 }
339 }
340 }
341 }
342 }
343 }
344
345 pub(crate) fn check_diagnostics(&self) {
346 let db: &TestDB = self;
347 let annotations = db.extract_annotations();
348 assert!(!annotations.is_empty());
349
350 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
351 db.diagnostics(&mut |frange, message| {
352 actual.entry(frange.file_id).or_default().push((frange.range, message));
353 });
354
355 for (file_id, diags) in actual.iter_mut() {
356 diags.sort_by_key(|it| it.0.start());
357 let text = db.file_text(*file_id);
358 // For multiline spans, place them on line start
359 for (range, content) in diags {
360 if text[*range].contains('\n') {
361 *range = TextRange::new(range.start(), range.start() + TextSize::from(1));
362 *content = format!("... {}", content);
363 }
364 }
365 }
366
367 assert_eq!(annotations, actual);
368 }
369
370 pub(crate) fn check_no_diagnostics(&self) {
371 let db: &TestDB = self;
372 let annotations = db.extract_annotations();
373 assert!(annotations.is_empty());
374
375 let mut has_diagnostics = false;
376 db.diagnostics(&mut |_, _| {
377 has_diagnostics = true;
378 });
379
380 assert!(!has_diagnostics);
381 }
382} 245}
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs
index cbde6b940..ffe499973 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -128,7 +128,7 @@ impl TypeRef {
128 /// Converts an `ast::TypeRef` to a `hir::TypeRef`. 128 /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
129 pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self { 129 pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
130 match node { 130 match node {
131 ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()), 131 ast::Type::ParenType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
132 ast::Type::TupleType(inner) => { 132 ast::Type::TupleType(inner) => {
133 TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect()) 133 TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect())
134 } 134 }
@@ -142,7 +142,7 @@ impl TypeRef {
142 .unwrap_or(TypeRef::Error) 142 .unwrap_or(TypeRef::Error)
143 } 143 }
144 ast::Type::PtrType(inner) => { 144 ast::Type::PtrType(inner) => {
145 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty()); 145 let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
146 let mutability = Mutability::from_mutable(inner.mut_token().is_some()); 146 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
147 TypeRef::RawPtr(Box::new(inner_ty), mutability) 147 TypeRef::RawPtr(Box::new(inner_ty), mutability)
148 } 148 }
@@ -156,13 +156,13 @@ impl TypeRef {
156 .map(ConstScalar::usize_from_literal_expr) 156 .map(ConstScalar::usize_from_literal_expr)
157 .unwrap_or(ConstScalar::Unknown); 157 .unwrap_or(ConstScalar::Unknown);
158 158
159 TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())), len) 159 TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len)
160 } 160 }
161 ast::Type::SliceType(inner) => { 161 ast::Type::SliceType(inner) => {
162 TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty()))) 162 TypeRef::Slice(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())))
163 } 163 }
164 ast::Type::RefType(inner) => { 164 ast::Type::RefType(inner) => {
165 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty()); 165 let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
166 let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(&lt)); 166 let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(&lt));
167 let mutability = Mutability::from_mutable(inner.mut_token().is_some()); 167 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
168 TypeRef::Reference(Box::new(inner_ty), lifetime, mutability) 168 TypeRef::Reference(Box::new(inner_ty), lifetime, mutability)
@@ -180,7 +180,7 @@ impl TypeRef {
180 is_varargs = param.dotdotdot_token().is_some(); 180 is_varargs = param.dotdotdot_token().is_some();
181 } 181 }
182 182
183 pl.params().map(|p| p.ty()).map(|it| TypeRef::from_ast_opt(&ctx, it)).collect() 183 pl.params().map(|p| p.ty()).map(|it| TypeRef::from_ast_opt(ctx, it)).collect()
184 } else { 184 } else {
185 Vec::new() 185 Vec::new()
186 }; 186 };
@@ -188,7 +188,7 @@ impl TypeRef {
188 TypeRef::Fn(params, is_varargs) 188 TypeRef::Fn(params, is_varargs)
189 } 189 }
190 // for types are close enough for our purposes to the inner type for now... 190 // for types are close enough for our purposes to the inner type for now...
191 ast::Type::ForType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()), 191 ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
192 ast::Type::ImplTraitType(inner) => { 192 ast::Type::ImplTraitType(inner) => {
193 TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) 193 TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
194 } 194 }
@@ -229,7 +229,7 @@ impl TypeRef {
229 TypeRef::RawPtr(type_ref, _) 229 TypeRef::RawPtr(type_ref, _)
230 | TypeRef::Reference(type_ref, ..) 230 | TypeRef::Reference(type_ref, ..)
231 | TypeRef::Array(type_ref, _) 231 | TypeRef::Array(type_ref, _)
232 | TypeRef::Slice(type_ref) => go(&type_ref, f), 232 | TypeRef::Slice(type_ref) => go(type_ref, f),
233 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { 233 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
234 for bound in bounds { 234 for bound in bounds {
235 match bound.as_ref() { 235 match bound.as_ref() {