]> git.lizzy.rs Git - rust.git/blob - src/types.rs
f6d7749f1600ef412fce2cc69947a9f27195164c
[rust.git] / src / types.rs
1
2
3 use syntax::ptr::P;
4 use syntax::ast;
5 use syntax::ast::*;
6 use rustc::lint::{Context, LintPass, LintArray, Lint, Level};
7 use syntax::codemap::Span;
8
9 use utils::{span_lint, span_help_and_lint};
10
11 /// Handles all the linting of funky types
12 #[allow(missing_copy_implementations)]
13 pub struct TypePass;
14
15 declare_lint!(pub BOX_VEC, Warn,
16               "Warn on usage of Box<Vec<T>>");
17 declare_lint!(pub LINKEDLIST, Warn,
18               "Warn on usage of LinkedList");
19
20 /// Matches a type with a provided string, and returns its type parameters if successful
21 pub fn match_ty_unwrap<'a>(ty: &'a Ty, segments: &[&str]) -> Option<&'a [P<Ty>]> {
22     match ty.node {
23         TyPath(_, Path {segments: ref seg, ..}) => {
24             // So ast::Path isn't the full path, just the tokens that were provided.
25             // I could muck around with the maps and find the full path
26             // however the more efficient way is to simply reverse the iterators and zip them
27             // which will compare them in reverse until one of them runs out of segments
28             if seg.iter().rev().zip(segments.iter().rev()).all(|(a,b)| a.identifier.name == b) {
29                 match seg[..].last() {
30                     Some(&PathSegment {parameters: AngleBracketedParameters(ref a), ..}) => {
31                         Some(&a.types[..])
32                     }
33                     _ => None
34                 }
35             } else {
36                 None
37             }
38         },
39         _ => None
40     }
41 }
42
43 impl LintPass for TypePass {
44     fn get_lints(&self) -> LintArray {
45         lint_array!(BOX_VEC, LINKEDLIST)
46     }
47
48     fn check_ty(&mut self, cx: &Context, ty: &ast::Ty) {
49         {
50             // In case stuff gets moved around
51             use std::boxed::Box;
52             use std::vec::Vec;
53         }
54         match_ty_unwrap(ty, &["std", "boxed", "Box"]).and_then(|t| t.first())
55           .and_then(|t| match_ty_unwrap(&**t, &["std", "vec", "Vec"]))
56           .map(|_| {
57             span_help_and_lint(cx, BOX_VEC, ty.span,
58                               "You seem to be trying to use Box<Vec<T>>. Did you mean to use Vec<T>?",
59                               "Vec<T> is already on the heap, Box<Vec<T>> makes an extra allocation");
60           });
61         {
62             // In case stuff gets moved around
63             use collections::linked_list::LinkedList as DL1;
64             use std::collections::linked_list::LinkedList as DL2;
65             use std::collections::linked_list::LinkedList as DL3;
66         }
67         let dlists = [vec!["std","collections","linked_list","LinkedList"],
68                       vec!["std","collections","linked_list","LinkedList"],
69                       vec!["collections","linked_list","LinkedList"]];
70         for path in dlists.iter() {
71             if match_ty_unwrap(ty, &path[..]).is_some() {
72                 span_help_and_lint(cx, LINKEDLIST, ty.span,
73                                    "I see you're using a LinkedList! Perhaps you meant some other data structure?",
74                                    "A RingBuf might work.");
75                 return;
76             }
77         }
78     }
79 }