diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index a0cc862899c19..ec522d7078498 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -45,7 +45,7 @@ use syntax::ast_map; use syntax::ast_util::is_shift_binop; use syntax::attr::AttrMetaMethods; use syntax::attr; -use syntax::codemap::Span; +use syntax::codemap::{Span, DUMMY_SP}; use syntax::parse::token; use syntax::{ast, ast_util, visit}; use syntax::ast::{TyI, TyU, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64}; @@ -1553,16 +1553,40 @@ declare_lint!(UNSTABLE, Allow, /// `#[unstable]` attributes, or no stability attribute. pub struct Stability; -impl LintPass for Stability { - fn get_lints(&self) -> LintArray { - lint_array!(DEPRECATED, EXPERIMENTAL, UNSTABLE) +impl Stability { + fn lint(&self, cx: &Context, id: ast::DefId, span: Span) { + let stability = stability::lookup(cx.tcx, id); + let cross_crate = !ast_util::is_local(id); + + // stability attributes are promises made across crates; only + // check DEPRECATED for crate-local usage. + let (lint, label) = match stability { + // no stability attributes == Unstable + None if cross_crate => (UNSTABLE, "unmarked"), + Some(attr::Stability { level: attr::Unstable, .. }) if cross_crate => + (UNSTABLE, "unstable"), + Some(attr::Stability { level: attr::Experimental, .. }) if cross_crate => + (EXPERIMENTAL, "experimental"), + Some(attr::Stability { level: attr::Deprecated, .. }) => + (DEPRECATED, "deprecated"), + _ => return + }; + + let msg = match stability { + Some(attr::Stability { text: Some(ref s), .. }) => { + format!("use of {} item: {}", label, *s) + } + _ => format!("use of {} item", label) + }; + + cx.span_lint(lint, span, msg.as_slice()); } - fn check_expr(&mut self, cx: &Context, e: &ast::Expr) { + fn is_internal(&self, cx: &Context, span: Span) -> bool { // first, check if the given expression was generated by a macro or not // we need to go back the expn_info tree to check only the arguments // of the initial macro call, not the nested ones. - let mut expnid = e.span.expn_id; + let mut expnid = span.expn_id; let mut is_internal = false; while cx.tcx.sess.codemap().with_expn_info(expnid, |expninfo| { match expninfo { @@ -1577,15 +1601,41 @@ impl LintPass for Stability { true // continue looping } else { // was this expression from the current macro arguments ? - is_internal = !( e.span.lo > info.call_site.lo && - e.span.hi < info.call_site.hi ); + is_internal = !( span.lo > info.call_site.lo && + span.hi < info.call_site.hi ); true // continue looping } }, _ => false // stop looping } }) { /* empty while loop body */ } - if is_internal { return; } + return is_internal; + } +} + +impl LintPass for Stability { + fn get_lints(&self) -> LintArray { + lint_array!(DEPRECATED, EXPERIMENTAL, UNSTABLE) + } + + fn check_view_item(&mut self, cx: &Context, item: &ast::ViewItem) { + // compiler-generated `extern crate` statements have a dummy span. + if item.span == DUMMY_SP { return } + + let id = match item.node { + ast::ViewItemExternCrate(_, _, id) => id, + ast::ViewItemUse(..) => return, + }; + let cnum = match cx.tcx.sess.cstore.find_extern_mod_stmt_cnum(id) { + Some(cnum) => cnum, + None => return, + }; + let id = ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID }; + self.lint(cx, id, item.span); + } + + fn check_expr(&mut self, cx: &Context, e: &ast::Expr) { + if self.is_internal(cx, e.span) { return; } let mut span = e.span; @@ -1629,32 +1679,30 @@ impl LintPass for Stability { } _ => return }; + self.lint(cx, id, span); + } - let stability = stability::lookup(cx.tcx, id); - let cross_crate = !ast_util::is_local(id); - - // stability attributes are promises made across crates; only - // check DEPRECATED for crate-local usage. - let (lint, label) = match stability { - // no stability attributes == Unstable - None if cross_crate => (UNSTABLE, "unmarked"), - Some(attr::Stability { level: attr::Unstable, .. }) if cross_crate => - (UNSTABLE, "unstable"), - Some(attr::Stability { level: attr::Experimental, .. }) if cross_crate => - (EXPERIMENTAL, "experimental"), - Some(attr::Stability { level: attr::Deprecated, .. }) => - (DEPRECATED, "deprecated"), - _ => return - }; + fn check_item(&mut self, cx: &Context, item: &ast::Item) { + if self.is_internal(cx, item.span) { return } - let msg = match stability { - Some(attr::Stability { text: Some(ref s), .. }) => { - format!("use of {} item: {}", label, *s) + match item.node { + ast::ItemTrait(_, _, ref supertraits, _) => { + for t in supertraits.iter() { + match *t { + ast::TraitTyParamBound(ref t) => { + let id = ty::trait_ref_to_def_id(cx.tcx, t); + self.lint(cx, id, t.path.span); + } + _ => (/* pass */) + } + } } - _ => format!("use of {} item", label) - }; - - cx.span_lint(lint, span, msg.as_slice()); + ast::ItemImpl(_, Some(ref t), _, _) => { + let id = ty::trait_ref_to_def_id(cx.tcx, t); + self.lint(cx, id, t.path.span); + } + _ => (/* pass */) + } } } diff --git a/src/test/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs index 06031eb6c6ccf..0be2f31e2827f 100644 --- a/src/test/auxiliary/lint_stability.rs +++ b/src/test/auxiliary/lint_stability.rs @@ -118,6 +118,9 @@ pub trait Trait { impl Trait for MethodTester {} +#[experimental] +pub trait ExperimentalTrait {} + #[deprecated] pub struct DeprecatedStruct { pub i: int } #[experimental] diff --git a/src/test/compile-fail/lint-output-format.rs b/src/test/compile-fail/lint-output-format.rs index db60002b468e1..35721ee5b148f 100644 --- a/src/test/compile-fail/lint-output-format.rs +++ b/src/test/compile-fail/lint-output-format.rs @@ -11,7 +11,7 @@ // compile-flags:-F experimental -D unstable // aux-build:lint_output_format.rs -extern crate lint_output_format; +extern crate lint_output_format; //~ ERROR: use of unmarked item use lint_output_format::{foo, bar, baz}; fn main() { diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index fdb0d801164bf..2074d00750230 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -19,7 +19,7 @@ mod cross_crate { #[phase(plugin, link)] - extern crate lint_stability; + extern crate lint_stability; //~ ERROR: use of unmarked item use self::lint_stability::*; fn test() { @@ -141,10 +141,16 @@ mod cross_crate { foo.trait_unmarked(); //~ ERROR use of unmarked item foo.trait_stable(); } + + struct S; + + impl ExperimentalTrait for S { } //~ ERROR use of experimental item + + trait LocalTrait : ExperimentalTrait { } //~ ERROR use of experimental item } mod inheritance { - extern crate inherited_stability; + extern crate inherited_stability; //~ ERROR: use of experimental item use self::inherited_stability::*; fn test_inheritance() { @@ -444,6 +450,15 @@ mod this_crate { foo.trait_unmarked(); foo.trait_stable(); } + + #[deprecated] + pub trait DeprecatedTrait {} + + struct S; + + impl DeprecatedTrait for S { } //~ ERROR use of deprecated item + + trait LocalTrait : DeprecatedTrait { } //~ ERROR use of deprecated item } fn main() {}