Skip to content

Commit 45fc8d5

Browse files
Merge #4587
4587: Add "missing unsafe" diagnostics r=Nashenas88 a=Nashenas88 Addresses #190 Co-authored-by: Paul Daniel Faria <[email protected]>
2 parents 9d1e2c4 + 9777d2c commit 45fc8d5

File tree

13 files changed

+328
-13
lines changed

13 files changed

+328
-13
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,5 @@ crates/*/target
77
*.log
88
*.iml
99
.vscode/settings.json
10-
*.html
1110
generated_assists.adoc
1211
generated_features.adoc

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ra_hir/src/code_model.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ use hir_ty::{
2626
autoderef,
2727
display::{HirDisplayError, HirFormatter},
2828
expr::ExprValidator,
29-
method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs,
30-
TraitEnvironment, Ty, TyDefId, TypeCtor,
29+
method_resolution,
30+
unsafe_validation::UnsafeValidator,
31+
ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs, TraitEnvironment, Ty,
32+
TyDefId, TypeCtor,
3133
};
3234
use ra_db::{CrateId, CrateName, Edition, FileId};
3335
use ra_prof::profile;
@@ -677,7 +679,9 @@ impl Function {
677679
let _p = profile("Function::diagnostics");
678680
let infer = db.infer(self.id.into());
679681
infer.add_diagnostics(db, self.id, sink);
680-
let mut validator = ExprValidator::new(self.id, infer, sink);
682+
let mut validator = ExprValidator::new(self.id, infer.clone(), sink);
683+
validator.validate_body(db);
684+
let mut validator = UnsafeValidator::new(self.id, infer, sink);
681685
validator.validate_body(db);
682686
}
683687
}

crates/ra_hir_def/src/body/lower.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ impl ExprCollector<'_> {
176176
if !self.expander.is_cfg_enabled(&expr) {
177177
return self.missing_expr();
178178
}
179+
179180
match expr {
180181
ast::Expr::IfExpr(e) => {
181182
let then_branch = self.collect_block_opt(e.then_branch());
@@ -218,8 +219,12 @@ impl ExprCollector<'_> {
218219
let body = self.collect_block_opt(e.block_expr());
219220
self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
220221
}
222+
ast::Effect::Unsafe(_) => {
223+
let body = self.collect_block_opt(e.block_expr());
224+
self.alloc_expr(Expr::Unsafe { body }, syntax_ptr)
225+
}
221226
// FIXME: we need to record these effects somewhere...
222-
ast::Effect::Async(_) | ast::Effect::Label(_) | ast::Effect::Unsafe(_) => {
227+
ast::Effect::Async(_) | ast::Effect::Label(_) => {
223228
self.collect_block_opt(e.block_expr())
224229
}
225230
},
@@ -445,7 +450,6 @@ impl ExprCollector<'_> {
445450
Mutability::from_mutable(e.mut_token().is_some())
446451
};
447452
let rawness = Rawness::from_raw(raw_tok);
448-
449453
self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)
450454
}
451455
ast::Expr::PrefixExpr(e) => {

crates/ra_hir_def/src/expr.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ pub enum Expr {
150150
Tuple {
151151
exprs: Vec<ExprId>,
152152
},
153+
Unsafe {
154+
body: ExprId,
155+
},
153156
Array(Array),
154157
Literal(Literal),
155158
}
@@ -247,7 +250,7 @@ impl Expr {
247250
f(*expr);
248251
}
249252
}
250-
Expr::TryBlock { body } => f(*body),
253+
Expr::TryBlock { body } | Expr::Unsafe { body } => f(*body),
251254
Expr::Loop { body, .. } => f(*body),
252255
Expr::While { condition, body, .. } => {
253256
f(*condition);

crates/ra_hir_ty/src/diagnostics.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,31 @@ impl AstDiagnostic for BreakOutsideOfLoop {
169169
ast::Expr::cast(node).unwrap()
170170
}
171171
}
172+
173+
#[derive(Debug)]
174+
pub struct MissingUnsafe {
175+
pub file: HirFileId,
176+
pub expr: AstPtr<ast::Expr>,
177+
}
178+
179+
impl Diagnostic for MissingUnsafe {
180+
fn message(&self) -> String {
181+
format!("This operation is unsafe and requires an unsafe function or block")
182+
}
183+
fn source(&self) -> InFile<SyntaxNodePtr> {
184+
InFile { file_id: self.file, value: self.expr.clone().into() }
185+
}
186+
fn as_any(&self) -> &(dyn Any + Send + 'static) {
187+
self
188+
}
189+
}
190+
191+
impl AstDiagnostic for MissingUnsafe {
192+
type AST = ast::Expr;
193+
194+
fn ast(&self, db: &impl AstDatabase) -> Self::AST {
195+
let root = db.parse_or_expand(self.source().file_id).unwrap();
196+
let node = self.source().value.to_node(&root);
197+
ast::Expr::cast(node).unwrap()
198+
}
199+
}

crates/ra_hir_ty/src/infer/expr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ impl<'a> InferenceContext<'a> {
142142
// FIXME: Breakable block inference
143143
self.infer_block(statements, *tail, expected)
144144
}
145+
Expr::Unsafe { body } => self.infer_expr(*body, expected),
145146
Expr::TryBlock { body } => {
146147
let _inner = self.infer_expr(*body, expected);
147148
// FIXME should be std::result::Result<{inner}, _>

crates/ra_hir_ty/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub(crate) mod utils;
3737
pub mod db;
3838
pub mod diagnostics;
3939
pub mod expr;
40+
pub mod unsafe_validation;
4041

4142
#[cfg(test)]
4243
mod tests;

crates/ra_hir_ty/src/test_db.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDataba
1111
use rustc_hash::FxHashSet;
1212
use stdx::format_to;
1313

14-
use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator};
14+
use crate::{
15+
db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator,
16+
unsafe_validation::UnsafeValidator,
17+
};
1518

1619
#[salsa::database(
1720
ra_db::SourceDatabaseExtStorage,
@@ -119,7 +122,9 @@ impl TestDB {
119122
let infer = self.infer(f.into());
120123
let mut sink = DiagnosticSink::new(&mut cb);
121124
infer.add_diagnostics(self, f, &mut sink);
122-
let mut validator = ExprValidator::new(f, infer, &mut sink);
125+
let mut validator = ExprValidator::new(f, infer.clone(), &mut sink);
126+
validator.validate_body(self);
127+
let mut validator = UnsafeValidator::new(f, infer, &mut sink);
123128
validator.validate_body(self);
124129
}
125130
}

crates/ra_hir_ty/src/tests.rs

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,155 @@ fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
538538
assert_snapshot!(diagnostics, @"");
539539
}
540540

541+
#[test]
542+
fn missing_unsafe_diagnostic_with_raw_ptr() {
543+
let diagnostics = TestDB::with_files(
544+
r"
545+
//- /lib.rs
546+
fn missing_unsafe() {
547+
let x = &5 as *const usize;
548+
let y = *x;
549+
}
550+
",
551+
)
552+
.diagnostics()
553+
.0;
554+
555+
assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#);
556+
}
557+
558+
#[test]
559+
fn missing_unsafe_diagnostic_with_unsafe_call() {
560+
let diagnostics = TestDB::with_files(
561+
r"
562+
//- /lib.rs
563+
unsafe fn unsafe_fn() {
564+
let x = &5 as *const usize;
565+
let y = *x;
566+
}
567+
568+
fn missing_unsafe() {
569+
unsafe_fn();
570+
}
571+
",
572+
)
573+
.diagnostics()
574+
.0;
575+
576+
assert_snapshot!(diagnostics, @r#""unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#);
577+
}
578+
579+
#[test]
580+
fn missing_unsafe_diagnostic_with_unsafe_method_call() {
581+
let diagnostics = TestDB::with_files(
582+
r"
583+
struct HasUnsafe;
584+
585+
impl HasUnsafe {
586+
unsafe fn unsafe_fn(&self) {
587+
let x = &5 as *const usize;
588+
let y = *x;
589+
}
590+
}
591+
592+
fn missing_unsafe() {
593+
HasUnsafe.unsafe_fn();
594+
}
595+
596+
",
597+
)
598+
.diagnostics()
599+
.0;
600+
601+
assert_snapshot!(diagnostics, @r#""HasUnsafe.unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#);
602+
}
603+
604+
#[test]
605+
fn no_missing_unsafe_diagnostic_with_raw_ptr_in_unsafe_block() {
606+
let diagnostics = TestDB::with_files(
607+
r"
608+
fn nothing_to_see_move_along() {
609+
let x = &5 as *const usize;
610+
unsafe {
611+
let y = *x;
612+
}
613+
}
614+
",
615+
)
616+
.diagnostics()
617+
.0;
618+
619+
assert_snapshot!(diagnostics, @"");
620+
}
621+
622+
#[test]
623+
fn missing_unsafe_diagnostic_with_raw_ptr_outside_unsafe_block() {
624+
let diagnostics = TestDB::with_files(
625+
r"
626+
fn nothing_to_see_move_along() {
627+
let x = &5 as *const usize;
628+
unsafe {
629+
let y = *x;
630+
}
631+
let z = *x;
632+
}
633+
",
634+
)
635+
.diagnostics()
636+
.0;
637+
638+
assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#);
639+
}
640+
641+
#[test]
642+
fn no_missing_unsafe_diagnostic_with_unsafe_call_in_unsafe_block() {
643+
let diagnostics = TestDB::with_files(
644+
r"
645+
unsafe fn unsafe_fn() {
646+
let x = &5 as *const usize;
647+
let y = *x;
648+
}
649+
650+
fn nothing_to_see_move_along() {
651+
unsafe {
652+
unsafe_fn();
653+
}
654+
}
655+
",
656+
)
657+
.diagnostics()
658+
.0;
659+
660+
assert_snapshot!(diagnostics, @"");
661+
}
662+
663+
#[test]
664+
fn no_missing_unsafe_diagnostic_with_unsafe_method_call_in_unsafe_block() {
665+
let diagnostics = TestDB::with_files(
666+
r"
667+
struct HasUnsafe;
668+
669+
impl HasUnsafe {
670+
unsafe fn unsafe_fn() {
671+
let x = &5 as *const usize;
672+
let y = *x;
673+
}
674+
}
675+
676+
fn nothing_to_see_move_along() {
677+
unsafe {
678+
HasUnsafe.unsafe_fn();
679+
}
680+
}
681+
682+
",
683+
)
684+
.diagnostics()
685+
.0;
686+
687+
assert_snapshot!(diagnostics, @"");
688+
}
689+
541690
#[test]
542691
fn break_outside_of_loop() {
543692
let diagnostics = TestDB::with_files(

crates/ra_hir_ty/src/tests/simple.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,6 +1880,7 @@ fn main() {
18801880
@r###"
18811881
10..130 '{ ...2 }; }': ()
18821882
20..21 'x': i32
1883+
24..37 'unsafe { 92 }': i32
18831884
31..37 '{ 92 }': i32
18841885
33..35 '92': i32
18851886
47..48 'y': {unknown}

0 commit comments

Comments
 (0)