about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNick Cameron <ncameron@mozilla.com>2014-11-23 22:29:41 +1300
committerNick Cameron <ncameron@mozilla.com>2014-12-27 09:55:25 +1300
commitdf0c6d93852c51b6936d4b72b6b4be5f1932fb8a (patch)
tree3bf587ea195de3cbe01ddbcfe33cd81b61c82727
parentbd3cf4c05fdec03ab22df27f33191f4851e18cc9 (diff)
downloadrust-df0c6d93852c51b6936d4b72b6b4be5f1932fb8a.tar.gz
rust-df0c6d93852c51b6936d4b72b6b4be5f1932fb8a.zip
save-analysis: emit names of items that a glob import actually imports.
There is also some work here to make resolve a bit more stable - it no longer overwrites a specific import with a glob import.

[breaking-change]

Import shadowing of single/list imports by globs is now forbidden. An interesting case is where a glob import imports a re-export (`pub use`) of a single import. This still counts as a single import for the purposes of shadowing .You can usually fix any bustage by re-ordering such imports. A single import may still shadow (override) a glob import or the prelude.
-rw-r--r--src/librustc/metadata/csearch.rs7
-rw-r--r--src/librustc/metadata/decoder.rs8
-rw-r--r--src/librustc/middle/ty.rs1
-rw-r--r--src/librustc_driver/driver.rs20
-rw-r--r--src/librustc_driver/test.rs2
-rw-r--r--src/librustc_resolve/check_unused.rs14
-rw-r--r--src/librustc_resolve/lib.rs229
-rw-r--r--src/librustc_trans/save/mod.rs24
-rw-r--r--src/librustc_trans/save/recorder.rs14
-rw-r--r--src/librustc_trans/save/span_utils.rs13
-rw-r--r--src/librustc_trans/trans/mod.rs1
11 files changed, 270 insertions, 63 deletions
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index 13342bf82cf..51cebbfb52c 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -146,6 +146,13 @@ pub fn get_impl_or_trait_item<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId)
                                     tcx)
 }
 
+pub fn get_trait_name(cstore: &cstore::CStore, def: ast::DefId) -> ast::Name {
+    let cdata = cstore.get_crate_data(def.krate);
+    decoder::get_trait_name(cstore.intr.clone(),
+                            &*cdata,
+                            def.node)
+}
+
 pub fn get_trait_item_name_and_kind(cstore: &cstore::CStore, def: ast::DefId)
                                     -> (ast::Name, def::TraitItemKind) {
     let cdata = cstore.get_crate_data(def.krate);
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index f05607a999b..ee928828827 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -781,6 +781,14 @@ pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId)
     impl_items
 }
 
+pub fn get_trait_name(intr: Rc<IdentInterner>,
+                      cdata: Cmd,
+                      id: ast::NodeId)
+                      -> ast::Name {
+    let doc = lookup_item(id, cdata.data());
+    item_name(&*intr, doc)
+}
+
 pub fn get_trait_item_name_and_kind(intr: Rc<IdentInterner>,
                                     cdata: Cmd,
                                     id: ast::NodeId)
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 9c1259f4120..79e24ad56e4 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -105,6 +105,7 @@ pub struct CrateAnalysis<'tcx> {
     pub ty_cx: ty::ctxt<'tcx>,
     pub reachable: NodeSet,
     pub name: String,
+    pub glob_map: Option<middle::resolve::GlobMap>,
 }
 
 #[deriving(Copy, PartialEq, Eq, Hash)]
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 20bb9c2f4fd..c727bea4c2c 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -342,17 +342,24 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
     let lang_items = time(time_passes, "language item collection", (), |_|
                           middle::lang_items::collect_language_items(krate, &sess));
 
