// Copyright 2012-2015 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.

#![allow(non_camel_case_types)]

//! Validates all used crates and extern libraries and loads their metadata

use cstore::{self, CStore, CrateSource, MetadataBlob};
use decoder;
use loader::{self, CratePaths};

use rustc::hir::def_id::DefIndex;
use rustc::hir::svh::Svh;
use rustc::dep_graph::{DepGraph, DepNode};
use rustc::session::{config, Session};
use rustc::session::config::PanicStrategy;
use rustc::session::search_paths::PathKind;
use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
use rustc::hir::map as hir_map;

use std::cell::{RefCell, Cell};
use std::path::PathBuf;
use std::rc::Rc;
use std::fs;

use syntax::ast;
use syntax::abi::Abi;
use syntax::codemap;
use syntax::parse;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::parse::token::InternedString;
use syntax::visit;
use syntax_pos::{self, Span, mk_sp, Pos};
use log;

struct LocalCrateReader<'a> {
    sess: &'a Session,
    cstore: &'a CStore,
    creader: CrateReader<'a>,
    krate: &'a ast::Crate,
    definitions: &'a hir_map::Definitions,
}

pub struct CrateReader<'a> {
    sess: &'a Session,
    cstore: &'a CStore,
    next_crate_num: ast::CrateNum,
    foreign_item_map: FnvHashMap<String, Vec<ast::NodeId>>,
    local_crate_name: String,
}

impl<'a> visit::Visitor for LocalCrateReader<'a> {
    fn visit_item(&mut self, a: &ast::Item) {
        self.process_item(a);
        visit::walk_item(self, a);
    }
}

fn dump_crates(cstore: &CStore) {
    info!("resolved crates:");
    cstore.iter_crate_data_origins(|_, data, opt_source| {
        info!("  name: {}", data.name());
        info!("  cnum: {}", data.cnum);
        info!("  hash: {}", data.hash());
        info!("  reqd: {}", data.explicitly_linked.get());
        opt_source.map(|cs| {
            let CrateSource { dylib, rlib, cnum: _ } = cs;
            dylib.map(|dl| info!("  dylib: {}", dl.0.display()));
            rlib.map(|rl|  info!("   rlib: {}", rl.0.display()));
        });
    })
}

fn should_link(i: &ast::Item) -> bool {
    !attr::contains_name(&i.attrs, "no_link")
}

#[derive(Debug)]
struct CrateInfo {
    ident: String,
    name: String,
    id: ast::NodeId,
    should_link: bool,
}

fn register_native_lib(sess: &Session,
                       cstore: &CStore,
                       span: Option<Span>,
                       name: String,
                       kind: cstore::NativeLibraryKind) {
    if name.is_empty() {
        match span {
            Some(span) => {
                span_err!(sess, span, E0454,
                          "#[link(name = \"\")] given with empty name");
            }
            None => {
                sess.err("empty library name given via `-l`");
            }
        }
        return
    }
    let is_osx = sess.target.target.options.is_like_osx;
    if kind == cstore::NativeFramework && !is_osx {
        let msg = "native frameworks are only available on OSX targets";
        match span {
            Some(span) => {
                span_err!(sess, span, E0455,
                          "{}", msg)
            }
            None => sess.err(msg),
        }
    }
    cstore.add_used_library(name, kind);
}

// Extra info about a crate loaded for plugins or exported macros.
struct ExtensionCrate {
    metadata: PMDSource,
    dylib: Option<PathBuf>,
    target_only: bool,
}

enum PMDSource {
    Registered(Rc<cstore::CrateMetadata>),
    Owned(MetadataBlob),
}

impl PMDSource {
    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
        match *self {
            PMDSource::Registered(ref cmd) => cmd.data(),
            PMDSource::Owned(ref mdb) => mdb.as_slice(),
        }
    }
}

enum LoadResult {
    Previous(ast::CrateNum),
    Loaded(loader::Library),
}

