Skip to content

Commit a4a249f

Browse files
committed
Auto merge of #31279 - DanielJCampbell:MacroReferencing, r=nrc
r? @nrc
2 parents b94cd7a + 1d32641 commit a4a249f

File tree

10 files changed

+221
-11
lines changed

10 files changed

+221
-11
lines changed

src/librustc/session/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use rustc_back::target::Target;
3030

3131
use std::path::{Path, PathBuf};
3232
use std::cell::{Cell, RefCell};
33-
use std::collections::HashSet;
33+
use std::collections::{HashMap, HashSet};
3434
use std::env;
3535
use std::rc::Rc;
3636

@@ -77,6 +77,11 @@ pub struct Session {
7777
/// available in this crate
7878
pub available_macros: RefCell<HashSet<Name>>,
7979

80+
/// Map from imported macro spans (which consist of
81+
/// the localized span for the macro body) to the
82+
/// macro name and defintion span in the source crate.
83+
pub imported_macro_spans: RefCell<HashMap<Span, (String, Span)>>,
84+
8085
next_node_id: Cell<ast::NodeId>,
8186
}
8287

@@ -479,6 +484,7 @@ pub fn build_session_(sopts: config::Options,
479484
next_node_id: Cell::new(1),
480485
injected_allocator: Cell::new(None),
481486
available_macros: RefCell::new(HashSet::new()),
487+
imported_macro_spans: RefCell::new(HashMap::new()),
482488
};
483489

484490
sess

src/librustc_metadata/common.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ pub const tag_polarity: usize = 0x9d;
223223
pub const tag_macro_defs: usize = 0x10e; // top-level only
224224
pub const tag_macro_def: usize = 0x9e;
225225
pub const tag_macro_def_body: usize = 0x9f;
226+
pub const tag_macro_def_span_lo: usize = 0xa8;
227+
pub const tag_macro_def_span_hi: usize = 0xa9;
226228

227229
pub const tag_paren_sugar: usize = 0xa0;
228230

