rust/src/new_without_default.rs

66 lines
2.0 KiB
Rust
Raw Normal View History

use rustc::lint::*;
use rustc_front::hir;
use rustc_front::intravisit::FnKind;
use syntax::ast;
use syntax::codemap::Span;
2016-03-01 20:38:21 +01:00
use utils::{get_trait_def_id, implements_trait, in_external_macro, return_ty, span_lint, DEFAULT_TRAIT_PATH};
/// **What it does:** This lints about type with a `fn new() -> Self` method and no `Default`
/// implementation.
///
/// **Why is this bad?** User might expect to be able to use `Default` is the type can be
/// constructed without arguments.
///
/// **Known problems:** Hopefully none.
///
/// **Example:**
///
/// ```rust,ignore
/// struct Foo;
///
/// impl Foo {
/// fn new() -> Self {
/// Foo
/// }
/// }
/// ```
declare_lint! {
pub NEW_WITHOUT_DEFAULT,
Warn,
"`fn new() -> Self` method without `Default` implementation"
}
#[derive(Copy,Clone)]
pub struct NewWithoutDefault;
impl LintPass for NewWithoutDefault {
fn get_lints(&self) -> LintArray {
lint_array!(NEW_WITHOUT_DEFAULT)
}
}
impl LateLintPass for NewWithoutDefault {
fn check_fn(&mut self, cx: &LateContext, kind: FnKind, decl: &hir::FnDecl, _: &hir::Block, span: Span, id: ast::NodeId) {
if in_external_macro(cx, span) {
return;
}
if let FnKind::Method(name, _, _) = kind {
if decl.inputs.is_empty() && name.as_str() == "new" {
2016-03-01 20:38:21 +01:00
let self_ty = cx.tcx.lookup_item_type(cx.tcx.map.local_def_id(cx.tcx.map.get_parent(id))).ty;
2016-03-01 20:38:21 +01:00
let ret_ty = return_ty(cx.tcx.node_id_to_type(id));
if Some(self_ty) == ret_ty {
if let Some(default_trait_id) = get_trait_def_id(cx, &DEFAULT_TRAIT_PATH) {
2016-03-01 20:38:21 +01:00
if !implements_trait(cx, self_ty, default_trait_id, Vec::new()) {
span_lint(cx, NEW_WITHOUT_DEFAULT, span,
2016-03-01 20:38:21 +01:00
&format!("you should consider adding a `Default` implementation for `{}`", self_ty));
}
}
}
}
}
}
}