diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 6206b4efa32..afc910056eb 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -312,7 +312,7 @@ pub fn phase_3_run_analysis_passes(sess: Session, &exported_items, reachable_map, crate)); time(time_passes, "lint checking", (), |_| - lint::check_crate(ty_cx, &exported_items, crate)); + lint::check_crate(ty_cx, method_map, &exported_items, crate)); CrateAnalysis { exp_map2: exp_map2, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 1ffadfb6ede..b27aa11651d 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -812,6 +812,10 @@ fn encode_info_for_method(ecx: &EncodeContext, encode_bounds_and_type(ebml_w, ecx, &tpt); encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident)); + match ast_method_opt { + Some(ast_method) => encode_attributes(ebml_w, ast_method.attrs), + None => () + } for ast_method in ast_method_opt.iter() { let num_params = tpt.generics.type_param_defs.len(); @@ -1205,11 +1209,13 @@ fn encode_info_for_item(ecx: &EncodeContext, } match ms[i] { - required(_) => { + required(ref tm) => { + encode_attributes(ebml_w, tm.attrs); encode_method_sort(ebml_w, 'r'); } provided(m) => { + encode_attributes(ebml_w, m.attrs); // If this is a static method, we've already encoded // this. if method_ty.explicit_self != sty_static { diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 5128f90a0a5..8f5ae723c54 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -37,6 +37,7 @@ use driver::session; use middle::privacy; use middle::trans::adt; // for `adt::is_ffi_safe` use middle::ty; +use middle::typeck; use middle::pat_util; use metadata::csearch; use util::ppaux::{ty_to_str}; @@ -359,6 +360,9 @@ struct Context<'a> { cur: SmallIntMap<(level, LintSource)>, // context we're checking in (used to access fields like sess) tcx: ty::ctxt, + // maps from an expression id that corresponds to a method call to the + // details of the method to be invoked + method_map: typeck::method_map, // Items exported by the crate; used by the missing_doc lint. exported_items: &'a privacy::ExportedItems, // The id of the current `ast::struct_def` being walked. @@ -1176,20 +1180,43 @@ fn check_missing_doc_variant(cx: &Context, v: &ast::variant) { /// Checks for use of items with #[deprecated], #[experimental] and /// #[unstable] (or none of them) attributes. fn check_stability(cx: &Context, e: &ast::Expr) { - let def = match e.node { - ast::ExprMethodCall(..) | - ast::ExprPath(..) | - ast::ExprStruct(..) => { + let id = match e.node { + ast::ExprPath(..) | ast::ExprStruct(..) => { match cx.tcx.def_map.find(&e.id) { - Some(&def) => def, + Some(&def) => ast_util::def_id_of_def(def), + None => return + } + } + ast::ExprMethodCall(..) => { + match cx.method_map.find(&e.id) { + Some(&typeck::method_map_entry { origin, .. }) => { + match origin { + typeck::method_static(def_id) => { + // If this implements a trait method, get def_id + // of the method inside trait definition. + // Otherwise, use the current def_id (which refers + // to the method inside impl). + ty::trait_method_of_method( + cx.tcx, def_id).unwrap_or(def_id) + } + typeck::method_param(typeck::method_param { + trait_id: trait_id, + method_num: index, + .. + }) + | typeck::method_object(typeck::method_object { + trait_id: trait_id, + method_num: index, + .. + }) => ty::trait_method(cx.tcx, trait_id, index).def_id + } + } None => return } } _ => return }; - let id = ast_util::def_id_of_def(def); - let stability = if ast_util::is_local(id) { // this crate match cx.tcx.items.find(&id.node) { @@ -1208,7 +1235,8 @@ fn check_stability(cx: &Context, e: &ast::Expr) { None => return } } - _ => cx.tcx.sess.bug(format!("handle_def: {:?} not found", id)) + _ => cx.tcx.sess.span_bug(e.span, + format!("handle_def: {:?} not found", id)) } } else { // cross-crate @@ -1395,12 +1423,14 @@ impl<'a> IdVisitingOperation for Context<'a> { } pub fn check_crate(tcx: ty::ctxt, + method_map: typeck::method_map, exported_items: &privacy::ExportedItems, crate: &ast::Crate) { let mut cx = Context { dict: @get_lint_dict(), cur: SmallIntMap::new(), tcx: tcx, + method_map: method_map, exported_items: exported_items, cur_struct_def_id: -1, is_doc_hidden: false, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 86a7250d6b9..1bdd88a3b7a 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4540,29 +4540,67 @@ pub fn populate_implementations_for_trait_if_necessary( tcx.populated_external_traits.insert(trait_id); } -/// If the given def ID describes a trait method, returns the ID of the trait -/// that the method belongs to. Otherwise, returns `None`. -pub fn trait_of_method(tcx: ctxt, def_id: ast::DefId) - -> Option { - match tcx.methods.find(&def_id) { - Some(method_descriptor) => { - match method_descriptor.container { - TraitContainer(id) => return Some(id), - _ => {} +/// Given the def_id of an impl, return the def_id of the trait it implements. +/// If it implements no trait, return `None`. +pub fn trait_id_of_impl(tcx: ctxt, + def_id: ast::DefId) -> Option { + let node = match tcx.items.find(&def_id.node) { + Some(node) => node, + None => return None + }; + match node { + &ast_map::node_item(item, _) => { + match item.node { + ast::item_impl(_, Some(ref trait_ref), _, _) => { + Some(node_id_to_trait_ref(tcx, trait_ref.ref_id).def_id) + } + _ => None } } - None => {} + _ => None } +} - // If the method was in the local crate, then if we got here we know the - // answer is negative. - if def_id.crate == LOCAL_CRATE { - return None +/// If the given def ID describes a method belonging to a trait (either a +/// default method or an implementation of a trait method), return the ID of +/// the trait that the method belongs to. Otherwise, return `None`. +pub fn trait_of_method(tcx: ctxt, def_id: ast::DefId) + -> Option { + if def_id.crate != LOCAL_CRATE { + return csearch::get_trait_of_method(tcx.cstore, def_id, tcx); } + match tcx.methods.find(&def_id) { + Some(method) => { + match method.container { + TraitContainer(def_id) => Some(def_id), + ImplContainer(def_id) => trait_id_of_impl(tcx, def_id), + } + } + None => None + } +} - let result = csearch::get_trait_of_method(tcx.cstore, def_id, tcx); - - result +/// If the given def ID describes a method belonging to a trait, (either a +/// default method or an implementation of a trait method), return the ID of +/// the method inside trait definition (this means that if the given def ID +/// is already that of the original trait method, then the return value is +/// the same). +/// Otherwise, return `None`. +pub fn trait_method_of_method(tcx: ctxt, + def_id: ast::DefId) -> Option { + let name = match tcx.methods.find(&def_id) { + Some(method) => method.ident.name, + None => return None + }; + match trait_of_method(tcx, def_id) { + Some(trait_did) => { + let trait_methods = ty::trait_methods(tcx, trait_did); + trait_methods.iter() + .position(|m| m.ident.name == name) + .map(|idx| ty::trait_method(tcx, trait_did, idx).def_id) + } + None => None + } } /// Creates a hash of the type `t` which will be the same no matter what crate diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index 9cc06cc5395..ceec1ae3d8a 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -26,32 +26,32 @@ mod cross_crate { let foo = MethodTester; deprecated(); //~ ERROR use of deprecated item - foo.method_deprecated(); // ~ ERROR use of deprecated item - foo.trait_deprecated(); // ~ ERROR use of deprecated item + foo.method_deprecated(); //~ ERROR use of deprecated item + foo.trait_deprecated(); //~ ERROR use of deprecated item deprecated_text(); //~ ERROR use of deprecated item: text - foo.method_deprecated_text(); // ~ ERROR use of deprecated item: text - foo.trait_deprecated_text(); // ~ ERROR use of deprecated item: text + foo.method_deprecated_text(); //~ ERROR use of deprecated item: text + foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text experimental(); //~ ERROR use of experimental item - foo.method_experimental(); // ~ ERROR use of experimental item - foo.trait_experimental(); // ~ ERROR use of experimental item + foo.method_experimental(); //~ ERROR use of experimental item + foo.trait_experimental(); //~ ERROR use of experimental item experimental_text(); //~ ERROR use of experimental item: text - foo.method_experimental_text(); // ~ ERROR use of experimental item: text - foo.trait_experimental_text(); // ~ ERROR use of experimental item: text + foo.method_experimental_text(); //~ ERROR use of experimental item: text + foo.trait_experimental_text(); //~ ERROR use of experimental item: text unstable(); //~ ERROR use of unstable item - foo.method_unstable(); // ~ ERROR use of unstable item - foo.trait_unstable(); // ~ ERROR use of unstable item + foo.method_unstable(); //~ ERROR use of unstable item + foo.trait_unstable(); //~ ERROR use of unstable item unstable_text(); //~ ERROR use of unstable item: text - foo.method_unstable_text(); // ~ ERROR use of unstable item: text - foo.trait_unstable_text(); // ~ ERROR use of unstable item: text + foo.method_unstable_text(); //~ ERROR use of unstable item: text + foo.trait_unstable_text(); //~ ERROR use of unstable item: text unmarked(); //~ ERROR use of unmarked item - foo.method_unmarked(); // ~ ERROR use of unmarked item - foo.trait_unmarked(); // ~ ERROR use of unmarked item + foo.method_unmarked(); //~ ERROR use of unmarked item + foo.trait_unmarked(); //~ ERROR use of unmarked item stable(); foo.method_stable(); @@ -102,6 +102,28 @@ mod cross_crate { let _ = FrozenVariant; let _ = LockedVariant; } + + fn test_method_param(foo: F) { + foo.trait_deprecated(); //~ ERROR use of deprecated item + foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + foo.trait_experimental(); //~ ERROR use of experimental item + foo.trait_experimental_text(); //~ ERROR use of experimental item: text + foo.trait_unstable(); //~ ERROR use of unstable item + foo.trait_unstable_text(); //~ ERROR use of unstable item: text + foo.trait_unmarked(); //~ ERROR use of unmarked item + foo.trait_stable(); + } + + fn test_method_object(foo: &Trait) { + foo.trait_deprecated(); //~ ERROR use of deprecated item + foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + foo.trait_experimental(); //~ ERROR use of experimental item + foo.trait_experimental_text(); //~ ERROR use of experimental item: text + foo.trait_unstable(); //~ ERROR use of unstable item + foo.trait_unstable_text(); //~ ERROR use of unstable item: text + foo.trait_unmarked(); //~ ERROR use of unmarked item + foo.trait_stable(); + } } mod this_crate { @@ -259,32 +281,32 @@ mod this_crate { let foo = MethodTester; deprecated(); //~ ERROR use of deprecated item - foo.method_deprecated(); // ~ ERROR use of deprecated item - foo.trait_deprecated(); // ~ ERROR use of deprecated item + foo.method_deprecated(); //~ ERROR use of deprecated item + foo.trait_deprecated(); //~ ERROR use of deprecated item deprecated_text(); //~ ERROR use of deprecated item: text - foo.method_deprecated_text(); // ~ ERROR use of deprecated item: text - foo.trait_deprecated_text(); // ~ ERROR use of deprecated item: text + foo.method_deprecated_text(); //~ ERROR use of deprecated item: text + foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text experimental(); //~ ERROR use of experimental item - foo.method_experimental(); // ~ ERROR use of experimental item - foo.trait_experimental(); // ~ ERROR use of experimental item + foo.method_experimental(); //~ ERROR use of experimental item + foo.trait_experimental(); //~ ERROR use of experimental item experimental_text(); //~ ERROR use of experimental item: text - foo.method_experimental_text(); // ~ ERROR use of experimental item: text - foo.trait_experimental_text(); // ~ ERROR use of experimental item: text + foo.method_experimental_text(); //~ ERROR use of experimental item: text + foo.trait_experimental_text(); //~ ERROR use of experimental item: text unstable(); //~ ERROR use of unstable item - foo.method_unstable(); // ~ ERROR use of unstable item - foo.trait_unstable(); // ~ ERROR use of unstable item + foo.method_unstable(); //~ ERROR use of unstable item + foo.trait_unstable(); //~ ERROR use of unstable item unstable_text(); //~ ERROR use of unstable item: text - foo.method_unstable_text(); // ~ ERROR use of unstable item: text - foo.trait_unstable_text(); // ~ ERROR use of unstable item: text + foo.method_unstable_text(); //~ ERROR use of unstable item: text + foo.trait_unstable_text(); //~ ERROR use of unstable item: text unmarked(); //~ ERROR use of unmarked item - foo.method_unmarked(); // ~ ERROR use of unmarked item - foo.trait_unmarked(); // ~ ERROR use of unmarked item + foo.method_unmarked(); //~ ERROR use of unmarked item + foo.trait_unmarked(); //~ ERROR use of unmarked item stable(); foo.method_stable(); @@ -335,6 +357,28 @@ mod this_crate { let _ = FrozenVariant; let _ = LockedVariant; } + + fn test_method_param(foo: F) { + foo.trait_deprecated(); //~ ERROR use of deprecated item + foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + foo.trait_experimental(); //~ ERROR use of experimental item + foo.trait_experimental_text(); //~ ERROR use of experimental item: text + foo.trait_unstable(); //~ ERROR use of unstable item + foo.trait_unstable_text(); //~ ERROR use of unstable item: text + foo.trait_unmarked(); //~ ERROR use of unmarked item + foo.trait_stable(); + } + + fn test_method_object(foo: &Trait) { + foo.trait_deprecated(); //~ ERROR use of deprecated item + foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + foo.trait_experimental(); //~ ERROR use of experimental item + foo.trait_experimental_text(); //~ ERROR use of experimental item: text + foo.trait_unstable(); //~ ERROR use of unstable item + foo.trait_unstable_text(); //~ ERROR use of unstable item: text + foo.trait_unmarked(); //~ ERROR use of unmarked item + foo.trait_stable(); + } } fn main() {}