src/librustc_metadata/creader.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ impl<'a> CrateReader<'a> {
494494
let mut macros = vec![];
495495
decoder::each_exported_macro(ekrate.metadata.as_slice(),
496496
&*self.cstore.intr,
497-
|name, attrs, body| {
497+
|name, attrs, span, body| {
498498
// NB: Don't use parse::parse_tts_from_source_str because it parses with
499499
// quote_depth > 0.
500500
let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess,
@@ -509,7 +509,7 @@ impl<'a> CrateReader<'a> {
509509
panic!(FatalError);
510510
}
511511
};
512-
let span = mk_sp(lo, p.last_span.hi);
512+
let local_span = mk_sp(lo, p.last_span.hi);
513513

514514
// Mark the attrs as used
515515
for attr in &attrs {
@@ -520,7 +520,7 @@ impl<'a> CrateReader<'a> {
520520
ident: ast::Ident::with_empty_ctxt(name),
521521
attrs: attrs,
522522
id: ast::DUMMY_NODE_ID,
523-
span: span,
523+
span: local_span,
524524
imported_from: Some(item.ident),
525525
// overridden in plugin/load.rs
526526
export: false,
@@ -529,6 +529,8 @@ impl<'a> CrateReader<'a> {
529529

530530
body: body,
531531
});
532+
self.sess.imported_macro_spans.borrow_mut()
533+
.insert(local_span, (name.as_str().to_string(), span));
532534
true
533535
}
534536
);

src/librustc_metadata/decoder.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use syntax::parse::token::{IdentInterner, special_idents};
5252
use syntax::parse::token;
5353
use syntax::ast;
5454
use syntax::abi;
55-
use syntax::codemap::{self, Span};
55+
use syntax::codemap::{self, Span, BytePos, NO_EXPANSION};
5656
use syntax::print::pprust;
5757
use syntax::ptr::P;
5858

@@ -1471,19 +1471,28 @@ pub fn get_plugin_registrar_fn(data: &[u8]) -> Option<DefIndex> {
14711471
}
14721472

14731473
pub fn each_exported_macro<F>(data: &[u8], intr: &IdentInterner, mut f: F) where
1474-
F: FnMut(ast::Name, Vec<ast::Attribute>, String) -> bool,
1474+
F: FnMut(ast::Name, Vec<ast::Attribute>, Span, String) -> bool,
14751475
{
14761476
let macros = reader::get_doc(rbml::Doc::new(data), tag_macro_defs);
14771477
for macro_doc in reader::tagged_docs(macros, tag_macro_def) {
14781478
let name = item_name(intr, macro_doc);
14791479
let attrs = get_attributes(macro_doc);
1480+
let span = get_macro_span(macro_doc);
14801481
let body = reader::get_doc(macro_doc, tag_macro_def_body);
1481-
if !f(name, attrs, body.as_str().to_string()) {
1482+
if !f(name, attrs, span, body.as_str().to_string()) {
14821483
break;
14831484
}
14841485
}
14851486
}
14861487

1488+
pub fn get_macro_span(doc: rbml::Doc) -> Span {
1489+
let lo_doc = reader::get_doc(doc, tag_macro_def_span_lo);
1490+
let lo = BytePos(reader::doc_as_u32(lo_doc));
1491+
let hi_doc = reader::get_doc(doc, tag_macro_def_span_hi);
1492+
let hi = BytePos(reader::doc_as_u32(hi_doc));
1493+
return Span { lo: lo, hi: hi, expn_id: NO_EXPANSION };
1494+
}
1495+
14871496
pub fn get_dylib_dependency_formats(cdata: Cmd)
14881497
-> Vec<(ast::CrateNum, LinkagePreference)>
14891498
{

src/librustc_metadata/encoder.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use std::rc::Rc;
4242
use std::u32;
4343
use syntax::abi;
4444
use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum};
45+
use syntax::codemap::BytePos;
4546
use syntax::attr;
4647
use syntax::attr::AttrMetaMethods;
4748
use syntax::errors::Handler;
@@ -1727,6 +1728,10 @@ fn encode_macro_defs(rbml_w: &mut Encoder,
17271728

17281729
encode_name(rbml_w, def.name);
17291730
encode_attributes(rbml_w, &def.attrs);
1731+
let &BytePos(lo) = &def.span.lo;
1732+
let &BytePos(hi) = &def.span.hi;
1733+
rbml_w.wr_tagged_u32(tag_macro_def_span_lo, lo);
1734+
rbml_w.wr_tagged_u32(tag_macro_def_span_hi, hi);
17301735

17311736
rbml_w.wr_tagged_str(tag_macro_def_body,
17321737
&::syntax::print::pprust::tts_to_string(&def.body));

src/librustc_trans/save/dump_csv.rs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ use middle::def_id::DefId;
3737
use middle::ty;
3838

3939
use std::fs::File;
40+
use std::hash::*;
41+
use std::collections::HashSet;
4042

4143
use syntax::ast::{self, NodeId};
4244
use syntax::codemap::*;
@@ -70,6 +72,14 @@ pub struct DumpCsvVisitor<'l, 'tcx: 'l> {
7072
fmt: FmtStrs<'l, 'tcx>,
7173

7274
cur_scope: NodeId,
75+
76+
// Set of macro definition (callee) spans, and the set
77+
// of macro use (callsite) spans. We store these to ensure
78+
// we only write one macro def per unique macro definition, and
79+
// one macro use per unique callsite span.
80+
mac_defs: HashSet<Span>,
81+
mac_uses: HashSet<Span>,
82+
7383
}
7484

7585
impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
@@ -92,6 +102,8 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
92102
span_utils,
93103
tcx),
94104
cur_scope: 0,
105+
mac_defs: HashSet::new(),
106+
mac_uses: HashSet::new(),
95107
}
96108
}
97109