-    let resolve::CrateMap {
+    let make_glob_map = match save_analysis(&sess) {
+        true => middle::resolve::MakeGlobMap::Yes,
+        false => middle::resolve::MakeGlobMap::No,
+    };
         def_map,
         freevars,
         capture_mode_map,
         export_map,
         trait_map,
         external_exports,
-        last_private_map
+        last_private_map,
+        glob_map,
     } =
         time(time_passes, "resolution", (),
-             |_| resolve::resolve_crate(&sess, &lang_items, krate));
+             |_| resolve::resolve_crate(&sess,
+                                        &lang_items,
+                                        krate,
+                                        make_glob_map));
 
     // Discard MTWT tables that aren't required past resolution.
     syntax::ext::mtwt::clear_tables();
@@ -454,14 +461,19 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
         public_items: public_items,
         reachable: reachable_map,
         name: name,
+        glob_map: glob_map,
     }
 }
 
+fn save_analysis(sess: &Session) -> bool {
+    (sess.opts.debugging_opts & config::SAVE_ANALYSIS) != 0
+}
+
 pub fn phase_save_analysis(sess: &Session,
                            krate: &ast::Crate,
                            analysis: &ty::CrateAnalysis,
                            odir: &Option<Path>) {
-    if (sess.opts.debugging_opts & config::SAVE_ANALYSIS) == 0 {
+    if !save_analysis(sess) {
         return;
     }
     time(sess.time_passes(), "save analysis", krate, |krate|
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 526bbca8d70..1ef1486dd54 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -123,7 +123,7 @@ fn test_env<F>(source_string: &str,
     // run just enough stuff to build a tcx:
     let lang_items = lang_items::collect_language_items(krate, &sess);
     let resolve::CrateMap { def_map, freevars, capture_mode_map, .. } =
-        resolve::resolve_crate(&sess, &lang_items, krate);
+        resolve::resolve_crate(&sess, &ast_map, &lang_items, krate, resolve::MakeGlobMap::No);
     let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
     let region_map = region::resolve_crate(&sess, krate);
     let stability_index = stability::Index::build(krate);
diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs
index 39cdf6fc8f3..c09014cdb7a 100644
--- a/src/librustc_resolve/check_unused.rs
+++ b/src/librustc_resolve/check_unused.rs
@@ -28,19 +28,19 @@ use syntax::ast::{ViewPathGlob, ViewPathList, ViewPathSimple};
 use syntax::codemap::{Span, DUMMY_SP};
 use syntax::visit::{mod, Visitor};
 
-struct UnusedImportCheckVisitor<'a, 'b:'a> {
-    resolver: &'a mut Resolver<'b>
+struct UnusedImportCheckVisitor<'a, 'b:'a, 'tcx:'b> {
+    resolver: &'a mut Resolver<'b, 'tcx>
 }
 
 // Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver.
-impl<'a, 'b> Deref<Resolver<'b>> for UnusedImportCheckVisitor<'a, 'b> {
-    fn deref<'c>(&'c self) -> &'c Resolver<'b> {
+impl<'a, 'b, 'tcx> Deref<Resolver<'b, 'tcx>> for UnusedImportCheckVisitor<'a, 'b, 'tcx:'b> {
+    fn deref<'c>(&'c self) -> &'c Resolver<'b, 'tcx> {
         &*self.resolver
     }
 }
 
-impl<'a, 'b> DerefMut<Resolver<'b>> for UnusedImportCheckVisitor<'a, 'b> {
-    fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> {
+impl<'a, 'b, 'tcx> DerefMut<Resolver<'b, 'tcx>> for UnusedImportCheckVisitor<'a, 'b, 'tcx:'b> {
+    fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b, 'tcx> {
         &mut *self.resolver
     }
 }
@@ -104,7 +104,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
     }
 }
 
