]> git.lizzy.rs Git - rust.git/blob - src/new_without_default.rs
Lint types with `fn new() -> Self` and no `Default` impl
[rust.git] / src / new_without_default.rs
1 use rustc::lint::*;
2 use rustc_front::hir;
3 use rustc_front::intravisit::FnKind;
4 use syntax::ast;
5 use syntax::codemap::Span;
6 use utils::{get_trait_def_id, implements_trait, in_external_macro, returns_self, span_lint, DEFAULT_TRAIT_PATH};
7
8 /// **What it does:** This lints about type with a `fn new() -> Self` method and no `Default`
9 /// implementation.
10 ///
11 /// **Why is this bad?** User might expect to be able to use `Default` is the type can be
12 /// constructed without arguments.
13 ///
14 /// **Known problems:** Hopefully none.
15 ///
16 /// **Example:**
17 ///
18 /// ```rust,ignore
19 /// struct Foo;
20 ///
21 /// impl Foo {
22 ///     fn new() -> Self {
23 ///         Foo
24 ///     }
25 /// }
26 /// ```
27 declare_lint! {
28     pub NEW_WITHOUT_DEFAULT,
29     Warn,
30     "`fn new() -> Self` method without `Default` implementation"
31 }
32
33 #[derive(Copy,Clone)]
34 pub struct NewWithoutDefault;
35
36 impl LintPass for NewWithoutDefault {
37     fn get_lints(&self) -> LintArray {
38         lint_array!(NEW_WITHOUT_DEFAULT)
39     }
40 }
41
42 impl LateLintPass for NewWithoutDefault {
43     fn check_fn(&mut self, cx: &LateContext, kind: FnKind, decl: &hir::FnDecl, _: &hir::Block, span: Span, id: ast::NodeId) {
44         if in_external_macro(cx, span) {
45             return;
46         }
47
48         if let FnKind::Method(name, _, _) = kind {
49             if decl.inputs.is_empty() && name.as_str() == "new" {
50                 let ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(cx.tcx.map.get_parent(id))).ty;
51
52                 if  returns_self(cx, &decl.output, ty) {
53                     if let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH) {
54                         if !implements_trait(cx, ty, default_trait_id, Vec::new()) {
55                             span_lint(cx, NEW_WITHOUT_DEFAULT, span,
56                                       &format!("you should consider adding a `Default` implementation for `{}`", ty));
57                         }
58                     }
59                 }
60             }
61         }
62     }
63 }