aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r--crates/ra_hir_ty/src/diagnostics/unsafe_check.rs38
-rw-r--r--crates/ra_hir_ty/src/infer.rs11
-rw-r--r--crates/ra_hir_ty/src/lower.rs5
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs38
4 files changed, 79 insertions, 13 deletions
diff --git a/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
index 5cc76bdce..61ffbf5d1 100644
--- a/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
+++ b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
@@ -6,6 +6,7 @@ use std::sync::Arc;
6use hir_def::{ 6use hir_def::{
7 body::Body, 7 body::Body,
8 expr::{Expr, ExprId, UnaryOp}, 8 expr::{Expr, ExprId, UnaryOp},
9 resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
9 DefWithBodyId, 10 DefWithBodyId,
10}; 11};
11use hir_expand::diagnostics::DiagnosticSink; 12use hir_expand::diagnostics::DiagnosticSink;
@@ -70,7 +71,7 @@ pub fn unsafe_expressions(
70) -> Vec<UnsafeExpr> { 71) -> Vec<UnsafeExpr> {
71 let mut unsafe_exprs = vec![]; 72 let mut unsafe_exprs = vec![];
72 let body = db.body(def); 73 let body = db.body(def);
73 walk_unsafe(&mut unsafe_exprs, db, infer, &body, body.body_expr, false); 74 walk_unsafe(&mut unsafe_exprs, db, infer, def, &body, body.body_expr, false);
74 75
75 unsafe_exprs 76 unsafe_exprs
76} 77}
@@ -79,6 +80,7 @@ fn walk_unsafe(
79 unsafe_exprs: &mut Vec<UnsafeExpr>, 80 unsafe_exprs: &mut Vec<UnsafeExpr>,
80 db: &dyn HirDatabase, 81 db: &dyn HirDatabase,
81 infer: &InferenceResult, 82 infer: &InferenceResult,
83 def: DefWithBodyId,
82 body: &Body, 84 body: &Body,
83 current: ExprId, 85 current: ExprId,
84 inside_unsafe_block: bool, 86 inside_unsafe_block: bool,
@@ -97,6 +99,15 @@ fn walk_unsafe(
97 } 99 }
98 } 100 }
99 } 101 }
102 Expr::Path(path) => {
103 let resolver = resolver_for_expr(db.upcast(), def, current);
104 let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path.mod_path());
105 if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial {
106 if db.static_data(id).mutable {
107 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
108 }
109 }
110 }
100 Expr::MethodCall { .. } => { 111 Expr::MethodCall { .. } => {
101 if infer 112 if infer
102 .method_resolution(current) 113 .method_resolution(current)
@@ -112,13 +123,13 @@ fn walk_unsafe(
112 } 123 }
113 } 124 }
114 Expr::Unsafe { body: child } => { 125 Expr::Unsafe { body: child } => {
115 return walk_unsafe(unsafe_exprs, db, infer, body, *child, true); 126 return walk_unsafe(unsafe_exprs, db, infer, def, body, *child, true);
116 } 127 }
117 _ => {} 128 _ => {}
118 } 129 }
119 130
120 expr.walk_child_exprs(|child| { 131 expr.walk_child_exprs(|child| {
121 walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block); 132 walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block);
122 }); 133 });
123} 134}
124 135
@@ -170,4 +181,25 @@ fn main() {
170"#, 181"#,
171 ); 182 );
172 } 183 }
184
185 #[test]
186 fn missing_unsafe_diagnostic_with_static_mut() {
187 check_diagnostics(
188 r#"
189struct Ty {
190 a: u8,
191}
192
193static mut static_mut: Ty = Ty { a: 0 };
194
195fn main() {
196 let x = static_mut.a;
197 //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
198 unsafe {
199 let x = static_mut.a;
200 }
201}
202"#,
203 );
204 }
173} 205}
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 28f32a0a4..3d12039a6 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -440,6 +440,12 @@ impl<'a> InferenceContext<'a> {
440 let ty = self.insert_type_vars(ty.subst(&substs)); 440 let ty = self.insert_type_vars(ty.subst(&substs));
441 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) 441 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
442 } 442 }
443 TypeNs::AdtId(AdtId::UnionId(u)) => {
444 let substs = Ty::substs_from_path(&ctx, path, u.into(), true);
445 let ty = self.db.ty(u.into());
446 let ty = self.insert_type_vars(ty.subst(&substs));
447 forbid_unresolved_segments((ty, Some(u.into())), unresolved)
448 }
443 TypeNs::EnumVariantId(var) => { 449 TypeNs::EnumVariantId(var) => {
444 let substs = Ty::substs_from_path(&ctx, path, var.into(), true); 450 let substs = Ty::substs_from_path(&ctx, path, var.into(), true);
445 let ty = self.db.ty(var.parent.into()); 451 let ty = self.db.ty(var.parent.into());
@@ -490,10 +496,7 @@ impl<'a> InferenceContext<'a> {
490 // FIXME potentially resolve assoc type 496 // FIXME potentially resolve assoc type
491 (Ty::Unknown, None) 497 (Ty::Unknown, None)
492 } 498 }
493 TypeNs::AdtId(AdtId::EnumId(_)) 499 TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) => {
494 | TypeNs::AdtId(AdtId::UnionId(_))
495 | TypeNs::BuiltinType(_)
496 | TypeNs::TraitId(_) => {
497 // FIXME diagnostic 500 // FIXME diagnostic
498 (Ty::Unknown, None) 501 (Ty::Unknown, None)
499 } 502 }
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 1eacc6f95..7638f167b 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -518,6 +518,7 @@ impl Ty {
518 let (segment, generic_def) = match resolved { 518 let (segment, generic_def) = match resolved {
519 ValueTyDefId::FunctionId(it) => (last, Some(it.into())), 519 ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
520 ValueTyDefId::StructId(it) => (last, Some(it.into())), 520 ValueTyDefId::StructId(it) => (last, Some(it.into())),
521 ValueTyDefId::UnionId(it) => (last, Some(it.into())),
521 ValueTyDefId::ConstId(it) => (last, Some(it.into())), 522 ValueTyDefId::ConstId(it) => (last, Some(it.into())),
522 ValueTyDefId::StaticId(_) => (last, None), 523 ValueTyDefId::StaticId(_) => (last, None),
523 ValueTyDefId::EnumVariantId(var) => { 524 ValueTyDefId::EnumVariantId(var) => {
@@ -1148,11 +1149,12 @@ impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefI
1148pub enum ValueTyDefId { 1149pub enum ValueTyDefId {
1149 FunctionId(FunctionId), 1150 FunctionId(FunctionId),
1150 StructId(StructId), 1151 StructId(StructId),
1152 UnionId(UnionId),
1151 EnumVariantId(EnumVariantId), 1153 EnumVariantId(EnumVariantId),
1152 ConstId(ConstId), 1154 ConstId(ConstId),
1153 StaticId(StaticId), 1155 StaticId(StaticId),
1154} 1156}
1155impl_from!(FunctionId, StructId, EnumVariantId, ConstId, StaticId for ValueTyDefId); 1157impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
1156 1158
1157/// Build the declared type of an item. This depends on the namespace; e.g. for 1159/// Build the declared type of an item. This depends on the namespace; e.g. for
1158/// `struct Foo(usize)`, we have two types: The type of the struct itself, and 1160/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
@@ -1179,6 +1181,7 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders
1179 match def { 1181 match def {
1180 ValueTyDefId::FunctionId(it) => type_for_fn(db, it), 1182 ValueTyDefId::FunctionId(it) => type_for_fn(db, it),
1181 ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), 1183 ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
1184 ValueTyDefId::UnionId(it) => type_for_adt(db, it.into()),
1182 ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), 1185 ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
1183 ValueTyDefId::ConstId(it) => type_for_const(db, it), 1186 ValueTyDefId::ConstId(it) => type_for_const(db, it),
1184 ValueTyDefId::StaticId(it) => type_for_static(db, it), 1187 ValueTyDefId::StaticId(it) => type_for_static(db, it),
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index 3fd7d5cd4..5a7cf9455 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -334,16 +334,44 @@ fn infer_union() {
334 bar: f32, 334 bar: f32,
335 } 335 }
336 336
337 fn test() {
338 let u = MyUnion { foo: 0 };
339 unsafe { baz(u); }
340 let u = MyUnion { bar: 0.0 };
341 unsafe { baz(u); }
342 }
343
337 unsafe fn baz(u: MyUnion) { 344 unsafe fn baz(u: MyUnion) {
338 let inner = u.foo; 345 let inner = u.foo;
346 let inner = u.bar;
339 } 347 }
340 "#, 348 "#,
341 expect![[r#" 349 expect![[r#"
342 61..62 'u': MyUnion 350 57..172 '{ ...); } }': ()
343 73..99 '{ ...foo; }': () 351 67..68 'u': MyUnion
344 83..88 'inner': u32 352 71..89 'MyUnio...o: 0 }': MyUnion
345 91..92 'u': MyUnion 353 86..87 '0': u32
346 91..96 'u.foo': u32 354 95..113 'unsafe...(u); }': ()
355 102..113 '{ baz(u); }': ()
356 104..107 'baz': fn baz(MyUnion)
357 104..110 'baz(u)': ()
358 108..109 'u': MyUnion
359 122..123 'u': MyUnion
360 126..146 'MyUnio... 0.0 }': MyUnion
361 141..144 '0.0': f32
362 152..170 'unsafe...(u); }': ()
363 159..170 '{ baz(u); }': ()
364 161..164 'baz': fn baz(MyUnion)
365 161..167 'baz(u)': ()
366 165..166 'u': MyUnion
367 188..189 'u': MyUnion
368 200..249 '{ ...bar; }': ()
369 210..215 'inner': u32
370 218..219 'u': MyUnion
371 218..223 'u.foo': u32
372 233..238 'inner': f32
373 241..242 'u': MyUnion
374 241..246 'u.bar': f32
347 "#]], 375 "#]],
348 ); 376 );
349} 377}