-impl<'a, 'b, 'v> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b> {
+impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
     fn visit_view_item(&mut self, vi: &ViewItem) {
         // Ignore is_public import statements because there's no way to be sure
         // whether they're used or not. Also ignore imports with a dummy span
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index bf9e9294307..815a8400a37 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -82,6 +82,7 @@ use syntax::ast::{Variant, ViewItem, ViewItemExternCrate};
 use syntax::ast::{ViewItemUse, ViewPathGlob, ViewPathList, ViewPathSimple};
 use syntax::ast::{Visibility};
 use syntax::ast;
+use syntax::ast_map;
 use syntax::ast_util::{mod, PostExpansionMethod, local_def, walk_pat};
 use syntax::attr::AttrMetaMethods;
 use syntax::ext::mtwt;
@@ -109,6 +110,10 @@ struct BindingInfo {
 // Map from the name in a pattern to its binding mode.
 type BindingMap = HashMap<Name, BindingInfo>;
 
+// Map from the NodeId of a glob import to a list of items which are actually
+// imported.
+pub type GlobMap = HashMap<NodeId, HashSet<Name>>;
+
 #[deriving(Copy, PartialEq)]
 enum PatternBindingMode {
     RefutableMode,
@@ -168,7 +173,7 @@ enum NameDefinition {
     ImportNameDefinition(Def, LastPrivate) //< The name identifies an import.
 }
 
-impl<'a, 'v> Visitor<'v> for Resolver<'a> {
+impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
     fn visit_item(&mut self, item: &Item) {
         self.resolve_item(item);
     }
@@ -340,6 +345,16 @@ impl Rib {
     }
 }
 
+/// Whether an import can be shadowed by another import.
+#[deriving(Show,PartialEq,Clone)]
+enum Shadowable {
+    Always,
+    /// Means that the recorded import obeys the glob shadowing rules, i.e., can
+    /// only be shadowed by another glob import.
+    Glob,
+    Never
+}
+
 /// One import directive.
 struct ImportDirective {
     module_path: Vec<Name>,
@@ -347,7 +362,7 @@ struct ImportDirective {
     span: Span,
     id: NodeId,
     is_public: bool, // see note in ImportResolution about how to use this
-    shadowable: bool,
+    shadowable: Shadowable,
 }
 
 impl ImportDirective {
@@ -356,7 +371,7 @@ impl ImportDirective {
            span: Span,
            id: NodeId,
            is_public: bool,
-           shadowable: bool)
+           shadowable: Shadowable)
            -> ImportDirective {
         ImportDirective {
             module_path: module_path,
@@ -374,13 +389,13 @@ impl ImportDirective {
 struct Target {
     target_module: Rc<Module>,
     bindings: Rc<NameBindings>,
-    shadowable: bool,
+    shadowable: Shadowable,
 }
 
 impl Target {
     fn new(target_module: Rc<Module>,
            bindings: Rc<NameBindings>,
-           shadowable: bool)
+           shadowable: Shadowable)
            -> Target {
         Target {
             target_module: target_module,
@@ -442,6 +457,15 @@ impl ImportResolution {
             ValueNS => self.value_id,
         }
     }
+
+    fn shadowable(&self, namespace: Namespace) -> Shadowable {
+        let target = self.target_for_namespace(namespace);
+        if target.is_none() {
+            return Shadowable::Always;
+        }
+
+        target.unwrap().shadowable
+    }
 }
 
 /// The link from a module up to its nearest parent node.
@@ -842,9 +866,11 @@ fn namespace_error_to_string(ns: NamespaceError) -> &'static str {
 }
 
 /// The main resolver class.
-struct Resolver<'a> {
+struct Resolver<'a, 'tcx:'a> {
     session: &'a Session,
 
+    ast_map: &'a ast_map::Map<'tcx>,
+
     graph_root: NameBindings,
 
     trait_item_map: FnvHashMap<(Name, DefId), TraitItemKind>,
@@ -895,16 +921,21 @@ struct Resolver<'a> {
     // so as to avoid printing duplicate errors
     emit_errors: bool,
 
+    make_glob_map: bool,
+    // Maps imports to the names of items actually imported (this actually maps
+    // all imports, but only glob imports are actually interesting).
+    glob_map: GlobMap,
+
     used_imports: HashSet<(NodeId, Namespace)>,
     used_crates: HashSet<CrateNum>,
 }
 
-struct BuildReducedGraphVisitor<'a, 'b:'a> {
-    resolver: &'a mut Resolver<'b>,
+struct BuildReducedGraphVisitor<'a, 'b:'a, 'tcx:'b> {
+    resolver: &'a mut Resolver<'b, 'tcx>,
     parent: ReducedGraphParent
 }
 
-impl<'a, 'b, 'v> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b> {
+impl<'a, 'b, 'v, 'tcx> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
 
     fn visit_item(&mut self, item: &Item) {
         let p = self.resolver.build_reduced_graph_for_item(item, self.parent.clone());
@@ -939,6 +970,20 @@ impl<'a, 'b, 'v> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b> {
 
 }
 
+<<<<<<< HEAD:src/librustc_resolve/lib.rs
+=======
+struct UnusedImportCheckVisitor<'a, 'b:'a, 'tcx:'b> {
+    resolver: &'a mut Resolver<'b, 'tcx>
+}
+
+impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
+    fn visit_view_item(&mut self, vi: &ViewItem) {
+        self.resolver.check_for_item_unused_imports(vi);
+        visit::walk_view_item(self, vi);
+    }
+}
+
+>>>>>>> save-analysis: emit names of items that a glob import actually imports.:src/librustc/middle/resolve.rs
 #[deriving(PartialEq)]
 enum FallbackChecks {
     Everything,
@@ -946,8 +991,11 @@ enum FallbackChecks {
 }
 
 
-impl<'a> Resolver<'a> {
-    fn new(session: &'a Session, crate_span: Span) -> Resolver<'a> {
+impl<'a, 'tcx> Resolver<'a, 'tcx> {
+    fn new(session: &'a Session,
+           ast_map: &'a ast_map::Map<'tcx>,
+           crate_span: Span,
+           make_glob_map: MakeGlobMap) -> Resolver<'a, 'tcx> {
         let graph_root = NameBindings::new();
 
         graph_root.define_module(NoParentLink,
@@ -962,6 +1010,8 @@ impl<'a> Resolver<'a> {
         Resolver {
             session: session,
 
+            ast_map: ast_map,
+
             // The outermost module has def ID 0; this is not reflected in the
             // AST.
 
@@ -997,6 +1047,8 @@ impl<'a> Resolver<'a> {
             last_private: NodeMap::new(),
 
             emit_errors: true,
+            make_glob_map: make_glob_map == MakeGlobMap::Yes,
+            glob_map: HashMap::new(),
         }
     }
 
@@ -1610,6 +1662,11 @@ impl<'a> Resolver<'a> {
                                  attr.name() == token::get_name(
                                     special_idents::prelude_import.name)
                              });
+                let shadowable = if shadowable {
+                    Shadowable::Always
+                } else {
+                    Shadowable::Never
+                };
 
                 match view_path.node {
                     ViewPathSimple(binding, ref full_path, id) => {
@@ -1680,7 +1737,11 @@ impl<'a> Resolver<'a> {
                                                     view_path.span,
                                                     id,
                                                     is_public,
-                                                    shadowable);
+                                                    if shadowable == Shadowable::Never {
+                                                        Shadowable::Glob
+                                                    } else {
+                                                        shadowable
+                                                    });
                     }
                 }
             }
@@ -2131,7 +2192,7 @@ impl<'a> Resolver<'a> {
                               span: Span,
                               id: NodeId,
                               is_public: bool,
-                              shadowable: bool) {
+                              shadowable: Shadowable) {
         module_.imports.borrow_mut().push(ImportDirective::new(module_path,
                                                                subclass,
                                                                span,
@@ -2326,6 +2387,29 @@ impl<'a> Resolver<'a> {
         }
     }
 
+    #[inline]
+    fn record_import_use(&mut self, import_id: NodeId, name: Name) {
+        if !self.make_glob_map {
+            return;
+        }
+        if self.glob_map.contains_key(&import_id) {
+            self.glob_map[import_id].insert(name);
+            return;
+        }
+
+        let mut new_set = HashSet::new();
+        new_set.insert(name);
+        self.glob_map.insert(import_id, new_set);
+    }
+
+    fn get_trait_name(&self, did: DefId) -> Name {
+        if did.krate == LOCAL_CRATE {
+            self.ast_map.expect_item(did.node).ident.name
+        } else {
+            csearch::get_trait_name(&self.session.cstore, did)
+        }
+    }
+
     /// Attempts to resolve the given import. The return value indicates
     /// failure if we're certain the name does not exist, indeterminate if we
     /// don't know whether the name exists at the moment due to other
@@ -2338,8 +2422,7 @@ impl<'a> Resolver<'a> {
         let mut resolution_result = Failed(None);
         let module_path = &import_directive.module_path;
 
-        debug!("(resolving import for module) resolving import `{}::...` in \
-                `{}`",
+        debug!("(resolving import for module) resolving import `{}::...` in `{}`",
                self.names_to_string(module_path[]),
                self.module_to_string(&*module_));
 
@@ -2526,7 +2609,8 @@ impl<'a> Resolver<'a> {
 
                         fn get_binding(this: &mut Resolver,
                                        import_resolution: &ImportResolution,
-                                       namespace: Namespace)
+                                       namespace: Namespace,
+                                       source: &Name)
                                     -> NamespaceResult {
 
                             // Import resolutions must be declared with "pub"
@@ -2550,6 +2634,7 @@ impl<'a> Resolver<'a> {
                                     let id = import_resolution.id(namespace);
                                     // track used imports and extern crates as well
                                     this.used_imports.insert((id, namespace));
+                                    this.record_import_use(id, *source);
                                     match target_module.def_id.get() {
                                         Some(DefId{krate: kid, ..}) => {
                                             this.used_crates.insert(kid);
@@ -2564,13 +2649,17 @@ impl<'a> Resolver<'a> {
                         // The name is an import which has been fully
                         // resolved. We can, therefore, just follow it.
                         if value_result.is_unknown() {
-                            value_result = get_binding(self, import_resolution,
-                                                       ValueNS);
+                            value_result = get_binding(self,
+                                                       import_resolution,
+                                                       ValueNS,
+                                                       &source);
                             value_used_reexport = import_resolution.is_public;
                         }
                         if type_result.is_unknown() {
-                            type_result = get_binding(self, import_resolution,
-                                                      TypeNS);
+                            type_result = get_binding(self,
+                                                      import_resolution,
+                                                      TypeNS,
+                                                      &source);
                             type_used_reexport = import_resolution.is_public;
                         }
 
@@ -2752,7 +2841,7 @@ impl<'a> Resolver<'a> {
         return Success(());
     }
 
-    // Resolves a glob import. Note that this function cannot panic; it either
+    // Resolves a glob import. Note that this function cannot fail; it either
     // succeeds or bails out (as importing * from an empty module or a module
     // that exports nothing is valid).
     fn resolve_glob_import(&mut self,
@@ -2883,7 +2972,9 @@ impl<'a> Resolver<'a> {
 
         let mut import_resolutions = module_.import_resolutions.borrow_mut();
         let dest_import_resolution = match import_resolutions.entry(name) {
-            Occupied(entry) => entry.into_mut(),
+            Occupied(entry) => {
+                entry.into_mut()
+            }
             Vacant(entry) => {
                 // Create a new import resolution from this child.
                 entry.set(ImportResolution::new(id, is_public))
@@ -2899,19 +2990,33 @@ impl<'a> Resolver<'a> {
         // Merge the child item into the import resolution.
         if name_bindings.defined_in_namespace_with(ValueNS, IMPORTABLE | PUBLIC) {
             debug!("(resolving glob import) ... for value target");
-            dest_import_resolution.value_target =
-                Some(Target::new(containing_module.clone(),
-                                 name_bindings.clone(),
-                                 import_directive.shadowable));
-            dest_import_resolution.value_id = id;
+            if dest_import_resolution.shadowable(ValueNS) == Shadowable::Never {
+                let msg = format!("a value named `{}` has already been imported \
+                                   in this module",
+                                  token::get_name(name).get());
+                self.session.span_err(import_directive.span, msg.as_slice());
+            } else {
+                dest_import_resolution.value_target =
+                    Some(Target::new(containing_module.clone(),
+                                     name_bindings.clone(),
+                                     import_directive.shadowable));
+                dest_import_resolution.value_id = id;
+            }
         }
         if name_bindings.defined_in_namespace_with(TypeNS, IMPORTABLE | PUBLIC) {
             debug!("(resolving glob import) ... for type target");
-            dest_import_resolution.type_target =
-                Some(Target::new(containing_module,
-                                 name_bindings.clone(),
-                                 import_directive.shadowable));
-            dest_import_resolution.type_id = id;
+            if dest_import_resolution.shadowable(TypeNS) == Shadowable::Never {
+                let msg = format!("a type named `{}` has already been imported \
+                                   in this module",
+                                  token::get_name(name).get());
+                self.session.span_err(import_directive.span, msg.as_slice());
+            } else {
+                dest_import_resolution.type_target =
+                    Some(Target::new(containing_module,
+                                     name_bindings.clone(),
+                                     import_directive.shadowable));
+                dest_import_resolution.type_id = id;
+            }
         }
         dest_import_resolution.is_public = is_public;
 
@@ -2933,7 +3038,7 @@ impl<'a> Resolver<'a> {
         }
 
         match *target {
-            Some(ref target) if !target.shadowable => {
+            Some(ref target) if target.shadowable != Shadowable::Always => {
                 let msg = format!("a {} named `{}` has already been imported \
                                    in this module",
                                   match namespace {
@@ -2976,7 +3081,7 @@ impl<'a> Resolver<'a> {
                  .borrow()
                  .contains_key(&name) {
             match import_resolution.type_target {
-                Some(ref target) if !target.shadowable => {
+                Some(ref target) if target.shadowable != Shadowable::Always => {
                     let msg = format!("import `{0}` conflicts with imported \
                                        crate in this module \
                                        (maybe you meant `use {0}::*`?)",
@@ -2998,7 +3103,7 @@ impl<'a> Resolver<'a> {
         };
 
         match import_resolution.value_target {
-            Some(ref target) if !target.shadowable => {
+            Some(ref target) if target.shadowable != Shadowable::Always => {
                 if let Some(ref value) = *name_bindings.value_def.borrow() {
                     let msg = format!("import `{}` conflicts with value \
                                        in this module",
@@ -3014,7 +3119,7 @@ impl<'a> Resolver<'a> {
         }
 
         match import_resolution.type_target {
-            Some(ref target) if !target.shadowable => {
+            Some(ref target) if target.shadowable != Shadowable::Always => {
                 if let Some(ref ty) = *name_bindings.type_def.borrow() {
                     match ty.module_def {
                         None => {
@@ -3347,7 +3452,7 @@ impl<'a> Resolver<'a> {
                 debug!("top name bindings succeeded");
                 return Success((Target::new(module_.clone(),
                                             name_bindings.clone(),
-                                            false),
+                                            Shadowable::Never),
                                false));
             }
             Some(_) | None => { /* Not found; continue. */ }
@@ -3369,9 +3474,11 @@ impl<'a> Resolver<'a> {
                     debug!("(resolving item in lexical scope) using \
                             import resolution");
                     // track used imports and extern crates as well
-                    self.used_imports.insert((import_resolution.id(namespace), namespace));
+                    let id = import_resolution.id(namespace);
+                    self.used_imports.insert((id, namespace));
+                    self.record_import_use(id, name);
                     if let Some(DefId{krate: kid, ..}) = target.target_module.def_id.get() {
-                        self.used_crates.insert(kid);
+                         self.used_crates.insert(kid);
                     }
                     return Success((target, false));
                 }
@@ -3384,7 +3491,9 @@ impl<'a> Resolver<'a> {
                 let name_bindings =
                     Rc::new(Resolver::create_name_bindings_from_module(module));
                 debug!("lower name bindings succeeded");
-                return Success((Target::new(module_, name_bindings, false),
+                return Success((Target::new(module_,
+                                            name_bindings,
+                                            Shadowable::Never),
                                 false));
             }
         }
@@ -3608,7 +3717,7 @@ impl<'a> Resolver<'a> {
                 debug!("(resolving name in module) found node as child");
                 return Success((Target::new(module_.clone(),
                                             name_bindings.clone(),
-                                            false),
+                                            Shadowable::Never),
                                false));
             }
             Some(_) | None => {
@@ -3645,7 +3754,9 @@ impl<'a> Resolver<'a> {
                         debug!("(resolving name in module) resolved to \
                                 import");
                         // track used imports and extern crates as well
-                        self.used_imports.insert((import_resolution.id(namespace), namespace));
+                        let id = import_resolution.id(namespace);
+                        self.used_imports.insert((id, namespace));
+                        self.record_import_use(id, name);
                         if let Some(DefId{krate: kid, ..}) = target.target_module.def_id.get() {
                             self.used_crates.insert(kid);
                         }
@@ -3661,7 +3772,9 @@ impl<'a> Resolver<'a> {
             if let Some(module) = module_.external_module_children.borrow().get(&name).cloned() {
                 let name_bindings =
                     Rc::new(Resolver::create_name_bindings_from_module(module));
-                return Success((Target::new(module_, name_bindings, false),
+                return Success((Target::new(module_,
+                                            name_bindings,
+                                            Shadowable::Never),
                                 false));
             }
         }
@@ -5171,6 +5284,7 @@ impl<'a> Resolver<'a> {
                             let id = import_resolution.id(namespace);
                             // track imports and extern crates as well
                             self.used_imports.insert((id, namespace));
+                            self.record_import_use(id, name);
                             match target.target_module.def_id.get() {
                                 Some(DefId{krate: kid, ..}) => {
                                     self.used_crates.insert(kid);
@@ -5859,7 +5973,10 @@ impl<'a> Resolver<'a> {
                 };
                 if self.trait_item_map.contains_key(&(name, did)) {
                     add_trait_info(&mut found_traits, did, name);
-                    self.used_imports.insert((import.type_id, TypeNS));
+                    let id = import.type_id;
+                    self.used_imports.insert((id, TypeNS));
+                    let trait_name = self.get_trait_name(did);
+                    self.record_import_use(id, trait_name);
                     if let Some(DefId{krate: kid, ..}) = target.target_module.def_id.get() {
                         self.used_crates.insert(kid);
                     }
@@ -5993,14 +6110,23 @@ pub struct CrateMap {
     pub trait_map: TraitMap,
     pub external_exports: ExternalExports,
     pub last_private_map: LastPrivateMap,
+    pub glob_map: Option<GlobMap>
+}
+
+#[deriving(PartialEq)]
+pub enum MakeGlobMap {
+    Yes,
+    No
 }
 
 /// Entry point to crate resolution.
-pub fn resolve_crate(session: &Session,
-                     _: &LanguageItems,
-                     krate: &Crate)
-                  -> CrateMap {
-    let mut resolver = Resolver::new(session, krate.span);
+pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
+                               ast_map: &'a ast_map::Map<'tcx>,
+                               _: &LanguageItems,
+                               krate: &Crate,
+                               make_glob_map: MakeGlobMap)
+                               -> CrateMap {
+    let mut resolver = Resolver::new(session, ast_map, krate.span, make_glob_map);
 
     resolver.build_reduced_graph(krate);
     session.abort_if_errors();
@@ -6024,5 +6150,10 @@ pub fn resolve_crate(session: &Session,
         trait_map: resolver.trait_map,
         external_exports: resolver.external_exports,
         last_private_map: resolver.last_private,
+        glob_map: if resolver.make_glob_map {
+                        Some(resolver.glob_map)
+                    } else {
+                        None
+                    },
     }
 }
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index 0183aa8c2aa..f491bc84b62 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -1197,7 +1197,28 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
                                                self.cur_scope);
                         self.write_sub_paths_truncated(path);
                     }
-                    ast::ViewPathGlob(ref path, _) => {
+                    ast::ViewPathGlob(ref path, id) => {
+                        // Make a comma-separated list of names of imported modules.
+                        let mut name_string = String::new();
+                        let glob_map = &self.analysis.glob_map;
+                        let glob_map = glob_map.as_ref().unwrap();
+                        if glob_map.contains_key(&id) {
+                            let names = glob_map.index(&id);
+                            for n in names.iter() {
+                                if name_string.len() > 0 {
+                                    name_string.push_str(", ");
+                                }
+                                name_string.push_str(n.as_str());
+                            }
+                        }
+
+                        let sub_span = self.span.sub_span_of_token(path.span,
+                                                                   token::BinOp(token::Star));
+                        self.fmt.use_glob_str(path.span,
+                                              sub_span,
+                                              id,
+                                              name_string.as_slice(),
+                                              self.cur_scope);
                         self.write_sub_paths(path);
                     }
                     ast::ViewPathList(ref path, ref list, _) => {
@@ -1482,6 +1503,7 @@ pub fn process_crate(sess: &Session,
         return;
     }
 
+    assert!(analysis.glob_map.is_some());
     let cratename = match attr::find_crate_name(krate.attrs[]) {
         Some(name) => name.get().to_string(),
         None => {
diff --git a/src/librustc_trans/save/recorder.rs b/src/librustc_trans/save/recorder.rs
index 08670864ade..b2dd9218f17 100644
--- a/src/librustc_trans/save/recorder.rs
+++ b/src/librustc_trans/save/recorder.rs
@@ -74,6 +74,7 @@ pub enum Row {
     Impl,
     Module,
     UseAlias,
+    UseGlob,
     ExternCrate,
     Inheritance,
     MethodCall,
@@ -125,6 +126,7 @@ impl<'a> FmtStrs<'a> {
             UseAlias => ("use_alias",
                          vec!("id","refid","refidcrate","name","scopeid"),
                          true, true),
+            UseGlob => ("use_glob", vec!("id","value","scopeid"), true, true),
             ExternCrate => ("extern_crate",
                             vec!("id","name","location","crate","scopeid"),
                             true, true),
@@ -480,6 +482,18 @@ impl<'a> FmtStrs<'a> {
                               svec!(id, mod_node, mod_crate, name, parent));
     }
 
+    pub fn use_glob_str(&mut self,
+                        span: Span,
+                        sub_span: Option<Span>,
+                        id: NodeId,
+                        values: &str,
+                        parent: NodeId) {
+        self.check_and_record(UseGlob,
+                              span,
+                              sub_span,
+                              svec!(id, values, parent));
+    }
+
     pub fn extern_crate_str(&mut self,
                           span: Span,
                           sub_span: Option<Span>,
diff --git a/src/librustc_trans/save/span_utils.rs b/src/librustc_trans/save/span_utils.rs
index a92d3c06e64..e9d862d3781 100644
--- a/src/librustc_trans/save/span_utils.rs
+++ b/src/librustc_trans/save/span_utils.rs
@@ -280,6 +280,19 @@ impl<'a> SpanUtils<'a> {
         }
     }
 
+    pub fn sub_span_of_token(&self, span: Span, tok: Token) -> Option<Span> {
+        let mut toks = self.retokenise_span(span);
+        loop {
+            let next = toks.real_token();
+            if next.tok == token::Eof {
+                return None;
+            }
+            if next.tok == tok {
+                return self.make_sub_span(span, Some(next.sp));
+            }
+        }
+    }
+
     pub fn sub_span_after_keyword(&self,
                               span: Span,
                               keyword: keywords::Keyword) -> Option<Span> {
diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs
index 05797d74fee..4b1b92b552c 100644
--- a/src/librustc_trans/trans/mod.rs
+++ b/src/librustc_trans/trans/mod.rs
@@ -69,4 +69,3 @@ pub struct CrateTranslation {
     pub crate_formats: dependency_format::Dependencies,
     pub no_builtins: bool,
 }
-