diff options
Diffstat (limited to 'crates/hir/src/lib.rs')
-rw-r--r-- | crates/hir/src/lib.rs | 175 |
1 files changed, 163 insertions, 12 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 8804e63c5..dd5515c2b 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -36,9 +36,11 @@ use std::{iter, sync::Arc}; | |||
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::{ | 38 | use diagnostics::{ |
39 | BreakOutsideOfLoop, InactiveCode, MacroError, MissingUnsafe, NoSuchField, | 39 | BreakOutsideOfLoop, InactiveCode, InternalBailedOut, MacroError, MismatchedArgCount, |
40 | UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, | 40 | MissingFields, MissingOkOrSomeInTailExpr, MissingPatFields, MissingUnsafe, NoSuchField, |
41 | UnresolvedModule, UnresolvedProcMacro, | 41 | RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, UnimplementedBuiltinMacro, |
42 | UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, UnresolvedModule, | ||
43 | UnresolvedProcMacro, | ||
42 | }; | 44 | }; |
43 | use either::Either; | 45 | use either::Either; |
44 | use hir_def::{ | 46 | use hir_def::{ |
@@ -61,6 +63,7 @@ use hir_ty::{ | |||
61 | autoderef, | 63 | autoderef, |
62 | consteval::ConstExt, | 64 | consteval::ConstExt, |
63 | could_unify, | 65 | could_unify, |
66 | diagnostics::BodyValidationDiagnostic, | ||
64 | diagnostics_sink::DiagnosticSink, | 67 | diagnostics_sink::DiagnosticSink, |
65 | method_resolution::{self, def_crates, TyFingerprint}, | 68 | method_resolution::{self, def_crates, TyFingerprint}, |
66 | primitive::UintTy, | 69 | primitive::UintTy, |
@@ -82,7 +85,10 @@ use syntax::{ | |||
82 | }; | 85 | }; |
83 | use tt::{Ident, Leaf, Literal, TokenTree}; | 86 | use tt::{Ident, Leaf, Literal, TokenTree}; |
84 | 87 | ||
85 | use crate::db::{DefDatabase, HirDatabase}; | 88 | use crate::{ |
89 | db::{DefDatabase, HirDatabase}, | ||
90 | diagnostics::MissingMatchArms, | ||
91 | }; | ||
86 | 92 | ||
87 | pub use crate::{ | 93 | pub use crate::{ |
88 | attrs::{HasAttrs, Namespace}, | 94 | attrs::{HasAttrs, Namespace}, |
@@ -447,7 +453,12 @@ impl Module { | |||
447 | 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.clone().into()) |
448 | } | 454 | } |
449 | 455 | ||
450 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 456 | pub fn diagnostics( |
457 | self, | ||
458 | db: &dyn HirDatabase, | ||
459 | sink: &mut DiagnosticSink, | ||
460 | internal_diagnostics: bool, | ||
461 | ) { | ||
451 | let _p = profile::span("Module::diagnostics").detail(|| { | 462 | let _p = profile::span("Module::diagnostics").detail(|| { |
452 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) | 463 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) |
453 | }); | 464 | }); |
@@ -593,11 +604,11 @@ impl Module { | |||
593 | } | 604 | } |
594 | for decl in self.declarations(db) { | 605 | for decl in self.declarations(db) { |
595 | match decl { | 606 | match decl { |
596 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), | 607 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink, internal_diagnostics), |
597 | crate::ModuleDef::Module(m) => { | 608 | crate::ModuleDef::Module(m) => { |
598 | // Only add diagnostics from inline modules | 609 | // Only add diagnostics from inline modules |
599 | if def_map[m.id.local_id].origin.is_inline() { | 610 | if def_map[m.id.local_id].origin.is_inline() { |
600 | m.diagnostics(db, sink) | 611 | m.diagnostics(db, sink, internal_diagnostics) |
601 | } | 612 | } |
602 | } | 613 | } |
603 | _ => { | 614 | _ => { |
@@ -609,7 +620,7 @@ impl Module { | |||
609 | for impl_def in self.impl_defs(db) { | 620 | for impl_def in self.impl_defs(db) { |
610 | for item in impl_def.items(db) { | 621 | for item in impl_def.items(db) { |
611 | if let AssocItem::Function(f) = item { | 622 | if let AssocItem::Function(f) = item { |
612 | f.diagnostics(db, sink); | 623 | f.diagnostics(db, sink, internal_diagnostics); |
613 | } | 624 | } |
614 | } | 625 | } |
615 | } | 626 | } |
@@ -1011,7 +1022,12 @@ impl Function { | |||
1011 | db.function_data(self.id).is_async() | 1022 | db.function_data(self.id).is_async() |
1012 | } | 1023 | } |
1013 | 1024 | ||
1014 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 1025 | pub fn diagnostics( |
1026 | self, | ||
1027 | db: &dyn HirDatabase, | ||
1028 | sink: &mut DiagnosticSink, | ||
1029 | internal_diagnostics: bool, | ||
1030 | ) { | ||
1015 | let krate = self.module(db).id.krate(); | 1031 | let krate = self.module(db).id.krate(); |
1016 | 1032 | ||
1017 | let source_map = db.body_with_source_map(self.id.into()).1; | 1033 | let source_map = db.body_with_source_map(self.id.into()).1; |
@@ -1067,14 +1083,149 @@ impl Function { | |||
1067 | sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value }) | 1083 | sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value }) |
1068 | } | 1084 | } |
1069 | Err(SyntheticSyntax) => { | 1085 | Err(SyntheticSyntax) => { |
1070 | // FIXME: The `expr` was desugared, report or assert that | 1086 | // FIXME: Here and eslwhere in this file, the `expr` was |
1071 | // this doesn't happen. | 1087 | // desugared, report or assert that this doesn't happen. |
1088 | } | ||
1089 | } | ||
1090 | } | ||
1091 | |||
1092 | for diagnostic in | ||
1093 | BodyValidationDiagnostic::collect(db, self.id.into(), internal_diagnostics) | ||
1094 | { | ||
1095 | match diagnostic { | ||
1096 | BodyValidationDiagnostic::RecordLiteralMissingFields { | ||
1097 | record_expr, | ||
1098 | variant, | ||
1099 | missed_fields, | ||
1100 | } => 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) = &source_ptr.value.to_node(&root) | ||
1104 | { | ||
1105 | if let Some(_) = record_expr.record_expr_field_list() { | ||
1106 | let variant_data = variant.variant_data(db.upcast()); | ||
1107 | let missed_fields = missed_fields | ||
1108 | .into_iter() | ||
1109 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
1110 | .collect(); | ||
1111 | sink.push(MissingFields { | ||
1112 | file: source_ptr.file_id, | ||
1113 | field_list_parent: AstPtr::new(&record_expr), | ||
1114 | field_list_parent_path: record_expr | ||
1115 | .path() | ||
1116 | .map(|path| AstPtr::new(&path)), | ||
1117 | missed_fields, | ||
1118 | }) | ||
1119 | } | ||
1120 | } | ||
1121 | } | ||
1122 | Err(SyntheticSyntax) => (), | ||
1123 | }, | ||
1124 | BodyValidationDiagnostic::RecordPatMissingFields { | ||
1125 | record_pat, | ||
1126 | variant, | ||
1127 | missed_fields, | ||
1128 | } => match source_map.pat_syntax(record_pat) { | ||
1129 | Ok(source_ptr) => { | ||
1130 | if let Some(expr) = source_ptr.value.as_ref().left() { | ||
1131 | let root = source_ptr.file_syntax(db.upcast()); | ||
1132 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { | ||
1133 | if let Some(_) = record_pat.record_pat_field_list() { | ||
1134 | let variant_data = variant.variant_data(db.upcast()); | ||
1135 | let missed_fields = missed_fields | ||
1136 | .into_iter() | ||
1137 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
1138 | .collect(); | ||
1139 | sink.push(MissingPatFields { | ||
1140 | file: source_ptr.file_id, | ||
1141 | field_list_parent: AstPtr::new(&record_pat), | ||
1142 | field_list_parent_path: record_pat | ||
1143 | .path() | ||
1144 | .map(|path| AstPtr::new(&path)), | ||
1145 | missed_fields, | ||
1146 | }) | ||
1147 | } | ||
1148 | } | ||
1149 | } | ||
1150 | } | ||
1151 | Err(SyntheticSyntax) => (), | ||
1152 | }, | ||
1153 | |||
1154 | BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => { | ||
1155 | if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) { | ||
1156 | sink.push(ReplaceFilterMapNextWithFindMap { | ||
1157 | file: next_source_ptr.file_id, | ||
1158 | next_expr: next_source_ptr.value, | ||
1159 | }); | ||
1160 | } | ||
1161 | } | ||
1162 | BodyValidationDiagnostic::MismatchedArgCount { call_expr, expected, found } => { | ||
1163 | match source_map.expr_syntax(call_expr) { | ||
1164 | Ok(source_ptr) => sink.push(MismatchedArgCount { | ||
1165 | file: source_ptr.file_id, | ||
1166 | call_expr: source_ptr.value, | ||
1167 | expected, | ||
1168 | found, | ||
1169 | }), | ||
1170 | Err(SyntheticSyntax) => (), | ||
1171 | } | ||
1172 | } | ||
1173 | BodyValidationDiagnostic::RemoveThisSemicolon { expr } => { | ||
1174 | match source_map.expr_syntax(expr) { | ||
1175 | Ok(source_ptr) => sink.push(RemoveThisSemicolon { | ||
1176 | file: source_ptr.file_id, | ||
1177 | expr: source_ptr.value, | ||
1178 | }), | ||
1179 | Err(SyntheticSyntax) => (), | ||
1180 | } | ||
1181 | } | ||
1182 | BodyValidationDiagnostic::MissingOkOrSomeInTailExpr { expr, required } => { | ||
1183 | match source_map.expr_syntax(expr) { | ||
1184 | Ok(source_ptr) => sink.push(MissingOkOrSomeInTailExpr { | ||
1185 | file: source_ptr.file_id, | ||
1186 | expr: source_ptr.value, | ||
1187 | required, | ||
1188 | }), | ||
1189 | Err(SyntheticSyntax) => (), | ||
1190 | } | ||
1191 | } | ||
1192 | BodyValidationDiagnostic::MissingMatchArms { match_expr } => { | ||
1193 | match source_map.expr_syntax(match_expr) { | ||
1194 | Ok(source_ptr) => { | ||
1195 | let root = source_ptr.file_syntax(db.upcast()); | ||
1196 | if let ast::Expr::MatchExpr(match_expr) = | ||
1197 | &source_ptr.value.to_node(&root) | ||
1198 | { | ||
1199 | if let (Some(match_expr), Some(arms)) = | ||
1200 | (match_expr.expr(), match_expr.match_arm_list()) | ||
1201 | { | ||
1202 | sink.push(MissingMatchArms { | ||
1203 | file: source_ptr.file_id, | ||
1204 | match_expr: AstPtr::new(&match_expr), | ||
1205 | arms: AstPtr::new(&arms), | ||
1206 | }) | ||
1207 | } | ||
1208 | } | ||
1209 | } | ||
1210 | Err(SyntheticSyntax) => (), | ||
1211 | } | ||
1212 | } | ||
1213 | BodyValidationDiagnostic::InternalBailedOut { pat } => { | ||
1214 | match source_map.pat_syntax(pat) { | ||
1215 | Ok(source_ptr) => { | ||
1216 | let pat_syntax_ptr = source_ptr.value.either(Into::into, Into::into); | ||
1217 | sink.push(InternalBailedOut { | ||
1218 | file: source_ptr.file_id, | ||
1219 | pat_syntax_ptr, | ||
1220 | }); | ||
1221 | } | ||
1222 | Err(SyntheticSyntax) => (), | ||
1223 | } | ||
1072 | } | 1224 | } |
1073 | } | 1225 | } |
1074 | } | 1226 | } |
1075 | 1227 | ||
1076 | hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); | 1228 | hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); |
1077 | hir_ty::diagnostics::validate_body(db, self.id.into(), sink); | ||
1078 | } | 1229 | } |
1079 | 1230 | ||
1080 | /// Whether this function declaration has a definition. | 1231 | /// Whether this function declaration has a definition. |