diff options
Diffstat (limited to 'crates/hir_ty')
-rw-r--r-- | crates/hir_ty/src/diagnostics.rs | 31 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/unsafe_check.rs | 148 | ||||
-rw-r--r-- | crates/hir_ty/src/infer.rs | 4 |
3 files changed, 21 insertions, 162 deletions
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs index 28d6ca567..12131d9bc 100644 --- a/crates/hir_ty/src/diagnostics.rs +++ b/crates/hir_ty/src/diagnostics.rs | |||
@@ -17,7 +17,10 @@ use crate::{ | |||
17 | diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink}, | 17 | diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink}, |
18 | }; | 18 | }; |
19 | 19 | ||
20 | pub use crate::diagnostics::expr::{record_literal_missing_fields, record_pattern_missing_fields}; | 20 | pub use crate::diagnostics::{ |
21 | expr::{record_literal_missing_fields, record_pattern_missing_fields}, | ||
22 | unsafe_check::missing_unsafe, | ||
23 | }; | ||
21 | 24 | ||
22 | pub fn validate_module_item( | 25 | pub fn validate_module_item( |
23 | db: &dyn HirDatabase, | 26 | db: &dyn HirDatabase, |
@@ -35,8 +38,6 @@ pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut Diag | |||
35 | let infer = db.infer(owner); | 38 | let infer = db.infer(owner); |
36 | let mut validator = expr::ExprValidator::new(owner, infer.clone(), sink); | 39 | let mut validator = expr::ExprValidator::new(owner, infer.clone(), sink); |
37 | validator.validate_body(db); | 40 | validator.validate_body(db); |
38 | let mut validator = unsafe_check::UnsafeValidator::new(owner, infer, sink); | ||
39 | validator.validate_body(db); | ||
40 | } | 41 | } |
41 | 42 | ||
42 | // Diagnostic: missing-structure-fields | 43 | // Diagnostic: missing-structure-fields |
@@ -219,30 +220,6 @@ impl Diagnostic for RemoveThisSemicolon { | |||
219 | } | 220 | } |
220 | } | 221 | } |
221 | 222 | ||
222 | // Diagnostic: missing-unsafe | ||
223 | // | ||
224 | // This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block. | ||
225 | #[derive(Debug)] | ||
226 | pub struct MissingUnsafe { | ||
227 | pub file: HirFileId, | ||
228 | pub expr: AstPtr<ast::Expr>, | ||
229 | } | ||
230 | |||
231 | impl Diagnostic for MissingUnsafe { | ||
232 | fn code(&self) -> DiagnosticCode { | ||
233 | DiagnosticCode("missing-unsafe") | ||
234 | } | ||
235 | fn message(&self) -> String { | ||
236 | format!("This operation is unsafe and requires an unsafe function or block") | ||
237 | } | ||
238 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
239 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
240 | } | ||
241 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
242 | self | ||
243 | } | ||
244 | } | ||
245 | |||
246 | // Diagnostic: mismatched-arg-count | 223 | // Diagnostic: mismatched-arg-count |
247 | // | 224 | // |
248 | // This diagnostic is triggered if a function is invoked with an incorrect amount of arguments. | 225 | // This diagnostic is triggered if a function is invoked with an incorrect amount of arguments. |
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs index c3c483425..a4054cef9 100644 --- a/crates/hir_ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs | |||
@@ -1,8 +1,6 @@ | |||
1 | //! Provides validations for unsafe code. Currently checks if unsafe functions are missing | 1 | //! Provides validations for unsafe code. Currently checks if unsafe functions are missing |
2 | //! unsafe blocks. | 2 | //! unsafe blocks. |
3 | 3 | ||
4 | use std::sync::Arc; | ||
5 | |||
6 | use hir_def::{ | 4 | use hir_def::{ |
7 | body::Body, | 5 | body::Body, |
8 | expr::{Expr, ExprId, UnaryOp}, | 6 | expr::{Expr, ExprId, UnaryOp}, |
@@ -10,52 +8,25 @@ use hir_def::{ | |||
10 | DefWithBodyId, | 8 | DefWithBodyId, |
11 | }; | 9 | }; |
12 | 10 | ||
13 | use crate::{ | 11 | use crate::{db::HirDatabase, InferenceResult, Interner, TyExt, TyKind}; |
14 | db::HirDatabase, diagnostics::MissingUnsafe, diagnostics_sink::DiagnosticSink, InferenceResult, | ||
15 | Interner, TyExt, TyKind, | ||
16 | }; | ||
17 | 12 | ||
18 | pub(super) struct UnsafeValidator<'a, 'b: 'a> { | 13 | pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> { |
19 | owner: DefWithBodyId, | 14 | let infer = db.infer(def); |
20 | infer: Arc<InferenceResult>, | ||
21 | sink: &'a mut DiagnosticSink<'b>, | ||
22 | } | ||
23 | 15 | ||
24 | impl<'a, 'b> UnsafeValidator<'a, 'b> { | 16 | // let unsafe_expressions = ; |
25 | pub(super) fn new( | 17 | let is_unsafe = match def { |
26 | owner: DefWithBodyId, | 18 | DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(), |
27 | infer: Arc<InferenceResult>, | 19 | DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false, |
28 | sink: &'a mut DiagnosticSink<'b>, | 20 | }; |
29 | ) -> UnsafeValidator<'a, 'b> { | 21 | if is_unsafe { |
30 | UnsafeValidator { owner, infer, sink } | 22 | return Vec::new(); |
31 | } | 23 | } |
32 | 24 | ||
33 | pub(super) fn validate_body(&mut self, db: &dyn HirDatabase) { | 25 | unsafe_expressions(db, &infer, def) |
34 | let def = self.owner; | 26 | .into_iter() |
35 | let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); | 27 | .filter(|it| !it.inside_unsafe_block) |
36 | let is_unsafe = match self.owner { | 28 | .map(|it| it.expr) |
37 | DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(), | 29 | .collect() |
38 | DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false, | ||
39 | }; | ||
40 | if is_unsafe | ||
41 | || unsafe_expressions | ||
42 | .iter() | ||
43 | .filter(|unsafe_expr| !unsafe_expr.inside_unsafe_block) | ||
44 | .count() | ||
45 | == 0 | ||
46 | { | ||
47 | return; | ||
48 | } | ||
49 | |||
50 | let (_, body_source) = db.body_with_source_map(def); | ||
51 | for unsafe_expr in unsafe_expressions { | ||
52 | if !unsafe_expr.inside_unsafe_block { | ||
53 | if let Ok(in_file) = body_source.as_ref().expr_syntax(unsafe_expr.expr) { | ||
54 | self.sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value }) | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | } | 30 | } |
60 | 31 | ||
61 | pub(crate) struct UnsafeExpr { | 32 | pub(crate) struct UnsafeExpr { |
@@ -126,92 +97,3 @@ fn walk_unsafe( | |||
126 | walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block); | 97 | walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block); |
127 | }); | 98 | }); |
128 | } | 99 | } |
129 | |||
130 | #[cfg(test)] | ||
131 | mod tests { | ||
132 | use crate::diagnostics::tests::check_diagnostics; | ||
133 | |||
134 | #[test] | ||
135 | fn missing_unsafe_diagnostic_with_raw_ptr() { | ||
136 | check_diagnostics( | ||
137 | r#" | ||
138 | fn main() { | ||
139 | let x = &5 as *const usize; | ||
140 | unsafe { let y = *x; } | ||
141 | let z = *x; | ||
142 | } //^^ This operation is unsafe and requires an unsafe function or block | ||
143 | "#, | ||
144 | ) | ||
145 | } | ||
146 | |||
147 | #[test] | ||
148 | fn missing_unsafe_diagnostic_with_unsafe_call() { | ||
149 | check_diagnostics( | ||
150 | r#" | ||
151 | struct HasUnsafe; | ||
152 | |||
153 | impl HasUnsafe { | ||
154 | unsafe fn unsafe_fn(&self) { | ||
155 | let x = &5 as *const usize; | ||
156 | let y = *x; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | unsafe fn unsafe_fn() { | ||
161 | let x = &5 as *const usize; | ||
162 | let y = *x; | ||
163 | } | ||
164 | |||
165 | fn main() { | ||
166 | unsafe_fn(); | ||
167 | //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
168 | HasUnsafe.unsafe_fn(); | ||
169 | //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
170 | unsafe { | ||
171 | unsafe_fn(); | ||
172 | HasUnsafe.unsafe_fn(); | ||
173 | } | ||
174 | } | ||
175 | "#, | ||
176 | ); | ||
177 | } | ||
178 | |||
179 | #[test] | ||
180 | fn missing_unsafe_diagnostic_with_static_mut() { | ||
181 | check_diagnostics( | ||
182 | r#" | ||
183 | struct Ty { | ||
184 | a: u8, | ||
185 | } | ||
186 | |||
187 | static mut STATIC_MUT: Ty = Ty { a: 0 }; | ||
188 | |||
189 | fn main() { | ||
190 | let x = STATIC_MUT.a; | ||
191 | //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
192 | unsafe { | ||
193 | let x = STATIC_MUT.a; | ||
194 | } | ||
195 | } | ||
196 | "#, | ||
197 | ); | ||
198 | } | ||
199 | |||
200 | #[test] | ||
201 | fn no_missing_unsafe_diagnostic_with_safe_intrinsic() { | ||
202 | check_diagnostics( | ||
203 | r#" | ||
204 | extern "rust-intrinsic" { | ||
205 | pub fn bitreverse(x: u32) -> u32; // Safe intrinsic | ||
206 | pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic | ||
207 | } | ||
208 | |||
209 | fn main() { | ||
210 | let _ = bitreverse(12); | ||
211 | let _ = floorf32(12.0); | ||
212 | //^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
213 | } | ||
214 | "#, | ||
215 | ); | ||
216 | } | ||
217 | } | ||
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index 7b57593e4..2c667da25 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -36,8 +36,8 @@ use syntax::SmolStr; | |||
36 | 36 | ||
37 | use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty}; | 37 | use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty}; |
38 | use crate::{ | 38 | use crate::{ |
39 | db::HirDatabase, fold_tys, lower::ImplTraitLoweringMode, | 39 | db::HirDatabase, fold_tys, lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, |
40 | to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, Substitution, TyBuilder, TyExt, TyKind, | 40 | Goal, Interner, Substitution, TyBuilder, TyExt, TyKind, |
41 | }; | 41 | }; |
42 | 42 | ||
43 | // This lint has a false positive here. See the link below for details. | 43 | // This lint has a false positive here. See the link below for details. |