Remove UnnecessaryUnsafe diagnostic, Fix Expr::Call unsafe analysis

This commit is contained in:
Paul Daniel Faria 2020-05-24 13:18:31 -04:00
parent b358fbfdf8
commit 499d4c454d
4 changed files with 22 additions and 70 deletions

View file

@ -3,7 +3,10 @@
use std::any::Any; use std::any::Any;
use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile};
use ra_syntax::{ast::{self, NameOwner}, AstNode, AstPtr, SyntaxNodePtr}; use ra_syntax::{
ast::{self, NameOwner},
AstNode, AstPtr, SyntaxNodePtr,
};
use stdx::format_to; use stdx::format_to;
pub use hir_def::{diagnostics::UnresolvedModule, expr::MatchArm, path::Path}; pub use hir_def::{diagnostics::UnresolvedModule, expr::MatchArm, path::Path};
@ -197,31 +200,3 @@ impl AstDiagnostic for MissingUnsafe {
ast::FnDef::cast(node).unwrap().name().unwrap() ast::FnDef::cast(node).unwrap().name().unwrap()
} }
} }
#[derive(Debug)]
pub struct UnnecessaryUnsafe {
pub file: HirFileId,
pub fn_def: AstPtr<ast::FnDef>,
}
impl Diagnostic for UnnecessaryUnsafe {
fn message(&self) -> String {
format!("Unnecessary unsafe keyword on fn")
}
fn source(&self) -> InFile<SyntaxNodePtr> {
InFile { file_id: self.file, value: self.fn_def.clone().into() }
}
fn as_any(&self) -> &(dyn Any + Send + 'static) {
self
}
}
impl AstDiagnostic for UnnecessaryUnsafe {
type AST = ast::Name;
fn ast(&self, db: &impl AstDatabase) -> Self::AST {
let root = db.parse_or_expand(self.source().file_id).unwrap();
let node = self.source().value.to_node(&root);
ast::FnDef::cast(node).unwrap().name().unwrap()
}
}

View file

