/src/librustc_metadata/macro_import.rs
https://gitlab.com/alx741/rust · Rust · 193 lines · 148 code · 25 blank · 20 comment · 27 complexity · 68da959f0bd20ec999bee2a93242d8f0 MD5 · raw file
- // 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.
- //! Used by `rustc` when loading a crate with exported macros.
- use creader::CrateReader;
- use cstore::CStore;
- use rustc::session::Session;
- use std::collections::{HashSet, HashMap};
- use syntax::codemap::Span;
- use syntax::parse::token;
- use syntax::ast;
- use syntax::attr;
- use syntax::visit;
- use syntax::visit::Visitor;
- use syntax::attr::AttrMetaMethods;
- struct MacroLoader<'a> {
- sess: &'a Session,
- span_whitelist: HashSet<Span>,
- reader: CrateReader<'a>,
- macros: Vec<ast::MacroDef>,
- }
- impl<'a> MacroLoader<'a> {
- fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> MacroLoader<'a> {
- MacroLoader {
- sess: sess,
- span_whitelist: HashSet::new(),
- reader: CrateReader::new(sess, cstore, crate_name),
- macros: vec![],
- }
- }
- }
- pub fn call_bad_macro_reexport(a: &Session, b: Span) {
- span_err!(a, b, E0467, "bad macro reexport");
- }
- /// Read exported macros.
- pub fn read_macro_defs(sess: &Session,
- cstore: &CStore,
- krate: &ast::Crate,
- crate_name: &str)
- -> Vec<ast::MacroDef>
- {
- let mut loader = MacroLoader::new(sess, cstore, crate_name);
- // We need to error on `#[macro_use] extern crate` when it isn't at the
- // crate root, because `$crate` won't work properly. Identify these by
- // spans, because the crate map isn't set up yet.
- for item in &krate.module.items {
- if let ast::ItemKind::ExternCrate(_) = item.node {
- loader.span_whitelist.insert(item.span);
- }
- }
- visit::walk_crate(&mut loader, krate);
- loader.macros
- }
- pub type MacroSelection = HashMap<token::InternedString, Span>;
- // note that macros aren't expanded yet, and therefore macros can't add macro imports.
- impl<'a, 'v> Visitor<'v> for MacroLoader<'a> {
- fn visit_item(&mut self, item: &ast::Item) {
- // We're only interested in `extern crate`.
- match item.node {
- ast::ItemKind::ExternCrate(_) => {}
- _ => {
- visit::walk_item(self, item);
- return;
- }
- }
- // Parse the attributes relating to macros.
- let mut import = Some(HashMap::new()); // None => load all
- let mut reexport = HashMap::new();
- for attr in &item.attrs {
- let mut used = true;
- match &attr.name()[..] {
- "macro_use" => {
- let names = attr.meta_item_list();
- if names.is_none() {
- // no names => load all
- import = None;
- }
- if let (Some(sel), Some(names)) = (import.as_mut(), names) {
- for attr in names {
- if let ast::MetaItemKind::Word(ref name) = attr.node {
- sel.insert(name.clone(), attr.span);
- } else {
- span_err!(self.sess, attr.span, E0466, "bad macro import");
- }
- }
- }
- }
- "macro_reexport" => {
- let names = match attr.meta_item_list() {
- Some(names) => names,
- None => {
- call_bad_macro_reexport(self.sess, attr.span);
- continue;
- }
- };
- for attr in names {
- if let ast::MetaItemKind::Word(ref name) = attr.node {
- reexport.insert(name.clone(), attr.span);
- } else {
- call_bad_macro_reexport(self.sess, attr.span);
- }
- }
- }
- _ => used = false,
- }
- if used {
- attr::mark_used(attr);
- }
- }
- self.load_macros(item, import, reexport)
- }
- fn visit_mac(&mut self, _: &ast::Mac) {
- // bummer... can't see macro imports inside macros.
- // do nothing.
- }
- }
- impl<'a> MacroLoader<'a> {
- fn load_macros<'b>(&mut self,
- vi: &ast::Item,
- import: Option<MacroSelection>,
- reexport: MacroSelection) {
- if let Some(sel) = import.as_ref() {
- if sel.is_empty() && reexport.is_empty() {
- return;
- }
- }
- if !self.span_whitelist.contains(&vi.span) {
- span_err!(self.sess, vi.span, E0468,
- "an `extern crate` loading macros must be at the crate root");
- return;
- }
- let macros = self.reader.read_exported_macros(vi);
- let mut seen = HashSet::new();
- for mut def in macros {
- let name = def.ident.name.as_str();
- def.use_locally = match import.as_ref() {
- None => true,
- Some(sel) => sel.contains_key(&name),
- };
- def.export = reexport.contains_key(&name);
- def.allow_internal_unstable = attr::contains_name(&def.attrs,
- "allow_internal_unstable");
- debug!("load_macros: loaded: {:?}", def);
- self.macros.push(def);
- seen.insert(name);
- }
- if let Some(sel) = import.as_ref() {
- for (name, span) in sel {
- if !seen.contains(&name) {
- span_err!(self.sess, *span, E0469,
- "imported macro not found");
- }
- }
- }
- for (name, span) in &reexport {
- if !seen.contains(&name) {
- span_err!(self.sess, *span, E0470,
- "reexported macro not found");
- }
- }
- }
- }