@@ -814,10 +826,41 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
814826
&typ);
815827
}
816828
}
829+
830+
/// Extract macro use and definition information from the AST node defined
831+
/// by the given NodeId, using the expansion information from the node's
832+
/// span.
833+
///
834+
/// If the span is not macro-generated, do nothing, else use callee and
835+
/// callsite spans to record macro definition and use data, using the
836+
/// mac_uses and mac_defs sets to prevent multiples.
837+
fn process_macro_use(&mut self, span: Span, id: NodeId) {
838+
let data = match self.save_ctxt.get_macro_use_data(span, id) {
839+
None => return,
840+
Some(data) => data,
841+
};
842+
let mut hasher = SipHasher::new();
843+
data.callee_span.hash(&mut hasher);
844+
let hash = hasher.finish();
845+
let qualname = format!("{}::{}", data.name, hash);
846+
// Don't write macro definition for imported macros
847+
if !self.mac_defs.contains(&data.callee_span)
848+
&& !data.imported {
849+
self.mac_defs.insert(data.callee_span);
850+
self.fmt.macro_str(data.callee_span, data.callee_span,
851+
data.name.clone(), qualname.clone());
852+
}
853+
if !self.mac_uses.contains(&data.span) {
854+
self.mac_uses.insert(data.span);
855+
self.fmt.macro_use_str(data.span, data.span, data.name,
856+
qualname, data.scope);
857+
}
858+
}
817859
}
818860

