From 2bcc15188854ff184c85426b5aa60535ed1bd8a8 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 11 Aug 2015 20:53:50 +0200 Subject: [PATCH] new lint for Option.unwrap() and Result.unwrap() The latter is set to Allow by default (fixes #24) --- src/lib.rs | 4 ++++ src/methods.rs | 39 +++++++++++++++++++++++++++++++++++ tests/compile-fail/methods.rs | 11 ++++++++++ 3 files changed, 54 insertions(+) create mode 100644 src/methods.rs create mode 100755 tests/compile-fail/methods.rs diff --git a/src/lib.rs b/src/lib.rs index 80ba04031fa..4009aa1cf8d 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,7 @@ pub mod collapsible_if; pub mod unicode; pub mod utils; pub mod strings; +pub mod methods; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -55,6 +56,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box unicode::Unicode as LintPassObject); reg.register_lint_pass(box strings::StringAdd as LintPassObject); reg.register_lint_pass(box misc::NeedlessReturn as LintPassObject); + reg.register_lint_pass(box methods::MethodsPass as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, misc::SINGLE_MATCH, misc::STR_TO_STRING, @@ -77,5 +79,7 @@ pub fn plugin_registrar(reg: &mut Registry) { strings::STRING_ADD_ASSIGN, misc::NEEDLESS_RETURN, misc::MODULO_ONE, + methods::OPTION_UNWRAP_USED, + methods::RESULT_UNWRAP_USED, ]); } diff --git a/src/methods.rs b/src/methods.rs new file mode 100644 index 00000000000..3d9aa8c6ffc --- /dev/null +++ b/src/methods.rs @@ -0,0 +1,39 @@ +use syntax::ast::*; +use rustc::lint::{Context, LintPass, LintArray}; +use rustc::middle::ty; + +use utils::{span_lint, match_def_path, walk_ptrs_ty}; + +#[derive(Copy,Clone)] +pub struct MethodsPass; + +declare_lint!(pub OPTION_UNWRAP_USED, Warn, + "Warn on using unwrap() on an Option value"); +declare_lint!(pub RESULT_UNWRAP_USED, Allow, + "Warn on using unwrap() on a Result value"); + +impl LintPass for MethodsPass { + fn get_lints(&self) -> LintArray { + lint_array!(OPTION_UNWRAP_USED, RESULT_UNWRAP_USED) + } + + fn check_expr(&mut self, cx: &Context, expr: &Expr) { + if let ExprMethodCall(ref ident, _, ref args) = expr.node { + if ident.node.name == "unwrap" { + if let ty::TyEnum(did, _) = walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty { + if match_def_path(cx, did.did, &["core", "option", "Option"]) { + span_lint(cx, OPTION_UNWRAP_USED, expr.span, + "used unwrap() on an Option value. If you don't want \ + to handle the None case gracefully, consider using + expect() to provide a better panic message."); + } + else if match_def_path(cx, did.did, &["core", "result", "Result"]) { + span_lint(cx, RESULT_UNWRAP_USED, expr.span, + "used unwrap() on a Result value. Graceful handling \ + of Err values is preferred."); + } + } + } + } + } +} diff --git a/tests/compile-fail/methods.rs b/tests/compile-fail/methods.rs new file mode 100755 index 00000000000..e989dffe5a7 --- /dev/null +++ b/tests/compile-fail/methods.rs @@ -0,0 +1,11 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[deny(option_unwrap_used, result_unwrap_used)] +fn main() { + let opt = Some(0); + let _ = opt.unwrap(); //~ERROR + + let res: Result = Ok(0); + let _ = res.unwrap(); //~ERROR +}