impl<'a> CrateReader<'a> {
    pub fn new(sess: &'a Session,
               cstore: &'a CStore,
               local_crate_name: &str) -> CrateReader<'a> {
        CrateReader {
            sess: sess,
            cstore: cstore,
            next_crate_num: cstore.next_crate_num(),
            foreign_item_map: FnvHashMap(),
            local_crate_name: local_crate_name.to_owned(),
        }
    }

    fn extract_crate_info(&self, i: &ast::Item) -> Option<CrateInfo> {
        match i.node {
            ast::ItemKind::ExternCrate(ref path_opt) => {
                debug!("resolving extern crate stmt. ident: {} path_opt: {:?}",
                       i.ident, path_opt);
                let name = match *path_opt {
                    Some(name) => {
                        validate_crate_name(Some(self.sess), &name.as_str(),
                                            Some(i.span));
                        name.to_string()
                    }
                    None => i.ident.to_string(),
                };
                Some(CrateInfo {
                    ident: i.ident.to_string(),
                    name: name,
                    id: i.id,
                    should_link: should_link(i),
                })
            }
            _ => None
        }
    }

    fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind)
                      -> Option<ast::CrateNum> {
        let mut ret = None;
        self.cstore.iter_crate_data(|cnum, data| {
            if data.name != name { return }

            match hash {
                Some(hash) if *hash == data.hash() => { ret = Some(cnum); return }
                Some(..) => return,
                None => {}
            }

            // When the hash is None we're dealing with a top-level dependency
            // in which case we may have a specification on the command line for
            // this library. Even though an upstream library may have loaded
            // something of the same name, we have to make sure it was loaded
            // from the exact same location as well.
            //
            // We're also sure to compare *paths*, not actual byte slices. The
            // `source` stores paths which are normalized which may be different
            // from the strings on the command line.
            let source = self.cstore.used_crate_source(cnum);
            if let Some(locs) = self.sess.opts.externs.get(name) {
                let found = locs.iter().any(|l| {
                    let l = fs::canonicalize(l).ok();
                    source.dylib.as_ref().map(|p| &p.0) == l.as_ref() ||
                    source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
                });
                if found {
                    ret = Some(cnum);
                }
                return
            }

            // Alright, so we've gotten this far which means that `data` has the
            // right name, we don't have a hash, and we don't have a --extern
            // pointing for ourselves. We're still not quite yet done because we
            // have to make sure that this crate was found in the crate lookup
            // path (this is a top-level dependency) as we don't want to
            // implicitly load anything inside the dependency lookup path.
            let prev_kind = source.dylib.as_ref().or(source.rlib.as_ref())
                                  .unwrap().1;
            if ret.is_none() && (prev_kind == kind || prev_kind == PathKind::All) {
                ret = Some(cnum);
            }
        });
        return ret;
    }

    fn verify_no_symbol_conflicts(&self,
                                  span: Span,
                                  metadata: &MetadataBlob) {
        let disambiguator = decoder::get_crate_disambiguator(metadata.as_slice());
        let crate_name = decoder::get_crate_name(metadata.as_slice());

        // Check for (potential) conflicts with the local crate
        if self.local_crate_name == crate_name &&
           self.sess.crate_disambiguator.get().as_str() == disambiguator {
            span_fatal!(self.sess, span, E0519,
                        "the current crate is indistinguishable from one of its \
                         dependencies: it has the same crate-name `{}` and was \
                         compiled with the same `-C metadata` arguments. This \
                         will result in symbol conflicts between the two.",
                        crate_name)
        }

        let svh = decoder::get_crate_hash(metadata.as_slice());
        // Check for conflicts with any crate loaded so far
        self.cstore.iter_crate_data(|_, other| {
            if other.name() == crate_name && // same crate-name
               other.disambiguator() == disambiguator &&  // same crate-disambiguator
               other.hash() != svh { // but different SVH
                span_fatal!(self.sess, span, E0523,
                        "found two different crates with name `{}` that are \
                         not distinguished by differing `-C metadata`. This \
                         will result in symbol conflicts between the two.",
                        crate_name)
            }
        });
    }

    fn register_crate(&mut self,
                      root: &Option<CratePaths>,
                      ident: &str,
                      name: &str,
                      span: Span,
                      lib: loader::Library,
                      explicitly_linked: bool)
                      -> (ast::CrateNum, Rc<cstore::CrateMetadata>,
                          cstore::CrateSource) {
        self.verify_no_symbol_conflicts(span, &lib.metadata);

        // Claim this crate number and cache it
        let cnum = self.next_crate_num;
        self.next_crate_num += 1;

        // Stash paths for top-most crate locally if necessary.
        let crate_paths = if root.is_none() {
            Some(CratePaths {
                ident: ident.to_string(),
                dylib: lib.dylib.clone().map(|p| p.0),
                rlib:  lib.rlib.clone().map(|p| p.0),
            })
        } else {
            None
        };
        // Maintain a reference to the top most crate.
        let root = if root.is_some() { root } else { &crate_paths };

        let loader::Library { dylib, rlib, metadata } = lib;

        let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), cnum, span);
        let staged_api = self.is_staged_api(metadata.as_slice());

        let cmeta = Rc::new(cstore::CrateMetadata {
            name: name.to_string(),
            extern_crate: Cell::new(None),
            index: decoder::load_index(metadata.as_slice()),
            xref_index: decoder::load_xrefs(metadata.as_slice()),
            key_map: decoder::load_key_map(metadata.as_slice()),
            data: metadata,
            cnum_map: RefCell::new(cnum_map),
            cnum: cnum,
            codemap_import_info: RefCell::new(vec![]),
            staged_api: staged_api,
            explicitly_linked: Cell::new(explicitly_linked),
        });

        let source = cstore::CrateSource {
            dylib: dylib,
            rlib: rlib,
            cnum: cnum,
        };

        self.cstore.set_crate_data(cnum, cmeta.clone());
        self.cstore.add_used_crate_source(source.clone());
        (cnum, cmeta, source)
    }

    fn is_staged_api(&self, data: &[u8]) -> bool {
        let attrs = decoder::get_crate_attributes(data);
        for attr in &attrs {
            if attr.name() == "stable" || attr.name() == "unstable" {
                return true
            }
        }
        false
    }

    fn resolve_crate(&mut self,
                     root: &Option<CratePaths>,
                     ident: &str,
                     name: &str,
                     hash: Option<&Svh>,
                     span: Span,
                     kind: PathKind,
                     explicitly_linked: bool)
                     -> (ast::CrateNum, Rc<cstore::CrateMetadata>, cstore::CrateSource) {
        let result = match self.existing_match(name, hash, kind) {
            Some(cnum) => LoadResult::Previous(cnum),
            None => {
                let mut load_ctxt = loader::Context {
                    sess: self.sess,
                    span: span,
                    ident: ident,
                    crate_name: name,
                    hash: hash.map(|a| &*a),
                    filesearch: self.sess.target_filesearch(kind),
                    target: &self.sess.target.target,
                    triple: &self.sess.opts.target_triple,
                    root: root,
                    rejected_via_hash: vec!(),
                    rejected_via_triple: vec!(),
                    rejected_via_kind: vec!(),
                    rejected_via_version: vec!(),
                    should_match_name: true,
                };
                match self.load(&mut load_ctxt) {
                    Some(result) => result,
                    None => load_ctxt.report_load_errs(),
                }
            }
        };

        match result {
            LoadResult::Previous(cnum) => {
                let data = self.cstore.get_crate_data(cnum);
                if explicitly_linked && !data.explicitly_linked.get() {
                    data.explicitly_linked.set(explicitly_linked);
                }
                (cnum, data, self.cstore.used_crate_source(cnum))
            }
            LoadResult::Loaded(library) => {
                self.register_crate(root, ident, name, span, library,
                                    explicitly_linked)
            }
        }
    }

    fn load(&mut self, loader: &mut loader::Context) -> Option<LoadResult> {
        let library = match loader.maybe_load_library_crate() {
            Some(lib) => lib,
            None => return None,
        };

        // In the case that we're loading a crate, but not matching
        // against a hash, we could load a crate which has the same hash
        // as an already loaded crate. If this is the case prevent
        // duplicates by just using the first crate.
        //
        // Note that we only do this for target triple crates, though, as we
        // don't want to match a host crate against an equivalent target one
        // already loaded.
        if loader.triple == self.sess.opts.target_triple {
            let meta_hash = decoder::get_crate_hash(library.metadata.as_slice());
            let meta_name = decoder::get_crate_name(library.metadata.as_slice())
                                    .to_string();
            let mut result = LoadResult::Loaded(library);
            self.cstore.iter_crate_data(|cnum, data| {
                if data.name() == meta_name && meta_hash == data.hash() {
                    assert!(loader.hash.is_none());
                    result = LoadResult::Previous(cnum);
                }
            });
            Some(result)
        } else {
            Some(LoadResult::Loaded(library))
        }
    }

    fn update_extern_crate(&mut self,
                           cnum: ast::CrateNum,
                           mut extern_crate: ExternCrate,
                           visited: &mut FnvHashSet<(ast::CrateNum, bool)>)
    {
        if !visited.insert((cnum, extern_crate.direct)) { return }

        let cmeta = self.cstore.get_crate_data(cnum);
        let old_extern_crate = cmeta.extern_crate.get();

        // Prefer:
        // - something over nothing (tuple.0);
        // - direct extern crate to indirect (tuple.1);
        // - shorter paths to longer (tuple.2).
        let new_rank = (true, extern_crate.direct, !extern_crate.path_len);
        let old_rank = match old_extern_crate {
            None => (false, false, !0),
            Some(ref c) => (true, c.direct, !c.path_len),
        };

        if old_rank >= new_rank {
            return; // no change needed
        }

        cmeta.extern_crate.set(Some(extern_crate));
        // Propagate the extern crate info to dependencies.
        extern_crate.direct = false;
        for &dep_cnum in cmeta.cnum_map.borrow().iter() {
            self.update_extern_crate(dep_cnum, extern_crate, visited);
        }
    }

    // Go through the crate metadata and load any crates that it references
    fn resolve_crate_deps(&mut self,
                          root: &Option<CratePaths>,
                          cdata: &[u8],
                          krate: ast::CrateNum,
                          span: Span)
                          -> cstore::CrateNumMap {
        debug!("resolving deps of external crate");
        // The map from crate numbers in the crate we're resolving to local crate
        // numbers
        let map: FnvHashMap<_, _> = decoder::get_crate_deps(cdata).iter().map(|dep| {
            debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
            let (local_cnum, _, _) = self.resolve_crate(root,
                                                        &dep.name,
                                                        &dep.name,
                                                        Some(&dep.hash),
                                                        span,
                                                        PathKind::Dependency,
                                                        dep.explicitly_linked);
            (dep.cnum, local_cnum)
        }).collect();

        let max_cnum = map.values().cloned().max().unwrap_or(0);

        // we map 0 and all other holes in the map to our parent crate. The "additional"
        // self-dependencies should be harmless.
        (0..max_cnum+1).map(|cnum| map.get(&cnum).cloned().unwrap_or(krate)).collect()
    }

    fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate {
        let target_triple = &self.sess.opts.target_triple[..];
        let is_cross = target_triple != config::host_triple();
        let mut should_link = info.should_link && !is_cross;
        let mut target_only = false;
        let ident = info.ident.clone();
        let name = info.name.clone();
        let mut load_ctxt = loader::Context {
            sess: self.sess,
            span: span,
            ident: &ident[..],
            crate_name: &name[..],
            hash: None,
            filesearch: self.sess.host_filesearch(PathKind::Crate),
            target: &self.sess.host,
            triple: config::host_triple(),
            root: &None,
            rejected_via_hash: vec!(),
            rejected_via_triple: vec!(),
            rejected_via_kind: vec!(),
            rejected_via_version: vec!(),
            should_match_name: true,
        };
        let library = self.load(&mut load_ctxt).or_else(|| {
            if !is_cross {
                return None
            }
            // Try loading from target crates. This will abort later if we
            // try to load a plugin registrar function,
            target_only = true;
            should_link = info.should_link;

            load_ctxt.target = &self.sess.target.target;
            load_ctxt.triple = target_triple;
            load_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate);

            self.load(&mut load_ctxt)
        });
        let library = match library {
            Some(l) => l,
            None => load_ctxt.report_load_errs(),
        };

        let (dylib, metadata) = match library {
            LoadResult::Previous(cnum) => {
                let dylib = self.cstore.opt_used_crate_source(cnum).unwrap().dylib;
                let data = self.cstore.get_crate_data(cnum);
                (dylib, PMDSource::Registered(data))
            }
            LoadResult::Loaded(library) => {
                let dylib = library.dylib.clone();
                let metadata = if should_link {
                    // Register crate now to avoid double-reading metadata
                    let (_, cmd, _) = self.register_crate(&None, &info.ident,
                                                          &info.name, span,
                                                          library, true);
                    PMDSource::Registered(cmd)
                } else {
                    // Not registering the crate; just hold on to the metadata
                    PMDSource::Owned(library.metadata)
                };
                (dylib, metadata)
            }
        };

        ExtensionCrate {
            metadata: metadata,
            dylib: dylib.map(|p| p.0),
            target_only: target_only,
        }
    }

    /// Read exported macros.
    pub fn read_exported_macros(&mut self, item: &ast::Item) -> Vec<ast::MacroDef> {
        let ci = self.extract_crate_info(item).unwrap();
        let ekrate = self.read_extension_crate(item.span, &ci);

        let source_name = format!("<{} macros>", item.ident);
        let mut macros = vec![];
        decoder::each_exported_macro(ekrate.metadata.as_slice(),
            |name, attrs, span, body| {
                // NB: Don't use parse::parse_tts_from_source_str because it parses with
                // quote_depth > 0.
                let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess,
                                                              self.sess.opts.cfg.clone(),
                                                              source_name.clone(),
                                                              body);
                let lo = p.span.lo;
                let body = match p.parse_all_token_trees() {
                    Ok(body) => body,
                    Err(mut err) => {
                        err.emit();
                        self.sess.abort_if_errors();
                        unreachable!();
                    }
                };
                let local_span = mk_sp(lo, p.last_span.hi);

                // Mark the attrs as used
                for attr in &attrs {
                    attr::mark_used(attr);
                }

                macros.push(ast::MacroDef {
                    ident: ast::Ident::with_empty_ctxt(name),
                    attrs: attrs,
                    id: ast::DUMMY_NODE_ID,
                    span: local_span,
                    imported_from: Some(item.ident),
                    // overridden in plugin/load.rs
                    export: false,
                    use_locally: false,
                    allow_internal_unstable: false,

                    body: body,
                });
                self.sess.imported_macro_spans.borrow_mut()
                    .insert(local_span, (name.as_str().to_string(), span));
                true
            }
        );
        macros
    }

    /// Look for a plugin registrar. Returns library path, crate
    /// SVH and DefIndex of the registrar function.
    pub fn find_plugin_registrar(&mut self, span: Span, name: &str)
                                 -> Option<(PathBuf, Svh, DefIndex)> {
        let ekrate = self.read_extension_crate(span, &CrateInfo {
             name: name.to_string(),
             ident: name.to_string(),
             id: ast::DUMMY_NODE_ID,
             should_link: false,
        });

        if ekrate.target_only {
            // Need to abort before syntax expansion.
            let message = format!("plugin `{}` is not available for triple `{}` \
                                   (only found {})",
                                  name,
                                  config::host_triple(),
                                  self.sess.opts.target_triple);
            span_fatal!(self.sess, span, E0456, "{}", &message[..]);
        }

        let svh = decoder::get_crate_hash(ekrate.metadata.as_slice());
        let registrar =
            decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice());

        match (ekrate.dylib.as_ref(), registrar) {
            (Some(dylib), Some(reg)) => {
                Some((dylib.to_path_buf(), svh, reg))
            }
            (None, Some(_)) => {
                span_err!(self.sess, span, E0457,
                          "plugin `{}` only found in rlib format, but must be available \
                           in dylib format",
                          name);
                // No need to abort because the loading code will just ignore this
                // empty dylib.
                None
            }
            _ => None,
        }
    }

    fn register_statically_included_foreign_items(&mut self) {
        let libs = self.cstore.get_used_libraries();
        for (lib, list) in self.foreign_item_map.iter() {
            let is_static = libs.borrow().iter().any(|&(ref name, kind)| {
                lib == name && kind == cstore::NativeStatic
            });
            if is_static {
                for id in list {
                    self.cstore.add_statically_included_foreign_item(*id);
                }
            }
        }
    }

    fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
        // If we're only compiling an rlib, then there's no need to select a
        // panic runtime, so we just skip this section entirely.
        let any_non_rlib = self.sess.crate_types.borrow().iter().any(|ct| {
            *ct != config::CrateTypeRlib
        });
        if !any_non_rlib {
            info!("panic runtime injection skipped, only generating rlib");
            return
        }

        // If we need a panic runtime, we try to find an existing one here. At
        // the same time we perform some general validation of the DAG we've got
        // going such as ensuring everything has a compatible panic strategy.
        //
        // The logic for finding the panic runtime here is pretty much the same
        // as the allocator case with the only addition that the panic strategy
        // compilation mode also comes into play.
        let desired_strategy = self.sess.opts.cg.panic.clone();
        let mut runtime_found = false;
        let mut needs_panic_runtime = attr::contains_name(&krate.attrs,
                                                          "needs_panic_runtime");
        self.cstore.iter_crate_data(|cnum, data| {
            needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
            if data.is_panic_runtime() {
                // Inject a dependency from all #![needs_panic_runtime] to this
                // #![panic_runtime] crate.
                self.inject_dependency_if(cnum, "a panic runtime",
                                          &|data| data.needs_panic_runtime());
                runtime_found = runtime_found || data.explicitly_linked.get();
            }
        });

        // If an explicitly linked and matching panic runtime was found, or if
        // we just don't need one at all, then we're done here and there's
        // nothing else to do.
        if !needs_panic_runtime || runtime_found {
            return
        }

        // By this point we know that we (a) need a panic runtime and (b) no
        // panic runtime was explicitly linked. Here we just load an appropriate
        // default runtime for our panic strategy and then inject the
        // dependencies.
        //
        // We may resolve to an already loaded crate (as the crate may not have
        // been explicitly linked prior to this) and we may re-inject
        // dependencies again, but both of those situations are fine.
        //
        // Also note that we have yet to perform validation of the crate graph
        // in terms of everyone has a compatible panic runtime format, that's
        // performed later as part of the `dependency_format` module.
        let name = match desired_strategy {
            PanicStrategy::Unwind => "panic_unwind",
            PanicStrategy::Abort => "panic_abort",
        };
        info!("panic runtime not found -- loading {}", name);

        let (cnum, data, _) = self.resolve_crate(&None, name, name, None,
                                                 syntax_pos::DUMMY_SP,
                                                 PathKind::Crate, false);

        // Sanity check the loaded crate to ensure it is indeed a panic runtime
        // and the panic strategy is indeed what we thought it was.
        if !data.is_panic_runtime() {
            self.sess.err(&format!("the crate `{}` is not a panic runtime",
                                   name));
        }
        if data.panic_strategy() != desired_strategy {
            self.sess.err(&format!("the crate `{}` does not have the panic \
                                    strategy `{}`",
                                   name, desired_strategy.desc()));
        }

        self.sess.injected_panic_runtime.set(Some(cnum));
        self.inject_dependency_if(cnum, "a panic runtime",
                                  &|data| data.needs_panic_runtime());
    }

    fn inject_allocator_crate(&mut self) {
        // Make sure that we actually need an allocator, if none of our
        // dependencies need one then we definitely don't!
        //
        // Also, if one of our dependencies has an explicit allocator, then we
        // also bail out as we don't need to implicitly inject one.
        let mut needs_allocator = false;
        let mut found_required_allocator = false;
        self.cstore.iter_crate_data(|cnum, data| {
            needs_allocator = needs_allocator || data.needs_allocator();
            if data.is_allocator() {
                info!("{} required by rlib and is an allocator", data.name());
                self.inject_dependency_if(cnum, "an allocator",
                                          &|data| data.needs_allocator());
                found_required_allocator = found_required_allocator ||
                    data.explicitly_linked.get();
            }
        });
        if !needs_allocator || found_required_allocator { return }

        // At this point we've determined that we need an allocator and no
        // previous allocator has been activated. We look through our outputs of
        // crate types to see what kind of allocator types we may need.
        //
        // The main special output type here is that rlibs do **not** need an
        // allocator linked in (they're just object files), only final products
        // (exes, dylibs, staticlibs) need allocators.
        let mut need_lib_alloc = false;
        let mut need_exe_alloc = false;
        for ct in self.sess.crate_types.borrow().iter() {
            match *ct {
                config::CrateTypeExecutable => need_exe_alloc = true,
                config::CrateTypeDylib |
                config::CrateTypeCdylib |
                config::CrateTypeStaticlib => need_lib_alloc = true,
                config::CrateTypeRlib => {}
            }
        }
        if !need_lib_alloc && !need_exe_alloc { return }

        // The default allocator crate comes from the custom target spec, and we
        // choose between the standard library allocator or exe allocator. This
        // distinction exists because the default allocator for binaries (where
        // the world is Rust) is different than library (where the world is
        // likely *not* Rust).
        //
        // If a library is being produced, but we're also flagged with `-C
        // prefer-dynamic`, then we interpret this as a *Rust* dynamic library
        // is being produced so we use the exe allocator instead.
        //
        // What this boils down to is:
        //
        // * Binaries use jemalloc
        // * Staticlibs and Rust dylibs use system malloc
        // * Rust dylibs used as dependencies to rust use jemalloc
        let name = if need_lib_alloc && !self.sess.opts.cg.prefer_dynamic {
            &self.sess.target.target.options.lib_allocation_crate
        } else {
            &self.sess.target.target.options.exe_allocation_crate
        };
        let (cnum, data, _) = self.resolve_crate(&None, name, name, None,
                                                 syntax_pos::DUMMY_SP,
                                                 PathKind::Crate, false);

        // Sanity check the crate we loaded to ensure that it is indeed an
        // allocator.
        if !data.is_allocator() {
            self.sess.err(&format!("the allocator crate `{}` is not tagged \
                                    with #![allocator]", data.name()));
        }

        self.sess.injected_allocator.set(Some(cnum));
        self.inject_dependency_if(cnum, "an allocator",
                                  &|data| data.needs_allocator());
    }

    fn inject_dependency_if(&self,
                            krate: ast::CrateNum,
                            what: &str,
                            needs_dep: &Fn(&cstore::CrateMetadata) -> bool) {
        // don't perform this validation if the session has errors, as one of
        // those errors may indicate a circular dependency which could cause
        // this to stack overflow.
        if self.sess.has_errors() {
            return
        }

        // Before we inject any dependencies, make sure we don't inject a
        // circular dependency by validating that this crate doesn't
        // transitively depend on any crates satisfying `needs_dep`.
        for dep in self.cstore.crate_dependencies_in_rpo(krate) {
            let data = self.cstore.get_crate_data(dep);
            if needs_dep(&data) {
                self.sess.err(&format!("the crate `{}` cannot depend \
                                        on a crate that needs {}, but \
                                        it depends on `{}`",
                                       self.cstore.get_crate_data(krate).name(),
                                       what,
                                       data.name()));
            }
        }

        // All crates satisfying `needs_dep` do not explicitly depend on the
        // crate provided for this compile, but in order for this compilation to
        // be successfully linked we need to inject a dependency (to order the
        // crates on the command line correctly).
        self.cstore.iter_crate_data(|cnum, data| {
            if !needs_dep(data) {
                return
            }

            info!("injecting a dep from {} to {}", cnum, krate);
            data.cnum_map.borrow_mut().push(krate);
        });
    }
}