819861
impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
820862
fn visit_item(&mut self, item: &ast::Item) {
863+
self.process_macro_use(item.span, item.id);
821864
match item.node {
822865
ast::ItemUse(ref use_item) => {
823866
match use_item.node {
@@ -970,6 +1013,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
9701013
}
9711014

9721015
fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
1016+
self.process_macro_use(trait_item.span, trait_item.id);
9731017
match trait_item.node {
9741018
ast::ConstTraitItem(ref ty, Some(ref expr)) => {
9751019
self.process_const(trait_item.id,
@@ -991,6 +1035,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
9911035
}
9921036

9931037
fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
1038+
self.process_macro_use(impl_item.span, impl_item.id);
9941039
match impl_item.node {
9951040
ast::ImplItemKind::Const(ref ty, ref expr) => {
9961041
self.process_const(impl_item.id,
@@ -1012,6 +1057,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
10121057
}
10131058

10141059
fn visit_ty(&mut self, t: &ast::Ty) {
1060+
self.process_macro_use(t.span, t.id);
10151061
match t.node {
10161062
ast::TyPath(_, ref path) => {
10171063
match self.lookup_type_ref(t.id) {
@@ -1031,6 +1077,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
10311077
}
10321078

10331079
fn visit_expr(&mut self, ex: &ast::Expr) {
1080+
self.process_macro_use(ex.span, ex.id);
10341081
match ex.node {
10351082
ast::ExprCall(ref _f, ref _args) => {
10361083
// Don't need to do anything for function calls,
@@ -1117,11 +1164,13 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
11171164
}
11181165
}
11191166

1120-
fn visit_mac(&mut self, _: &ast::Mac) {
1121-
// Just stop, macros are poison to us.
1167+
fn visit_mac(&mut self, mac: &ast::Mac) {
1168+
// These shouldn't exist in the AST at this point, log a span bug.
1169+
self.sess.span_bug(mac.span, "macro invocation should have been expanded out of AST");
11221170
}
11231171

11241172
fn visit_pat(&mut self, p: &ast::Pat) {
1173+
self.process_macro_use(p.span, p.id);
11251174
self.process_pat(p);
11261175
}
11271176

@@ -1177,10 +1226,13 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
11771226
}
11781227

11791228
fn visit_stmt(&mut self, s: &ast::Stmt) {
1229+
let id = s.node.id();
1230+
self.process_macro_use(s.span, id.unwrap());
11801231
visit::walk_stmt(self, s)
11811232
}
11821233

11831234
fn visit_local(&mut self, l: &ast::Local) {
1235+
self.process_macro_use(l.span, l.id);
11841236
let value = self.span.snippet(l.span);
11851237
self.process_var_decl(&l.pat, value);
11861238

src/librustc_trans/save/mod.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ pub enum Data {
7373
FunctionCallData(FunctionCallData),
7474
/// Data about a method call.
7575
MethodCallData(MethodCallData),
76+
/// Data about a macro use.
77+
MacroUseData(MacroUseData),
7678
}
7779

7880
/// Data for all kinds of functions and methods.
@@ -174,6 +176,22 @@ pub struct MethodCallData {
174176
pub decl_id: Option<DefId>,
175177
}
176178

179+
/// Data about a macro use.
180+
#[derive(Debug)]
181+
pub struct MacroUseData {
182+
pub span: Span,
183+
pub name: String,
184+
// Because macro expansion happens before ref-ids are determined,
185+
// we use the callee span to reference the associated macro definition.
186+
pub callee_span: Span,
187+
pub scope: NodeId,
188+
pub imported: bool,
189+
}
190+
191+
macro_rules! option_try(
192+
($e:expr) => (match $e { Some(e) => e, None => return None })
193+
);
194+
177195

178196

179197
impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
@@ -655,6 +673,51 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
655673
})
656674
}
657675

676+
/// Attempt to return MacroUseData for any AST node.
677+
///
678+
/// For a given piece of AST defined by the supplied Span and NodeId,
679+
/// returns None if the node is not macro-generated or the span is malformed,
680+
/// else uses the expansion callsite and callee to return some MacroUseData.
681+
pub fn get_macro_use_data(&self, span: Span, id: NodeId) -> Option<MacroUseData> {
682+
if !generated_code(span) {
683+
return None;
684+
}
685+
// Note we take care to use the source callsite/callee, to handle
686+
// nested expansions and ensure we only generate data for source-visible
687+
// macro uses.
688+
let callsite = self.tcx.sess.codemap().source_callsite(span);
689+
let callee = self.tcx.sess.codemap().source_callee(span);
690+
let callee = option_try!(callee);
691+
let callee_span = option_try!(callee.span);
692+
693+
// Ignore attribute macros, their spans are usually mangled
694+
if let MacroAttribute(_) = callee.format {
695+
return None;
696+
}
697+
698+
// If the callee is an imported macro from an external crate, need to get
699+
// the source span and name from the session, as their spans are localized
700+
// when read in, and no longer correspond to the source.
701+
if let Some(mac) = self.tcx.sess.imported_macro_spans.borrow().get(&callee_span) {
702+
let &(ref mac_name, mac_span) = mac;
703+
return Some(MacroUseData {
704+
span: callsite,
705+
name: mac_name.clone(),
706+
callee_span: mac_span,
707+
scope: self.enclosing_scope(id),
708+
imported: true,
709+
});
710+
}
711+
712+
Some(MacroUseData {
713+
span: callsite,
714+
name: callee.name().to_string(),
715+
callee_span: callee_span,
716+
scope: self.enclosing_scope(id),
717+
imported: false,
718+
})
719+
}
720+
658721
pub fn get_data_for_id(&self, _id: &NodeId) -> Data {
659722
// FIXME
660723
unimplemented!();

src/librustc_trans/save/recorder.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ pub enum Row {
9696
VarRef,
9797
TypeRef,
9898
FnRef,
99+
Macro,
100+
MacroUse,
99101
}
100102

101103
impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> {
@@ -219,6 +221,14 @@ impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> {
219221
vec!("refid", "refidcrate", "qualname", "scopeid"),
220222
true,
221223
true),
224+
Macro => ("macro",
225+
vec!("name", "qualname"),
226+
true,
227+
true),
228+
MacroUse => ("macro_use",
229+
vec!("callee_name", "qualname", "scopeid"),
230+
true,
231+
true),
222232
}
223233
}
224234

@@ -686,4 +696,19 @@ impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> {
686696
sub_span,
687697
svec!(id.index.as_usize(), id.krate, "", scope_id));
688698
}
699+
700+
pub fn macro_str(&mut self, span: Span, sub_span: Span, name: String, qualname: String) {
701+
self.record_with_span(Macro, span, sub_span, svec!(name, qualname));
702+
}
703+
704+
pub fn macro_use_str(&mut self,
705+
span: Span,
706+
sub_span: Span,
707+
name: String,
708+
qualname: String,
709+
scope_id: NodeId) {
710+
let scope_id = self.normalize_node_id(scope_id);
711+
self.record_with_span(MacroUse, span, sub_span,
712+
svec!(name, qualname, scope_id));
713+
}
689714
}

0 commit comments

Comments
 (0)