diff --git a/README.md b/README.md index 91caaeba41a9..3d5e366f56db 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Lints included in this crate: - `clippy_box_vec`: Warns on usage of `Box>` - `clippy_dlist`: Warns on usage of `DList` - `clippy_str_to_string`: Warns on usage of `str::to_string()` + - `clippy_toplevel_ref_arg`: Warns when a function argument is declared `ref` (i.e. `fn foo(ref x: u8)`, but not `fn foo((ref x, ref y): (u8, u8))`). More to come, please [file an issue](https://github.com/Manishearth/rust-clippy/issues) if you have ideas! diff --git a/examples/toplevel_ref_arg.rs b/examples/toplevel_ref_arg.rs new file mode 100644 index 000000000000..0be737f90288 --- /dev/null +++ b/examples/toplevel_ref_arg.rs @@ -0,0 +1,14 @@ +#![feature(phase)] + +#[phase(plugin)] +extern crate rust_clippy; + +fn the_answer(ref mut x: u8) { + *x = 42; +} + +fn main() { + let mut x = 0; + the_answer(x); + println!("The answer is {}.", x); +} diff --git a/src/lib.rs b/src/lib.rs index 386e8180c22d..9ac74eb2320b 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 8c4fbe0597c6..c72f39ba3150 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; @@ -39,7 +40,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() - ); + ); } } } @@ -83,3 +84,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?" + ); + } + } + } +}