Repository: rust-analyzer/rust-analyzer
Pull request #5358 (2020-07-14 08:29:52)

Cleanup hir diagnostics API


bors r+
🤖


Patch:
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 9222009fec..42c9ca189f 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -25,11 +25,8 @@ use hir_expand::{
 use hir_ty::{
     autoderef,
     display::{HirDisplayError, HirFormatter},
-    expr::ExprValidator,
-    method_resolution,
-    unsafe_validation::UnsafeValidator,
-    ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, TraitEnvironment, Ty,
-    TyDefId, TypeCtor,
+    method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs,
+    TraitEnvironment, Ty, TyDefId, TypeCtor,
 };
 use ra_db::{CrateId, Edition, FileId};
 use ra_prof::profile;
@@ -680,13 +677,7 @@ impl Function {
     }
 
     pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
-        let _p = profile("Function::diagnostics");
-        let infer = db.infer(self.id.into());
-        infer.add_diagnostics(db, self.id, sink);
-        let mut validator = ExprValidator::new(self.id, infer.clone(), sink);
-        validator.validate_body(db);
-        let mut validator = UnsafeValidator::new(self.id, infer, sink);
-        validator.validate_body(db);
+        hir_ty::diagnostics::validate_body(db, self.id.into(), sink)
     }
 }
 
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index f74b78b237..bfa543e5b6 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -18,7 +18,7 @@ use hir_def::{
 };
 use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
 use hir_ty::{
-    expr::{record_literal_missing_fields, record_pattern_missing_fields},
+    diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields},
     InferenceResult, Substs, Ty,
 };
 use ra_syntax::{
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index 5b0dda634f..d9c2b1214f 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -1,14 +1,30 @@
 //! FIXME: write short doc here
+pub mod expr;
+mod match_check;
+pub mod unsafe_check;
 
 use std::any::Any;
 
 use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile};
+use ra_prof::profile;
 use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
 use stdx::format_to;
 
-pub use hir_def::{diagnostics::UnresolvedModule, expr::MatchArm, path::Path};
+pub use hir_def::{diagnostics::UnresolvedModule, expr::MatchArm, path::Path, DefWithBodyId};
 pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
 