@ -13,8 +13,8 @@ use crate::{
db::HirDatabase, db::HirDatabase,
diagnostics::{ diagnostics::{
MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields, MissingUnsafe, MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields, MissingUnsafe,
UnnecessaryUnsafe,
}, },
lower::CallableDef,
utils::variant_data, utils::variant_data,
ApplicationTy, InferenceResult, Ty, TypeCtor, ApplicationTy, InferenceResult, Ty, TypeCtor,
_match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
@ -328,17 +328,14 @@ pub fn unsafe_expressions(
for (id, expr) in body.exprs.iter() { for (id, expr) in body.exprs.iter() {
match expr { match expr {
Expr::Call { callee, .. } => { Expr::Call { callee, .. } => {
if infer let ty = &infer.type_of_expr[*callee];
.method_resolution(/* id */ *callee) if let &Ty::Apply(ApplicationTy {ctor: TypeCtor::FnDef(CallableDef::FunctionId(func)), .. }) = ty {
.map(|func| db.function_data(func).is_unsafe) if db.function_data(func).is_unsafe {
.unwrap_or(false)
{
unsafe_expr_ids.push(id); unsafe_expr_ids.push(id);
} }
} }
Expr::MethodCall {/*_receiver, method_name,*/ .. } => { }
// let receiver_ty = &infer.type_of_expr[*receiver]; Expr::MethodCall { .. } => {
// receiver_ty
if infer if infer
.method_resolution(id) .method_resolution(id)
.map(|func| { .map(|func| {
@ -382,9 +379,7 @@ impl<'a, 'b> UnsafeValidator<'a, 'b> {
let def = self.func.into(); let def = self.func.into();
let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def);
let func_data = db.function_data(self.func); let func_data = db.function_data(self.func);
let unnecessary = func_data.is_unsafe && unsafe_expressions.len() == 0; if func_data.is_unsafe || unsafe_expressions.len() == 0 {
let missing = !func_data.is_unsafe && unsafe_expressions.len() > 0;
if !(unnecessary || missing) {
return; return;
} }
@ -394,10 +389,6 @@ impl<'a, 'b> UnsafeValidator<'a, 'b> {
let file = in_file.file_id; let file = in_file.file_id;
let fn_def = AstPtr::new(&in_file.value); let fn_def = AstPtr::new(&in_file.value);
if unnecessary {
self.sink.push(UnnecessaryUnsafe { file, fn_def })
} else {
self.sink.push(MissingUnsafe { file, fn_def }) self.sink.push(MissingUnsafe { file, fn_def })
} }
}
} }

View file

@ -544,7 +544,7 @@ fn missing_unsafe_diagnostic_with_raw_ptr() {
r" r"
//- /lib.rs //- /lib.rs
fn missing_unsafe() { fn missing_unsafe() {
let x = &5 as *usize; let x = &5 as *const usize;
let y = *x; let y = *x;
} }
", ",
@ -552,7 +552,7 @@ fn missing_unsafe() {
.diagnostics() .diagnostics()
.0; .0;
assert_snapshot!(diagnostics, @r#""fn missing_unsafe() {\n let x = &5 as *usize;\n let y = *x;\n}": Missing unsafe keyword on fn"#); assert_snapshot!(diagnostics, @r#""fn missing_unsafe() {\n let x = &5 as *const usize;\n let y = *x;\n}": Missing unsafe keyword on fn"#);
} }
#[test] #[test]
@ -561,7 +561,7 @@ fn missing_unsafe_diagnostic_with_unsafe_call() {
r" r"
//- /lib.rs //- /lib.rs
unsafe fn unsafe_fn() { unsafe fn unsafe_fn() {
let x = &5 as *usize; let x = &5 as *const usize;
let y = *x; let y = *x;
} }
@ -585,7 +585,7 @@ struct HasUnsafe;
impl HasUnsafe { impl HasUnsafe {
unsafe fn unsafe_fn() { unsafe fn unsafe_fn() {
let x = &5 as *usize; let x = &5 as *const usize;
let y = *x; let y = *x;
} }
} }
@ -609,7 +609,7 @@ fn no_missing_unsafe_diagnostic_with_raw_ptr_in_unsafe_block() {
//- /lib.rs //- /lib.rs
fn nothing_to_see_move_along() { fn nothing_to_see_move_along() {
unsafe { unsafe {
let x = &5 as *usize; let x = &5 as *const usize;
let y = *x; let y = *x;
} }
} }
@ -627,7 +627,7 @@ fn no_missing_unsafe_diagnostic_with_unsafe_call_in_unsafe_block() {
r" r"
//- /lib.rs //- /lib.rs
unsafe fn unsafe_fn() { unsafe fn unsafe_fn() {
let x = &5 as *usize; let x = &5 as *const usize;
let y = *x; let y = *x;
} }
@ -653,7 +653,7 @@ struct HasUnsafe;
impl HasUnsafe { impl HasUnsafe {
unsafe fn unsafe_fn() { unsafe fn unsafe_fn() {
let x = &5 as *usize; let x = &5 as *const usize;
let y = *x; let y = *x;
} }
} }
@ -672,20 +672,6 @@ fn nothing_to_see_move_along() {
assert_snapshot!(diagnostics, @""); assert_snapshot!(diagnostics, @"");
} }
#[test]
fn unnecessary_unsafe_diagnostic() {
let diagnostics = TestDB::with_files(
r"
//- /lib.rs
unsafe fn actually_safe_fn() {}
",
)
.diagnostics()
.0;
assert_snapshot!(diagnostics, @r#""unsafe fn actually_safe_fn() {}": Unnecessary unsafe keyword on fn"#);
}
#[test] #[test]
fn break_outside_of_loop() { fn break_outside_of_loop() {
let diagnostics = TestDB::with_files( let diagnostics = TestDB::with_files(

View file

@ -899,7 +899,7 @@ impl ast::LoopBodyOwner for LoopExpr {}
impl LoopExpr { impl LoopExpr {
pub fn loop_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![loop]) } pub fn loop_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![loop]) }
} }
/// Block expression with an optional prefix (label, try ketword, /// Block expression with an optional prefix (label, try keyword,
/// unsafe keyword, async keyword...). /// unsafe keyword, async keyword...).
/// ///
/// ``` /// ```