impl<'a> LocalCrateReader<'a> {
    fn new(sess: &'a Session,
           cstore: &'a CStore,
           defs: &'a hir_map::Definitions,
           krate: &'a ast::Crate,
           local_crate_name: &str)
           -> LocalCrateReader<'a> {
        LocalCrateReader {
            sess: sess,
            cstore: cstore,
            creader: CrateReader::new(sess, cstore, local_crate_name),
            krate: krate,
            definitions: defs,
        }
    }

    // Traverses an AST, reading all the information about use'd crates and
    // extern libraries necessary for later resolving, typechecking, linking,
    // etc.
    fn read_crates(&mut self, dep_graph: &DepGraph) {
        let _task = dep_graph.in_task(DepNode::CrateReader);

        self.process_crate(self.krate);
        visit::walk_crate(self, self.krate);
        self.creader.inject_allocator_crate();
        self.creader.inject_panic_runtime(self.krate);

        if log_enabled!(log::INFO) {
            dump_crates(&self.cstore);
        }

        for &(ref name, kind) in &self.sess.opts.libs {
            register_native_lib(self.sess, self.cstore, None, name.clone(), kind);
        }
        self.creader.register_statically_included_foreign_items();
    }

    fn process_crate(&self, c: &ast::Crate) {
        for a in c.attrs.iter().filter(|m| m.name() == "link_args") {
            if let Some(ref linkarg) = a.value_str() {
                self.cstore.add_used_link_args(&linkarg);
            }
        }
    }

    fn process_item(&mut self, i: &ast::Item) {
        match i.node {
            ast::ItemKind::ExternCrate(_) => {
                if !should_link(i) {
                    return;
                }

                if let Some(info) = self.creader.extract_crate_info(i) {
                    let (cnum, _, _) = self.creader.resolve_crate(&None,
                                                                  &info.ident,
                                                                  &info.name,
                                                                  None,
                                                                  i.span,
                                                                  PathKind::Crate,
                                                                  true);

                    let def_id = self.definitions.opt_local_def_id(i.id).unwrap();
                    let len = self.definitions.def_path(def_id.index).data.len();

                    self.creader.update_extern_crate(cnum,
                                                     ExternCrate {
                                                         def_id: def_id,
                                                         span: i.span,
                                                         direct: true,
                                                         path_len: len,
                                                     },
                                                     &mut FnvHashSet());
                    self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
                }
            }
            ast::ItemKind::ForeignMod(ref fm) => self.process_foreign_mod(i, fm),
            _ => { }
        }
    }

    fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod) {
        if fm.abi == Abi::Rust || fm.abi == Abi::RustIntrinsic || fm.abi == Abi::PlatformIntrinsic {
            return;
        }

        // First, add all of the custom #[link_args] attributes
        for m in i.attrs.iter().filter(|a| a.check_name("link_args")) {
            if let Some(linkarg) = m.value_str() {
                self.cstore.add_used_link_args(&linkarg);
            }
        }

        // Next, process all of the #[link(..)]-style arguments
        for m in i.attrs.iter().filter(|a| a.check_name("link")) {
            let items = match m.meta_item_list() {
                Some(item) => item,
                None => continue,
            };
            let kind = items.iter().find(|k| {
                k.check_name("kind")
            }).and_then(|a| a.value_str());
            let kind = match kind.as_ref().map(|s| &s[..]) {
                Some("static") => cstore::NativeStatic,
                Some("dylib") => cstore::NativeUnknown,
                Some("framework") => cstore::NativeFramework,
                Some(k) => {
                    span_err!(self.sess, m.span, E0458,
                              "unknown kind: `{}`", k);
                    cstore::NativeUnknown
                }
                None => cstore::NativeUnknown
            };
            let n = items.iter().find(|n| {
                n.check_name("name")
            }).and_then(|a| a.value_str());
            let n = match n {
                Some(n) => n,
                None => {
                    span_err!(self.sess, m.span, E0459,
                              "#[link(...)] specified without `name = \"foo\"`");
                    InternedString::new("foo")
                }
            };
            register_native_lib(self.sess, self.cstore, Some(m.span), n.to_string(), kind);
        }

        // Finally, process the #[linked_from = "..."] attribute
        for m in i.attrs.iter().filter(|a| a.check_name("linked_from")) {
            let lib_name = match m.value_str() {
                Some(name) => name,
                None => continue,
            };
            let list = self.creader.foreign_item_map.entry(lib_name.to_string())
                                                    .or_insert(Vec::new());
            list.extend(fm.items.iter().map(|it| it.id));
        }
    }
}

