diff options
Diffstat (limited to 'crates/hir')
-rw-r--r-- | crates/hir/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/hir/src/diagnostics.rs | 297 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 407 | ||||
-rw-r--r-- | crates/hir/src/semantics.rs | 109 | ||||
-rw-r--r-- | crates/hir/src/semantics/source_to_def.rs | 121 | ||||
-rw-r--r-- | crates/hir/src/source_analyzer.rs | 6 |
6 files changed, 572 insertions, 369 deletions
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 d3ef29db4..5bc0b2338 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -15,7 +15,7 @@ | |||
15 | //! | 15 | //! |
16 | //! `hir` is what insulates the "we don't know how to actually write an incremental compiler" | 16 | //! `hir` is what insulates the "we don't know how to actually write an incremental compiler" |
17 | //! from the ide with completions, hovers, etc. It is a (soft, internal) boundary: | 17 | //! from the ide with completions, hovers, etc. It is a (soft, internal) boundary: |
18 | //! https://www.tedinski.com/2018/02/06/system-boundaries.html. | 18 | //! <https://www.tedinski.com/2018/02/06/system-boundaries.html>. |
19 | 19 | ||
20 | #![recursion_limit = "512"] | 20 | #![recursion_limit = "512"] |
21 | 21 | ||
@@ -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, |
@@ -50,7 +46,6 @@ use hir_def::{ | |||
50 | per_ns::PerNs, | 46 | per_ns::PerNs, |
51 | resolver::{HasResolver, Resolver}, | 47 | resolver::{HasResolver, Resolver}, |
52 | src::HasSource as _, | 48 | src::HasSource as _, |
53 | type_ref::TraitRef, | ||
54 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, | 49 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, |
55 | DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, | 50 | DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, |
56 | LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, | 51 | LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, |
@@ -61,8 +56,8 @@ use hir_ty::{ | |||
61 | autoderef, | 56 | autoderef, |
62 | consteval::ConstExt, | 57 | consteval::ConstExt, |
63 | could_unify, | 58 | could_unify, |
64 | diagnostics_sink::DiagnosticSink, | 59 | diagnostics::BodyValidationDiagnostic, |
65 | method_resolution::{self, def_crates, TyFingerprint}, | 60 | method_resolution::{self, TyFingerprint}, |
66 | primitive::UintTy, | 61 | primitive::UintTy, |
67 | subst_prefix, | 62 | subst_prefix, |
68 | traits::FnTrait, | 63 | traits::FnTrait, |
@@ -73,6 +68,7 @@ use hir_ty::{ | |||
73 | }; | 68 | }; |
74 | use itertools::Itertools; | 69 | use itertools::Itertools; |
75 | use nameres::diagnostics::DefDiagnosticKind; | 70 | use nameres::diagnostics::DefDiagnosticKind; |
71 | use once_cell::unsync::Lazy; | ||
76 | use rustc_hash::FxHashSet; | 72 | use rustc_hash::FxHashSet; |
77 | use stdx::{format_to, impl_from}; | 73 | use stdx::{format_to, impl_from}; |
78 | use syntax::{ | 74 | use syntax::{ |
@@ -85,6 +81,13 @@ use crate::db::{DefDatabase, HirDatabase}; | |||
85 | 81 | ||
86 | pub use crate::{ | 82 | pub use crate::{ |
87 | 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 | }, | ||
88 | has_source::HasSource, | 91 | has_source::HasSource, |
89 | semantics::{PathResolution, Semantics, SemanticsScope}, | 92 | semantics::{PathResolution, Semantics, SemanticsScope}, |
90 | }; | 93 | }; |
@@ -192,6 +195,7 @@ impl Crate { | |||
192 | db: &dyn DefDatabase, | 195 | db: &dyn DefDatabase, |
193 | query: import_map::Query, | 196 | query: import_map::Query, |
194 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 197 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { |
198 | let _p = profile::span("query_external_importables"); | ||
195 | 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 { |
196 | 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()), |
197 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), | 201 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), |
@@ -332,7 +336,7 @@ impl ModuleDef { | |||
332 | } | 336 | } |
333 | } | 337 | } |
334 | 338 | ||
335 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 339 | pub fn diagnostics(self, db: &dyn HirDatabase) -> Vec<AnyDiagnostic> { |
336 | let id = match self { | 340 | let id = match self { |
337 | ModuleDef::Adt(it) => match it { | 341 | ModuleDef::Adt(it) => match it { |
338 | Adt::Struct(it) => it.id.into(), | 342 | Adt::Struct(it) => it.id.into(), |
@@ -345,15 +349,19 @@ impl ModuleDef { | |||
345 | ModuleDef::Module(it) => it.id.into(), | 349 | ModuleDef::Module(it) => it.id.into(), |
346 | ModuleDef::Const(it) => it.id.into(), | 350 | ModuleDef::Const(it) => it.id.into(), |
347 | ModuleDef::Static(it) => it.id.into(), | 351 | ModuleDef::Static(it) => it.id.into(), |
348 | _ => return, | 352 | _ => return Vec::new(), |
349 | }; | 353 | }; |
350 | 354 | ||
351 | let module = match self.module(db) { | 355 | let module = match self.module(db) { |
352 | Some(it) => it, | 356 | Some(it) => it, |
353 | None => return, | 357 | None => return Vec::new(), |
354 | }; | 358 | }; |
355 | 359 | ||
356 | 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 | ||
357 | } | 365 | } |
358 | } | 366 | } |
359 | 367 | ||
@@ -442,10 +450,10 @@ impl Module { | |||
442 | } | 450 | } |
443 | 451 | ||
444 | 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> { |
445 | 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()) |
446 | } | 454 | } |
447 | 455 | ||
448 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 456 | pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) { |
449 | let _p = profile::span("Module::diagnostics").detail(|| { | 457 | let _p = profile::span("Module::diagnostics").detail(|| { |
450 | 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())) |
451 | }); | 459 | }); |
@@ -458,18 +466,22 @@ impl Module { | |||
458 | match &diag.kind { | 466 | match &diag.kind { |
459 | DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => { | 467 | DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => { |
460 | let decl = declaration.to_node(db.upcast()); | 468 | let decl = declaration.to_node(db.upcast()); |
461 | sink.push(UnresolvedModule { | 469 | acc.push( |
462 | file: declaration.file_id, | 470 | UnresolvedModule { |
463 | decl: AstPtr::new(&decl), | 471 | decl: InFile::new(declaration.file_id, AstPtr::new(&decl)), |
464 | candidate: candidate.clone(), | 472 | candidate: candidate.clone(), |
465 | }) | 473 | } |
474 | .into(), | ||
475 | ) | ||
466 | } | 476 | } |
467 | DefDiagnosticKind::UnresolvedExternCrate { ast } => { | 477 | DefDiagnosticKind::UnresolvedExternCrate { ast } => { |
468 | let item = ast.to_node(db.upcast()); | 478 | let item = ast.to_node(db.upcast()); |
469 | sink.push(UnresolvedExternCrate { | 479 | acc.push( |
470 | file: ast.file_id, | 480 | UnresolvedExternCrate { |
471 | item: AstPtr::new(&item), | 481 | decl: InFile::new(ast.file_id, AstPtr::new(&item)), |
472 | }); | 482 | } |
483 | .into(), | ||
484 | ); | ||
473 | } | 485 | } |
474 | 486 | ||
475 | DefDiagnosticKind::UnresolvedImport { id, index } => { | 487 | DefDiagnosticKind::UnresolvedImport { id, index } => { |
@@ -478,25 +490,30 @@ impl Module { | |||
478 | let import = &item_tree[id.value]; | 490 | let import = &item_tree[id.value]; |
479 | 491 | ||
480 | 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); |
481 | 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 | ); | ||
482 | } | 497 | } |
483 | 498 | ||
484 | DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => { | 499 | DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => { |
485 | let item = ast.to_node(db.upcast()); | 500 | let item = ast.to_node(db.upcast()); |
486 | sink.push(InactiveCode { | 501 | acc.push( |
487 | file: ast.file_id, | 502 | InactiveCode { |
488 | node: AstPtr::new(&item).into(), | 503 | node: ast.with_value(AstPtr::new(&item).into()), |
489 | cfg: cfg.clone(), | 504 | cfg: cfg.clone(), |
490 | opts: opts.clone(), | 505 | opts: opts.clone(), |
491 | }); | 506 | } |
507 | .into(), | ||
508 | ); | ||
492 | } | 509 | } |
493 | 510 | ||
494 | DefDiagnosticKind::UnresolvedProcMacro { ast } => { | 511 | DefDiagnosticKind::UnresolvedProcMacro { ast } => { |
495 | let mut precise_location = None; | 512 | let mut precise_location = None; |
496 | let (file, ast, name) = match ast { | 513 | let (node, name) = match ast { |
497 | MacroCallKind::FnLike { ast_id, .. } => { | 514 | MacroCallKind::FnLike { ast_id, .. } => { |
498 | let node = ast_id.to_node(db.upcast()); | 515 | let node = ast_id.to_node(db.upcast()); |
499 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None) | 516 | (ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), None) |
500 | } | 517 | } |
501 | MacroCallKind::Derive { ast_id, derive_name, .. } => { | 518 | MacroCallKind::Derive { ast_id, derive_name, .. } => { |
502 | let node = ast_id.to_node(db.upcast()); | 519 | let node = ast_id.to_node(db.upcast()); |
@@ -529,71 +546,84 @@ impl Module { | |||
529 | } | 546 | } |
530 | 547 | ||
531 | ( | 548 | ( |
532 | ast_id.file_id, | 549 | ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), |
533 | SyntaxNodePtr::from(AstPtr::new(&node)), | ||
534 | Some(derive_name.clone()), | 550 | Some(derive_name.clone()), |
535 | ) | 551 | ) |
536 | } | 552 | } |
553 | MacroCallKind::Attr { ast_id, invoc_attr_index, attr_name, .. } => { | ||
554 | let node = ast_id.to_node(db.upcast()); | ||
555 | let attr = | ||
556 | node.attrs().nth((*invoc_attr_index) as usize).unwrap_or_else( | ||
557 | || panic!("cannot find attribute #{}", invoc_attr_index), | ||
558 | ); | ||
559 | ( | ||
560 | ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))), | ||
561 | Some(attr_name.clone()), | ||
562 | ) | ||
563 | } | ||
537 | }; | 564 | }; |
538 | sink.push(UnresolvedProcMacro { | 565 | acc.push( |
539 | file, | 566 | UnresolvedProcMacro { node, precise_location, macro_name: name }.into(), |
540 | node: ast, | 567 | ); |
541 | precise_location, | ||
542 | macro_name: name, | ||
543 | }); | ||
544 | } | 568 | } |
545 | 569 | ||
546 | DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { | 570 | DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { |
547 | let node = ast.to_node(db.upcast()); | 571 | let node = ast.to_node(db.upcast()); |
548 | sink.push(UnresolvedMacroCall { | 572 | acc.push( |
549 | file: ast.file_id, | 573 | UnresolvedMacroCall { |
550 | node: AstPtr::new(&node), | 574 | macro_call: InFile::new(ast.file_id, AstPtr::new(&node)), |
551 | path: path.clone(), | 575 | path: path.clone(), |
552 | }); | 576 | } |
577 | .into(), | ||
578 | ); | ||
553 | } | 579 | } |
554 | 580 | ||
555 | DefDiagnosticKind::MacroError { ast, message } => { | 581 | DefDiagnosticKind::MacroError { ast, message } => { |
556 | let (file, ast) = match ast { | 582 | let node = match ast { |
557 | MacroCallKind::FnLike { ast_id, .. } => { | 583 | MacroCallKind::FnLike { ast_id, .. } => { |
558 | let node = ast_id.to_node(db.upcast()); | 584 | let node = ast_id.to_node(db.upcast()); |
559 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) | 585 | ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))) |
560 | } | 586 | } |
561 | MacroCallKind::Derive { ast_id, .. } => { | 587 | MacroCallKind::Derive { ast_id, .. } |
588 | | MacroCallKind::Attr { ast_id, .. } => { | ||
589 | // FIXME: point to the attribute instead, this creates very large diagnostics | ||
562 | let node = ast_id.to_node(db.upcast()); | 590 | let node = ast_id.to_node(db.upcast()); |
563 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) | 591 | ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))) |
564 | } | 592 | } |
565 | }; | 593 | }; |
566 | sink.push(MacroError { file, node: ast, message: message.clone() }); | 594 | acc.push(MacroError { node, message: message.clone() }.into()); |
567 | } | 595 | } |
568 | 596 | ||
569 | DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { | 597 | DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { |
570 | let node = ast.to_node(db.upcast()); | 598 | let node = ast.to_node(db.upcast()); |
571 | // Must have a name, otherwise we wouldn't emit it. | 599 | // Must have a name, otherwise we wouldn't emit it. |
572 | let name = node.name().expect("unimplemented builtin macro with no name"); | 600 | let name = node.name().expect("unimplemented builtin macro with no name"); |
573 | let ptr = SyntaxNodePtr::from(AstPtr::new(&name)); | 601 | acc.push( |
574 | 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 | ); | ||
575 | } | 607 | } |
576 | } | 608 | } |
577 | } | 609 | } |
578 | for decl in self.declarations(db) { | 610 | for decl in self.declarations(db) { |
579 | match decl { | 611 | match decl { |
580 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), | 612 | ModuleDef::Function(f) => f.diagnostics(db, acc), |
581 | crate::ModuleDef::Module(m) => { | 613 | ModuleDef::Module(m) => { |
582 | // Only add diagnostics from inline modules | 614 | // Only add diagnostics from inline modules |
583 | if def_map[m.id.local_id].origin.is_inline() { | 615 | if def_map[m.id.local_id].origin.is_inline() { |
584 | m.diagnostics(db, sink) | 616 | m.diagnostics(db, acc) |
585 | } | 617 | } |
586 | } | 618 | } |
587 | _ => { | 619 | _ => acc.extend(decl.diagnostics(db)), |
588 | decl.diagnostics(db, sink); | ||
589 | } | ||
590 | } | 620 | } |
591 | } | 621 | } |
592 | 622 | ||
593 | for impl_def in self.impl_defs(db) { | 623 | for impl_def in self.impl_defs(db) { |
594 | for item in impl_def.items(db) { | 624 | for item in impl_def.items(db) { |
595 | if let AssocItem::Function(f) = item { | 625 | if let AssocItem::Function(f) = item { |
596 | f.diagnostics(db, sink); | 626 | f.diagnostics(db, acc); |
597 | } | 627 | } |
598 | } | 628 | } |
599 | } | 629 | } |
@@ -995,41 +1025,191 @@ impl Function { | |||
995 | db.function_data(self.id).is_async() | 1025 | db.function_data(self.id).is_async() |
996 | } | 1026 | } |
997 | 1027 | ||
998 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 1028 | pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) { |
999 | let krate = self.module(db).id.krate(); | 1029 | let krate = self.module(db).id.krate(); |
1000 | 1030 | ||
1001 | 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; |
1002 | for diag in source_map.diagnostics() { | 1032 | for diag in source_map.diagnostics() { |
1003 | match diag { | 1033 | match diag { |
1004 | BodyDiagnostic::InactiveCode { node, cfg, opts } => sink.push(InactiveCode { | 1034 | BodyDiagnostic::InactiveCode { node, cfg, opts } => acc.push( |
1005 | file: node.file_id, | 1035 | InactiveCode { node: node.clone(), cfg: cfg.clone(), opts: opts.clone() } |
1006 | node: node.value.clone(), | 1036 | .into(), |
1007 | cfg: cfg.clone(), | 1037 | ), |
1008 | opts: opts.clone(), | 1038 | BodyDiagnostic::MacroError { node, message } => acc.push( |
1009 | }), | 1039 | MacroError { |
1010 | BodyDiagnostic::MacroError { node, message } => sink.push(MacroError { | 1040 | node: node.clone().map(|it| it.into()), |
1011 | file: node.file_id, | 1041 | message: message.to_string(), |
1012 | node: node.value.clone().into(), | 1042 | } |
1013 | message: message.to_string(), | 1043 | .into(), |
1014 | }), | 1044 | ), |
1015 | BodyDiagnostic::UnresolvedProcMacro { node } => sink.push(UnresolvedProcMacro { | 1045 | BodyDiagnostic::UnresolvedProcMacro { node } => acc.push( |
1016 | file: node.file_id, | 1046 | UnresolvedProcMacro { |
1017 | node: node.value.clone().into(), | 1047 | node: node.clone().map(|it| it.into()), |
1018 | precise_location: None, | 1048 | precise_location: None, |
1019 | macro_name: None, | 1049 | macro_name: None, |
1020 | }), | 1050 | } |
1021 | BodyDiagnostic::UnresolvedMacroCall { node, path } => { | 1051 | .into(), |
1022 | sink.push(UnresolvedMacroCall { | 1052 | ), |
1023 | file: node.file_id, | 1053 | BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push( |
1024 | node: node.value.clone(), | 1054 | UnresolvedMacroCall { macro_call: node.clone(), path: path.clone() }.into(), |
1025 | path: path.clone(), | 1055 | ), |
1026 | }) | 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 | } | ||
1027 | } | 1206 | } |
1028 | } | 1207 | } |
1029 | } | 1208 | } |
1030 | 1209 | ||
1031 | 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()) { |
1032 | hir_ty::diagnostics::validate_body(db, self.id.into(), sink); | 1211 | acc.push(diag.into()) |
1212 | } | ||
1033 | } | 1213 | } |
1034 | 1214 | ||
1035 | /// Whether this function declaration has a definition. | 1215 | /// Whether this function declaration has a definition. |
@@ -1331,6 +1511,7 @@ impl MacroDef { | |||
1331 | MacroDefKind::Declarative(_) => MacroKind::Declarative, | 1511 | MacroDefKind::Declarative(_) => MacroKind::Declarative, |
1332 | MacroDefKind::BuiltIn(_, _) | MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn, | 1512 | MacroDefKind::BuiltIn(_, _) | MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn, |
1333 | MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive, | 1513 | MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive, |
1514 | MacroDefKind::BuiltInAttr(_, _) => MacroKind::Attr, | ||
1334 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::CustomDerive, _) => { | 1515 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::CustomDerive, _) => { |
1335 | MacroKind::Derive | 1516 | MacroKind::Derive |
1336 | } | 1517 | } |
@@ -1338,6 +1519,13 @@ impl MacroDef { | |||
1338 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::FuncLike, _) => MacroKind::ProcMacro, | 1519 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::FuncLike, _) => MacroKind::ProcMacro, |
1339 | } | 1520 | } |
1340 | } | 1521 | } |
1522 | |||
1523 | pub fn is_fn_like(&self) -> bool { | ||
1524 | match self.kind() { | ||
1525 | MacroKind::Declarative | MacroKind::BuiltIn | MacroKind::ProcMacro => true, | ||
1526 | MacroKind::Attr | MacroKind::Derive => false, | ||
1527 | } | ||
1528 | } | ||
1341 | } | 1529 | } |
1342 | 1530 | ||
1343 | /// Invariant: `inner.as_assoc_item(db).is_some()` | 1531 | /// Invariant: `inner.as_assoc_item(db).is_some()` |
@@ -1429,6 +1617,20 @@ impl AssocItem { | |||
1429 | _ => None, | 1617 | _ => None, |
1430 | } | 1618 | } |
1431 | } | 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 | } | ||
1432 | } | 1634 | } |
1433 | 1635 | ||
1434 | impl HasVisibility for AssocItem { | 1636 | impl HasVisibility for AssocItem { |
@@ -1726,7 +1928,7 @@ impl Impl { | |||
1726 | } | 1928 | } |
1727 | 1929 | ||
1728 | 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> { |
1729 | let def_crates = match def_crates(db, &ty, krate) { | 1931 | let def_crates = match method_resolution::def_crates(db, &ty, krate) { |
1730 | Some(def_crates) => def_crates, | 1932 | Some(def_crates) => def_crates, |
1731 | None => return Vec::new(), | 1933 | None => return Vec::new(), |
1732 | }; | 1934 | }; |
@@ -1783,9 +1985,11 @@ impl Impl { | |||
1783 | } | 1985 | } |
1784 | 1986 | ||
1785 | // FIXME: the return type is wrong. This should be a hir version of | 1987 | // FIXME: the return type is wrong. This should be a hir version of |
1786 | // `TraitRef` (ie, resolved `TypeRef`). | 1988 | // `TraitRef` (to account for parameters and qualifiers) |
1787 | pub fn trait_(self, db: &dyn HirDatabase) -> Option<TraitRef> { | 1989 | pub fn trait_(self, db: &dyn HirDatabase) -> Option<Trait> { |
1788 | db.impl_data(self.id).target_trait.as_deref().cloned() | 1990 | let trait_ref = db.impl_trait(self.id)?.skip_binders().clone(); |
1991 | let id = hir_ty::from_chalk_trait_id(trait_ref.trait_id); | ||
1992 | Some(Trait { id }) | ||
1789 | } | 1993 | } |
1790 | 1994 | ||
1791 | pub fn self_ty(self, db: &dyn HirDatabase) -> Type { | 1995 | pub fn self_ty(self, db: &dyn HirDatabase) -> Type { |
@@ -2130,7 +2334,7 @@ impl Type { | |||
2130 | krate: Crate, | 2334 | krate: Crate, |
2131 | mut callback: impl FnMut(AssocItem) -> Option<T>, | 2335 | mut callback: impl FnMut(AssocItem) -> Option<T>, |
2132 | ) -> Option<T> { | 2336 | ) -> Option<T> { |
2133 | for krate in def_crates(db, &self.ty, krate.id)? { | 2337 | for krate in method_resolution::def_crates(db, &self.ty, krate.id)? { |
2134 | let impls = db.inherent_impls_in_crate(krate); | 2338 | let impls = db.inherent_impls_in_crate(krate); |
2135 | 2339 | ||
2136 | for impl_def in impls.for_self_ty(&self.ty) { | 2340 | for impl_def in impls.for_self_ty(&self.ty) { |
@@ -2162,6 +2366,7 @@ impl Type { | |||
2162 | name: Option<&Name>, | 2366 | name: Option<&Name>, |
2163 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 2367 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
2164 | ) -> Option<T> { | 2368 | ) -> Option<T> { |
2369 | let _p = profile::span("iterate_method_candidates"); | ||
2165 | // There should be no inference vars in types passed here | 2370 | // There should be no inference vars in types passed here |
2166 | // FIXME check that? | 2371 | // FIXME check that? |
2167 | // FIXME replace Unknown by bound vars here | 2372 | // FIXME replace Unknown by bound vars here |
@@ -2195,6 +2400,7 @@ impl Type { | |||
2195 | name: Option<&Name>, | 2400 | name: Option<&Name>, |
2196 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, | 2401 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, |
2197 | ) -> Option<T> { | 2402 | ) -> Option<T> { |
2403 | let _p = profile::span("iterate_path_candidates"); | ||
2198 | let canonical = hir_ty::replace_errors_with_variables(&self.ty); | 2404 | let canonical = hir_ty::replace_errors_with_variables(&self.ty); |
2199 | 2405 | ||
2200 | let env = self.env.clone(); | 2406 | let env = self.env.clone(); |
@@ -2232,6 +2438,7 @@ impl Type { | |||
2232 | &'a self, | 2438 | &'a self, |
2233 | db: &'a dyn HirDatabase, | 2439 | db: &'a dyn HirDatabase, |
2234 | ) -> impl Iterator<Item = Trait> + 'a { | 2440 | ) -> impl Iterator<Item = Trait> + 'a { |
2441 | let _p = profile::span("applicable_inherent_traits"); | ||
2235 | self.autoderef(db) | 2442 | self.autoderef(db) |
2236 | .filter_map(|derefed_type| derefed_type.ty.dyn_trait()) | 2443 | .filter_map(|derefed_type| derefed_type.ty.dyn_trait()) |
2237 | .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)) |
@@ -2304,13 +2511,13 @@ impl Type { | |||
2304 | match ty.kind(&Interner) { | 2511 | match ty.kind(&Interner) { |
2305 | TyKind::Adt(_, substs) => { | 2512 | TyKind::Adt(_, substs) => { |
2306 | cb(type_.derived(ty.clone())); | 2513 | cb(type_.derived(ty.clone())); |
2307 | walk_substs(db, type_, &substs, cb); | 2514 | walk_substs(db, type_, substs, cb); |
2308 | } | 2515 | } |
2309 | TyKind::AssociatedType(_, substs) => { | 2516 | TyKind::AssociatedType(_, substs) => { |
2310 | if let Some(_) = ty.associated_type_parent_trait(db) { | 2517 | if let Some(_) = ty.associated_type_parent_trait(db) { |
2311 | cb(type_.derived(ty.clone())); | 2518 | cb(type_.derived(ty.clone())); |
2312 | } | 2519 | } |
2313 | walk_substs(db, type_, &substs, cb); | 2520 | walk_substs(db, type_, substs, cb); |
2314 | } | 2521 | } |
2315 | TyKind::OpaqueType(_, subst) => { | 2522 | TyKind::OpaqueType(_, subst) => { |
2316 | if let Some(bounds) = ty.impl_trait_bounds(db) { | 2523 | if let Some(bounds) = ty.impl_trait_bounds(db) { |
@@ -2350,7 +2557,7 @@ impl Type { | |||
2350 | TyKind::FnDef(_, substs) | 2557 | TyKind::FnDef(_, substs) |
2351 | | TyKind::Tuple(_, substs) | 2558 | | TyKind::Tuple(_, substs) |
2352 | | TyKind::Closure(.., substs) => { | 2559 | | TyKind::Closure(.., substs) => { |
2353 | walk_substs(db, type_, &substs, cb); | 2560 | walk_substs(db, type_, substs, cb); |
2354 | } | 2561 | } |
2355 | TyKind::Function(hir_ty::FnPointer { substitution, .. }) => { | 2562 | TyKind::Function(hir_ty::FnPointer { substitution, .. }) => { |
2356 | walk_substs(db, type_, &substitution.0, cb); | 2563 | walk_substs(db, type_, &substitution.0, cb); |
@@ -2481,6 +2688,18 @@ impl ScopeDef { | |||
2481 | 2688 | ||
2482 | items | 2689 | items |
2483 | } | 2690 | } |
2691 | |||
2692 | pub fn is_value_def(&self) -> bool { | ||
2693 | matches!( | ||
2694 | self, | ||
2695 | ScopeDef::ModuleDef(ModuleDef::Function(_)) | ||
2696 | | ScopeDef::ModuleDef(ModuleDef::Variant(_)) | ||
2697 | | ScopeDef::ModuleDef(ModuleDef::Const(_)) | ||
2698 | | ScopeDef::ModuleDef(ModuleDef::Static(_)) | ||
2699 | | ScopeDef::GenericParam(GenericParam::ConstParam(_)) | ||
2700 | | ScopeDef::Local(_) | ||
2701 | ) | ||
2702 | } | ||
2484 | } | 2703 | } |
2485 | 2704 | ||
2486 | impl From<ItemInNs> for ScopeDef { | 2705 | impl From<ItemInNs> for ScopeDef { |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index c7f2c02e4..613266e07 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -17,7 +17,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
17 | use syntax::{ | 17 | use syntax::{ |
18 | algo::find_node_at_offset, | 18 | algo::find_node_at_offset, |
19 | ast::{self, GenericParamsOwner, LoopBodyOwner}, | 19 | ast::{self, GenericParamsOwner, LoopBodyOwner}, |
20 | match_ast, AstNode, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize, | 20 | match_ast, AstNode, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize, |
21 | }; | 21 | }; |
22 | 22 | ||
23 | use crate::{ | 23 | use crate::{ |
@@ -35,8 +35,9 @@ pub enum PathResolution { | |||
35 | Def(ModuleDef), | 35 | Def(ModuleDef), |
36 | /// A local binding (only value namespace) | 36 | /// A local binding (only value namespace) |
37 | Local(Local), | 37 | Local(Local), |
38 | /// A generic parameter | 38 | /// A type parameter |
39 | TypeParam(TypeParam), | 39 | TypeParam(TypeParam), |
40 | /// A const parameter | ||
40 | ConstParam(ConstParam), | 41 | ConstParam(ConstParam), |
41 | SelfType(Impl), | 42 | SelfType(Impl), |
42 | Macro(MacroDef), | 43 | Macro(MacroDef), |
@@ -117,6 +118,16 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
117 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { | 118 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { |
118 | self.imp.expand(macro_call) | 119 | self.imp.expand(macro_call) |
119 | } | 120 | } |
121 | |||
122 | /// If `item` has an attribute macro attached to it, expands it. | ||
123 | pub fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> { | ||
124 | self.imp.expand_attr_macro(item) | ||
125 | } | ||
126 | |||
127 | pub fn is_attr_macro_call(&self, item: &ast::Item) -> bool { | ||
128 | self.imp.is_attr_macro_call(item) | ||
129 | } | ||
130 | |||
120 | pub fn speculative_expand( | 131 | pub fn speculative_expand( |
121 | &self, | 132 | &self, |
122 | actual_macro_call: &ast::MacroCall, | 133 | actual_macro_call: &ast::MacroCall, |
@@ -181,7 +192,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
181 | node: &SyntaxNode, | 192 | node: &SyntaxNode, |
182 | offset: TextSize, | 193 | offset: TextSize, |
183 | ) -> Option<N> { | 194 | ) -> Option<N> { |
184 | if let Some(it) = find_node_at_offset(&node, offset) { | 195 | if let Some(it) = find_node_at_offset(node, offset) { |
185 | return Some(it); | 196 | return Some(it); |
186 | } | 197 | } |
187 | 198 | ||
@@ -332,6 +343,22 @@ impl<'db> SemanticsImpl<'db> { | |||
332 | Some(node) | 343 | Some(node) |
333 | } | 344 | } |
334 | 345 | ||
346 | fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> { | ||
347 | let sa = self.analyze(item.syntax()); | ||
348 | let src = InFile::new(sa.file_id, item.clone()); | ||
349 | let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?; | ||
350 | let file_id = macro_call_id.as_file(); | ||
351 | let node = self.db.parse_or_expand(file_id)?; | ||
352 | self.cache(node.clone(), file_id); | ||
353 | Some(node) | ||
354 | } | ||
355 | |||
356 | fn is_attr_macro_call(&self, item: &ast::Item) -> bool { | ||
357 | let sa = self.analyze(item.syntax()); | ||
358 | let src = InFile::new(sa.file_id, item.clone()); | ||
359 | self.with_ctx(|ctx| ctx.item_to_macro_call(src).is_some()) | ||
360 | } | ||
361 | |||
335 | fn speculative_expand( | 362 | fn speculative_expand( |
336 | &self, | 363 | &self, |
337 | actual_macro_call: &ast::MacroCall, | 364 | actual_macro_call: &ast::MacroCall, |
@@ -362,25 +389,65 @@ impl<'db> SemanticsImpl<'db> { | |||
362 | 389 | ||
363 | let token = successors(Some(InFile::new(sa.file_id, token)), |token| { | 390 | let token = successors(Some(InFile::new(sa.file_id, token)), |token| { |
364 | self.db.unwind_if_cancelled(); | 391 | self.db.unwind_if_cancelled(); |
365 | let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; | 392 | |
366 | let tt = macro_call.token_tree()?; | 393 | for node in token.value.ancestors() { |
367 | if !tt.syntax().text_range().contains_range(token.value.text_range()) { | 394 | match_ast! { |
368 | return None; | 395 | match node { |
369 | } | 396 | ast::MacroCall(macro_call) => { |
370 | let file_id = sa.expand(self.db, token.with_value(¯o_call))?; | 397 | let tt = macro_call.token_tree()?; |
371 | let token = self | 398 | let l_delim = match tt.left_delimiter_token() { |
372 | .expansion_info_cache | 399 | Some(it) => it.text_range().end(), |
373 | .borrow_mut() | 400 | None => tt.syntax().text_range().start() |
374 | .entry(file_id) | 401 | }; |
375 | .or_insert_with(|| file_id.expansion_info(self.db.upcast())) | 402 | let r_delim = match tt.right_delimiter_token() { |
376 | .as_ref()? | 403 | Some(it) => it.text_range().start(), |
377 | .map_token_down(token.as_ref())?; | 404 | None => tt.syntax().text_range().end() |
378 | 405 | }; | |
379 | if let Some(parent) = token.value.parent() { | 406 | if !TextRange::new(l_delim, r_delim).contains_range(token.value.text_range()) { |
380 | self.cache(find_root(&parent), token.file_id); | 407 | return None; |
408 | } | ||
409 | let file_id = sa.expand(self.db, token.with_value(¯o_call))?; | ||
410 | let token = self | ||
411 | .expansion_info_cache | ||
412 | .borrow_mut() | ||
413 | .entry(file_id) | ||
414 | .or_insert_with(|| file_id.expansion_info(self.db.upcast())) | ||
415 | .as_ref()? | ||
416 | .map_token_down(token.as_ref())?; | ||
417 | |||
418 | if let Some(parent) = token.value.parent() { | ||
419 | self.cache(find_root(&parent), token.file_id); | ||
420 | } | ||
421 | |||
422 | return Some(token); | ||
423 | }, | ||
424 | ast::Item(item) => { | ||
425 | match self.with_ctx(|ctx| ctx.item_to_macro_call(token.with_value(item))) { | ||
426 | Some(call_id) => { | ||
427 | let file_id = call_id.as_file(); | ||
428 | let token = self | ||
429 | .expansion_info_cache | ||
430 | .borrow_mut() | ||
431 | .entry(file_id) | ||
432 | .or_insert_with(|| file_id.expansion_info(self.db.upcast())) | ||
433 | .as_ref()? | ||
434 | .map_token_down(token.as_ref())?; | ||
435 | |||
436 | if let Some(parent) = token.value.parent() { | ||
437 | self.cache(find_root(&parent), token.file_id); | ||
438 | } | ||
439 | |||
440 | return Some(token); | ||
441 | } | ||
442 | None => {} | ||
443 | } | ||
444 | }, | ||
445 | _ => {} | ||
446 | } | ||
447 | } | ||
381 | } | 448 | } |
382 | 449 | ||
383 | Some(token) | 450 | None |
384 | }) | 451 | }) |
385 | .last() | 452 | .last() |
386 | .unwrap(); | 453 | .unwrap(); |
@@ -677,7 +744,7 @@ impl<'db> SemanticsImpl<'db> { | |||
677 | return None; | 744 | return None; |
678 | } | 745 | } |
679 | 746 | ||
680 | 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)?; |
681 | let res = match func.self_param(self.db)?.access(self.db) { | 748 | let res = match func.self_param(self.db)?.access(self.db) { |
682 | Access::Shared | Access::Exclusive => true, | 749 | Access::Shared | Access::Exclusive => true, |
683 | Access::Owned => false, | 750 | Access::Owned => false, |
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 9a5a2255f..e8c2ed48e 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs | |||
@@ -10,7 +10,7 @@ use hir_def::{ | |||
10 | ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, | 10 | ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, |
11 | UnionId, VariantId, | 11 | UnionId, VariantId, |
12 | }; | 12 | }; |
13 | use hir_expand::{name::AsName, AstId, MacroDefKind}; | 13 | use hir_expand::{name::AsName, AstId, MacroCallId, MacroDefKind}; |
14 | use rustc_hash::FxHashMap; | 14 | use rustc_hash::FxHashMap; |
15 | use smallvec::SmallVec; | 15 | use smallvec::SmallVec; |
16 | use stdx::impl_from; | 16 | use stdx::impl_from; |
@@ -145,16 +145,25 @@ impl SourceToDefCtx<'_, '_> { | |||
145 | Some((container, label_id)) | 145 | Some((container, label_id)) |
146 | } | 146 | } |
147 | 147 | ||
148 | pub(super) fn item_to_macro_call(&mut self, src: InFile<ast::Item>) -> Option<MacroCallId> { | ||
149 | let map = self.dyn_map(src.as_ref())?; | ||
150 | map[keys::ATTR_MACRO].get(&src).copied() | ||
151 | } | ||
152 | |||
148 | fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>( | 153 | fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>( |
149 | &mut self, | 154 | &mut self, |
150 | src: InFile<Ast>, | 155 | src: InFile<Ast>, |
151 | key: Key<Ast, ID>, | 156 | key: Key<Ast, ID>, |
152 | ) -> Option<ID> { | 157 | ) -> Option<ID> { |
153 | let container = self.find_container(src.as_ref().map(|it| it.syntax()))?; | 158 | self.dyn_map(src.as_ref())?[key].get(&src).copied() |
159 | } | ||
160 | |||
161 | fn dyn_map<Ast: AstNode + 'static>(&mut self, src: InFile<&Ast>) -> Option<&DynMap> { | ||
162 | let container = self.find_container(src.map(|it| it.syntax()))?; | ||
154 | let db = self.db; | 163 | let db = self.db; |
155 | let dyn_map = | 164 | let dyn_map = |
156 | &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db)); | 165 | &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db)); |
157 | dyn_map[key].get(&src).copied() | 166 | Some(dyn_map) |
158 | } | 167 | } |
159 | 168 | ||
160 | pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> { | 169 | pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> { |
@@ -202,62 +211,68 @@ impl SourceToDefCtx<'_, '_> { | |||
202 | 211 | ||
203 | pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> { | 212 | pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> { |
204 | for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { | 213 | for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { |
205 | let res: ChildContainer = match_ast! { | 214 | if let Some(res) = self.container_to_def(container) { |
206 | match (container.value) { | 215 | return Some(res); |
207 | ast::Module(it) => { | 216 | } |
208 | let def = self.module_to_def(container.with_value(it))?; | ||
209 | def.into() | ||
210 | }, | ||
211 | ast::Trait(it) => { | ||
212 | let def = self.trait_to_def(container.with_value(it))?; | ||
213 | def.into() | ||
214 | }, | ||
215 | ast::Impl(it) => { | ||
216 | let def = self.impl_to_def(container.with_value(it))?; | ||
217 | def.into() | ||
218 | }, | ||
219 | ast::Fn(it) => { | ||
220 | let def = self.fn_to_def(container.with_value(it))?; | ||
221 | DefWithBodyId::from(def).into() | ||
222 | }, | ||
223 | ast::Struct(it) => { | ||
224 | let def = self.struct_to_def(container.with_value(it))?; | ||
225 | VariantId::from(def).into() | ||
226 | }, | ||
227 | ast::Enum(it) => { | ||
228 | let def = self.enum_to_def(container.with_value(it))?; | ||
229 | def.into() | ||
230 | }, | ||
231 | ast::Union(it) => { | ||
232 | let def = self.union_to_def(container.with_value(it))?; | ||
233 | VariantId::from(def).into() | ||
234 | }, | ||
235 | ast::Static(it) => { | ||
236 | let def = self.static_to_def(container.with_value(it))?; | ||
237 | DefWithBodyId::from(def).into() | ||
238 | }, | ||
239 | ast::Const(it) => { | ||
240 | let def = self.const_to_def(container.with_value(it))?; | ||
241 | DefWithBodyId::from(def).into() | ||
242 | }, | ||
243 | ast::TypeAlias(it) => { | ||
244 | let def = self.type_alias_to_def(container.with_value(it))?; | ||
245 | def.into() | ||
246 | }, | ||
247 | ast::Variant(it) => { | ||
248 | let def = self.enum_variant_to_def(container.with_value(it))?; | ||
249 | VariantId::from(def).into() | ||
250 | }, | ||
251 | _ => continue, | ||
252 | } | ||
253 | }; | ||
254 | return Some(res); | ||
255 | } | 217 | } |
256 | 218 | ||
257 | let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).get(0).copied()?; | 219 | let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).get(0).copied()?; |
258 | Some(def.into()) | 220 | Some(def.into()) |
259 | } | 221 | } |
260 | 222 | ||
223 | fn container_to_def(&mut self, container: InFile<SyntaxNode>) -> Option<ChildContainer> { | ||
224 | let cont = match_ast! { | ||
225 | match (container.value) { | ||
226 | ast::Module(it) => { | ||
227 | let def = self.module_to_def(container.with_value(it))?; | ||
228 | def.into() | ||
229 | }, | ||
230 | ast::Trait(it) => { | ||
231 | let def = self.trait_to_def(container.with_value(it))?; | ||
232 | def.into() | ||
233 | }, | ||
234 | ast::Impl(it) => { | ||
235 | let def = self.impl_to_def(container.with_value(it))?; | ||
236 | def.into() | ||
237 | }, | ||
238 | ast::Fn(it) => { | ||
239 | let def = self.fn_to_def(container.with_value(it))?; | ||
240 | DefWithBodyId::from(def).into() | ||
241 | }, | ||
242 | ast::Struct(it) => { | ||
243 | let def = self.struct_to_def(container.with_value(it))?; | ||
244 | VariantId::from(def).into() | ||
245 | }, | ||
246 | ast::Enum(it) => { | ||
247 | let def = self.enum_to_def(container.with_value(it))?; | ||
248 | def.into() | ||
249 | }, | ||
250 | ast::Union(it) => { | ||
251 | let def = self.union_to_def(container.with_value(it))?; | ||
252 | VariantId::from(def).into() | ||
253 | }, | ||
254 | ast::Static(it) => { | ||
255 | let def = self.static_to_def(container.with_value(it))?; | ||
256 | DefWithBodyId::from(def).into() | ||
257 | }, | ||
258 | ast::Const(it) => { | ||
259 | let def = self.const_to_def(container.with_value(it))?; | ||
260 | DefWithBodyId::from(def).into() | ||
261 | }, | ||
262 | ast::TypeAlias(it) => { | ||
263 | let def = self.type_alias_to_def(container.with_value(it))?; | ||
264 | def.into() | ||
265 | }, | ||
266 | ast::Variant(it) => { | ||
267 | let def = self.enum_variant_to_def(container.with_value(it))?; | ||
268 | VariantId::from(def).into() | ||
269 | }, | ||
270 | _ => return None, | ||
271 | } | ||
272 | }; | ||
273 | Some(cont) | ||
274 | } | ||
275 | |||
261 | fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> { | 276 | fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> { |
262 | for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { | 277 | for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { |
263 | let res: GenericDefId = match_ast! { | 278 | let res: GenericDefId = match_ast! { |
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 | ||