| // Copyright 2012-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 <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| |
| |
| // Export recording |
| // |
| // This pass simply determines what all "export" keywords refer to and |
| // writes the results into the export map. |
| // |
| // FIXME #4953 This pass will be removed once exports change to per-item. |
| // Then this operation can simply be performed as part of item (or import) |
| // processing. |
| |
| use {Module, NameBindings, Resolver}; |
| use Namespace::{self, TypeNS, ValueNS}; |
| |
| use build_reduced_graph; |
| use module_to_string; |
| |
| use rustc::middle::def::Export; |
| use syntax::ast; |
| |
| use std::ops::{Deref, DerefMut}; |
| use std::rc::Rc; |
| |
| struct ExportRecorder<'a, 'b:'a, 'tcx:'b> { |
| resolver: &'a mut Resolver<'b, 'tcx> |
| } |
| |
| // Deref and DerefMut impls allow treating ExportRecorder as Resolver. |
| impl<'a, 'b, 'tcx:'b> Deref for ExportRecorder<'a, 'b, 'tcx> { |
| type Target = Resolver<'b, 'tcx>; |
| |
| fn deref<'c>(&'c self) -> &'c Resolver<'b, 'tcx> { |
| &*self.resolver |
| } |
| } |
| |
| impl<'a, 'b, 'tcx:'b> DerefMut for ExportRecorder<'a, 'b, 'tcx> { |
| fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b, 'tcx> { |
| &mut *self.resolver |
| } |
| } |
| |
| impl<'a, 'b, 'tcx> ExportRecorder<'a, 'b, 'tcx> { |
| fn record_exports_for_module_subtree(&mut self, |
| module_: Rc<Module>) { |
| // If this isn't a local krate, then bail out. We don't need to record |
| // exports for nonlocal crates. |
| |
| match module_.def_id.get() { |
| Some(def_id) if def_id.is_local() => { |
| // OK. Continue. |
| debug!("(recording exports for module subtree) recording \ |
| exports for local module `{}`", |
| module_to_string(&*module_)); |
| } |
| None => { |
| // Record exports for the root module. |
| debug!("(recording exports for module subtree) recording \ |
| exports for root module `{}`", |
| module_to_string(&*module_)); |
| } |
| Some(_) => { |
| // Bail out. |
| debug!("(recording exports for module subtree) not recording \ |
| exports for `{}`", |
| module_to_string(&*module_)); |
| return; |
| } |
| } |
| |
| self.record_exports_for_module(&*module_); |
| build_reduced_graph::populate_module_if_necessary(self.resolver, &module_); |
| |
| for (_, child_name_bindings) in module_.children.borrow().iter() { |
| match child_name_bindings.get_module_if_available() { |
| None => { |
| // Nothing to do. |
| } |
| Some(child_module) => { |
| self.record_exports_for_module_subtree(child_module); |
| } |
| } |
| } |
| |
| for (_, child_module) in module_.anonymous_children.borrow().iter() { |
| self.record_exports_for_module_subtree(child_module.clone()); |
| } |
| } |
| |
| fn record_exports_for_module(&mut self, module_: &Module) { |
| let mut exports = Vec::new(); |
| |
| self.add_exports_for_module(&mut exports, module_); |
| match module_.def_id.get() { |
| Some(def_id) => { |
| self.export_map.insert(def_id.node, exports); |
| debug!("(computing exports) writing exports for {} (some)", |
| def_id.node); |
| } |
| None => {} |
| } |
| } |
| |
| fn add_exports_of_namebindings(&mut self, |
| exports: &mut Vec<Export>, |
| name: ast::Name, |
| namebindings: &NameBindings, |
| ns: Namespace) { |
| match namebindings.def_for_namespace(ns) { |
| Some(d) => { |
| debug!("(computing exports) YES: export '{}' => {:?}", |
| name, d.def_id()); |
| exports.push(Export { |
| name: name, |
| def_id: d.def_id() |
| }); |
| } |
| d_opt => { |
| debug!("(computing exports) NO: {:?}", d_opt); |
| } |
| } |
| } |
| |
| fn add_exports_for_module(&mut self, |
| exports: &mut Vec<Export>, |
| module_: &Module) { |
| for (name, import_resolution) in module_.import_resolutions.borrow().iter() { |
| if !import_resolution.is_public { |
| continue |
| } |
| let xs = [TypeNS, ValueNS]; |
| for &ns in &xs { |
| match import_resolution.target_for_namespace(ns) { |
| Some(target) => { |
| debug!("(computing exports) maybe export '{}'", |
| name); |
| self.add_exports_of_namebindings(exports, |
| *name, |
| &*target.bindings, |
| ns) |
| } |
| _ => () |
| } |
| } |
| } |
| } |
| } |
| |
| pub fn record(resolver: &mut Resolver) { |
| let mut recorder = ExportRecorder { resolver: resolver }; |
| let root_module = recorder.graph_root.get_module(); |
| recorder.record_exports_for_module_subtree(root_module); |
| } |