/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

  1. // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
  2. // file at the top-level directory of this distribution and at
  3. // http://rust-lang.org/COPYRIGHT.
  4. //
  5. // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
  6. // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
  7. // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
  8. // option. This file may not be copied, modified, or distributed
  9. // except according to those terms.
  10. //! Used by `rustc` when loading a crate with exported macros.
  11. use creader::CrateReader;
  12. use cstore::CStore;
  13. use rustc::session::Session;
  14. use std::collections::{HashSet, HashMap};
  15. use syntax::codemap::Span;
  16. use syntax::parse::token;
  17. use syntax::ast;
  18. use syntax::attr;
  19. use syntax::visit;
  20. use syntax::visit::Visitor;
  21. use syntax::attr::AttrMetaMethods;
  22. struct MacroLoader<'a> {
  23. sess: &'a Session,
  24. span_whitelist: HashSet<Span>,
  25. reader: CrateReader<'a>,
  26. macros: Vec<ast::MacroDef>,
  27. }
  28. impl<'a> MacroLoader<'a> {
  29. fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> MacroLoader<'a> {
  30. MacroLoader {
  31. sess: sess,
  32. span_whitelist: HashSet::new(),
  33. reader: CrateReader::new(sess, cstore, crate_name),
  34. macros: vec![],
  35. }
  36. }
  37. }
  38. pub fn call_bad_macro_reexport(a: &Session, b: Span) {
  39. span_err!(a, b, E0467, "bad macro reexport");
  40. }
  41. /// Read exported macros.
  42. pub fn read_macro_defs(sess: &Session,
  43. cstore: &CStore,
  44. krate: &ast::Crate,
  45. crate_name: &str)
  46. -> Vec<ast::MacroDef>
  47. {
  48. let mut loader = MacroLoader::new(sess, cstore, crate_name);
  49. // We need to error on `#[macro_use] extern crate` when it isn't at the
  50. // crate root, because `$crate` won't work properly. Identify these by
  51. // spans, because the crate map isn't set up yet.
  52. for item in &krate.module.items {
  53. if let ast::ItemKind::ExternCrate(_) = item.node {
  54. loader.span_whitelist.insert(item.span);
  55. }
  56. }
  57. visit::walk_crate(&mut loader, krate);
  58. loader.macros
  59. }
  60. pub type MacroSelection = HashMap<token::InternedString, Span>;
  61. // note that macros aren't expanded yet, and therefore macros can't add macro imports.
  62. impl<'a, 'v> Visitor<'v> for MacroLoader<'a> {
  63. fn visit_item(&mut self, item: &ast::Item) {
  64. // We're only interested in `extern crate`.
  65. match item.node {
  66. ast::ItemKind::ExternCrate(_) => {}
  67. _ => {
  68. visit::walk_item(self, item);
  69. return;
  70. }
  71. }
  72. // Parse the attributes relating to macros.
  73. let mut import = Some(HashMap::new()); // None => load all
  74. let mut reexport = HashMap::new();
  75. for attr in &item.attrs {
  76. let mut used = true;
  77. match &attr.name()[..] {
  78. "macro_use" => {
  79. let names = attr.meta_item_list();
  80. if names.is_none() {
  81. // no names => load all
  82. import = None;
  83. }
  84. if let (Some(sel), Some(names)) = (import.as_mut(), names) {
  85. for attr in names {
  86. if let ast::MetaItemKind::Word(ref name) = attr.node {
  87. sel.insert(name.clone(), attr.span);
  88. } else {
  89. span_err!(self.sess, attr.span, E0466, "bad macro import");
  90. }
  91. }
  92. }
  93. }
  94. "macro_reexport" => {
  95. let names = match attr.meta_item_list() {
  96. Some(names) => names,
  97. None => {
  98. call_bad_macro_reexport(self.sess, attr.span);
  99. continue;
  100. }
  101. };
  102. for attr in names {
  103. if let ast::MetaItemKind::Word(ref name) = attr.node {
  104. reexport.insert(name.clone(), attr.span);
  105. } else {
  106. call_bad_macro_reexport(self.sess, attr.span);
  107. }
  108. }
  109. }
  110. _ => used = false,
  111. }
  112. if used {
  113. attr::mark_used(attr);
  114. }
  115. }
  116. self.load_macros(item, import, reexport)
  117. }
  118. fn visit_mac(&mut self, _: &ast::Mac) {
  119. // bummer... can't see macro imports inside macros.
  120. // do nothing.
  121. }
  122. }
  123. impl<'a> MacroLoader<'a> {
  124. fn load_macros<'b>(&mut self,
  125. vi: &ast::Item,
  126. import: Option<MacroSelection>,
  127. reexport: MacroSelection) {
  128. if let Some(sel) = import.as_ref() {
  129. if sel.is_empty() && reexport.is_empty() {
  130. return;
  131. }
  132. }
  133. if !self.span_whitelist.contains(&vi.span) {
  134. span_err!(self.sess, vi.span, E0468,
  135. "an `extern crate` loading macros must be at the crate root");
  136. return;
  137. }
  138. let macros = self.reader.read_exported_macros(vi);
  139. let mut seen = HashSet::new();
  140. for mut def in macros {
  141. let name = def.ident.name.as_str();
  142. def.use_locally = match import.as_ref() {
  143. None => true,
  144. Some(sel) => sel.contains_key(&name),
  145. };
  146. def.export = reexport.contains_key(&name);
  147. def.allow_internal_unstable = attr::contains_name(&def.attrs,
  148. "allow_internal_unstable");
  149. debug!("load_macros: loaded: {:?}", def);
  150. self.macros.push(def);
  151. seen.insert(name);
  152. }
  153. if let Some(sel) = import.as_ref() {
  154. for (name, span) in sel {
  155. if !seen.contains(&name) {
  156. span_err!(self.sess, *span, E0469,
  157. "imported macro not found");
  158. }
  159. }
  160. }
  161. for (name, span) in &reexport {
  162. if !seen.contains(&name) {
  163. span_err!(self.sess, *span, E0470,
  164. "reexported macro not found");
  165. }
  166. }
  167. }
  168. }