aboutsummaryrefslogtreecommitdiff
path: root/crates/hir/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir/src')
-rw-r--r--crates/hir/src/diagnostics.rs297
-rw-r--r--crates/hir/src/lib.rs364
-rw-r--r--crates/hir/src/semantics.rs4
-rw-r--r--crates/hir/src/source_analyzer.rs6
4 files changed, 378 insertions, 293 deletions
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.
6use std::any::Any; 6use cfg::{CfgExpr, CfgOptions};
7 7use either::Either;
8use cfg::{CfgExpr, CfgOptions, DnfExpr};
9use hir_def::path::ModPath; 8use hir_def::path::ModPath;
10use hir_expand::{HirFileId, InFile}; 9use hir_expand::{name::Name, HirFileId, InFile};
11use stdx::format_to;
12use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; 10use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
13 11
14pub use hir_ty::{ 12macro_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
28diagnostics![
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)]
27pub struct UnresolvedModule { 50pub 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
33impl 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)]
52pub struct UnresolvedExternCrate { 56pub struct UnresolvedExternCrate {
53 pub file: HirFileId, 57 pub decl: InFile<AstPtr<ast::ExternCrate>>,
54 pub item: AstPtr<ast::ExternCrate>,
55}
56
57impl 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)]
73pub struct UnresolvedImport { 61pub struct UnresolvedImport {
74 pub file: HirFileId, 62 pub decl: InFile<AstPtr<ast::UseTree>>,
75 pub node: AstPtr<ast::UseTree>, 63}
76} 64
77
78impl 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)]
105pub struct UnresolvedMacroCall { 66pub 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
111impl 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)]
133pub struct InactiveCode { 72pub 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
140impl 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)]
172pub struct UnresolvedProcMacro { 79pub 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
181impl Diagnostic for UnresolvedProcMacro { 87#[derive(Debug, Clone, Eq, PartialEq)]
182 fn code(&self) -> DiagnosticCode { 88pub 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 { 94pub 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()) 99pub 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 104pub struct BreakOutsideOfLoop {
199 } 105 pub expr: InFile<AstPtr<ast::Expr>>,
200} 106}
201 107
202// Diagnostic: macro-error 108#[derive(Debug)]
203// 109pub struct MissingUnsafe {
204// This diagnostic is shown for macro expansion errors. 110 pub expr: InFile<AstPtr<ast::Expr>>,
205#[derive(Debug, Clone, Eq, PartialEq)]
206pub struct MacroError {
207 pub file: HirFileId,
208 pub node: SyntaxNodePtr,
209 pub message: String,
210} 111}
211 112
212impl Diagnostic for MacroError { 113#[derive(Debug)]
213 fn code(&self) -> DiagnosticCode { 114pub 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)]
232pub struct UnimplementedBuiltinMacro { 122pub 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
237impl Diagnostic for UnimplementedBuiltinMacro { 128#[derive(Debug)]
238 fn code(&self) -> DiagnosticCode { 129pub 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() 136pub 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()) 141pub 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 148pub struct MissingMatchArms {
252 } 149 pub file: HirFileId,
150 pub match_expr: AstPtr<ast::Expr>,
151 pub arms: AstPtr<ast::MatchArmList>,
253} 152}
153
154pub 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
36use arrayvec::ArrayVec; 36use arrayvec::ArrayVec;
37use base_db::{CrateDisplayName, CrateId, Edition, FileId}; 37use base_db::{CrateDisplayName, CrateId, Edition, FileId};
38use diagnostics::{
39 InactiveCode, MacroError, UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport,
40 UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro,
41};
42use either::Either; 38use either::Either;
43use hir_def::{ 39use 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};
73use itertools::Itertools; 69use itertools::Itertools;
74use nameres::diagnostics::DefDiagnosticKind; 70use nameres::diagnostics::DefDiagnosticKind;
71use once_cell::unsync::Lazy;
75use rustc_hash::FxHashSet; 72use rustc_hash::FxHashSet;
76use stdx::{format_to, impl_from}; 73use stdx::{format_to, impl_from};
77use syntax::{ 74use syntax::{
@@ -84,6 +81,13 @@ use crate::db::{DefDatabase, HirDatabase};
84 81
85pub use crate::{ 82pub 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
1455impl HasVisibility for AssocItem { 1636impl 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