/// Traverses an AST, reading all the information about use'd crates and extern
/// libraries necessary for later resolving, typechecking, linking, etc.
pub fn read_local_crates(sess: & Session,
                         cstore: & CStore,
                         defs: & hir_map::Definitions,
                         krate: & ast::Crate,
                         local_crate_name: &str,
                         dep_graph: &DepGraph) {
    LocalCrateReader::new(sess, cstore, defs, krate, local_crate_name).read_crates(dep_graph)
}

/// Imports the codemap from an external crate into the codemap of the crate
/// currently being compiled (the "local crate").
///
/// The import algorithm works analogous to how AST items are inlined from an
/// external crate's metadata:
/// For every FileMap in the external codemap an 'inline' copy is created in the
/// local codemap. The correspondence relation between external and local
/// FileMaps is recorded in the `ImportedFileMap` objects returned from this
/// function. When an item from an external crate is later inlined into this
/// crate, this correspondence information is used to translate the span
/// information of the inlined item so that it refers the correct positions in
/// the local codemap (see `astencode::DecodeContext::tr_span()`).
///
/// The import algorithm in the function below will reuse FileMaps already
/// existing in the local codemap. For example, even if the FileMap of some
/// source file of libstd gets imported many times, there will only ever be
/// one FileMap object for the corresponding file in the local codemap.
///
/// Note that imported FileMaps do not actually contain the source code of the
/// file they represent, just information about length, line breaks, and
/// multibyte characters. This information is enough to generate valid debuginfo
/// for items inlined from other crates.
pub fn import_codemap(local_codemap: &codemap::CodeMap,
                      metadata: &MetadataBlob)
                      -> Vec<cstore::ImportedFileMap> {
    let external_codemap = decoder::get_imported_filemaps(metadata.as_slice());

    let imported_filemaps = external_codemap.into_iter().map(|filemap_to_import| {
        // Try to find an existing FileMap that can be reused for the filemap to
        // be imported. A FileMap is reusable if it is exactly the same, just
        // positioned at a different offset within the codemap.
        let reusable_filemap = {
            local_codemap.files
                         .borrow()
                         .iter()
                         .find(|fm| are_equal_modulo_startpos(&fm, &filemap_to_import))
                         .map(|rc| rc.clone())
        };

        match reusable_filemap {
            Some(fm) => {
                cstore::ImportedFileMap {
                    original_start_pos: filemap_to_import.start_pos,
                    original_end_pos: filemap_to_import.end_pos,
                    translated_filemap: fm
                }
            }
            None => {
                // We can't reuse an existing FileMap, so allocate a new one
                // containing the information we need.
                let syntax_pos::FileMap {
                    name,
                    abs_path,
                    start_pos,
                    end_pos,
                    lines,
                    multibyte_chars,
                    ..
                } = filemap_to_import;

                let source_length = (end_pos - start_pos).to_usize();

                // Translate line-start positions and multibyte character
                // position into frame of reference local to file.
                // `CodeMap::new_imported_filemap()` will then translate those
                // coordinates to their new global frame of reference when the
                // offset of the FileMap is known.
                let mut lines = lines.into_inner();
                for pos in &mut lines {
                    *pos = *pos - start_pos;
                }
                let mut multibyte_chars = multibyte_chars.into_inner();
                for mbc in &mut multibyte_chars {
                    mbc.pos = mbc.pos - start_pos;
                }

                let local_version = local_codemap.new_imported_filemap(name,
                                                                       abs_path,
                                                                       source_length,
                                                                       lines,
                                                                       multibyte_chars);
                cstore::ImportedFileMap {
                    original_start_pos: start_pos,
                    original_end_pos: end_pos,
                    translated_filemap: local_version
                }
            }
        }
    }).collect();

    return imported_filemaps;

    fn are_equal_modulo_startpos(fm1: &syntax_pos::FileMap,
                                 fm2: &syntax_pos::FileMap)
                                 -> bool {
        if fm1.name != fm2.name {
            return false;
        }

        let lines1 = fm1.lines.borrow();
        let lines2 = fm2.lines.borrow();

        if lines1.len() != lines2.len() {
            return false;
        }

        for (&line1, &line2) in lines1.iter().zip(lines2.iter()) {
            if (line1 - fm1.start_pos) != (line2 - fm2.start_pos) {
                return false;
            }
        }

        let multibytes1 = fm1.multibyte_chars.borrow();
        let multibytes2 = fm2.multibyte_chars.borrow();

        if multibytes1.len() != multibytes2.len() {
            return false;
        }

        for (mb1, mb2) in multibytes1.iter().zip(multibytes2.iter()) {
            if (mb1.bytes != mb2.bytes) ||
               ((mb1.pos - fm1.start_pos) != (mb2.pos - fm2.start_pos)) {
                return false;
            }
        }

        true
    }
}
