diff --git a/src/lib.rs b/src/lib.rs index 386e8180c22..9ac74eb2320 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ -#![feature(globs, phase, plugin_registrar)] +#![feature(globs, phase, plugin_registrar)] #![allow(unused_imports)] -#[phase(plugin,link)] +#[phase(plugin, link)] extern crate syntax; #[phase(plugin, link)] extern crate rustc; @@ -21,4 +21,5 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box types::TypePass as LintPassObject); reg.register_lint_pass(box misc::MiscPass as LintPassObject); reg.register_lint_pass(box misc::StrToStringPass as LintPassObject); + reg.register_lint_pass(box misc::TopLevelRefPass as LintPassObject); } diff --git a/src/misc.rs b/src/misc.rs index 68195994907..47e8733abfb 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,6 +1,7 @@ use syntax::ptr::P; use syntax::ast; use syntax::ast::*; +use syntax::visit::{FnKind}; use rustc::lint::{Context, LintPass, LintArray, Lint, Level}; use rustc::middle::ty::{mod, expr_ty, ty_str, ty_ptr, ty_rptr}; use syntax::codemap::Span; @@ -38,7 +39,7 @@ impl LintPass for MiscPass { format!("Try if let {} = {} {{ ... }}", map.span_to_snippet(arms[0].pats[0].span).unwrap_or("..".to_string()), map.span_to_snippet(ex.span).unwrap_or("..".to_string())).as_slice() - ); + ); } } } @@ -81,3 +82,26 @@ impl LintPass for StrToStringPass { } } } + + +declare_lint!(CLIPPY_TOPLEVEL_REF_ARG, Warn, "Warn about pattern matches with top-level `ref` bindings"); + +pub struct TopLevelRefPass; + +impl LintPass for TopLevelRefPass { + fn get_lints(&self) -> LintArray { + lint_array!(CLIPPY_TOPLEVEL_REF_ARG) + } + + fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &FnDecl, _: &Block, _: Span, _: NodeId) { + for ref arg in decl.inputs.iter() { + if let PatIdent(BindByRef(_), _, _) = arg.pat.node { + cx.span_lint( + CLIPPY_TOPLEVEL_REF_ARG, + arg.pat.span, + "`ref` directly on a function argument is ignored. Have you considered using a reference type instead?" + ); + } + } + } +}