diff --git a/src/types.rs b/src/types.rs index 915ffb15fe5..986fb1016ed 100644 --- a/src/types.rs +++ b/src/types.rs @@ -2,11 +2,10 @@ use rustc::lint::*; use syntax::ast; use syntax::ast::*; use syntax::ast_util::{is_comparison_binop, binop_to_string}; -use syntax::ptr::P; use rustc::middle::ty; use syntax::codemap::ExpnInfo; -use utils::{in_macro, snippet, span_lint, span_help_and_lint, in_external_macro}; +use utils::{in_macro, match_def_path, snippet, span_lint, span_help_and_lint, in_external_macro}; /// Handles all the linting of funky types #[allow(missing_copy_implementations)] @@ -18,61 +17,37 @@ declare_lint!(pub LINKEDLIST, Warn, "usage of LinkedList, usually a vector is faster, or a more specialized data \ structure like a RingBuf"); -/// Matches a type with a provided string, and returns its type parameters if successful -pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P]> { - match ty.node { - TyPath(_, Path {segments: ref seg, ..}) => { - // So ast::Path isn't the full path, just the tokens that were provided. - // I could muck around with the maps and find the full path - // however the more efficient way is to simply reverse the iterators and zip them - // which will compare them in reverse until one of them runs out of segments - if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.name == b) { - match seg[..].last() { - Some(&PathSegment {parameters: AngleBracketedParameters(ref a), ..}) => { - Some(&a.types[..]) - } - _ => None - } - } else { - None - } - }, - _ => None - } -} - #[allow(unused_imports)] impl LintPass for TypePass { fn get_lints(&self) -> LintArray { lint_array!(BOX_VEC, LINKEDLIST) } - fn check_ty(&mut self, cx: &Context, ty: &ast::Ty) { + fn check_ty(&mut self, cx: &Context, ast_ty: &ast::Ty) { { // In case stuff gets moved around - use std::boxed::Box; - use std::vec::Vec; + use collections::vec::Vec; + use collections::linked_list::LinkedList; } - match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.first()) - .and_then(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"])) - .map(|_| { - span_help_and_lint(cx, BOX_VEC, ty.span, - "you seem to be trying to use `Box>`. Did you mean to use `Vec`?", - "`Vec` is already on the heap, `Box>` makes an extra allocation"); - }); - { - // In case stuff gets moved around - use collections::linked_list::LinkedList as DL1; - use std::collections::linked_list::LinkedList as DL2; - } - let dlists = [vec!["std","collections","linked_list","LinkedList"], - vec!["collections","linked_list","LinkedList"]]; - for path in &dlists { - if match_ty_unwrap(ty, &path[..]).is_some() { - span_help_and_lint(cx, LINKEDLIST, ty.span, - "I see you're using a LinkedList! Perhaps you meant some other data structure?", - "a RingBuf might work"); - return; + if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { + if let ty::TyBox(ref inner) = ty.sty { + if let ty::TyStruct(did, _) = inner.sty { + if match_def_path(cx, did.did, &["collections", "vec", "Vec"]) { + span_help_and_lint( + cx, BOX_VEC, ast_ty.span, + "you seem to be trying to use `Box>`. Did you mean to use `Vec`?", + "`Vec` is already on the heap, `Box>` makes an extra allocation"); + } + } + } + if let ty::TyStruct(did, _) = ty.sty { + if match_def_path(cx, did.did, &["collections", "linked_list", "LinkedList"]) { + span_help_and_lint( + cx, LINKEDLIST, ast_ty.span, + "I see you're using a LinkedList! Perhaps you meant some other data structure?", + "a RingBuf might work"); + return; + } } } } diff --git a/tests/compile-fail/dlist.rs b/tests/compile-fail/dlist.rs old mode 100644 new mode 100755 index a2343c339ad..a800c045a50 --- a/tests/compile-fail/dlist.rs +++ b/tests/compile-fail/dlist.rs @@ -12,4 +12,4 @@ pub fn test(foo: LinkedList) { //~ ERROR I see you're using a LinkedList! fn main(){ test(LinkedList::new()); -} \ No newline at end of file +}