diff options
Diffstat (limited to 'crates/hir/src/lib.rs')
-rw-r--r-- | crates/hir/src/lib.rs | 236 |
1 files changed, 218 insertions, 18 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index b9c1dc44d..2468c0dc6 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -27,6 +27,7 @@ mod attrs; | |||
27 | mod has_source; | 27 | mod has_source; |
28 | 28 | ||
29 | pub mod diagnostics; | 29 | pub mod diagnostics; |
30 | pub mod diagnostics_sink; | ||
30 | pub mod db; | 31 | pub mod db; |
31 | 32 | ||
32 | mod display; | 33 | mod display; |
@@ -35,14 +36,10 @@ use std::{iter, sync::Arc}; | |||
35 | 36 | ||
36 | use arrayvec::ArrayVec; | 37 | use arrayvec::ArrayVec; |
37 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; | 38 | 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; | 39 | use either::Either; |
43 | use hir_def::{ | 40 | use hir_def::{ |
44 | adt::{ReprKind, VariantData}, | 41 | adt::{ReprKind, VariantData}, |
45 | body::BodyDiagnostic, | 42 | body::{BodyDiagnostic, SyntheticSyntax}, |
46 | expr::{BindingAnnotation, LabelId, Pat, PatId}, | 43 | expr::{BindingAnnotation, LabelId, Pat, PatId}, |
47 | item_tree::ItemTreeNode, | 44 | item_tree::ItemTreeNode, |
48 | lang_item::LangItemTarget, | 45 | lang_item::LangItemTarget, |
@@ -60,8 +57,8 @@ use hir_ty::{ | |||
60 | autoderef, | 57 | autoderef, |
61 | consteval::ConstExt, | 58 | consteval::ConstExt, |
62 | could_unify, | 59 | could_unify, |
63 | diagnostics_sink::DiagnosticSink, | 60 | diagnostics::BodyValidationDiagnostic, |
64 | method_resolution::{self, def_crates, TyFingerprint}, | 61 | method_resolution::{self, TyFingerprint}, |
65 | primitive::UintTy, | 62 | primitive::UintTy, |
66 | subst_prefix, | 63 | subst_prefix, |
67 | traits::FnTrait, | 64 | traits::FnTrait, |
@@ -72,6 +69,7 @@ use hir_ty::{ | |||
72 | }; | 69 | }; |
73 | use itertools::Itertools; | 70 | use itertools::Itertools; |
74 | use nameres::diagnostics::DefDiagnosticKind; | 71 | use nameres::diagnostics::DefDiagnosticKind; |
72 | use once_cell::unsync::Lazy; | ||
75 | use rustc_hash::FxHashSet; | 73 | use rustc_hash::FxHashSet; |
76 | use stdx::{format_to, impl_from}; | 74 | use stdx::{format_to, impl_from}; |
77 | use syntax::{ | 75 | use syntax::{ |
@@ -80,7 +78,17 @@ use syntax::{ | |||
80 | }; | 78 | }; |
81 | use tt::{Ident, Leaf, Literal, TokenTree}; | 79 | use tt::{Ident, Leaf, Literal, TokenTree}; |
82 | 80 | ||
83 | use crate::db::{DefDatabase, HirDatabase}; | 81 | use crate::{ |
82 | db::{DefDatabase, HirDatabase}, | ||
83 | diagnostics::{ | ||
84 | BreakOutsideOfLoop, InactiveCode, InternalBailedOut, MacroError, MismatchedArgCount, | ||
85 | MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, MissingPatFields, | ||
86 | MissingUnsafe, NoSuchField, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, | ||
87 | UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, | ||
88 | UnresolvedModule, UnresolvedProcMacro, | ||
89 | }, | ||
90 | diagnostics_sink::DiagnosticSink, | ||
91 | }; | ||
84 | 92 | ||
85 | pub use crate::{ | 93 | pub use crate::{ |
86 | attrs::{HasAttrs, Namespace}, | 94 | attrs::{HasAttrs, Namespace}, |
@@ -353,7 +361,9 @@ impl ModuleDef { | |||
353 | None => return, | 361 | None => return, |
354 | }; | 362 | }; |
355 | 363 | ||
356 | hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id, sink) | 364 | for diag in hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id) { |
365 | sink.push(diag) | ||
366 | } | ||
357 | } | 367 | } |
358 | } | 368 | } |
359 | 369 | ||
@@ -445,7 +455,12 @@ impl Module { | |||
445 | self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into()) | 455 | self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into()) |
446 | } | 456 | } |
447 | 457 | ||
448 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 458 | pub fn diagnostics( |
459 | self, | ||
460 | db: &dyn HirDatabase, | ||
461 | sink: &mut DiagnosticSink, | ||
462 | internal_diagnostics: bool, | ||
463 | ) { | ||
449 | let _p = profile::span("Module::diagnostics").detail(|| { | 464 | let _p = profile::span("Module::diagnostics").detail(|| { |
450 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) | 465 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) |
451 | }); | 466 | }); |
@@ -591,11 +606,11 @@ impl Module { | |||
591 | } | 606 | } |
592 | for decl in self.declarations(db) { | 607 | for decl in self.declarations(db) { |
593 | match decl { | 608 | match decl { |
594 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), | 609 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink, internal_diagnostics), |
595 | crate::ModuleDef::Module(m) => { | 610 | crate::ModuleDef::Module(m) => { |
596 | // Only add diagnostics from inline modules | 611 | // Only add diagnostics from inline modules |
597 | if def_map[m.id.local_id].origin.is_inline() { | 612 | if def_map[m.id.local_id].origin.is_inline() { |
598 | m.diagnostics(db, sink) | 613 | m.diagnostics(db, sink, internal_diagnostics) |
599 | } | 614 | } |
600 | } | 615 | } |
601 | _ => { | 616 | _ => { |
@@ -607,7 +622,7 @@ impl Module { | |||
607 | for impl_def in self.impl_defs(db) { | 622 | for impl_def in self.impl_defs(db) { |
608 | for item in impl_def.items(db) { | 623 | for item in impl_def.items(db) { |
609 | if let AssocItem::Function(f) = item { | 624 | if let AssocItem::Function(f) = item { |
610 | f.diagnostics(db, sink); | 625 | f.diagnostics(db, sink, internal_diagnostics); |
611 | } | 626 | } |
612 | } | 627 | } |
613 | } | 628 | } |
@@ -1009,7 +1024,12 @@ impl Function { | |||
1009 | db.function_data(self.id).is_async() | 1024 | db.function_data(self.id).is_async() |
1010 | } | 1025 | } |
1011 | 1026 | ||
1012 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 1027 | pub fn diagnostics( |
1028 | self, | ||
1029 | db: &dyn HirDatabase, | ||
1030 | sink: &mut DiagnosticSink, | ||
1031 | internal_diagnostics: bool, | ||
1032 | ) { | ||
1013 | let krate = self.module(db).id.krate(); | 1033 | let krate = self.module(db).id.krate(); |
1014 | 1034 | ||
1015 | let source_map = db.body_with_source_map(self.id.into()).1; | 1035 | let source_map = db.body_with_source_map(self.id.into()).1; |
@@ -1042,8 +1062,174 @@ impl Function { | |||
1042 | } | 1062 | } |
1043 | } | 1063 | } |
1044 | 1064 | ||
1045 | hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); | 1065 | let infer = db.infer(self.id.into()); |
1046 | hir_ty::diagnostics::validate_body(db, self.id.into(), sink); | 1066 | let source_map = Lazy::new(|| db.body_with_source_map(self.id.into()).1); |
1067 | for d in &infer.diagnostics { | ||
1068 | match d { | ||
1069 | hir_ty::InferenceDiagnostic::NoSuchField { expr } => { | ||
1070 | let field = source_map.field_syntax(*expr); | ||
1071 | sink.push(NoSuchField { file: field.file_id, field: field.value }) | ||
1072 | } | ||
1073 | hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => { | ||
1074 | let ptr = source_map | ||
1075 | .expr_syntax(*expr) | ||
1076 | .expect("break outside of loop in synthetic syntax"); | ||
1077 | sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value }) | ||
1078 | } | ||
1079 | } | ||
1080 | } | ||
1081 | |||
1082 | for expr in hir_ty::diagnostics::missing_unsafe(db, self.id.into()) { | ||
1083 | match source_map.expr_syntax(expr) { | ||
1084 | Ok(in_file) => { | ||
1085 | sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value }) | ||
1086 | } | ||
1087 | Err(SyntheticSyntax) => { | ||
1088 | // FIXME: Here and eslwhere in this file, the `expr` was | ||
1089 | // desugared, report or assert that this doesn't happen. | ||
1090 | } | ||
1091 | } | ||
1092 | } | ||
1093 | |||
1094 | for diagnostic in | ||
1095 | BodyValidationDiagnostic::collect(db, self.id.into(), internal_diagnostics) | ||
1096 | { | ||
1097 | match diagnostic { | ||
1098 | BodyValidationDiagnostic::RecordLiteralMissingFields { | ||
1099 | record_expr, | ||
1100 | variant, | ||
1101 | missed_fields, | ||
1102 | } => match source_map.expr_syntax(record_expr) { | ||
1103 | Ok(source_ptr) => { | ||
1104 | let root = source_ptr.file_syntax(db.upcast()); | ||
1105 | if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) | ||
1106 | { | ||
1107 | if let Some(_) = record_expr.record_expr_field_list() { | ||
1108 | let variant_data = variant.variant_data(db.upcast()); | ||
1109 | let missed_fields = missed_fields | ||
1110 | .into_iter() | ||
1111 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
1112 | .collect(); | ||
1113 | sink.push(MissingFields { | ||
1114 | file: source_ptr.file_id, | ||
1115 | field_list_parent: AstPtr::new(&record_expr), | ||
1116 | field_list_parent_path: record_expr | ||
1117 | .path() | ||
1118 | .map(|path| AstPtr::new(&path)), | ||
1119 | missed_fields, | ||
1120 | }) | ||
1121 | } | ||
1122 | } | ||
1123 | } | ||
1124 | Err(SyntheticSyntax) => (), | ||
1125 | }, | ||
1126 | BodyValidationDiagnostic::RecordPatMissingFields { | ||
1127 | record_pat, | ||
1128 | variant, | ||
1129 | missed_fields, | ||
1130 | } => match source_map.pat_syntax(record_pat) { | ||
1131 | Ok(source_ptr) => { | ||
1132 | if let Some(expr) = source_ptr.value.as_ref().left() { | ||
1133 | let root = source_ptr.file_syntax(db.upcast()); | ||
1134 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { | ||
1135 | if let Some(_) = record_pat.record_pat_field_list() { | ||
1136 | let variant_data = variant.variant_data(db.upcast()); | ||
1137 | let missed_fields = missed_fields | ||
1138 | .into_iter() | ||
1139 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
1140 | .collect(); | ||
1141 | sink.push(MissingPatFields { | ||
1142 | file: source_ptr.file_id, | ||
1143 | field_list_parent: AstPtr::new(&record_pat), | ||
1144 | field_list_parent_path: record_pat | ||
1145 | .path() | ||
1146 | .map(|path| AstPtr::new(&path)), | ||
1147 | missed_fields, | ||
1148 | }) | ||
1149 | } | ||
1150 | } | ||
1151 | } | ||
1152 | } | ||
1153 | Err(SyntheticSyntax) => (), | ||
1154 | }, | ||
1155 | |||
1156 | BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => { | ||
1157 | if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) { | ||
1158 | sink.push(ReplaceFilterMapNextWithFindMap { | ||
1159 | file: next_source_ptr.file_id, | ||
1160 | next_expr: next_source_ptr.value, | ||
1161 | }); | ||
1162 | } | ||
1163 | } | ||
1164 | BodyValidationDiagnostic::MismatchedArgCount { call_expr, expected, found } => { | ||
1165 | match source_map.expr_syntax(call_expr) { | ||
1166 | Ok(source_ptr) => sink.push(MismatchedArgCount { | ||
1167 | file: source_ptr.file_id, | ||
1168 | call_expr: source_ptr.value, | ||
1169 | expected, | ||
1170 | found, | ||
1171 | }), | ||
1172 | Err(SyntheticSyntax) => (), | ||
1173 | } | ||
1174 | } | ||
1175 | BodyValidationDiagnostic::RemoveThisSemicolon { expr } => { | ||
1176 | match source_map.expr_syntax(expr) { | ||
1177 | Ok(source_ptr) => sink.push(RemoveThisSemicolon { | ||
1178 | file: source_ptr.file_id, | ||
1179 | expr: source_ptr.value, | ||
1180 | }), | ||
1181 | Err(SyntheticSyntax) => (), | ||
1182 | } | ||
1183 | } | ||
1184 | BodyValidationDiagnostic::MissingOkOrSomeInTailExpr { expr, required } => { | ||
1185 | match source_map.expr_syntax(expr) { | ||
1186 | Ok(source_ptr) => sink.push(MissingOkOrSomeInTailExpr { | ||
1187 | file: source_ptr.file_id, | ||
1188 | expr: source_ptr.value, | ||
1189 | required, | ||
1190 | }), | ||
1191 | Err(SyntheticSyntax) => (), | ||
1192 | } | ||
1193 | } | ||
1194 | BodyValidationDiagnostic::MissingMatchArms { match_expr } => { | ||
1195 | match source_map.expr_syntax(match_expr) { | ||
1196 | Ok(source_ptr) => { | ||
1197 | let root = source_ptr.file_syntax(db.upcast()); | ||
1198 | if let ast::Expr::MatchExpr(match_expr) = | ||
1199 | &source_ptr.value.to_node(&root) | ||
1200 | { | ||
1201 | if let (Some(match_expr), Some(arms)) = | ||
1202 | (match_expr.expr(), match_expr.match_arm_list()) | ||
1203 | { | ||
1204 | sink.push(MissingMatchArms { | ||
1205 | file: source_ptr.file_id, | ||
1206 | match_expr: AstPtr::new(&match_expr), | ||
1207 | arms: AstPtr::new(&arms), | ||
1208 | }) | ||
1209 | } | ||
1210 | } | ||
1211 | } | ||
1212 | Err(SyntheticSyntax) => (), | ||
1213 | } | ||
1214 | } | ||
1215 | BodyValidationDiagnostic::InternalBailedOut { pat } => { | ||
1216 | match source_map.pat_syntax(pat) { | ||
1217 | Ok(source_ptr) => { | ||
1218 | let pat_syntax_ptr = source_ptr.value.either(Into::into, Into::into); | ||
1219 | sink.push(InternalBailedOut { | ||
1220 | file: source_ptr.file_id, | ||
1221 | pat_syntax_ptr, | ||
1222 | }); | ||
1223 | } | ||
1224 | Err(SyntheticSyntax) => (), | ||
1225 | } | ||
1226 | } | ||
1227 | } | ||
1228 | } | ||
1229 | |||
1230 | for diag in hir_ty::diagnostics::validate_module_item(db, krate, self.id.into()) { | ||
1231 | sink.push(diag) | ||
1232 | } | ||
1047 | } | 1233 | } |
1048 | 1234 | ||
1049 | /// Whether this function declaration has a definition. | 1235 | /// Whether this function declaration has a definition. |
@@ -1451,6 +1637,20 @@ impl AssocItem { | |||
1451 | _ => None, | 1637 | _ => None, |
1452 | } | 1638 | } |
1453 | } | 1639 | } |
1640 | |||
1641 | pub fn containing_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1642 | match self.container(db) { | ||
1643 | AssocItemContainer::Impl(i) => i.trait_(db), | ||
1644 | _ => None, | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | pub fn containing_trait_or_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1649 | match self.container(db) { | ||
1650 | AssocItemContainer::Trait(t) => Some(t), | ||
1651 | AssocItemContainer::Impl(i) => i.trait_(db), | ||
1652 | } | ||
1653 | } | ||
1454 | } | 1654 | } |
1455 | 1655 | ||
1456 | impl HasVisibility for AssocItem { | 1656 | impl HasVisibility for AssocItem { |
@@ -1748,7 +1948,7 @@ impl Impl { | |||
1748 | } | 1948 | } |
1749 | 1949 | ||
1750 | pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> { | 1950 | pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> { |
1751 | let def_crates = match def_crates(db, &ty, krate) { | 1951 | let def_crates = match method_resolution::def_crates(db, &ty, krate) { |
1752 | Some(def_crates) => def_crates, | 1952 | Some(def_crates) => def_crates, |
1753 | None => return Vec::new(), | 1953 | None => return Vec::new(), |
1754 | }; | 1954 | }; |
@@ -2154,7 +2354,7 @@ impl Type { | |||
2154 | krate: Crate, | 2354 | krate: Crate, |
2155 | mut callback: impl FnMut(AssocItem) -> Option<T>, | 2355 | mut callback: impl FnMut(AssocItem) -> Option<T>, |
2156 | ) -> Option<T> { | 2356 | ) -> Option<T> { |
2157 | for krate in def_crates(db, &self.ty, krate.id)? { | 2357 | for krate in method_resolution::def_crates(db, &self.ty, krate.id)? { |
2158 | let impls = db.inherent_impls_in_crate(krate); | 2358 | let impls = db.inherent_impls_in_crate(krate); |
2159 | 2359 | ||
2160 | for impl_def in impls.for_self_ty(&self.ty) { | 2360 | for impl_def in impls.for_self_ty(&self.ty) { |