diff --git a/src/doc/rust.md b/src/doc/rust.md index b015cb0fbb8c6..463e3edff4db3 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -1905,6 +1905,11 @@ type int8_t = i8; static may change depending on the current thread. The exact consequences of this are implementation-defined. +### Implementation-only attributes + +- `no_default_methods` - force this implementation to implement all methods + in the trait so that default methods are not used. + ### FFI attributes On an `extern` block, the following attributes are interpreted: diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 3f4f512369971..ab81603473ddf 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -36,11 +36,12 @@ use util::nodemap::NodeSet; use lint::{Context, LintPass, LintArray}; use std::cmp; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}; use std::gc::Gc; use syntax::abi; use syntax::ast_map; +use syntax::ast_util::PostExpansionMethod; use syntax::attr::AttrMetaMethods; use syntax::attr; use syntax::codemap::Span; @@ -1413,6 +1414,41 @@ impl LintPass for MissingDoc { } } +declare_lint!(MISSING_OVERRIDE, Warn, + "detects missing override methods") + +pub struct MissingOverride; + +impl LintPass for MissingOverride { + fn get_lints(&self) -> LintArray { + lint_array!(MISSING_OVERRIDE) + } + + fn check_item(&mut self, cx: &Context, item: &ast::Item) { + match item.node { + ast::ItemImpl(_, Some(ref ast_trait_ref), _, ref impl_methods) => { + let attr = match item.attrs.iter().find(|a| a.check_name("no_default_methods")) { + Some(attr) => attr, + None => return + }; + let trait_ref = ty::node_id_to_trait_ref(cx.tcx, ast_trait_ref.ref_id); + let trait_methods = ty::trait_methods(cx.tcx, trait_ref.def_id); + let impl_set: HashSet = + impl_methods.iter().map(|m| { m.pe_ident().name }).collect(); + let missing: Vec = trait_methods.iter() + .filter(|m| !impl_set.contains(&m.ident.name)) + .map(|m| format!("`{}`", token::get_name(m.ident.name))).collect(); + if !missing.is_empty() { + let msg = format!("some default methods are not overridden: {}", + missing.connect(", ")); + cx.span_lint(MISSING_OVERRIDE, attr.span, msg.as_slice()); + } + } + _ => () + } + } +} + declare_lint!(DEPRECATED, Warn, "detects use of #[deprecated] items") diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 7d9ec29d70144..58705ca2daf3c 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -155,6 +155,7 @@ impl LintStore { UnsafeBlock, UnusedMut, UnnecessaryAllocation, + MissingOverride, Stability, ) diff --git a/src/test/compile-fail/lint-missing-override.rs b/src/test/compile-fail/lint-missing-override.rs new file mode 100644 index 0000000000000..936a10902112c --- /dev/null +++ b/src/test/compile-fail/lint-missing-override.rs @@ -0,0 +1,24 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(missing_override)] + +trait Foo { + fn foo(&self) {} +} + +struct Bar; + +#[no_default_methods] //~ ERROR: some default methods are not overridden: `foo` +impl Foo for Bar {} + +fn main() { + Bar.foo(); +}