+use crate::db::HirDatabase;
+
+pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) {
+    let _p = profile("validate_body");
+    let infer = db.infer(owner);
+    infer.add_diagnostics(db, owner, sink);
+    let mut validator = expr::ExprValidator::new(owner, infer.clone(), sink);
+    validator.validate_body(db);
+    let mut validator = unsafe_check::UnsafeValidator::new(owner, infer, sink);
+    validator.validate_body(db);
+}
+
 #[derive(Debug)]
 pub struct NoSuchField {
     pub file: HirFileId,
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs
similarity index 94%
rename from crates/ra_hir_ty/src/expr.rs
rename to crates/ra_hir_ty/src/diagnostics/expr.rs
index d44562b227..239be779fa 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/diagnostics/expr.rs
@@ -2,7 +2,7 @@
 
 use std::sync::Arc;
 
-use hir_def::{path::path, resolver::HasResolver, AdtId, FunctionId};
+use hir_def::{path::path, resolver::HasResolver, AdtId, DefWithBodyId};
 use hir_expand::diagnostics::DiagnosticSink;
 use ra_syntax::{ast, AstPtr};
 use rustc_hash::FxHashSet;
@@ -10,9 +10,9 @@ use rustc_hash::FxHashSet;
 use crate::{
     db::HirDatabase,
     diagnostics::{
+        match_check::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
         MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields,
     },
-    match_checking::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
     utils::variant_data,
     ApplicationTy, InferenceResult, Ty, TypeCtor,
 };
@@ -30,23 +30,23 @@ pub use hir_def::{
     LocalFieldId, Lookup, VariantId,
 };
 
-pub struct ExprValidator<'a, 'b: 'a> {
-    func: FunctionId,
+pub(super) struct ExprValidator<'a, 'b: 'a> {
+    owner: DefWithBodyId,
     infer: Arc<InferenceResult>,
     sink: &'a mut DiagnosticSink<'b>,
 }
 
 impl<'a, 'b> ExprValidator<'a, 'b> {
-    pub fn new(
-        func: FunctionId,
+    pub(super) fn new(
+        owner: DefWithBodyId,
         infer: Arc<InferenceResult>,
         sink: &'a mut DiagnosticSink<'b>,
     ) -> ExprValidator<'a, 'b> {
-        ExprValidator { func, infer, sink }
+        ExprValidator { owner, infer, sink }
     }
 
-    pub fn validate_body(&mut self, db: &dyn HirDatabase) {
-        let body = db.body(self.func.into());
+    pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) {
+        let body = db.body(self.owner.into());
 
         for (id, expr) in body.exprs.iter() {
             if let Some((variant_def, missed_fields, true)) =
@@ -96,7 +96,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
         missed_fields: Vec<LocalFieldId>,
     ) {
         // XXX: only look at source_map if we do have missing fields
-        let (_, source_map) = db.body_with_source_map(self.func.into());
+        let (_, source_map) = db.body_with_source_map(self.owner.into());
 
         if let Ok(source_ptr) = source_map.expr_syntax(id) {
             let root = source_ptr.file_syntax(db.upcast());
@@ -125,7 +125,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
         missed_fields: Vec<LocalFieldId>,
     ) {
         // XXX: only look at source_map if we do have missing fields
-        let (_, source_map) = db.body_with_source_map(self.func.into());
+        let (_, source_map) = db.body_with_source_map(self.owner.into());
 
         if let Ok(source_ptr) = source_map.pat_syntax(id) {
             if let Some(expr) = source_ptr.value.as_ref().left() {
@@ -181,7 +181,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
         let mut arg_count = args.len();
 
         if arg_count != param_count {
-            let (_, source_map) = db.body_with_source_map(self.func.into());
+            let (_, source_map) = db.body_with_source_map(self.owner.into());
             if let Ok(source_ptr) = source_map.expr_syntax(call_id) {
                 if is_method_call {
                     param_count -= 1;
@@ -208,7 +208,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
         infer: Arc<InferenceResult>,
     ) {
         let (body, source_map): (Arc<Body>, Arc<BodySourceMap>) =
-            db.body_with_source_map(self.func.into());
+            db.body_with_source_map(self.owner.into());
 
         let match_expr_ty = match infer.type_of_expr.get(match_expr) {
             Some(ty) => ty,
@@ -289,7 +289,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
 
         let core_result_path = path![core::result::Result];
 
-        let resolver = self.func.resolver(db.upcast());
+        let resolver = self.owner.resolver(db.upcast());
         let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) {
             Some(it) => it,
             _ => return,
@@ -304,7 +304,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
         };
 
         if params.len() == 2 && params[0] == mismatch.actual {
-            let (_, source_map) = db.body_with_source_map(self.func.into());
+            let (_, source_map) = db.body_with_source_map(self.owner.into());
 
             if let Ok(source_ptr) = source_map.expr_syntax(id) {
                 self.sink
diff --git a/crates/ra_hir_ty/src/match_checking.rs b/crates/ra_hir_ty/src/diagnostics/match_check.rs
similarity index 99%
rename from crates/ra_hir_ty/src/match_checking.rs
rename to crates/ra_hir_ty/src/diagnostics/match_check.rs
index 5495ce284f..722c0e9eea 100644
--- a/crates/ra_hir_ty/src/match_checking.rs
+++ b/crates/ra_hir_ty/src/diagnostics/match_check.rs
@@ -218,15 +218,16 @@
 //!   ```
 use std::sync::Arc;
 
-use smallvec::{smallvec, SmallVec};
-
-use crate::{
-    db::HirDatabase,
-    expr::{Body, Expr, Literal, Pat, PatId},
-    ApplicationTy, InferenceResult, Ty, TypeCtor,
+use hir_def::{
+    adt::VariantData,
+    body::Body,
+    expr::{Expr, Literal, Pat, PatId},
+    AdtId, EnumVariantId, VariantId,
 };
-use hir_def::{adt::VariantData, AdtId, EnumVariantId, VariantId};
 use ra_arena::Idx;
+use smallvec::{smallvec, SmallVec};
+
+use crate::{db::HirDatabase, ApplicationTy, InferenceResult, Ty, TypeCtor};
 
 #[derive(Debug, Clone, Copy)]
 /// Either a pattern from the source code being analyzed, represented as
diff --git a/crates/ra_hir_ty/src/unsafe_validation.rs b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
similarity index 85%
rename from crates/ra_hir_ty/src/unsafe_validation.rs
rename to crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
index c512c4f8e9..b8ff95ee1e 100644
--- a/crates/ra_hir_ty/src/unsafe_validation.rs
+++ b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
@@ -6,7 +6,7 @@ use std::sync::Arc;
 use hir_def::{
     body::Body,
     expr::{Expr, ExprId, UnaryOp},
-    DefWithBodyId, FunctionId,
+    DefWithBodyId,
 };
 use hir_expand::diagnostics::DiagnosticSink;
 
@@ -15,26 +15,29 @@ use crate::{
     InferenceResult, Ty, TypeCtor,
 };
 
-pub struct UnsafeValidator<'a, 'b: 'a> {
-    func: FunctionId,
+pub(super) struct UnsafeValidator<'a, 'b: 'a> {
+    owner: DefWithBodyId,
     infer: Arc<InferenceResult>,
     sink: &'a mut DiagnosticSink<'b>,
 }
 
 impl<'a, 'b> UnsafeValidator<'a, 'b> {
-    pub fn new(
-        func: FunctionId,
+    pub(super) fn new(
+        owner: DefWithBodyId,
         infer: Arc<InferenceResult>,
         sink: &'a mut DiagnosticSink<'b>,
     ) -> UnsafeValidator<'a, 'b> {
-        UnsafeValidator { func, infer, sink }
+        UnsafeValidator { owner, infer, sink }
     }
 
-    pub fn validate_body(&mut self, db: &dyn HirDatabase) {
-        let def = self.func.into();
+    pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) {
+        let def = self.owner.into();
         let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def);
-        let func_data = db.function_data(self.func);
-        if func_data.is_unsafe
+        let is_unsafe = match self.owner {
+            DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe,
+            DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
+        };
+        if is_unsafe
             || unsafe_expressions
                 .iter()
                 .filter(|unsafe_expr| !unsafe_expr.inside_unsafe_block)
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 2ce4f65ccc..28f32a0a4d 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -168,7 +168,7 @@ impl InferenceResult {
     pub fn add_diagnostics(
         &self,
         db: &dyn HirDatabase,
-        owner: FunctionId,
+        owner: DefWithBodyId,
         sink: &mut DiagnosticSink,
     ) {
         self.diagnostics.iter().for_each(|it| it.add_to(db, owner, sink))
@@ -760,7 +760,7 @@ impl std::ops::BitOrAssign for Diverges {
 }
 
 mod diagnostics {
-    use hir_def::{expr::ExprId, FunctionId};
+    use hir_def::{expr::ExprId, DefWithBodyId};
     use hir_expand::diagnostics::DiagnosticSink;
 
     use crate::{
@@ -778,17 +778,17 @@ mod diagnostics {
         pub(super) fn add_to(
             &self,
             db: &dyn HirDatabase,
-            owner: FunctionId,
+            owner: DefWithBodyId,
             sink: &mut DiagnosticSink,
         ) {
             match self {
                 InferenceDiagnostic::NoSuchField { expr, field } => {
-                    let (_, source_map) = db.body_with_source_map(owner.into());
+                    let (_, source_map) = db.body_with_source_map(owner);
                     let field = source_map.field_syntax(*expr, *field);
                     sink.push(NoSuchField { file: field.file_id, field: field.value })
                 }
                 InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
-                    let (_, source_map) = db.body_with_source_map(owner.into());
+                    let (_, source_map) = db.body_with_source_map(owner);
                     let ptr = source_map
                         .expr_syntax(*expr)
                         .expect("break outside of loop in synthetic syntax");
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 2652d200f5..d54568e67a 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -12,15 +12,12 @@ pub mod traits;
 pub mod method_resolution;
 mod op;
 mod lower;
-mod match_checking;
 pub(crate) mod infer;
 pub(crate) mod utils;
 
 pub mod display;
 pub mod db;
 pub mod diagnostics;
-pub mod expr;
-pub mod unsafe_validation;
 
 #[cfg(test)]
 mod tests;


Test patch:
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index dc447955f7..daf2b909eb 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -13,10 +13,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
 use stdx::format_to;
 use test_utils::extract_annotations;
 
-use crate::{
-    db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator,
-    unsafe_validation::UnsafeValidator,
-};
+use crate::diagnostics::{validate_body, Diagnostic};
 
 #[salsa::database(
     ra_db::SourceDatabaseExtStorage,
@@ -118,13 +115,8 @@ impl TestDB {
             }
 
             for f in fns {
-                let infer = self.infer(f.into());
                 let mut sink = DiagnosticSink::new(&mut cb);
-                infer.add_diagnostics(self, f, &mut sink);
-                let mut validator = ExprValidator::new(f, infer.clone(), &mut sink);
-                validator.validate_body(self);
-                let mut validator = UnsafeValidator::new(f, infer, &mut sink);
-                validator.validate_body(self);
+                validate_body(self, f.into(), &mut sink);
             }
         }
     }