aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/expr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src/expr.rs')
-rw-r--r--crates/ra_hir_ty/src/expr.rs70
1 files changed, 61 insertions, 9 deletions
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs
index 795f1762c..7532e2dc7 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -2,14 +2,19 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{path::path, resolver::HasResolver, AdtId, DefWithBodyId, FunctionId}; 5use hir_def::{
6 path::path, resolver::HasResolver, src::HasSource, AdtId, DefWithBodyId, FunctionId, Lookup,
7};
6use hir_expand::diagnostics::DiagnosticSink; 8use hir_expand::diagnostics::DiagnosticSink;
7use ra_syntax::{ast, AstPtr}; 9use ra_syntax::{ast, AstPtr};
8use rustc_hash::FxHashSet; 10use rustc_hash::FxHashSet;
9 11
10use crate::{ 12use crate::{
11 db::HirDatabase, 13 db::HirDatabase,
12 diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields}, 14 diagnostics::{
15 MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields, MissingUnsafe,
16 UnnecessaryUnsafe,
17 },
13 utils::variant_data, 18 utils::variant_data,
14 ApplicationTy, InferenceResult, Ty, TypeCtor, 19 ApplicationTy, InferenceResult, Ty, TypeCtor,
15 _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, 20 _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
@@ -321,16 +326,63 @@ pub fn unsafe_expressions(
321 let mut unsafe_expr_ids = vec![]; 326 let mut unsafe_expr_ids = vec![];
322 let body = db.body(def); 327 let body = db.body(def);
323 for (id, expr) in body.exprs.iter() { 328 for (id, expr) in body.exprs.iter() {
324 if let Expr::Call { callee, .. } = expr { 329 match expr {
325 if infer 330 Expr::Call { callee, .. } => {
326 .method_resolution(*callee) 331 if infer
327 .map(|func| db.function_data(func).is_unsafe) 332 .method_resolution(*callee)
328 .unwrap_or(false) 333 .map(|func| db.function_data(func).is_unsafe)
329 { 334 .unwrap_or(false)
330 unsafe_expr_ids.push(id); 335 {
336 unsafe_expr_ids.push(id);
337 }
338 }
339 Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
340 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }) = &infer[*expr] {
341 unsafe_expr_ids.push(id);
342 }
331 } 343 }
344 _ => {}
332 } 345 }
333 } 346 }
334 347
335 unsafe_expr_ids 348 unsafe_expr_ids
336} 349}
350
351pub struct UnsafeValidator<'a, 'b: 'a> {
352 func: FunctionId,
353 infer: Arc<InferenceResult>,
354 sink: &'a mut DiagnosticSink<'b>,
355}
356
357impl<'a, 'b> UnsafeValidator<'a, 'b> {
358 pub fn new(
359 func: FunctionId,
360 infer: Arc<InferenceResult>,
361 sink: &'a mut DiagnosticSink<'b>,
362 ) -> UnsafeValidator<'a, 'b> {
363 UnsafeValidator { func, infer, sink }
364 }
365
366 pub fn validate_body(&mut self, db: &dyn HirDatabase) {
367 let def = self.func.into();
368 let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def);
369 let func_data = db.function_data(self.func);
370 let unnecessary = func_data.is_unsafe && unsafe_expressions.len() == 0;
371 let missing = !func_data.is_unsafe && unsafe_expressions.len() > 0;
372 if !(unnecessary || missing) {
373 return;
374 }
375
376 let loc = self.func.lookup(db.upcast());
377 let in_file = loc.source(db.upcast());
378
379 let file = in_file.file_id;
380 let fn_def = AstPtr::new(&in_file.value);
381
382 if unnecessary {
383 self.sink.push(UnnecessaryUnsafe { file, fn_def })
384 } else {
385 self.sink.push(MissingUnsafe { file, fn_def })
386 }
387 }
388}