diff options
259 files changed, 6376 insertions, 6100 deletions
diff --git a/Cargo.lock b/Cargo.lock index 505263c64..e47b87964 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -245,9 +245,9 @@ dependencies = [ | |||
245 | 245 | ||
246 | [[package]] | 246 | [[package]] |
247 | name = "cov-mark" | 247 | name = "cov-mark" |
248 | version = "1.1.0" | 248 | version = "2.0.0-pre.1" |
249 | source = "registry+https://github.com/rust-lang/crates.io-index" | 249 | source = "registry+https://github.com/rust-lang/crates.io-index" |
250 | checksum = "9ffa3d3e0138386cd4361f63537765cac7ee40698028844635a54495a92f67f3" | 250 | checksum = "0d48d8f76bd9331f19fe2aaf3821a9f9fb32c3963e1e3d6ce82a8c09cef7444a" |
251 | 251 | ||
252 | [[package]] | 252 | [[package]] |
253 | name = "crc32fast" | 253 | name = "crc32fast" |
@@ -482,6 +482,7 @@ dependencies = [ | |||
482 | "hir_ty", | 482 | "hir_ty", |
483 | "itertools", | 483 | "itertools", |
484 | "log", | 484 | "log", |
485 | "once_cell", | ||
485 | "profile", | 486 | "profile", |
486 | "rustc-hash", | 487 | "rustc-hash", |
487 | "smallvec", | 488 | "smallvec", |
@@ -765,9 +766,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" | |||
765 | 766 | ||
766 | [[package]] | 767 | [[package]] |
767 | name = "libc" | 768 | name = "libc" |
768 | version = "0.2.95" | 769 | version = "0.2.97" |
769 | source = "registry+https://github.com/rust-lang/crates.io-index" | 770 | source = "registry+https://github.com/rust-lang/crates.io-index" |
770 | checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" | 771 | checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" |
771 | 772 | ||
772 | [[package]] | 773 | [[package]] |
773 | name = "libloading" | 774 | name = "libloading" |
@@ -1158,6 +1159,15 @@ dependencies = [ | |||
1158 | [[package]] | 1159 | [[package]] |
1159 | name = "proc_macro_test" | 1160 | name = "proc_macro_test" |
1160 | version = "0.0.0" | 1161 | version = "0.0.0" |
1162 | dependencies = [ | ||
1163 | "cargo_metadata", | ||
1164 | "proc_macro_test_impl", | ||
1165 | "toolchain", | ||
1166 | ] | ||
1167 | |||
1168 | [[package]] | ||
1169 | name = "proc_macro_test_impl" | ||
1170 | version = "0.0.0" | ||
1161 | 1171 | ||
1162 | [[package]] | 1172 | [[package]] |
1163 | name = "profile" | 1173 | name = "profile" |
@@ -1170,6 +1180,7 @@ dependencies = [ | |||
1170 | "once_cell", | 1180 | "once_cell", |
1171 | "perf-event", | 1181 | "perf-event", |
1172 | "tikv-jemalloc-ctl", | 1182 | "tikv-jemalloc-ctl", |
1183 | "winapi", | ||
1173 | ] | 1184 | ] |
1174 | 1185 | ||
1175 | [[package]] | 1186 | [[package]] |
@@ -1792,9 +1803,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" | |||
1792 | 1803 | ||
1793 | [[package]] | 1804 | [[package]] |
1794 | name = "ungrammar" | 1805 | name = "ungrammar" |
1795 | version = "1.13.0" | 1806 | version = "1.14.0" |
1796 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1807 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1797 | checksum = "76760314176cc2b94047af2f921b92c39f11a34dc05c43a3c2b0fc91cb22959f" | 1808 | checksum = "50ef6d7335c77ec3e4a7c4be74c2b9e4642569e94a4004c836f8cca71fede3a7" |
1798 | 1809 | ||
1799 | [[package]] | 1810 | [[package]] |
1800 | name = "unicase" | 1811 | name = "unicase" |
diff --git a/Cargo.toml b/Cargo.toml index 32ba3923b..4d6908fa9 100644 --- a/Cargo.toml +++ b/Cargo.toml | |||
@@ -1,6 +1,7 @@ | |||
1 | [workspace] | 1 | [workspace] |
2 | resolver = "2" | 2 | resolver = "2" |
3 | members = ["xtask/", "lib/*", "crates/*"] | 3 | members = ["xtask/", "lib/*", "crates/*"] |
4 | exclude = ["crates/proc_macro_test/imp"] | ||
4 | 5 | ||
5 | [profile.dev] | 6 | [profile.dev] |
6 | # Disabling debug info speeds up builds a bunch, | 7 | # Disabling debug info speeds up builds a bunch, |
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs index 69ceba735..da4afb5eb 100644 --- a/crates/base_db/src/fixture.rs +++ b/crates/base_db/src/fixture.rs | |||
@@ -190,7 +190,7 @@ impl From<Fixture> for FileMeta { | |||
190 | edition: f | 190 | edition: f |
191 | .edition | 191 | .edition |
192 | .as_ref() | 192 | .as_ref() |
193 | .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()), | 193 | .map_or(Edition::Edition2018, |v| Edition::from_str(v).unwrap()), |
194 | env: f.env.into_iter().collect(), | 194 | env: f.env.into_iter().collect(), |
195 | introduce_new_source_root: f.introduce_new_source_root, | 195 | introduce_new_source_root: f.introduce_new_source_root, |
196 | } | 196 | } |
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs index 62bf2a4b2..d26f8f180 100644 --- a/crates/base_db/src/lib.rs +++ b/crates/base_db/src/lib.rs | |||
@@ -42,7 +42,7 @@ pub struct FilePosition { | |||
42 | pub offset: TextSize, | 42 | pub offset: TextSize, |
43 | } | 43 | } |
44 | 44 | ||
45 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] | 45 | #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] |
46 | pub struct FileRange { | 46 | pub struct FileRange { |
47 | pub file_id: FileId, | 47 | pub file_id: FileId, |
48 | pub range: TextRange, | 48 | pub range: TextRange, |
@@ -120,6 +120,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { | |||
120 | } | 120 | } |
121 | 121 | ||
122 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { | 122 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
123 | let _p = profile::span("relevant_crates"); | ||
123 | let source_root = self.0.file_source_root(file_id); | 124 | let source_root = self.0.file_source_root(file_id); |
124 | self.0.source_root_crates(source_root) | 125 | self.0.source_root_crates(source_root) |
125 | } | 126 | } |
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index 560b15238..7c148fd40 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml | |||
@@ -16,6 +16,7 @@ either = "1.5.3" | |||
16 | arrayvec = "0.7" | 16 | arrayvec = "0.7" |
17 | itertools = "0.10.0" | 17 | itertools = "0.10.0" |
18 | smallvec = "1.4.0" | 18 | smallvec = "1.4.0" |
19 | once_cell = "1" | ||
19 | 20 | ||
20 | stdx = { path = "../stdx", version = "0.0.0" } | 21 | stdx = { path = "../stdx", version = "0.0.0" } |
21 | syntax = { path = "../syntax", version = "0.0.0" } | 22 | syntax = { path = "../syntax", version = "0.0.0" } |
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 2cdbd172a..b4c505898 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs | |||
@@ -3,251 +3,152 @@ | |||
3 | //! | 3 | //! |
4 | //! This probably isn't the best way to do this -- ideally, diagnistics should | 4 | //! This probably isn't the best way to do this -- ideally, diagnistics should |
5 | //! be expressed in terms of hir types themselves. | 5 | //! be expressed in terms of hir types themselves. |
6 | use std::any::Any; | 6 | use cfg::{CfgExpr, CfgOptions}; |
7 | 7 | use either::Either; | |
8 | use cfg::{CfgExpr, CfgOptions, DnfExpr}; | ||
9 | use hir_def::path::ModPath; | 8 | use hir_def::path::ModPath; |
10 | use hir_expand::{HirFileId, InFile}; | 9 | use hir_expand::{name::Name, HirFileId, InFile}; |
11 | use stdx::format_to; | ||
12 | use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; | 10 | use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; |
13 | 11 | ||
14 | pub use hir_ty::{ | 12 | macro_rules! diagnostics { |
15 | diagnostics::{ | 13 | ($($diag:ident,)*) => { |
16 | IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, | 14 | pub enum AnyDiagnostic {$( |
17 | MissingOkOrSomeInTailExpr, NoSuchField, RemoveThisSemicolon, | 15 | $diag(Box<$diag>), |
18 | ReplaceFilterMapNextWithFindMap, | 16 | )*} |
19 | }, | 17 | |
20 | diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder}, | 18 | $( |
21 | }; | 19 | impl From<$diag> for AnyDiagnostic { |
22 | 20 | fn from(d: $diag) -> AnyDiagnostic { | |
23 | // Diagnostic: unresolved-module | 21 | AnyDiagnostic::$diag(Box::new(d)) |
24 | // | 22 | } |
25 | // This diagnostic is triggered if rust-analyzer is unable to discover referred module. | 23 | } |
24 | )* | ||
25 | }; | ||
26 | } | ||
27 | |||
28 | diagnostics![ | ||
29 | BreakOutsideOfLoop, | ||
30 | InactiveCode, | ||
31 | IncorrectCase, | ||
32 | MacroError, | ||
33 | MismatchedArgCount, | ||
34 | MissingFields, | ||
35 | MissingMatchArms, | ||
36 | MissingOkOrSomeInTailExpr, | ||
37 | MissingUnsafe, | ||
38 | NoSuchField, | ||
39 | RemoveThisSemicolon, | ||
40 | ReplaceFilterMapNextWithFindMap, | ||
41 | UnimplementedBuiltinMacro, | ||
42 | UnresolvedExternCrate, | ||
43 | UnresolvedImport, | ||
44 | UnresolvedMacroCall, | ||
45 | UnresolvedModule, | ||
46 | UnresolvedProcMacro, | ||
47 | ]; | ||
48 | |||
26 | #[derive(Debug)] | 49 | #[derive(Debug)] |
27 | pub struct UnresolvedModule { | 50 | pub struct UnresolvedModule { |
28 | pub file: HirFileId, | 51 | pub decl: InFile<AstPtr<ast::Module>>, |
29 | pub decl: AstPtr<ast::Module>, | ||
30 | pub candidate: String, | 52 | pub candidate: String, |
31 | } | 53 | } |
32 | 54 | ||
33 | impl Diagnostic for UnresolvedModule { | ||
34 | fn code(&self) -> DiagnosticCode { | ||
35 | DiagnosticCode("unresolved-module") | ||
36 | } | ||
37 | fn message(&self) -> String { | ||
38 | "unresolved module".to_string() | ||
39 | } | ||
40 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
41 | InFile::new(self.file, self.decl.clone().into()) | ||
42 | } | ||
43 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
44 | self | ||
45 | } | ||
46 | } | ||
47 | |||
48 | // Diagnostic: unresolved-extern-crate | ||
49 | // | ||
50 | // This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate. | ||
51 | #[derive(Debug)] | 55 | #[derive(Debug)] |
52 | pub struct UnresolvedExternCrate { | 56 | pub struct UnresolvedExternCrate { |
53 | pub file: HirFileId, | 57 | pub decl: InFile<AstPtr<ast::ExternCrate>>, |
54 | pub item: AstPtr<ast::ExternCrate>, | ||
55 | } | ||
56 | |||
57 | impl Diagnostic for UnresolvedExternCrate { | ||
58 | fn code(&self) -> DiagnosticCode { | ||
59 | DiagnosticCode("unresolved-extern-crate") | ||
60 | } | ||
61 | fn message(&self) -> String { | ||
62 | "unresolved extern crate".to_string() | ||
63 | } | ||
64 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
65 | InFile::new(self.file, self.item.clone().into()) | ||
66 | } | ||
67 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
68 | self | ||
69 | } | ||
70 | } | 58 | } |
71 | 59 | ||
72 | #[derive(Debug)] | 60 | #[derive(Debug)] |
73 | pub struct UnresolvedImport { | 61 | pub struct UnresolvedImport { |
74 | pub file: HirFileId, | 62 | pub decl: InFile<AstPtr<ast::UseTree>>, |
75 | pub node: AstPtr<ast::UseTree>, | 63 | } |
76 | } | 64 | |
77 | |||
78 | impl Diagnostic for UnresolvedImport { | ||
79 | fn code(&self) -> DiagnosticCode { | ||
80 | DiagnosticCode("unresolved-import") | ||
81 | } | ||
82 | fn message(&self) -> String { | ||
83 | "unresolved import".to_string() | ||
84 | } | ||
85 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
86 | InFile::new(self.file, self.node.clone().into()) | ||
87 | } | ||
88 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
89 | self | ||
90 | } | ||
91 | fn is_experimental(&self) -> bool { | ||
92 | // This currently results in false positives in the following cases: | ||
93 | // - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly) | ||
94 | // - `core::arch` (we don't handle `#[path = "../<path>"]` correctly) | ||
95 | // - proc macros and/or proc macro generated code | ||
96 | true | ||
97 | } | ||
98 | } | ||
99 | |||
100 | // Diagnostic: unresolved-macro-call | ||
101 | // | ||
102 | // This diagnostic is triggered if rust-analyzer is unable to resolve the path to a | ||
103 | // macro in a macro invocation. | ||
104 | #[derive(Debug, Clone, Eq, PartialEq)] | 65 | #[derive(Debug, Clone, Eq, PartialEq)] |
105 | pub struct UnresolvedMacroCall { | 66 | pub struct UnresolvedMacroCall { |
106 | pub file: HirFileId, | 67 | pub macro_call: InFile<AstPtr<ast::MacroCall>>, |
107 | pub node: AstPtr<ast::MacroCall>, | ||
108 | pub path: ModPath, | 68 | pub path: ModPath, |
109 | } | 69 | } |
110 | 70 | ||
111 | impl Diagnostic for UnresolvedMacroCall { | ||
112 | fn code(&self) -> DiagnosticCode { | ||
113 | DiagnosticCode("unresolved-macro-call") | ||
114 | } | ||
115 | fn message(&self) -> String { | ||
116 | format!("unresolved macro `{}!`", self.path) | ||
117 | } | ||
118 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
119 | InFile::new(self.file, self.node.clone().into()) | ||
120 | } | ||
121 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
122 | self | ||
123 | } | ||
124 | fn is_experimental(&self) -> bool { | ||
125 | true | ||
126 | } | ||
127 | } | ||
128 | |||
129 | // Diagnostic: inactive-code | ||
130 | // | ||
131 | // This diagnostic is shown for code with inactive `#[cfg]` attributes. | ||
132 | #[derive(Debug, Clone, Eq, PartialEq)] | 71 | #[derive(Debug, Clone, Eq, PartialEq)] |
133 | pub struct InactiveCode { | 72 | pub struct InactiveCode { |
134 | pub file: HirFileId, | 73 | pub node: InFile<SyntaxNodePtr>, |
135 | pub node: SyntaxNodePtr, | ||
136 | pub cfg: CfgExpr, | 74 | pub cfg: CfgExpr, |
137 | pub opts: CfgOptions, | 75 | pub opts: CfgOptions, |
138 | } | 76 | } |
139 | 77 | ||
140 | impl Diagnostic for InactiveCode { | ||
141 | fn code(&self) -> DiagnosticCode { | ||
142 | DiagnosticCode("inactive-code") | ||
143 | } | ||
144 | fn message(&self) -> String { | ||
145 | let inactive = DnfExpr::new(self.cfg.clone()).why_inactive(&self.opts); | ||
146 | let mut buf = "code is inactive due to #[cfg] directives".to_string(); | ||
147 | |||
148 | if let Some(inactive) = inactive { | ||
149 | format_to!(buf, ": {}", inactive); | ||
150 | } | ||
151 | |||
152 | buf | ||
153 | } | ||
154 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
155 | InFile::new(self.file, self.node.clone()) | ||
156 | } | ||
157 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
158 | self | ||
159 | } | ||
160 | } | ||
161 | |||
162 | // Diagnostic: unresolved-proc-macro | ||
163 | // | ||
164 | // This diagnostic is shown when a procedural macro can not be found. This usually means that | ||
165 | // procedural macro support is simply disabled (and hence is only a weak hint instead of an error), | ||
166 | // but can also indicate project setup problems. | ||
167 | // | ||
168 | // If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the | ||
169 | // `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can | ||
170 | // enable support for procedural macros (see `rust-analyzer.procMacro.enable`). | ||
171 | #[derive(Debug, Clone, Eq, PartialEq)] | 78 | #[derive(Debug, Clone, Eq, PartialEq)] |
172 | pub struct UnresolvedProcMacro { | 79 | pub struct UnresolvedProcMacro { |
173 | pub file: HirFileId, | 80 | pub node: InFile<SyntaxNodePtr>, |
174 | pub node: SyntaxNodePtr, | ||
175 | /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange` | 81 | /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange` |
176 | /// to use instead. | 82 | /// to use instead. |
177 | pub precise_location: Option<TextRange>, | 83 | pub precise_location: Option<TextRange>, |
178 | pub macro_name: Option<String>, | 84 | pub macro_name: Option<String>, |
179 | } | 85 | } |
180 | 86 | ||
181 | impl Diagnostic for UnresolvedProcMacro { | 87 | #[derive(Debug, Clone, Eq, PartialEq)] |
182 | fn code(&self) -> DiagnosticCode { | 88 | pub struct MacroError { |
183 | DiagnosticCode("unresolved-proc-macro") | 89 | pub node: InFile<SyntaxNodePtr>, |
184 | } | 90 | pub message: String, |
91 | } | ||
185 | 92 | ||
186 | fn message(&self) -> String { | 93 | #[derive(Debug)] |
187 | match &self.macro_name { | 94 | pub struct UnimplementedBuiltinMacro { |
188 | Some(name) => format!("proc macro `{}` not expanded", name), | 95 | pub node: InFile<SyntaxNodePtr>, |
189 | None => "proc macro not expanded".to_string(), | 96 | } |
190 | } | ||
191 | } | ||
192 | 97 | ||
193 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | 98 | #[derive(Debug)] |
194 | InFile::new(self.file, self.node.clone()) | 99 | pub struct NoSuchField { |
195 | } | 100 | pub field: InFile<AstPtr<ast::RecordExprField>>, |
101 | } | ||
196 | 102 | ||
197 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 103 | #[derive(Debug)] |
198 | self | 104 | pub struct BreakOutsideOfLoop { |
199 | } | 105 | pub expr: InFile<AstPtr<ast::Expr>>, |
200 | } | 106 | } |
201 | 107 | ||
202 | // Diagnostic: macro-error | 108 | #[derive(Debug)] |
203 | // | 109 | pub struct MissingUnsafe { |
204 | // This diagnostic is shown for macro expansion errors. | 110 | pub expr: InFile<AstPtr<ast::Expr>>, |
205 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
206 | pub struct MacroError { | ||
207 | pub file: HirFileId, | ||
208 | pub node: SyntaxNodePtr, | ||
209 | pub message: String, | ||
210 | } | 111 | } |
211 | 112 | ||
212 | impl Diagnostic for MacroError { | 113 | #[derive(Debug)] |
213 | fn code(&self) -> DiagnosticCode { | 114 | pub struct MissingFields { |
214 | DiagnosticCode("macro-error") | 115 | pub file: HirFileId, |
215 | } | 116 | pub field_list_parent: Either<AstPtr<ast::RecordExpr>, AstPtr<ast::RecordPat>>, |
216 | fn message(&self) -> String { | 117 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, |
217 | self.message.clone() | 118 | pub missed_fields: Vec<Name>, |
218 | } | ||
219 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
220 | InFile::new(self.file, self.node.clone()) | ||
221 | } | ||
222 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
223 | self | ||
224 | } | ||
225 | fn is_experimental(&self) -> bool { | ||
226 | // Newly added and not very well-tested, might contain false positives. | ||
227 | true | ||
228 | } | ||
229 | } | 119 | } |
230 | 120 | ||
231 | #[derive(Debug)] | 121 | #[derive(Debug)] |
232 | pub struct UnimplementedBuiltinMacro { | 122 | pub struct ReplaceFilterMapNextWithFindMap { |
233 | pub file: HirFileId, | 123 | pub file: HirFileId, |
234 | pub node: SyntaxNodePtr, | 124 | /// This expression is the whole method chain up to and including `.filter_map(..).next()`. |
125 | pub next_expr: AstPtr<ast::Expr>, | ||
235 | } | 126 | } |
236 | 127 | ||
237 | impl Diagnostic for UnimplementedBuiltinMacro { | 128 | #[derive(Debug)] |
238 | fn code(&self) -> DiagnosticCode { | 129 | pub struct MismatchedArgCount { |
239 | DiagnosticCode("unimplemented-builtin-macro") | 130 | pub call_expr: InFile<AstPtr<ast::Expr>>, |
240 | } | 131 | pub expected: usize, |
132 | pub found: usize, | ||
133 | } | ||
241 | 134 | ||
242 | fn message(&self) -> String { | 135 | #[derive(Debug)] |
243 | "unimplemented built-in macro".to_string() | 136 | pub struct RemoveThisSemicolon { |
244 | } | 137 | pub expr: InFile<AstPtr<ast::Expr>>, |
138 | } | ||
245 | 139 | ||
246 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | 140 | #[derive(Debug)] |
247 | InFile::new(self.file, self.node.clone()) | 141 | pub struct MissingOkOrSomeInTailExpr { |
248 | } | 142 | pub expr: InFile<AstPtr<ast::Expr>>, |
143 | // `Some` or `Ok` depending on whether the return type is Result or Option | ||
144 | pub required: String, | ||
145 | } | ||
249 | 146 | ||
250 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 147 | #[derive(Debug)] |
251 | self | 148 | pub struct MissingMatchArms { |
252 | } | 149 | pub file: HirFileId, |
150 | pub match_expr: AstPtr<ast::Expr>, | ||
151 | pub arms: AstPtr<ast::MatchArmList>, | ||
253 | } | 152 | } |
153 | |||
154 | pub use hir_ty::diagnostics::IncorrectCase; | ||
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 2ec568b26..5bc0b2338 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -35,14 +35,10 @@ use std::{iter, sync::Arc}; | |||
35 | 35 | ||
36 | use arrayvec::ArrayVec; | 36 | use arrayvec::ArrayVec; |
37 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; | 37 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; |
38 | use diagnostics::{ | ||
39 | InactiveCode, MacroError, UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, | ||
40 | UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro, | ||
41 | }; | ||
42 | use either::Either; | 38 | use either::Either; |
43 | use hir_def::{ | 39 | use hir_def::{ |
44 | adt::{ReprKind, VariantData}, | 40 | adt::{ReprKind, VariantData}, |
45 | body::BodyDiagnostic, | 41 | body::{BodyDiagnostic, SyntheticSyntax}, |
46 | expr::{BindingAnnotation, LabelId, Pat, PatId}, | 42 | expr::{BindingAnnotation, LabelId, Pat, PatId}, |
47 | item_tree::ItemTreeNode, | 43 | item_tree::ItemTreeNode, |
48 | lang_item::LangItemTarget, | 44 | lang_item::LangItemTarget, |
@@ -60,8 +56,8 @@ use hir_ty::{ | |||
60 | autoderef, | 56 | autoderef, |
61 | consteval::ConstExt, | 57 | consteval::ConstExt, |
62 | could_unify, | 58 | could_unify, |
63 | diagnostics_sink::DiagnosticSink, | 59 | diagnostics::BodyValidationDiagnostic, |
64 | method_resolution::{self, def_crates, TyFingerprint}, | 60 | method_resolution::{self, TyFingerprint}, |
65 | primitive::UintTy, | 61 | primitive::UintTy, |
66 | subst_prefix, | 62 | subst_prefix, |
67 | traits::FnTrait, | 63 | traits::FnTrait, |
@@ -72,6 +68,7 @@ use hir_ty::{ | |||
72 | }; | 68 | }; |
73 | use itertools::Itertools; | 69 | use itertools::Itertools; |
74 | use nameres::diagnostics::DefDiagnosticKind; | 70 | use nameres::diagnostics::DefDiagnosticKind; |
71 | use once_cell::unsync::Lazy; | ||
75 | use rustc_hash::FxHashSet; | 72 | use rustc_hash::FxHashSet; |
76 | use stdx::{format_to, impl_from}; | 73 | use stdx::{format_to, impl_from}; |
77 | use syntax::{ | 74 | use syntax::{ |
@@ -84,6 +81,13 @@ use crate::db::{DefDatabase, HirDatabase}; | |||
84 | 81 | ||
85 | pub use crate::{ | 82 | pub use crate::{ |
86 | attrs::{HasAttrs, Namespace}, | 83 | attrs::{HasAttrs, Namespace}, |
84 | diagnostics::{ | ||
85 | AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, MacroError, | ||
86 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, | ||
87 | MissingUnsafe, NoSuchField, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, | ||
88 | UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, | ||
89 | UnresolvedModule, UnresolvedProcMacro, | ||
90 | }, | ||
87 | has_source::HasSource, | 91 | has_source::HasSource, |
88 | semantics::{PathResolution, Semantics, SemanticsScope}, | 92 | semantics::{PathResolution, Semantics, SemanticsScope}, |
89 | }; | 93 | }; |
@@ -191,6 +195,7 @@ impl Crate { | |||
191 | db: &dyn DefDatabase, | 195 | db: &dyn DefDatabase, |
192 | query: import_map::Query, | 196 | query: import_map::Query, |
193 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 197 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { |
198 | let _p = profile::span("query_external_importables"); | ||
194 | import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item { | 199 | import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item { |
195 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), | 200 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), |
196 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), | 201 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), |
@@ -331,7 +336,7 @@ impl ModuleDef { | |||
331 | } | 336 | } |
332 | } | 337 | } |
333 | 338 | ||
334 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 339 | pub fn diagnostics(self, db: &dyn HirDatabase) -> Vec<AnyDiagnostic> { |
335 | let id = match self { | 340 | let id = match self { |
336 | ModuleDef::Adt(it) => match it { | 341 | ModuleDef::Adt(it) => match it { |
337 | Adt::Struct(it) => it.id.into(), | 342 | Adt::Struct(it) => it.id.into(), |
@@ -344,15 +349,19 @@ impl ModuleDef { | |||
344 | ModuleDef::Module(it) => it.id.into(), | 349 | ModuleDef::Module(it) => it.id.into(), |
345 | ModuleDef::Const(it) => it.id.into(), | 350 | ModuleDef::Const(it) => it.id.into(), |
346 | ModuleDef::Static(it) => it.id.into(), | 351 | ModuleDef::Static(it) => it.id.into(), |
347 | _ => return, | 352 | _ => return Vec::new(), |
348 | }; | 353 | }; |
349 | 354 | ||
350 | let module = match self.module(db) { | 355 | let module = match self.module(db) { |
351 | Some(it) => it, | 356 | Some(it) => it, |
352 | None => return, | 357 | None => return Vec::new(), |
353 | }; | 358 | }; |
354 | 359 | ||
355 | hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id, sink) | 360 | let mut acc = Vec::new(); |
361 | for diag in hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id) { | ||
362 | acc.push(diag.into()) | ||
363 | } | ||
364 | acc | ||
356 | } | 365 | } |
357 | } | 366 | } |
358 | 367 | ||
@@ -441,10 +450,10 @@ impl Module { | |||
441 | } | 450 | } |
442 | 451 | ||
443 | pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> { | 452 | pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> { |
444 | self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into()) | 453 | self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of((*def).into()) |
445 | } | 454 | } |
446 | 455 | ||
447 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 456 | pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) { |
448 | let _p = profile::span("Module::diagnostics").detail(|| { | 457 | let _p = profile::span("Module::diagnostics").detail(|| { |
449 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) | 458 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) |
450 | }); | 459 | }); |
@@ -457,18 +466,22 @@ impl Module { | |||
457 | match &diag.kind { | 466 | match &diag.kind { |
458 | DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => { | 467 | DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => { |
459 | let decl = declaration.to_node(db.upcast()); | 468 | let decl = declaration.to_node(db.upcast()); |
460 | sink.push(UnresolvedModule { | 469 | acc.push( |
461 | file: declaration.file_id, | 470 | UnresolvedModule { |
462 | decl: AstPtr::new(&decl), | 471 | decl: InFile::new(declaration.file_id, AstPtr::new(&decl)), |
463 | candidate: candidate.clone(), | 472 | candidate: candidate.clone(), |
464 | }) | 473 | } |
474 | .into(), | ||
475 | ) | ||
465 | } | 476 | } |
466 | DefDiagnosticKind::UnresolvedExternCrate { ast } => { | 477 | DefDiagnosticKind::UnresolvedExternCrate { ast } => { |
467 | let item = ast.to_node(db.upcast()); | 478 | let item = ast.to_node(db.upcast()); |
468 | sink.push(UnresolvedExternCrate { | 479 | acc.push( |
469 | file: ast.file_id, | 480 | UnresolvedExternCrate { |
470 | item: AstPtr::new(&item), | 481 | decl: InFile::new(ast.file_id, AstPtr::new(&item)), |
471 | }); | 482 | } |
483 | .into(), | ||
484 | ); | ||
472 | } | 485 | } |
473 | 486 | ||
474 | DefDiagnosticKind::UnresolvedImport { id, index } => { | 487 | DefDiagnosticKind::UnresolvedImport { id, index } => { |
@@ -477,25 +490,30 @@ impl Module { | |||
477 | let import = &item_tree[id.value]; | 490 | let import = &item_tree[id.value]; |
478 | 491 | ||
479 | let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index); | 492 | let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index); |
480 | sink.push(UnresolvedImport { file: file_id, node: AstPtr::new(&use_tree) }); | 493 | acc.push( |
494 | UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) } | ||
495 | .into(), | ||
496 | ); | ||
481 | } | 497 | } |
482 | 498 | ||
483 | DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => { | 499 | DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => { |
484 | let item = ast.to_node(db.upcast()); | 500 | let item = ast.to_node(db.upcast()); |
485 | sink.push(InactiveCode { | 501 | acc.push( |
486 | file: ast.file_id, | 502 | InactiveCode { |
487 | node: AstPtr::new(&item).into(), | 503 | node: ast.with_value(AstPtr::new(&item).into()), |
488 | cfg: cfg.clone(), | 504 | cfg: cfg.clone(), |
489 | opts: opts.clone(), | 505 | opts: opts.clone(), |
490 | }); | 506 | } |
507 | .into(), | ||
508 | ); | ||
491 | } | 509 | } |
492 | 510 | ||
493 | DefDiagnosticKind::UnresolvedProcMacro { ast } => { | 511 | DefDiagnosticKind::UnresolvedProcMacro { ast } => { |
494 | let mut precise_location = None; | 512 | let mut precise_location = None; |
495 | let (file, ast, name) = match ast { | 513 | let (node, name) = match ast { |
496 | MacroCallKind::FnLike { ast_id, .. } => { | 514 | MacroCallKind::FnLike { ast_id, .. } => { |
497 | let node = ast_id.to_node(db.upcast()); | 515 | let node = ast_id.to_node(db.upcast()); |
498 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None) | 516 | (ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), None) |
499 | } | 517 | } |
500 | MacroCallKind::Derive { ast_id, derive_name, .. } => { | 518 | MacroCallKind::Derive { ast_id, derive_name, .. } => { |
501 | let node = ast_id.to_node(db.upcast()); | 519 | let node = ast_id.to_node(db.upcast()); |
@@ -528,8 +546,7 @@ impl Module { | |||
528 | } | 546 | } |
529 | 547 | ||
530 | ( | 548 | ( |
531 | ast_id.file_id, | 549 | ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), |
532 | SyntaxNodePtr::from(AstPtr::new(&node)), | ||
533 | Some(derive_name.clone()), | 550 | Some(derive_name.clone()), |
534 | ) | 551 | ) |
535 | } | 552 | } |
@@ -540,73 +557,73 @@ impl Module { | |||
540 | || panic!("cannot find attribute #{}", invoc_attr_index), | 557 | || panic!("cannot find attribute #{}", invoc_attr_index), |
541 | ); | 558 | ); |
542 | ( | 559 | ( |
543 | ast_id.file_id, | 560 | ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))), |
544 | SyntaxNodePtr::from(AstPtr::new(&attr)), | ||
545 | Some(attr_name.clone()), | 561 | Some(attr_name.clone()), |
546 | ) | 562 | ) |
547 | } | 563 | } |
548 | }; | 564 | }; |
549 | sink.push(UnresolvedProcMacro { | 565 | acc.push( |
550 | file, | 566 | UnresolvedProcMacro { node, precise_location, macro_name: name }.into(), |
551 | node: ast, | 567 | ); |
552 | precise_location, | ||
553 | macro_name: name, | ||
554 | }); | ||
555 | } | 568 | } |
556 | 569 | ||
557 | DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { | 570 | DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { |
558 | let node = ast.to_node(db.upcast()); | 571 | let node = ast.to_node(db.upcast()); |
559 | sink.push(UnresolvedMacroCall { | 572 | acc.push( |
560 | file: ast.file_id, | 573 | UnresolvedMacroCall { |
561 | node: AstPtr::new(&node), | 574 | macro_call: InFile::new(ast.file_id, AstPtr::new(&node)), |
562 | path: path.clone(), | 575 | path: path.clone(), |
563 | }); | 576 | } |
577 | .into(), | ||
578 | ); | ||
564 | } | 579 | } |
565 | 580 | ||
566 | DefDiagnosticKind::MacroError { ast, message } => { | 581 | DefDiagnosticKind::MacroError { ast, message } => { |
567 | let (file, ast) = match ast { | 582 | let node = match ast { |
568 | MacroCallKind::FnLike { ast_id, .. } => { | 583 | MacroCallKind::FnLike { ast_id, .. } => { |
569 | let node = ast_id.to_node(db.upcast()); | 584 | let node = ast_id.to_node(db.upcast()); |
570 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) | 585 | ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))) |
571 | } | 586 | } |
572 | MacroCallKind::Derive { ast_id, .. } | 587 | MacroCallKind::Derive { ast_id, .. } |
573 | | MacroCallKind::Attr { ast_id, .. } => { | 588 | | MacroCallKind::Attr { ast_id, .. } => { |
574 | // FIXME: point to the attribute instead, this creates very large diagnostics | 589 | // FIXME: point to the attribute instead, this creates very large diagnostics |
575 | let node = ast_id.to_node(db.upcast()); | 590 | let node = ast_id.to_node(db.upcast()); |
576 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) | 591 | ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))) |
577 | } | 592 | } |
578 | }; | 593 | }; |
579 | sink.push(MacroError { file, node: ast, message: message.clone() }); | 594 | acc.push(MacroError { node, message: message.clone() }.into()); |
580 | } | 595 | } |
581 | 596 | ||
582 | DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { | 597 | DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { |
583 | let node = ast.to_node(db.upcast()); | 598 | let node = ast.to_node(db.upcast()); |
584 | // Must have a name, otherwise we wouldn't emit it. | 599 | // Must have a name, otherwise we wouldn't emit it. |
585 | let name = node.name().expect("unimplemented builtin macro with no name"); | 600 | let name = node.name().expect("unimplemented builtin macro with no name"); |
586 | let ptr = SyntaxNodePtr::from(AstPtr::new(&name)); | 601 | acc.push( |
587 | sink.push(UnimplementedBuiltinMacro { file: ast.file_id, node: ptr }); | 602 | UnimplementedBuiltinMacro { |
603 | node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&name))), | ||
604 | } | ||
605 | .into(), | ||
606 | ); | ||
588 | } | 607 | } |
589 | } | 608 | } |
590 | } | 609 | } |
591 | for decl in self.declarations(db) { | 610 | for decl in self.declarations(db) { |
592 | match decl { | 611 | match decl { |
593 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), | 612 | ModuleDef::Function(f) => f.diagnostics(db, acc), |
594 | crate::ModuleDef::Module(m) => { | 613 | ModuleDef::Module(m) => { |
595 | // Only add diagnostics from inline modules | 614 | // Only add diagnostics from inline modules |
596 | if def_map[m.id.local_id].origin.is_inline() { | 615 | if def_map[m.id.local_id].origin.is_inline() { |
597 | m.diagnostics(db, sink) | 616 | m.diagnostics(db, acc) |
598 | } | 617 | } |
599 | } | 618 | } |
600 | _ => { | 619 | _ => acc.extend(decl.diagnostics(db)), |
601 | decl.diagnostics(db, sink); | ||
602 | } | ||
603 | } | 620 | } |
604 | } | 621 | } |
605 | 622 | ||
606 | for impl_def in self.impl_defs(db) { | 623 | for impl_def in self.impl_defs(db) { |
607 | for item in impl_def.items(db) { | 624 | for item in impl_def.items(db) { |
608 | if let AssocItem::Function(f) = item { | 625 | if let AssocItem::Function(f) = item { |
609 | f.diagnostics(db, sink); | 626 | f.diagnostics(db, acc); |
610 | } | 627 | } |
611 | } | 628 | } |
612 | } | 629 | } |
@@ -1008,41 +1025,191 @@ impl Function { | |||
1008 | db.function_data(self.id).is_async() | 1025 | db.function_data(self.id).is_async() |
1009 | } | 1026 | } |
1010 | 1027 | ||
1011 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 1028 | pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) { |
1012 | let krate = self.module(db).id.krate(); | 1029 | let krate = self.module(db).id.krate(); |
1013 | 1030 | ||
1014 | let source_map = db.body_with_source_map(self.id.into()).1; | 1031 | let source_map = db.body_with_source_map(self.id.into()).1; |
1015 | for diag in source_map.diagnostics() { | 1032 | for diag in source_map.diagnostics() { |
1016 | match diag { | 1033 | match diag { |
1017 | BodyDiagnostic::InactiveCode { node, cfg, opts } => sink.push(InactiveCode { | 1034 | BodyDiagnostic::InactiveCode { node, cfg, opts } => acc.push( |
1018 | file: node.file_id, | 1035 | InactiveCode { node: node.clone(), cfg: cfg.clone(), opts: opts.clone() } |
1019 | node: node.value.clone(), | 1036 | .into(), |
1020 | cfg: cfg.clone(), | 1037 | ), |
1021 | opts: opts.clone(), | 1038 | BodyDiagnostic::MacroError { node, message } => acc.push( |
1022 | }), | 1039 | MacroError { |
1023 | BodyDiagnostic::MacroError { node, message } => sink.push(MacroError { | 1040 | node: node.clone().map(|it| it.into()), |
1024 | file: node.file_id, | 1041 | message: message.to_string(), |
1025 | node: node.value.clone().into(), | 1042 | } |
1026 | message: message.to_string(), | 1043 | .into(), |
1027 | }), | 1044 | ), |
1028 | BodyDiagnostic::UnresolvedProcMacro { node } => sink.push(UnresolvedProcMacro { | 1045 | BodyDiagnostic::UnresolvedProcMacro { node } => acc.push( |
1029 | file: node.file_id, | 1046 | UnresolvedProcMacro { |
1030 | node: node.value.clone().into(), | 1047 | node: node.clone().map(|it| it.into()), |
1031 | precise_location: None, | 1048 | precise_location: None, |
1032 | macro_name: None, | 1049 | macro_name: None, |
1033 | }), | 1050 | } |
1034 | BodyDiagnostic::UnresolvedMacroCall { node, path } => { | 1051 | .into(), |
1035 | sink.push(UnresolvedMacroCall { | 1052 | ), |
1036 | file: node.file_id, | 1053 | BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push( |
1037 | node: node.value.clone(), | 1054 | UnresolvedMacroCall { macro_call: node.clone(), path: path.clone() }.into(), |
1038 | path: path.clone(), | 1055 | ), |
1039 | }) | 1056 | } |
1057 | } | ||
1058 | |||
1059 | let infer = db.infer(self.id.into()); | ||
1060 | let source_map = Lazy::new(|| db.body_with_source_map(self.id.into()).1); | ||
1061 | for d in &infer.diagnostics { | ||
1062 | match d { | ||
1063 | hir_ty::InferenceDiagnostic::NoSuchField { expr } => { | ||
1064 | let field = source_map.field_syntax(*expr); | ||
1065 | acc.push(NoSuchField { field }.into()) | ||
1066 | } | ||
1067 | hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => { | ||
1068 | let expr = source_map | ||
1069 | .expr_syntax(*expr) | ||
1070 | .expect("break outside of loop in synthetic syntax"); | ||
1071 | acc.push(BreakOutsideOfLoop { expr }.into()) | ||
1072 | } | ||
1073 | } | ||
1074 | } | ||
1075 | |||
1076 | for expr in hir_ty::diagnostics::missing_unsafe(db, self.id.into()) { | ||
1077 | match source_map.expr_syntax(expr) { | ||
1078 | Ok(expr) => acc.push(MissingUnsafe { expr }.into()), | ||
1079 | Err(SyntheticSyntax) => { | ||
1080 | // FIXME: Here and eslwhere in this file, the `expr` was | ||
1081 | // desugared, report or assert that this doesn't happen. | ||
1082 | } | ||
1083 | } | ||
1084 | } | ||
1085 | |||
1086 | for diagnostic in BodyValidationDiagnostic::collect(db, self.id.into()) { | ||
1087 | match diagnostic { | ||
1088 | BodyValidationDiagnostic::RecordMissingFields { | ||
1089 | record, | ||
1090 | variant, | ||
1091 | missed_fields, | ||
1092 | } => { | ||
1093 | let variant_data = variant.variant_data(db.upcast()); | ||
1094 | let missed_fields = missed_fields | ||
1095 | .into_iter() | ||
1096 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
1097 | .collect(); | ||
1098 | |||
1099 | match record { | ||
1100 | Either::Left(record_expr) => match source_map.expr_syntax(record_expr) { | ||
1101 | Ok(source_ptr) => { | ||
1102 | let root = source_ptr.file_syntax(db.upcast()); | ||
1103 | if let ast::Expr::RecordExpr(record_expr) = | ||
1104 | &source_ptr.value.to_node(&root) | ||
1105 | { | ||
1106 | if let Some(_) = record_expr.record_expr_field_list() { | ||
1107 | acc.push( | ||
1108 | MissingFields { | ||
1109 | file: source_ptr.file_id, | ||
1110 | field_list_parent: Either::Left(AstPtr::new( | ||
1111 | record_expr, | ||
1112 | )), | ||
1113 | field_list_parent_path: record_expr | ||
1114 | .path() | ||
1115 | .map(|path| AstPtr::new(&path)), | ||
1116 | missed_fields, | ||
1117 | } | ||
1118 | .into(), | ||
1119 | ) | ||
1120 | } | ||
1121 | } | ||
1122 | } | ||
1123 | Err(SyntheticSyntax) => (), | ||
1124 | }, | ||
1125 | Either::Right(record_pat) => match source_map.pat_syntax(record_pat) { | ||
1126 | Ok(source_ptr) => { | ||
1127 | if let Some(expr) = source_ptr.value.as_ref().left() { | ||
1128 | let root = source_ptr.file_syntax(db.upcast()); | ||
1129 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { | ||
1130 | if let Some(_) = record_pat.record_pat_field_list() { | ||
1131 | acc.push( | ||
1132 | MissingFields { | ||
1133 | file: source_ptr.file_id, | ||
1134 | field_list_parent: Either::Right(AstPtr::new( | ||
1135 | &record_pat, | ||
1136 | )), | ||
1137 | field_list_parent_path: record_pat | ||
1138 | .path() | ||
1139 | .map(|path| AstPtr::new(&path)), | ||
1140 | missed_fields, | ||
1141 | } | ||
1142 | .into(), | ||
1143 | ) | ||
1144 | } | ||
1145 | } | ||
1146 | } | ||
1147 | } | ||
1148 | Err(SyntheticSyntax) => (), | ||
1149 | }, | ||
1150 | } | ||
1151 | } | ||
1152 | BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => { | ||
1153 | if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) { | ||
1154 | acc.push( | ||
1155 | ReplaceFilterMapNextWithFindMap { | ||
1156 | file: next_source_ptr.file_id, | ||
1157 | next_expr: next_source_ptr.value, | ||
1158 | } | ||
1159 | .into(), | ||
1160 | ); | ||
1161 | } | ||
1162 | } | ||
1163 | BodyValidationDiagnostic::MismatchedArgCount { call_expr, expected, found } => { | ||
1164 | match source_map.expr_syntax(call_expr) { | ||
1165 | Ok(source_ptr) => acc.push( | ||
1166 | MismatchedArgCount { call_expr: source_ptr, expected, found }.into(), | ||
1167 | ), | ||
1168 | Err(SyntheticSyntax) => (), | ||
1169 | } | ||
1170 | } | ||
1171 | BodyValidationDiagnostic::RemoveThisSemicolon { expr } => { | ||
1172 | match source_map.expr_syntax(expr) { | ||
1173 | Ok(expr) => acc.push(RemoveThisSemicolon { expr }.into()), | ||
1174 | Err(SyntheticSyntax) => (), | ||
1175 | } | ||
1176 | } | ||
1177 | BodyValidationDiagnostic::MissingOkOrSomeInTailExpr { expr, required } => { | ||
1178 | match source_map.expr_syntax(expr) { | ||
1179 | Ok(expr) => acc.push(MissingOkOrSomeInTailExpr { expr, required }.into()), | ||
1180 | Err(SyntheticSyntax) => (), | ||
1181 | } | ||
1182 | } | ||
1183 | BodyValidationDiagnostic::MissingMatchArms { match_expr } => { | ||
1184 | match source_map.expr_syntax(match_expr) { | ||
1185 | Ok(source_ptr) => { | ||
1186 | let root = source_ptr.file_syntax(db.upcast()); | ||
1187 | if let ast::Expr::MatchExpr(match_expr) = | ||
1188 | &source_ptr.value.to_node(&root) | ||
1189 | { | ||
1190 | if let (Some(match_expr), Some(arms)) = | ||
1191 | (match_expr.expr(), match_expr.match_arm_list()) | ||
1192 | { | ||
1193 | acc.push( | ||
1194 | MissingMatchArms { | ||
1195 | file: source_ptr.file_id, | ||
1196 | match_expr: AstPtr::new(&match_expr), | ||
1197 | arms: AstPtr::new(&arms), | ||
1198 | } | ||
1199 | .into(), | ||
1200 | ) | ||
1201 | } | ||
1202 | } | ||
1203 | } | ||
1204 | Err(SyntheticSyntax) => (), | ||
1205 | } | ||
1040 | } | 1206 | } |
1041 | } | 1207 | } |
1042 | } | 1208 | } |
1043 | 1209 | ||
1044 | hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); | 1210 | for diag in hir_ty::diagnostics::validate_module_item(db, krate, self.id.into()) { |
1045 | hir_ty::diagnostics::validate_body(db, self.id.into(), sink); | 1211 | acc.push(diag.into()) |
1212 | } | ||
1046 | } | 1213 | } |
1047 | 1214 | ||
1048 | /// Whether this function declaration has a definition. | 1215 | /// Whether this function declaration has a definition. |
@@ -1450,6 +1617,20 @@ impl AssocItem { | |||
1450 | _ => None, | 1617 | _ => None, |
1451 | } | 1618 | } |
1452 | } | 1619 | } |
1620 | |||
1621 | pub fn containing_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1622 | match self.container(db) { | ||
1623 | AssocItemContainer::Impl(i) => i.trait_(db), | ||
1624 | _ => None, | ||
1625 | } | ||
1626 | } | ||
1627 | |||
1628 | pub fn containing_trait_or_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1629 | match self.container(db) { | ||
1630 | AssocItemContainer::Trait(t) => Some(t), | ||
1631 | AssocItemContainer::Impl(i) => i.trait_(db), | ||
1632 | } | ||
1633 | } | ||
1453 | } | 1634 | } |
1454 | 1635 | ||
1455 | impl HasVisibility for AssocItem { | 1636 | impl HasVisibility for AssocItem { |
@@ -1747,7 +1928,7 @@ impl Impl { | |||
1747 | } | 1928 | } |
1748 | 1929 | ||
1749 | pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> { | 1930 | pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> { |
1750 | let def_crates = match def_crates(db, &ty, krate) { | 1931 | let def_crates = match method_resolution::def_crates(db, &ty, krate) { |
1751 | Some(def_crates) => def_crates, | 1932 | Some(def_crates) => def_crates, |
1752 | None => return Vec::new(), | 1933 | None => return Vec::new(), |
1753 | }; | 1934 | }; |
@@ -2153,7 +2334,7 @@ impl Type { | |||
2153 | krate: Crate, | 2334 | krate: Crate, |
2154 | mut callback: impl FnMut(AssocItem) -> Option<T>, | 2335 | mut callback: impl FnMut(AssocItem) -> Option<T>, |
2155 | ) -> Option<T> { | 2336 | ) -> Option<T> { |
2156 | for krate in def_crates(db, &self.ty, krate.id)? { | 2337 | for krate in method_resolution::def_crates(db, &self.ty, krate.id)? { |
2157 | let impls = db.inherent_impls_in_crate(krate); | 2338 | let impls = db.inherent_impls_in_crate(krate); |
2158 | 2339 | ||
2159 | for impl_def in impls.for_self_ty(&self.ty) { | 2340 | for impl_def in impls.for_self_ty(&self.ty) { |
@@ -2185,6 +2366,7 @@ impl Type { | |||
2185 | name: Option<&Name>, | 2366 | name: Option<&Name>, |
2186 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 2367 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
2187 | ) -> Option<T> { | 2368 | ) -> Option<T> { |
2369 | let _p = profile::span("iterate_method_candidates"); | ||
2188 | // There should be no inference vars in types passed here | 2370 | // There should be no inference vars in types passed here |
2189 | // FIXME check that? | 2371 | // FIXME check that? |
2190 | // FIXME replace Unknown by bound vars here | 2372 | // FIXME replace Unknown by bound vars here |
@@ -2218,6 +2400,7 @@ impl Type { | |||
2218 | name: Option<&Name>, | 2400 | name: Option<&Name>, |
2219 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, | 2401 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, |
2220 | ) -> Option<T> { | 2402 | ) -> Option<T> { |
2403 | let _p = profile::span("iterate_path_candidates"); | ||
2221 | let canonical = hir_ty::replace_errors_with_variables(&self.ty); | 2404 | let canonical = hir_ty::replace_errors_with_variables(&self.ty); |
2222 | 2405 | ||
2223 | let env = self.env.clone(); | 2406 | let env = self.env.clone(); |
@@ -2255,6 +2438,7 @@ impl Type { | |||
2255 | &'a self, | 2438 | &'a self, |
2256 | db: &'a dyn HirDatabase, | 2439 | db: &'a dyn HirDatabase, |
2257 | ) -> impl Iterator<Item = Trait> + 'a { | 2440 | ) -> impl Iterator<Item = Trait> + 'a { |
2441 | let _p = profile::span("applicable_inherent_traits"); | ||
2258 | self.autoderef(db) | 2442 | self.autoderef(db) |
2259 | .filter_map(|derefed_type| derefed_type.ty.dyn_trait()) | 2443 | .filter_map(|derefed_type| derefed_type.ty.dyn_trait()) |
2260 | .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id)) | 2444 | .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id)) |
@@ -2327,13 +2511,13 @@ impl Type { | |||
2327 | match ty.kind(&Interner) { | 2511 | match ty.kind(&Interner) { |
2328 | TyKind::Adt(_, substs) => { | 2512 | TyKind::Adt(_, substs) => { |
2329 | cb(type_.derived(ty.clone())); | 2513 | cb(type_.derived(ty.clone())); |
2330 | walk_substs(db, type_, &substs, cb); | 2514 | walk_substs(db, type_, substs, cb); |
2331 | } | 2515 | } |
2332 | TyKind::AssociatedType(_, substs) => { | 2516 | TyKind::AssociatedType(_, substs) => { |
2333 | if let Some(_) = ty.associated_type_parent_trait(db) { | 2517 | if let Some(_) = ty.associated_type_parent_trait(db) { |
2334 | cb(type_.derived(ty.clone())); | 2518 | cb(type_.derived(ty.clone())); |
2335 | } | 2519 | } |
2336 | walk_substs(db, type_, &substs, cb); | 2520 | walk_substs(db, type_, substs, cb); |
2337 | } | 2521 | } |
2338 | TyKind::OpaqueType(_, subst) => { | 2522 | TyKind::OpaqueType(_, subst) => { |
2339 | if let Some(bounds) = ty.impl_trait_bounds(db) { | 2523 | if let Some(bounds) = ty.impl_trait_bounds(db) { |
@@ -2373,7 +2557,7 @@ impl Type { | |||
2373 | TyKind::FnDef(_, substs) | 2557 | TyKind::FnDef(_, substs) |
2374 | | TyKind::Tuple(_, substs) | 2558 | | TyKind::Tuple(_, substs) |
2375 | | TyKind::Closure(.., substs) => { | 2559 | | TyKind::Closure(.., substs) => { |
2376 | walk_substs(db, type_, &substs, cb); | 2560 | walk_substs(db, type_, substs, cb); |
2377 | } | 2561 | } |
2378 | TyKind::Function(hir_ty::FnPointer { substitution, .. }) => { | 2562 | TyKind::Function(hir_ty::FnPointer { substitution, .. }) => { |
2379 | walk_substs(db, type_, &substitution.0, cb); | 2563 | walk_substs(db, type_, &substitution.0, cb); |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index d522d5245..613266e07 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -192,7 +192,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
192 | node: &SyntaxNode, | 192 | node: &SyntaxNode, |
193 | offset: TextSize, | 193 | offset: TextSize, |
194 | ) -> Option<N> { | 194 | ) -> Option<N> { |
195 | if let Some(it) = find_node_at_offset(&node, offset) { | 195 | if let Some(it) = find_node_at_offset(node, offset) { |
196 | return Some(it); | 196 | return Some(it); |
197 | } | 197 | } |
198 | 198 | ||
@@ -744,7 +744,7 @@ impl<'db> SemanticsImpl<'db> { | |||
744 | return None; | 744 | return None; |
745 | } | 745 | } |
746 | 746 | ||
747 | let func = self.resolve_method_call(&method_call_expr).map(Function::from)?; | 747 | let func = self.resolve_method_call(method_call_expr).map(Function::from)?; |
748 | let res = match func.self_param(self.db)?.access(self.db) { | 748 | let res = match func.self_param(self.db)?.access(self.db) { |
749 | Access::Shared | Access::Exclusive => true, | 749 | Access::Shared | Access::Exclusive => true, |
750 | Access::Owned => false, | 750 | Access::Owned => false, |
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 37a050415..c9744d81d 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
@@ -222,7 +222,7 @@ impl SourceAnalyzer { | |||
222 | Pat::Path(path) => path, | 222 | Pat::Path(path) => path, |
223 | _ => return None, | 223 | _ => return None, |
224 | }; | 224 | }; |
225 | let res = resolve_hir_path(db, &self.resolver, &path)?; | 225 | let res = resolve_hir_path(db, &self.resolver, path)?; |
226 | match res { | 226 | match res { |
227 | PathResolution::Def(def) => Some(def), | 227 | PathResolution::Def(def) => Some(def), |
228 | _ => None, | 228 | _ => None, |
@@ -329,7 +329,7 @@ impl SourceAnalyzer { | |||
329 | 329 | ||
330 | let (variant, missing_fields, _exhaustive) = | 330 | let (variant, missing_fields, _exhaustive) = |
331 | record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?; | 331 | record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?; |
332 | let res = self.missing_fields(db, krate, &substs, variant, missing_fields); | 332 | let res = self.missing_fields(db, krate, substs, variant, missing_fields); |
333 | Some(res) | 333 | Some(res) |
334 | } | 334 | } |
335 | 335 | ||
@@ -347,7 +347,7 @@ impl SourceAnalyzer { | |||
347 | 347 | ||
348 | let (variant, missing_fields, _exhaustive) = | 348 | let (variant, missing_fields, _exhaustive) = |
349 | record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?; | 349 | record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?; |
350 | let res = self.missing_fields(db, krate, &substs, variant, missing_fields); | 350 | let res = self.missing_fields(db, krate, substs, variant, missing_fields); |
351 | Some(res) | 351 | Some(res) |
352 | } | 352 | } |
353 | 353 | ||
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml index 43324d8d9..bb86f6a73 100644 --- a/crates/hir_def/Cargo.toml +++ b/crates/hir_def/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = { version = "1.1", features = ["thread-local"] } | 13 | cov-mark = "2.0.0-pre.1" |
14 | dashmap = { version = "4.0.2", features = ["raw-api"] } | 14 | dashmap = { version = "4.0.2", features = ["raw-api"] } |
15 | log = "0.4.8" | 15 | log = "0.4.8" |
16 | once_cell = "1.3.1" | 16 | once_cell = "1.3.1" |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 3886b6c04..d07adb084 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -106,7 +106,9 @@ impl RawAttrs { | |||
106 | ) -> Self { | 106 | ) -> Self { |
107 | let entries = collect_attrs(owner) | 107 | let entries = collect_attrs(owner) |
108 | .flat_map(|(id, attr)| match attr { | 108 | .flat_map(|(id, attr)| match attr { |
109 | 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 | } | ||
110 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { | 112 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { |
111 | id, | 113 | id, |
112 | input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))), | 114 | input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))), |
@@ -172,10 +174,9 @@ impl RawAttrs { | |||
172 | let index = attr.id; | 174 | let index = attr.id; |
173 | let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { | 175 | let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { |
174 | let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; | 176 | let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; |
175 | let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; | ||
176 | // FIXME hygiene | 177 | // FIXME hygiene |
177 | let hygiene = Hygiene::new_unhygienic(); | 178 | let hygiene = Hygiene::new_unhygienic(); |
178 | Attr::from_src(db, attr, &hygiene, index) | 179 | Attr::from_tt(db, &tree, &hygiene, index) |
179 | }); | 180 | }); |
180 | 181 | ||
181 | let cfg_options = &crate_graph[krate].cfg_options; | 182 | let cfg_options = &crate_graph[krate].cfg_options; |
@@ -582,13 +583,13 @@ impl AttrSourceMap { | |||
582 | .get(id.ast_index as usize) | 583 | .get(id.ast_index as usize) |
583 | .unwrap_or_else(|| panic!("cannot find doc comment at index {:?}", id)) | 584 | .unwrap_or_else(|| panic!("cannot find doc comment at index {:?}", id)) |
584 | .clone() | 585 | .clone() |
585 | .map(|attr| Either::Right(attr)) | 586 | .map(Either::Right) |
586 | } else { | 587 | } else { |
587 | self.attrs | 588 | self.attrs |
588 | .get(id.ast_index as usize) | 589 | .get(id.ast_index as usize) |
589 | .unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", id)) | 590 | .unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", id)) |
590 | .clone() | 591 | .clone() |
591 | .map(|attr| Either::Left(attr)) | 592 | .map(Either::Left) |
592 | } | 593 | } |
593 | } | 594 | } |
594 | } | 595 | } |
@@ -605,7 +606,7 @@ pub struct DocsRangeMap { | |||
605 | impl DocsRangeMap { | 606 | impl DocsRangeMap { |
606 | pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> { | 607 | pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> { |
607 | 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()?; |
608 | 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]; |
609 | if !line_docs_range.contains_range(range) { | 610 | if !line_docs_range.contains_range(range) { |
610 | return None; | 611 | return None; |
611 | } | 612 | } |
@@ -664,7 +665,7 @@ impl fmt::Display for AttrInput { | |||
664 | impl Attr { | 665 | impl Attr { |
665 | fn from_src( | 666 | fn from_src( |
666 | db: &dyn DefDatabase, | 667 | db: &dyn DefDatabase, |
667 | ast: ast::Attr, | 668 | ast: ast::Meta, |
668 | hygiene: &Hygiene, | 669 | hygiene: &Hygiene, |
669 | id: AttrId, | 670 | id: AttrId, |
670 | ) -> Option<Attr> { | 671 | ) -> Option<Attr> { |
@@ -683,6 +684,19 @@ impl Attr { | |||
683 | Some(Attr { id, path, input }) | 684 | Some(Attr { id, path, input }) |
684 | } | 685 | } |
685 | 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 | |||
686 | /// 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 |
687 | /// to derive macros. | 701 | /// to derive macros. |
688 | /// | 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; | |||
3 | use base_db::{fixture::WithFixture, SourceDatabase}; | 3 | use base_db::{fixture::WithFixture, SourceDatabase}; |
4 | use expect_test::Expect; | 4 | use expect_test::Expect; |
5 | 5 | ||
6 | use crate::{test_db::TestDB, ModuleDefId}; | 6 | use crate::ModuleDefId; |
7 | 7 | ||
8 | use super::*; | 8 | use 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 | ||
31 | fn check_diagnostics(ra_fixture: &str) { | ||
32 | let db: TestDB = TestDB::with_files(ra_fixture); | ||
33 | db.check_diagnostics(); | ||
34 | } | ||
35 | |||
36 | fn block_def_map_at(ra_fixture: &str) -> String { | 31 | fn 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) { | |||
57 | fn your_stack_belongs_to_me() { | 52 | fn 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#" |
61 | macro_rules! n_nuple { | 56 | macro_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 | } |
67 | fn main() { n_nuple!(1,2,3); } | 62 | fn 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); } | |||
73 | fn macro_resolve() { | 68 | fn 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#" |
77 | macro_rules! vec { | 72 | macro_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] | ||
92 | fn cfg_diagnostics() { | ||
93 | check_diagnostics( | ||
94 | r" | ||
95 | fn 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] | ||
125 | fn macro_diag_builtin() { | ||
126 | check_diagnostics( | ||
127 | r#" | ||
128 | #[rustc_builtin_macro] | ||
129 | macro_rules! env {} | ||
130 | |||
131 | #[rustc_builtin_macro] | ||
132 | macro_rules! include {} | ||
133 | |||
134 | #[rustc_builtin_macro] | ||
135 | macro_rules! compile_error {} | ||
136 | |||
137 | #[rustc_builtin_macro] | ||
138 | macro_rules! format_args { | ||
139 | () => {} | ||
140 | } | ||
141 | |||
142 | fn 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] | ||
169 | fn macro_rules_diag() { | ||
170 | check_diagnostics( | ||
171 | r#" | ||
172 | macro_rules! m { | ||
173 | () => {}; | ||
174 | } | ||
175 | fn f() { | ||
176 | m!(); | ||
177 | |||
178 | m!(hi); | ||
179 | //^^^^^^ leftover tokens | ||
180 | } | ||
181 | "#, | ||
182 | ); | 83 | ); |
183 | } | 84 | } |
184 | |||
185 | #[test] | ||
186 | fn unresolved_macro_diag() { | ||
187 | check_diagnostics( | ||
188 | r#" | ||
189 | fn f() { | ||
190 | m!(); | ||
191 | //^^^^ UnresolvedMacroCall | ||
192 | } | ||
193 | "#, | ||
194 | ); | ||
195 | } | ||
196 | |||
197 | #[test] | ||
198 | fn dollar_crate_in_builtin_macro() { | ||
199 | check_diagnostics( | ||
200 | r#" | ||
201 | #[macro_export] | ||
202 | #[rustc_builtin_macro] | ||
203 | macro_rules! format_args {} | ||
204 | |||
205 | #[macro_export] | ||
206 | macro_rules! arg { | ||
207 | () => {} | ||
208 | } | ||
209 | |||
210 | #[macro_export] | ||
211 | macro_rules! outer { | ||
212 | () => { | ||
213 | $crate::format_args!( "", $crate::arg!(1) ) | ||
214 | }; | ||
215 | } | ||
216 | |||
217 | fn 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#" |
166 | macro_rules! hit { | 166 | macro_rules! mark { |
167 | () => { | 167 | () => { |
168 | struct Hit {} | 168 | struct Hit {} |
169 | } | 169 | } |
170 | } | 170 | } |
171 | 171 | ||
172 | fn f() { | 172 | fn f() { |
173 | hit!(); | 173 | mark!(); |
174 | $0 | 174 | $0 |
175 | } | 175 | } |
176 | "#, | 176 | "#, |
@@ -193,20 +193,20 @@ use core::cov_mark; | |||
193 | 193 | ||
194 | fn f() { | 194 | fn 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 |
201 | pub mod cov_mark { | 201 | pub 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/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 | ||
3 | use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc}; | 3 | use std::{fmt, hash::BuildHasherDefault, sync::Arc}; |
4 | 4 | ||
5 | use base_db::CrateId; | 5 | use base_db::CrateId; |
6 | use fst::{self, Streamer}; | 6 | use fst::{self, Streamer}; |
@@ -69,81 +69,11 @@ pub struct ImportMap { | |||
69 | impl ImportMap { | 69 | impl 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 | ||
144 | fn 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 | |||
213 | impl PartialEq for ImportMap { | 222 | impl 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 | ||
242 | fn fst_path(path: &ImportPath) -> String { | 251 | fn 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 | ||
248 | fn 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)] |
255 | pub enum ImportKind { | 259 | pub 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 0f74f050d..08407ebfa 100644 --- a/crates/hir_def/src/item_scope.rs +++ b/crates/hir_def/src/item_scope.rs | |||
@@ -59,7 +59,7 @@ pub struct ItemScope { | |||
59 | pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { | 59 | pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { |
60 | BuiltinType::ALL | 60 | BuiltinType::ALL |
61 | .iter() | 61 | .iter() |
62 | .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public))) | 62 | .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public))) |
63 | .collect() | 63 | .collect() |
64 | }); | 64 | }); |
65 | 65 | ||
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index cfda7cb32..3f90bda74 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -823,7 +823,7 @@ fn is_intrinsic_fn_unsafe(name: &Name) -> bool { | |||
823 | known::type_name, | 823 | known::type_name, |
824 | known::variant_count, | 824 | known::variant_count, |
825 | ] | 825 | ] |
826 | .contains(&name) | 826 | .contains(name) |
827 | } | 827 | } |
828 | 828 | ||
829 | fn lower_abi(abi: ast::Abi) -> Interned<str> { | 829 | fn lower_abi(abi: ast::Abi) -> Interned<str> { |
@@ -855,7 +855,7 @@ impl UseTreeLowering<'_> { | |||
855 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) | 855 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) |
856 | // 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`) |
857 | Some(path) => { | 857 | Some(path) => { |
858 | match ModPath::from_src(self.db, path, &self.hygiene) { | 858 | match ModPath::from_src(self.db, path, self.hygiene) { |
859 | Some(it) => Some(it), | 859 | Some(it) => Some(it), |
860 | None => return None, // FIXME: report errors somewhere | 860 | None => return None, // FIXME: report errors somewhere |
861 | } | 861 | } |
@@ -874,7 +874,7 @@ impl UseTreeLowering<'_> { | |||
874 | } else { | 874 | } else { |
875 | let is_glob = tree.star_token().is_some(); | 875 | let is_glob = tree.star_token().is_some(); |
876 | let path = match tree.path() { | 876 | let path = match tree.path() { |
877 | Some(path) => Some(ModPath::from_src(self.db, path, &self.hygiene)?), | 877 | Some(path) => Some(ModPath::from_src(self.db, path, self.hygiene)?), |
878 | None => None, | 878 | None => None, |
879 | }; | 879 | }; |
880 | 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/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 987485acc..bb174aec8 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -112,6 +112,10 @@ impl ModuleId { | |||
112 | self.def_map(db).containing_module(self.local_id) | 112 | self.def_map(db).containing_module(self.local_id) |
113 | } | 113 | } |
114 | 114 | ||
115 | pub fn containing_block(&self) -> Option<BlockId> { | ||
116 | self.block | ||
117 | } | ||
118 | |||
115 | /// Returns `true` if this module represents a block expression. | 119 | /// Returns `true` if this module represents a block expression. |
116 | /// | 120 | /// |
117 | /// 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 |
@@ -581,6 +585,18 @@ impl HasModule for GenericDefId { | |||
581 | } | 585 | } |
582 | } | 586 | } |
583 | 587 | ||
588 | impl HasModule for TypeAliasId { | ||
589 | fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { | ||
590 | self.lookup(db).module(db) | ||
591 | } | ||
592 | } | ||
593 | |||
594 | impl HasModule for TraitId { | ||
595 | fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { | ||
596 | self.lookup(db).container | ||
597 | } | ||
598 | } | ||
599 | |||
584 | impl HasModule for StaticLoc { | 600 | impl HasModule for StaticLoc { |
585 | fn module(&self, _db: &dyn db::DefDatabase) -> ModuleId { | 601 | fn module(&self, _db: &dyn db::DefDatabase) -> ModuleId { |
586 | self.container | 602 | self.container |
@@ -731,13 +747,11 @@ fn macro_call_as_call_id( | |||
731 | ) | 747 | ) |
732 | .map(MacroCallId::from) | 748 | .map(MacroCallId::from) |
733 | } else { | 749 | } else { |
734 | Ok(def | 750 | Ok(def.as_lazy_macro( |
735 | .as_lazy_macro( | 751 | db.upcast(), |
736 | db.upcast(), | 752 | krate, |
737 | krate, | 753 | MacroCallKind::FnLike { ast_id: call.ast_id, fragment }, |
738 | MacroCallKind::FnLike { ast_id: call.ast_id, fragment }, | 754 | )) |
739 | ) | ||
740 | .into()) | ||
741 | }; | 755 | }; |
742 | Ok(res) | 756 | Ok(res) |
743 | } | 757 | } |
@@ -756,17 +770,15 @@ fn derive_macro_as_call_id( | |||
756 | .segments() | 770 | .segments() |
757 | .last() | 771 | .last() |
758 | .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?; | 772 | .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?; |
759 | let res = def | 773 | let res = def.as_lazy_macro( |
760 | .as_lazy_macro( | 774 | db.upcast(), |
761 | db.upcast(), | 775 | krate, |
762 | krate, | 776 | MacroCallKind::Derive { |
763 | MacroCallKind::Derive { | 777 | ast_id: item_attr.ast_id, |
764 | ast_id: item_attr.ast_id, | 778 | derive_name: last_segment.to_string(), |
765 | derive_name: last_segment.to_string(), | 779 | derive_attr_index: derive_attr.ast_index, |
766 | derive_attr_index: derive_attr.ast_index, | 780 | }, |
767 | }, | 781 | ); |
768 | ) | ||
769 | .into(); | ||
770 | Ok(res) | 782 | Ok(res) |
771 | } | 783 | } |
772 | 784 | ||
@@ -794,17 +806,15 @@ fn attr_macro_as_call_id( | |||
794 | // The parentheses are always disposed here. | 806 | // The parentheses are always disposed here. |
795 | arg.delimiter = None; | 807 | arg.delimiter = None; |
796 | 808 | ||
797 | let res = def | 809 | let res = def.as_lazy_macro( |
798 | .as_lazy_macro( | 810 | db.upcast(), |
799 | db.upcast(), | 811 | krate, |
800 | krate, | 812 | MacroCallKind::Attr { |
801 | MacroCallKind::Attr { | 813 | ast_id: item_attr.ast_id, |
802 | ast_id: item_attr.ast_id, | 814 | attr_name: last_segment.to_string(), |
803 | attr_name: last_segment.to_string(), | 815 | attr_args: arg, |
804 | attr_args: arg, | 816 | invoc_attr_index: macro_attr.id.ast_index, |
805 | invoc_attr_index: macro_attr.id.ast_index, | 817 | }, |
806 | }, | 818 | ); |
807 | ) | ||
808 | .into(); | ||
809 | Ok(res) | 819 | Ok(res) |
810 | } | 820 | } |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 93f30f23d..6fab58f15 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -500,7 +500,7 @@ impl DefCollector<'_> { | |||
500 | let (per_ns, _) = self.def_map.resolve_path( | 500 | let (per_ns, _) = self.def_map.resolve_path( |
501 | self.db, | 501 | self.db, |
502 | self.def_map.root, | 502 | self.def_map.root, |
503 | &path, | 503 | path, |
504 | BuiltinShadowMode::Other, | 504 | BuiltinShadowMode::Other, |
505 | ); | 505 | ); |
506 | 506 | ||
@@ -722,7 +722,7 @@ impl DefCollector<'_> { | |||
722 | if import.is_extern_crate { | 722 | if import.is_extern_crate { |
723 | let res = self.def_map.resolve_name_in_extern_prelude( | 723 | let res = self.def_map.resolve_name_in_extern_prelude( |
724 | self.db, | 724 | self.db, |
725 | &import | 725 | import |
726 | .path | 726 | .path |
727 | .as_ident() | 727 | .as_ident() |
728 | .expect("extern crate should have been desugared to one-element path"), | 728 | .expect("extern crate should have been desugared to one-element path"), |
@@ -1351,7 +1351,7 @@ impl ModCollector<'_, '_> { | |||
1351 | let imports = Import::from_use( | 1351 | let imports = Import::from_use( |
1352 | self.def_collector.db, | 1352 | self.def_collector.db, |
1353 | krate, | 1353 | krate, |
1354 | &self.item_tree, | 1354 | self.item_tree, |
1355 | ItemTreeId::new(self.file_id, import_id), | 1355 | ItemTreeId::new(self.file_id, import_id), |
1356 | ); | 1356 | ); |
1357 | self.def_collector.unresolved_imports.extend(imports.into_iter().map( | 1357 | self.def_collector.unresolved_imports.extend(imports.into_iter().map( |
@@ -1368,7 +1368,7 @@ impl ModCollector<'_, '_> { | |||
1368 | import: Import::from_extern_crate( | 1368 | import: Import::from_extern_crate( |
1369 | self.def_collector.db, | 1369 | self.def_collector.db, |
1370 | krate, | 1370 | krate, |
1371 | &self.item_tree, | 1371 | self.item_tree, |
1372 | ItemTreeId::new(self.file_id, import_id), | 1372 | ItemTreeId::new(self.file_id, import_id), |
1373 | ), | 1373 | ), |
1374 | status: PartialResolvedImport::Unresolved, | 1374 | status: PartialResolvedImport::Unresolved, |
@@ -1889,7 +1889,7 @@ impl ModCollector<'_, '_> { | |||
1889 | self.def_collector.def_map.with_ancestor_maps( | 1889 | self.def_collector.def_map.with_ancestor_maps( |
1890 | self.def_collector.db, | 1890 | self.def_collector.db, |
1891 | self.module_id, | 1891 | self.module_id, |
1892 | &mut |map, module| map[module].scope.get_legacy_macro(&name), | 1892 | &mut |map, module| map[module].scope.get_legacy_macro(name), |
1893 | ) | 1893 | ) |
1894 | }) | 1894 | }) |
1895 | }, | 1895 | }, |
@@ -1993,7 +1993,7 @@ mod tests { | |||
1993 | } | 1993 | } |
1994 | 1994 | ||
1995 | fn do_resolve(code: &str) -> DefMap { | 1995 | fn do_resolve(code: &str) -> DefMap { |
1996 | let (db, _file_id) = TestDB::with_single_file(&code); | 1996 | let (db, _file_id) = TestDB::with_single_file(code); |
1997 | let krate = db.test_crate(); | 1997 | let krate = db.test_crate(); |
1998 | 1998 | ||
1999 | 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; | |||
2 | mod incremental; | 2 | mod incremental; |
3 | mod macros; | 3 | mod macros; |
4 | mod mod_resolution; | 4 | mod mod_resolution; |
5 | mod diagnostics; | ||
6 | mod primitives; | 5 | mod primitives; |
7 | 6 | ||
8 | use std::sync::Arc; | 7 | use 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 @@ | |||
1 | use base_db::fixture::WithFixture; | ||
2 | |||
3 | use crate::test_db::TestDB; | ||
4 | |||
5 | fn check_diagnostics(ra_fixture: &str) { | ||
6 | let db: TestDB = TestDB::with_files(ra_fixture); | ||
7 | db.check_diagnostics(); | ||
8 | } | ||
9 | |||
10 | fn check_no_diagnostics(ra_fixture: &str) { | ||
11 | let db: TestDB = TestDB::with_files(ra_fixture); | ||
12 | db.check_no_diagnostics(); | ||
13 | } | ||
14 | |||
15 | #[test] | ||
16 | fn 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] | ||
29 | fn 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] | ||
42 | fn 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] | ||
58 | fn 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] | ||
82 | fn 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] | ||
96 | fn 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] | ||
119 | fn 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] | ||
138 | fn 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] | ||
152 | fn 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] | ||
169 | fn 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] | ||
183 | fn 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] | ||
198 | fn 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] | ||
215 | fn 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] | ||
225 | struct 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 b20b066e2..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 | ||
8 | use base_db::{ | 8 | use base_db::{ |
9 | salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition, FileRange, Upcast, | 9 | salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition, |
10 | SourceDatabase, Upcast, | ||
10 | }; | 11 | }; |
11 | use base_db::{AnchoredPath, SourceDatabase}; | ||
12 | use hir_expand::{db::AstDatabase, InFile}; | 12 | use hir_expand::{db::AstDatabase, InFile}; |
13 | use rustc_hash::FxHashMap; | ||
14 | use rustc_hash::FxHashSet; | 13 | use rustc_hash::FxHashSet; |
15 | use syntax::{algo, ast, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize}; | 14 | use syntax::{algo, ast, AstNode}; |
16 | use test_utils::extract_annotations; | ||
17 | 15 | ||
18 | use crate::{ | 16 | use 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 | }; |
@@ -245,145 +242,4 @@ impl TestDB { | |||
245 | }) | 242 | }) |
246 | .collect() | 243 | .collect() |
247 | } | 244 | } |
248 | |||
249 | pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> { | ||
250 | let mut files = Vec::new(); | ||
251 | let crate_graph = self.crate_graph(); | ||
252 | for krate in crate_graph.iter() { | ||
253 | let crate_def_map = self.crate_def_map(krate); | ||
254 | for (module_id, _) in crate_def_map.modules() { | ||
255 | let file_id = crate_def_map[module_id].origin.file_id(); | ||
256 | files.extend(file_id) | ||
257 | } | ||
258 | } | ||
259 | assert!(!files.is_empty()); | ||
260 | files | ||
261 | .into_iter() | ||
262 | .filter_map(|file_id| { | ||
263 | let text = self.file_text(file_id); | ||
264 | let annotations = extract_annotations(&text); | ||
265 | if annotations.is_empty() { | ||
266 | return None; | ||
267 | } | ||
268 | Some((file_id, annotations)) | ||
269 | }) | ||
270 | .collect() | ||
271 | } | ||
272 | |||
273 | pub(crate) fn diagnostics(&self, cb: &mut dyn FnMut(FileRange, String)) { | ||
274 | let crate_graph = self.crate_graph(); | ||
275 | for krate in crate_graph.iter() { | ||
276 | let crate_def_map = self.crate_def_map(krate); | ||
277 | |||
278 | for diag in crate_def_map.diagnostics() { | ||
279 | let (node, message): (InFile<SyntaxNode>, &str) = match &diag.kind { | ||
280 | DefDiagnosticKind::UnresolvedModule { ast, .. } => { | ||
281 | let node = ast.to_node(self.upcast()); | ||
282 | (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedModule") | ||
283 | } | ||
284 | DefDiagnosticKind::UnresolvedExternCrate { ast, .. } => { | ||
285 | let node = ast.to_node(self.upcast()); | ||
286 | (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedExternCrate") | ||
287 | } | ||
288 | DefDiagnosticKind::UnresolvedImport { id, .. } => { | ||
289 | let item_tree = id.item_tree(self.upcast()); | ||
290 | let import = &item_tree[id.value]; | ||
291 | let node = InFile::new(id.file_id(), import.ast_id).to_node(self.upcast()); | ||
292 | (InFile::new(id.file_id(), node.syntax().clone()), "UnresolvedImport") | ||
293 | } | ||
294 | DefDiagnosticKind::UnconfiguredCode { ast, .. } => { | ||
295 | let node = ast.to_node(self.upcast()); | ||
296 | (InFile::new(ast.file_id, node.syntax().clone()), "UnconfiguredCode") | ||
297 | } | ||
298 | DefDiagnosticKind::UnresolvedProcMacro { ast, .. } => { | ||
299 | (ast.to_node(self.upcast()), "UnresolvedProcMacro") | ||
300 | } | ||
301 | DefDiagnosticKind::UnresolvedMacroCall { ast, .. } => { | ||
302 | let node = ast.to_node(self.upcast()); | ||
303 | (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedMacroCall") | ||
304 | } | ||
305 | DefDiagnosticKind::MacroError { ast, message } => { | ||
306 | (ast.to_node(self.upcast()), message.as_str()) | ||
307 | } | ||
308 | DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { | ||
309 | let node = ast.to_node(self.upcast()); | ||
310 | ( | ||
311 | InFile::new(ast.file_id, node.syntax().clone()), | ||
312 | "UnimplementedBuiltinMacro", | ||
313 | ) | ||
314 | } | ||
315 | }; | ||
316 | |||
317 | let frange = node.as_ref().original_file_range(self); | ||
318 | cb(frange, message.to_string()) | ||
319 | } | ||
320 | |||
321 | for (_module_id, module) in crate_def_map.modules() { | ||
322 | for decl in module.scope.declarations() { | ||
323 | if let ModuleDefId::FunctionId(it) = decl { | ||
324 | let source_map = self.body_with_source_map(it.into()).1; | ||
325 | for diag in source_map.diagnostics() { | ||
326 | let (ptr, message): (InFile<SyntaxNodePtr>, &str) = match diag { | ||
327 | BodyDiagnostic::InactiveCode { node, .. } => { | ||
328 | (node.clone().map(|it| it.into()), "InactiveCode") | ||
329 | } | ||
330 | BodyDiagnostic::MacroError { node, message } => { | ||
331 | (node.clone().map(|it| it.into()), message.as_str()) | ||
332 | } | ||
333 | BodyDiagnostic::UnresolvedProcMacro { node } => { | ||
334 | (node.clone().map(|it| it.into()), "UnresolvedProcMacro") | ||
335 | } | ||
336 | BodyDiagnostic::UnresolvedMacroCall { node, .. } => { | ||
337 | (node.clone().map(|it| it.into()), "UnresolvedMacroCall") | ||
338 | } | ||
339 | }; | ||
340 | |||
341 | let root = self.parse_or_expand(ptr.file_id).unwrap(); | ||
342 | let node = ptr.map(|ptr| ptr.to_node(&root)); | ||
343 | let frange = node.as_ref().original_file_range(self); | ||
344 | cb(frange, message.to_string()) | ||
345 | } | ||
346 | } | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | } | ||
351 | |||
352 | pub(crate) fn check_diagnostics(&self) { | ||
353 | let db: &TestDB = self; | ||
354 | let annotations = db.extract_annotations(); | ||
355 | assert!(!annotations.is_empty()); | ||
356 | |||
357 | let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); | ||
358 | db.diagnostics(&mut |frange, message| { | ||
359 | actual.entry(frange.file_id).or_default().push((frange.range, message)); | ||
360 | }); | ||
361 | |||
362 | for (file_id, diags) in actual.iter_mut() { | ||
363 | diags.sort_by_key(|it| it.0.start()); | ||
364 | let text = db.file_text(*file_id); | ||
365 | // For multiline spans, place them on line start | ||
366 | for (range, content) in diags { | ||
367 | if text[*range].contains('\n') { | ||
368 | *range = TextRange::new(range.start(), range.start() + TextSize::from(1)); | ||
369 | *content = format!("... {}", content); | ||
370 | } | ||
371 | } | ||
372 | } | ||
373 | |||
374 | assert_eq!(annotations, actual); | ||
375 | } | ||
376 | |||
377 | pub(crate) fn check_no_diagnostics(&self) { | ||
378 | let db: &TestDB = self; | ||
379 | let annotations = db.extract_annotations(); | ||
380 | assert!(annotations.is_empty()); | ||
381 | |||
382 | let mut has_diagnostics = false; | ||
383 | db.diagnostics(&mut |_, _| { | ||
384 | has_diagnostics = true; | ||
385 | }); | ||
386 | |||
387 | assert!(!has_diagnostics); | ||
388 | } | ||
389 | } | 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(<)); | 166 | let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(<)); |
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() { |
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs index fe9497b50..4610f6f91 100644 --- a/crates/hir_expand/src/builtin_derive.rs +++ b/crates/hir_expand/src/builtin_derive.rs | |||
@@ -325,7 +325,7 @@ $0 | |||
325 | }, | 325 | }, |
326 | }; | 326 | }; |
327 | 327 | ||
328 | let id: MacroCallId = db.intern_macro(loc).into(); | 328 | let id: MacroCallId = db.intern_macro(loc); |
329 | let parsed = db.parse_or_expand(id.as_file()).unwrap(); | 329 | let parsed = db.parse_or_expand(id.as_file()).unwrap(); |
330 | 330 | ||
331 | // FIXME text() for syntax nodes parsed from token tree looks weird | 331 | // FIXME text() for syntax nodes parsed from token tree looks weird |
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index 0b310ba2f..f24d1d919 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs | |||
@@ -354,7 +354,7 @@ fn concat_expand( | |||
354 | // concat works with string and char literals, so remove any quotes. | 354 | // concat works with string and char literals, so remove any quotes. |
355 | // It also works with integer, float and boolean literals, so just use the rest | 355 | // It also works with integer, float and boolean literals, so just use the rest |
356 | // as-is. | 356 | // as-is. |
357 | let component = unquote_str(&it).unwrap_or_else(|| it.text.to_string()); | 357 | let component = unquote_str(it).unwrap_or_else(|| it.text.to_string()); |
358 | text.push_str(&component); | 358 | text.push_str(&component); |
359 | } | 359 | } |
360 | // handle boolean literals | 360 | // handle boolean literals |
@@ -417,7 +417,7 @@ fn parse_string(tt: &tt::Subtree) -> Result<String, mbe::ExpandError> { | |||
417 | tt.token_trees | 417 | tt.token_trees |
418 | .get(0) | 418 | .get(0) |
419 | .and_then(|tt| match tt { | 419 | .and_then(|tt| match tt { |
420 | tt::TokenTree::Leaf(tt::Leaf::Literal(it)) => unquote_str(&it), | 420 | tt::TokenTree::Leaf(tt::Leaf::Literal(it)) => unquote_str(it), |
421 | _ => None, | 421 | _ => None, |
422 | }) | 422 | }) |
423 | .ok_or_else(|| mbe::ExpandError::ConversionError) | 423 | .ok_or_else(|| mbe::ExpandError::ConversionError) |
@@ -430,7 +430,7 @@ fn include_expand( | |||
430 | ) -> ExpandResult<Option<ExpandedEager>> { | 430 | ) -> ExpandResult<Option<ExpandedEager>> { |
431 | let res = (|| { | 431 | let res = (|| { |
432 | let path = parse_string(tt)?; | 432 | let path = parse_string(tt)?; |
433 | let file_id = relative_file(db, arg_id.into(), &path, false)?; | 433 | let file_id = relative_file(db, arg_id, &path, false)?; |
434 | 434 | ||
435 | let subtree = parse_to_token_tree(&db.file_text(file_id)) | 435 | let subtree = parse_to_token_tree(&db.file_text(file_id)) |
436 | .ok_or_else(|| mbe::ExpandError::ConversionError)? | 436 | .ok_or_else(|| mbe::ExpandError::ConversionError)? |
@@ -480,7 +480,7 @@ fn include_str_expand( | |||
480 | // it's unusual to `include_str!` a Rust file), but we can return an empty string. | 480 | // it's unusual to `include_str!` a Rust file), but we can return an empty string. |
481 | // Ideally, we'd be able to offer a precise expansion if the user asks for macro | 481 | // Ideally, we'd be able to offer a precise expansion if the user asks for macro |
482 | // expansion. | 482 | // expansion. |
483 | let file_id = match relative_file(db, arg_id.into(), &path, true) { | 483 | let file_id = match relative_file(db, arg_id, &path, true) { |
484 | Ok(file_id) => file_id, | 484 | Ok(file_id) => file_id, |
485 | Err(_) => { | 485 | Err(_) => { |
486 | return ExpandResult::ok(Some(ExpandedEager::new(quote!("")))); | 486 | return ExpandResult::ok(Some(ExpandedEager::new(quote!("")))); |
@@ -561,7 +561,7 @@ mod tests { | |||
561 | use syntax::ast::NameOwner; | 561 | use syntax::ast::NameOwner; |
562 | 562 | ||
563 | fn expand_builtin_macro(ra_fixture: &str) -> String { | 563 | fn expand_builtin_macro(ra_fixture: &str) -> String { |
564 | let (db, file_id) = TestDB::with_single_file(&ra_fixture); | 564 | let (db, file_id) = TestDB::with_single_file(ra_fixture); |
565 | let parsed = db.parse(file_id); | 565 | let parsed = db.parse(file_id); |
566 | let mut macro_rules: Vec<_> = | 566 | let mut macro_rules: Vec<_> = |
567 | parsed.syntax_node().descendants().filter_map(ast::MacroRules::cast).collect(); | 567 | parsed.syntax_node().descendants().filter_map(ast::MacroRules::cast).collect(); |
@@ -598,7 +598,7 @@ mod tests { | |||
598 | }, | 598 | }, |
599 | }; | 599 | }; |
600 | 600 | ||
601 | let id: MacroCallId = db.intern_macro(loc).into(); | 601 | let id: MacroCallId = db.intern_macro(loc); |
602 | id.as_file() | 602 | id.as_file() |
603 | } | 603 | } |
604 | Either::Right(expander) => { | 604 | Either::Right(expander) => { |
@@ -635,7 +635,7 @@ mod tests { | |||
635 | kind: MacroCallKind::FnLike { ast_id: call_id, fragment }, | 635 | kind: MacroCallKind::FnLike { ast_id: call_id, fragment }, |
636 | }; | 636 | }; |
637 | 637 | ||
638 | let id: MacroCallId = db.intern_macro(loc).into(); | 638 | let id: MacroCallId = db.intern_macro(loc); |
639 | id.as_file() | 639 | id.as_file() |
640 | } | 640 | } |
641 | }; | 641 | }; |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 45e6e446a..66f44202b 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -57,7 +57,7 @@ impl TokenExpander { | |||
57 | // We store the result in salsa db to prevent non-deterministic behavior in | 57 | // We store the result in salsa db to prevent non-deterministic behavior in |
58 | // some proc-macro implementation | 58 | // some proc-macro implementation |
59 | // See #4315 for details | 59 | // See #4315 for details |
60 | db.expand_proc_macro(id.into()).into() | 60 | db.expand_proc_macro(id).into() |
61 | } | 61 | } |
62 | } | 62 | } |
63 | } | 63 | } |
@@ -241,7 +241,7 @@ fn parse_macro_expansion( | |||
241 | } | 241 | } |
242 | }; | 242 | }; |
243 | if is_self_replicating(&node, &call_node.value) { | 243 | if is_self_replicating(&node, &call_node.value) { |
244 | return ExpandResult::only_err(err); | 244 | ExpandResult::only_err(err) |
245 | } else { | 245 | } else { |
246 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) } | 246 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) } |
247 | } | 247 | } |
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index c25ce7634..584ddcf9f 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs | |||
@@ -128,7 +128,7 @@ pub fn expand_eager_macro( | |||
128 | }), | 128 | }), |
129 | kind: MacroCallKind::FnLike { ast_id: call_id, fragment: FragmentKind::Expr }, | 129 | kind: MacroCallKind::FnLike { ast_id: call_id, fragment: FragmentKind::Expr }, |
130 | }); | 130 | }); |
131 | let arg_file_id: MacroCallId = arg_id.into(); | 131 | let arg_file_id: MacroCallId = arg_id; |
132 | 132 | ||
133 | let parsed_args = | 133 | let parsed_args = |
134 | diagnostic_sink.result(mbe::token_tree_to_syntax_node(&parsed_args, FragmentKind::Expr))?.0; | 134 | diagnostic_sink.result(mbe::token_tree_to_syntax_node(&parsed_args, FragmentKind::Expr))?.0; |
@@ -177,13 +177,11 @@ fn lazy_expand( | |||
177 | let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); | 177 | let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); |
178 | 178 | ||
179 | let fragment = crate::to_fragment_kind(¯o_call.value); | 179 | let fragment = crate::to_fragment_kind(¯o_call.value); |
180 | let id: MacroCallId = def | 180 | let id: MacroCallId = def.as_lazy_macro( |
181 | .as_lazy_macro( | 181 | db, |
182 | db, | 182 | krate, |
183 | krate, |