Account for static mut in missing unsafe diagnostic

This commit is contained in:
Paul Daniel Faria 2020-08-06 20:55:29 -04:00
parent f1d507270c
commit f089690a21

View file

@ -6,6 +6,7 @@ use std::sync::Arc;
use hir_def::{ use hir_def::{
body::Body, body::Body,
expr::{Expr, ExprId, UnaryOp}, expr::{Expr, ExprId, UnaryOp},
resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
DefWithBodyId, DefWithBodyId,
}; };
use hir_expand::diagnostics::DiagnosticSink; use hir_expand::diagnostics::DiagnosticSink;
@ -70,7 +71,7 @@ pub fn unsafe_expressions(
) -> Vec<UnsafeExpr> { ) -> Vec<UnsafeExpr> {
let mut unsafe_exprs = vec![]; let mut unsafe_exprs = vec![];
let body = db.body(def); let body = db.body(def);
walk_unsafe(&mut unsafe_exprs, db, infer, &body, body.body_expr, false); walk_unsafe(&mut unsafe_exprs, db, infer, def, &body, body.body_expr, false);
unsafe_exprs unsafe_exprs
} }
@ -79,6 +80,7 @@ fn walk_unsafe(
unsafe_exprs: &mut Vec<UnsafeExpr>, unsafe_exprs: &mut Vec<UnsafeExpr>,
db: &dyn HirDatabase, db: &dyn HirDatabase,
infer: &InferenceResult, infer: &InferenceResult,
def: DefWithBodyId,
body: &Body, body: &Body,
current: ExprId, current: ExprId,
inside_unsafe_block: bool, inside_unsafe_block: bool,
@ -97,6 +99,15 @@ fn walk_unsafe(
} }
} }
} }
Expr::Path(path) => {
let resolver = resolver_for_expr(db.upcast(), def, current);
let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path.mod_path());
if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial {
if db.static_data(id).mutable {
unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
}
}
}
Expr::MethodCall { .. } => { Expr::MethodCall { .. } => {
if infer if infer
.method_resolution(current) .method_resolution(current)
@ -112,13 +123,13 @@ fn walk_unsafe(
} }
} }
Expr::Unsafe { body: child } => { Expr::Unsafe { body: child } => {
return walk_unsafe(unsafe_exprs, db, infer, body, *child, true); return walk_unsafe(unsafe_exprs, db, infer, def, body, *child, true);
} }
_ => {} _ => {}
} }
expr.walk_child_exprs(|child| { expr.walk_child_exprs(|child| {
walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block); walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block);
}); });
} }
@ -167,6 +178,27 @@ fn main() {
HasUnsafe.unsafe_fn(); HasUnsafe.unsafe_fn();
} }
} }
"#,
);
}
#[test]
fn missing_unsafe_diagnostic_with_static_mut() {
check_diagnostics(
r#"
struct Ty {
a: u8,
}
static mut static_mut: Ty = Ty { a: 0 };
fn main() {
let x = static_mut.a;
//^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
unsafe {
let x = static_mut.a;
}
}
"#, "#,
); );
} }