From 0af81d37734cc9b85aaac05c1ba2ac56584a54ef Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Tue, 29 Jul 2014 02:09:42 +0900 Subject: [PATCH 1/2] Add no_default_methods attribute and the associated lint --- src/doc/rust.md | 5 +++ src/librustc/lint/builtin.rs | 36 ++++++++++++++++++- src/librustc/lint/context.rs | 1 + .../compile-fail/lint-missing-override.rs | 24 +++++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/lint-missing-override.rs 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..659e32e50d00e 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,39 @@ 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 trait_set: HashSet = + trait_methods.iter().map(|m| { m.ident.name }).collect(); + let impl_set: HashSet = + impl_methods.iter().map(|m| { m.pe_ident().name }).collect(); + if !trait_set.is_subset(&impl_set) { + cx.span_lint(MISSING_OVERRIDE, attr.span, + "some default methods are not overridden"); + } + } + _ => () + } + } +} + 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..bbaae4575c266 --- /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 +impl Foo for Bar {} + +fn main() { + Bar.foo(); +} From bf7bf6b3b1a35545a5137449da51c3570150f96c Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Tue, 29 Jul 2014 19:29:49 +0900 Subject: [PATCH 2/2] Mention the names of the missing methods --- src/librustc/lint/builtin.rs | 12 +++++++----- src/test/compile-fail/lint-missing-override.rs | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 659e32e50d00e..ab81603473ddf 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1433,13 +1433,15 @@ impl LintPass for MissingOverride { }; 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 trait_set: HashSet = - trait_methods.iter().map(|m| { m.ident.name }).collect(); let impl_set: HashSet = impl_methods.iter().map(|m| { m.pe_ident().name }).collect(); - if !trait_set.is_subset(&impl_set) { - cx.span_lint(MISSING_OVERRIDE, attr.span, - "some default methods are not overridden"); + 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()); } } _ => () diff --git a/src/test/compile-fail/lint-missing-override.rs b/src/test/compile-fail/lint-missing-override.rs index bbaae4575c266..936a10902112c 100644 --- a/src/test/compile-fail/lint-missing-override.rs +++ b/src/test/compile-fail/lint-missing-override.rs @@ -16,7 +16,7 @@ trait Foo { struct Bar; -#[no_default_methods] //~ ERROR: some default methods are not overridden +#[no_default_methods] //~ ERROR: some default methods are not overridden: `foo` impl Foo for Bar {} fn main() {