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, + 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, 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, } #[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) { - 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(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> for UnusedImportCheckVisitor<'a, 'b> { - fn deref<'c>(&'c self) -> &'c Resolver<'b> { +impl<'a, 'b, 'tcx> Deref> for UnusedImportCheckVisitor<'a, 'b, 'tcx:'b> { + fn deref<'c>(&'c self) -> &'c Resolver<'b, 'tcx> { &*self.resolver } } -impl<'a, 'b> DerefMut> for UnusedImportCheckVisitor<'a, 'b> { - fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> { +impl<'a, 'b, 'tcx> DerefMut> 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; +// Map from the NodeId of a glob import to a list of items which are actually +// imported. +pub type GlobMap = HashMap>; + #[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, @@ -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, bindings: Rc, - shadowable: bool, + shadowable: Shadowable, } impl Target { fn new(target_module: Rc, bindings: Rc, - 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, } -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 +} + +#[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, + 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, 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 { + 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 { 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, } -