forked from rust-lang/rust
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added restriction lint that prohibits the usage of unimplemented, unr…
…eachable or panic in a function of type result or option
- Loading branch information
Vali Schneider
committed
Aug 27, 2020
1 parent
dead45f
commit 459969f
Showing
6 changed files
with
280 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
use crate::utils::{is_expn_of, is_type_diagnostic_item, return_ty, span_lint_and_then}; | ||
use if_chain::if_chain; | ||
use rustc_hir as hir; | ||
use rustc_lint::{LateContext, LateLintPass}; | ||
use rustc_middle::hir::map::Map; | ||
use rustc_session::{declare_lint_pass, declare_tool_lint}; | ||
use rustc_span::Span; | ||
|
||
declare_clippy_lint! { | ||
/// **What it does:** Checks for usage of `panic!`, `unimplemented!` or `unreachable!` in a function of type result/option. | ||
/// | ||
/// **Why is this bad?** For some codebases, | ||
/// | ||
/// **Known problems:** None. | ||
/// | ||
/// **Example:** | ||
/// | ||
/// ```rust | ||
/// fn option_with_panic() -> Option<bool> // should emit lint | ||
/// { | ||
/// panic!("error"); | ||
/// } | ||
/// ``` | ||
|
||
pub PANIC_IN_RESULT, | ||
restriction, | ||
"functions of type `Result<..>` / `Option`<...> that contain `panic!()` or `unreachable()` or `unimplemented()` " | ||
} | ||
|
||
declare_lint_pass!(PanicInResult => [PANIC_IN_RESULT]); | ||
|
||
impl<'tcx> LateLintPass<'tcx> for PanicInResult { | ||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { | ||
if_chain! { | ||
// first check if it's a method or function | ||
if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind; | ||
// checking if its return type is `result` or `option` | ||
if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(result_type)) | ||
|| is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(option_type)); | ||
then { | ||
lint_impl_body(cx, impl_item.span, impl_item); | ||
} | ||
} | ||
} | ||
} | ||
|
||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; | ||
use rustc_hir::{Expr, ImplItemKind}; | ||
|
||
struct FindPanicUnimplementedUnreachable { | ||
result: Vec<Span>, | ||
} | ||
|
||
impl<'tcx> Visitor<'tcx> for FindPanicUnimplementedUnreachable { | ||
type Map = Map<'tcx>; | ||
|
||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { | ||
if is_expn_of(expr.span, "unimplemented").is_some() { | ||
self.result.push(expr.span); | ||
} else if is_expn_of(expr.span, "unreachable").is_some() { | ||
self.result.push(expr.span); | ||
} else if is_expn_of(expr.span, "panic").is_some() { | ||
self.result.push(expr.span); | ||
} | ||
|
||
// and check sub-expressions | ||
intravisit::walk_expr(self, expr); | ||
} | ||
|
||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { | ||
NestedVisitorMap::None | ||
} | ||
} | ||
|
||
fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) { | ||
if_chain! { | ||
if let ImplItemKind::Fn(_, body_id) = impl_item.kind; | ||
then { | ||
let body = cx.tcx.hir().body(body_id); | ||
let mut fpu = FindPanicUnimplementedUnreachable { | ||
result: Vec::new(), | ||
}; | ||
fpu.visit_expr(&body.value); | ||
|
||
// if we've found one, lint | ||
if !fpu.result.is_empty() { | ||
span_lint_and_then( | ||
cx, | ||
PANIC_IN_RESULT, | ||
impl_span, | ||
"used unimplemented, unreachable or panic in a function that returns result or option", | ||
move |diag| { | ||
diag.help( | ||
"unimplemented, unreachable or panic should not be used in a function that returns result or option" ); | ||
diag.span_note(fpu.result, "will cause the application to crash."); | ||
}); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#![warn(clippy::panic_in_result)] | ||
|
||
struct A; | ||
|
||
impl A { | ||
fn result_with_panic() -> Result<bool, String> // should emit lint | ||
{ | ||
panic!("error"); | ||
} | ||
|
||
fn result_with_unimplemented() -> Result<bool, String> // should emit lint | ||
{ | ||
unimplemented!(); | ||
} | ||
|
||
fn result_with_unreachable() -> Result<bool, String> // should emit lint | ||
{ | ||
unreachable!(); | ||
} | ||
|
||
fn option_with_unreachable() -> Option<bool> // should emit lint | ||
{ | ||
unreachable!(); | ||
} | ||
|
||
fn option_with_unimplemented() -> Option<bool> // should emit lint | ||
{ | ||
unimplemented!(); | ||
} | ||
|
||
fn option_with_panic() -> Option<bool> // should emit lint | ||
{ | ||
panic!("error"); | ||
} | ||
|
||
fn other_with_panic() // should not emit lint | ||
{ | ||
panic!(""); | ||
} | ||
|
||
fn other_with_unreachable() // should not emit lint | ||
{ | ||
unreachable!(); | ||
} | ||
|
||
fn other_with_unimplemented() // should not emit lint | ||
{ | ||
unimplemented!(); | ||
} | ||
|
||
fn result_without_banned_functions() -> Result<bool, String> // should not emit lint | ||
{ | ||
Ok(true) | ||
} | ||
|
||
fn option_without_banned_functions() -> Option<bool> // should not emit lint | ||
{ | ||
Some(true) | ||
} | ||
} | ||
|
||
fn main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
error: used unimplemented, unreachable or panic in a function that returns result or option | ||
--> $DIR/panic_in_result.rs:6:5 | ||
| | ||
LL | / fn result_with_panic() -> Result<bool, String> // should emit lint | ||
LL | | { | ||
LL | | panic!("error"); | ||
LL | | } | ||
| |_____^ | ||
| | ||
= note: `-D clippy::panic-in-result` implied by `-D warnings` | ||
= help: unimplemented, unreachable or panic should not be used in a function that returns result or option | ||
note: will cause the application to crash. | ||
--> $DIR/panic_in_result.rs:8:9 | ||
| | ||
LL | panic!("error"); | ||
| ^^^^^^^^^^^^^^^^ | ||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error: used unimplemented, unreachable or panic in a function that returns result or option | ||
--> $DIR/panic_in_result.rs:11:5 | ||
| | ||
LL | / fn result_with_unimplemented() -> Result<bool, String> // should emit lint | ||
LL | | { | ||
LL | | unimplemented!(); | ||
LL | | } | ||
| |_____^ | ||
| | ||
= help: unimplemented, unreachable or panic should not be used in a function that returns result or option | ||
note: will cause the application to crash. | ||
--> $DIR/panic_in_result.rs:13:9 | ||
| | ||
LL | unimplemented!(); | ||
| ^^^^^^^^^^^^^^^^^ | ||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error: used unimplemented, unreachable or panic in a function that returns result or option | ||
--> $DIR/panic_in_result.rs:16:5 | ||
| | ||
LL | / fn result_with_unreachable() -> Result<bool, String> // should emit lint | ||
LL | | { | ||
LL | | unreachable!(); | ||
LL | | } | ||
| |_____^ | ||
| | ||
= help: unimplemented, unreachable or panic should not be used in a function that returns result or option | ||
note: will cause the application to crash. | ||
--> $DIR/panic_in_result.rs:18:9 | ||
| | ||
LL | unreachable!(); | ||
| ^^^^^^^^^^^^^^^ | ||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error: used unimplemented, unreachable or panic in a function that returns result or option | ||
--> $DIR/panic_in_result.rs:21:5 | ||
| | ||
LL | / fn option_with_unreachable() -> Option<bool> // should emit lint | ||
LL | | { | ||
LL | | unreachable!(); | ||
LL | | } | ||
| |_____^ | ||
| | ||
= help: unimplemented, unreachable or panic should not be used in a function that returns result or option | ||
note: will cause the application to crash. | ||
--> $DIR/panic_in_result.rs:23:9 | ||
| | ||
LL | unreachable!(); | ||
| ^^^^^^^^^^^^^^^ | ||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error: used unimplemented, unreachable or panic in a function that returns result or option | ||
--> $DIR/panic_in_result.rs:26:5 | ||
| | ||
LL | / fn option_with_unimplemented() -> Option<bool> // should emit lint | ||
LL | | { | ||
LL | | unimplemented!(); | ||
LL | | } | ||
| |_____^ | ||
| | ||
= help: unimplemented, unreachable or panic should not be used in a function that returns result or option | ||
note: will cause the application to crash. | ||
--> $DIR/panic_in_result.rs:28:9 | ||
| | ||
LL | unimplemented!(); | ||
| ^^^^^^^^^^^^^^^^^ | ||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error: used unimplemented, unreachable or panic in a function that returns result or option | ||
--> $DIR/panic_in_result.rs:31:5 | ||
| | ||
LL | / fn option_with_panic() -> Option<bool> // should emit lint | ||
LL | | { | ||
LL | | panic!("error"); | ||
LL | | } | ||
| |_____^ | ||
| | ||
= help: unimplemented, unreachable or panic should not be used in a function that returns result or option | ||
note: will cause the application to crash. | ||
--> $DIR/panic_in_result.rs:33:9 | ||
| | ||
LL | panic!("error"); | ||
| ^^^^^^^^^^^^^^^^ | ||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error: aborting due to 6 previous errors | ||
|