Skip to content

Implemented macro referencing for save analysis #31279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use rustc_back::target::Target;

use std::path::{Path, PathBuf};
use std::cell::{Cell, RefCell};
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};
use std::env;
use std::rc::Rc;

Expand Down Expand Up @@ -77,6 +77,11 @@ pub struct Session {
/// available in this crate
pub available_macros: RefCell<HashSet<Name>>,

/// Map from imported macro spans (which consist of
/// the localized span for the macro body) to the
/// macro name and defintion span in the source crate.
pub imported_macro_spans: RefCell<HashMap<Span, (String, Span)>>,

next_node_id: Cell<ast::NodeId>,
}

Expand Down Expand Up @@ -490,6 +495,7 @@ pub fn build_session_(sopts: config::Options,
next_node_id: Cell::new(1),
injected_allocator: Cell::new(None),
available_macros: RefCell::new(HashSet::new()),
imported_macro_spans: RefCell::new(HashMap::new()),
};

sess
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_metadata/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ pub const tag_polarity: usize = 0x9d;
pub const tag_macro_defs: usize = 0x10e; // top-level only
pub const tag_macro_def: usize = 0x9e;
pub const tag_macro_def_body: usize = 0x9f;
pub const tag_macro_def_span_lo: usize = 0xa8;
pub const tag_macro_def_span_hi: usize = 0xa9;

pub const tag_paren_sugar: usize = 0xa0;

Expand Down
8 changes: 5 additions & 3 deletions src/librustc_metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ impl<'a> CrateReader<'a> {
let mut macros = vec![];
decoder::each_exported_macro(ekrate.metadata.as_slice(),
&*self.cstore.intr,
|name, attrs, body| {
|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,
Expand All @@ -509,7 +509,7 @@ impl<'a> CrateReader<'a> {
panic!(FatalError);
}
};
let span = mk_sp(lo, p.last_span.hi);
let local_span = mk_sp(lo, p.last_span.hi);

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

body: body,
});
self.sess.imported_macro_spans.borrow_mut()
.insert(local_span, (name.as_str().to_string(), span));
true
}
);
Expand Down
15 changes: 12 additions & 3 deletions src/librustc_metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use syntax::parse::token::{IdentInterner, special_idents};
use syntax::parse::token;
use syntax::ast;
use syntax::abi;
use syntax::codemap::{self, Span};
use syntax::codemap::{self, Span, BytePos, NO_EXPANSION};
use syntax::print::pprust;
use syntax::ptr::P;

Expand Down Expand Up @@ -1461,19 +1461,28 @@ pub fn get_plugin_registrar_fn(data: &[u8]) -> Option<DefIndex> {
}

pub fn each_exported_macro<F>(data: &[u8], intr: &IdentInterner, mut f: F) where
F: FnMut(ast::Name, Vec<ast::Attribute>, String) -> bool,
F: FnMut(ast::Name, Vec<ast::Attribute>, Span, String) -> bool,
{
let macros = reader::get_doc(rbml::Doc::new(data), tag_macro_defs);
for macro_doc in reader::tagged_docs(macros, tag_macro_def) {
let name = item_name(intr, macro_doc);
let attrs = get_attributes(macro_doc);
let span = get_macro_span(macro_doc);
let body = reader::get_doc(macro_doc, tag_macro_def_body);
if !f(name, attrs, body.as_str().to_string()) {
if !f(name, attrs, span, body.as_str().to_string()) {
break;
}
}
}

pub fn get_macro_span(doc: rbml::Doc) -> Span {
let lo_doc = reader::get_doc(doc, tag_macro_def_span_lo);
let lo = BytePos(reader::doc_as_u32(lo_doc));
let hi_doc = reader::get_doc(doc, tag_macro_def_span_hi);
let hi = BytePos(reader::doc_as_u32(hi_doc));
return Span { lo: lo, hi: hi, expn_id: NO_EXPANSION };
}

pub fn get_dylib_dependency_formats(cdata: Cmd)
-> Vec<(ast::CrateNum, LinkagePreference)>
{
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ use std::rc::Rc;
use std::u32;
use syntax::abi;
use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum};
use syntax::codemap::BytePos;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::errors::Handler;
Expand Down Expand Up @@ -1727,6 +1728,10 @@ fn encode_macro_defs(rbml_w: &mut Encoder,

encode_name(rbml_w, def.name);
encode_attributes(rbml_w, &def.attrs);
let &BytePos(lo) = &def.span.lo;
let &BytePos(hi) = &def.span.hi;
rbml_w.wr_tagged_u32(tag_macro_def_span_lo, lo);
rbml_w.wr_tagged_u32(tag_macro_def_span_hi, hi);

rbml_w.wr_tagged_str(tag_macro_def_body,
&::syntax::print::pprust::tts_to_string(&def.body));
Expand Down
56 changes: 54 additions & 2 deletions src/librustc_trans/save/dump_csv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ use middle::def_id::DefId;
use middle::ty;

use std::fs::File;
use std::hash::*;
use std::collections::HashSet;

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

cur_scope: NodeId,

// Set of macro definition (callee) spans, and the set
// of macro use (callsite) spans. We store these to ensure
// we only write one macro def per unique macro definition, and
// one macro use per unique callsite span.
mac_defs: HashSet<Span>,
mac_uses: HashSet<Span>,

}

impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
Expand All @@ -92,6 +102,8 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
span_utils,
tcx),
cur_scope: 0,
mac_defs: HashSet::new(),
mac_uses: HashSet::new(),
}
}

Expand Down Expand Up @@ -814,10 +826,41 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
&typ);
}
}

/// Extract macro use and definition information from the AST node defined
/// by the given NodeId, using the expansion information from the node's
/// span.
///
/// If the span is not macro-generated, do nothing, else use callee and
/// callsite spans to record macro definition and use data, using the
/// mac_uses and mac_defs sets to prevent multiples.
fn process_macro_use(&mut self, span: Span, id: NodeId) {
let data = match self.save_ctxt.get_macro_use_data(span, id) {
None => return,
Some(data) => data,
};
let mut hasher = SipHasher::new();
data.callee_span.hash(&mut hasher);
let hash = hasher.finish();
let qualname = format!("{}::{}", data.name, hash);
// Don't write macro definition for imported macros
if !self.mac_defs.contains(&data.callee_span)
&& !data.imported {
self.mac_defs.insert(data.callee_span);
self.fmt.macro_str(data.callee_span, data.callee_span,
data.name.clone(), qualname.clone());
}
if !self.mac_uses.contains(&data.span) {
self.mac_uses.insert(data.span);
self.fmt.macro_use_str(data.span, data.span, data.name,
qualname, data.scope);
}
}
}

impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
fn visit_item(&mut self, item: &ast::Item) {
self.process_macro_use(item.span, item.id);
match item.node {
ast::ItemUse(ref use_item) => {
match use_item.node {
Expand Down Expand Up @@ -970,6 +1013,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
}

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

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

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

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

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

fn visit_pat(&mut self, p: &ast::Pat) {
self.process_macro_use(p.span, p.id);
self.process_pat(p);
}

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

fn visit_stmt(&mut self, s: &ast::Stmt) {
let id = s.node.id();
self.process_macro_use(s.span, id.unwrap());
visit::walk_stmt(self, s)
}

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

Expand Down
63 changes: 63 additions & 0 deletions src/librustc_trans/save/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ pub enum Data {
FunctionCallData(FunctionCallData),
/// Data about a method call.
MethodCallData(MethodCallData),
/// Data about a macro use.
MacroUseData(MacroUseData),
}

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

/// Data about a macro use.
#[derive(Debug)]
pub struct MacroUseData {
pub span: Span,
pub name: String,
// Because macro expansion happens before ref-ids are determined,
// we use the callee span to reference the associated macro definition.
pub callee_span: Span,
pub scope: NodeId,
pub imported: bool,
}

macro_rules! option_try(
($e:expr) => (match $e { Some(e) => e, None => return None })
);



impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
Expand Down Expand Up @@ -652,6 +670,51 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
})
}

/// Attempt to return MacroUseData for any AST node.
///
/// For a given piece of AST defined by the supplied Span and NodeId,
/// returns None if the node is not macro-generated or the span is malformed,
/// else uses the expansion callsite and callee to return some MacroUseData.
pub fn get_macro_use_data(&self, span: Span, id: NodeId) -> Option<MacroUseData> {
if !generated_code(span) {
return None;
}
// Note we take care to use the source callsite/callee, to handle
// nested expansions and ensure we only generate data for source-visible
// macro uses.
let callsite = self.tcx.sess.codemap().source_callsite(span);
let callee = self.tcx.sess.codemap().source_callee(span);
let callee = option_try!(callee);
let callee_span = option_try!(callee.span);

// Ignore attribute macros, their spans are usually mangled
if let MacroAttribute(_) = callee.format {
return None;
}

// If the callee is an imported macro from an external crate, need to get
// the source span and name from the session, as their spans are localized
// when read in, and no longer correspond to the source.
if let Some(mac) = self.tcx.sess.imported_macro_spans.borrow().get(&callee_span) {
let &(ref mac_name, mac_span) = mac;
return Some(MacroUseData {
span: callsite,
name: mac_name.clone(),
callee_span: mac_span,
scope: self.enclosing_scope(id),
imported: true,
});
}

Some(MacroUseData {
span: callsite,
name: callee.name().to_string(),
callee_span: callee_span,
scope: self.enclosing_scope(id),
imported: false,
})
}

pub fn get_data_for_id(&self, _id: &NodeId) -> Data {
// FIXME
unimplemented!();
Expand Down
25 changes: 25 additions & 0 deletions src/librustc_trans/save/recorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ pub enum Row {
VarRef,
TypeRef,
FnRef,
Macro,
MacroUse,
}

impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> {
Expand Down Expand Up @@ -219,6 +221,14 @@ impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> {
vec!("refid", "refidcrate", "qualname", "scopeid"),
true,
true),
Macro => ("macro",
vec!("name", "qualname"),
true,
true),
MacroUse => ("macro_use",
vec!("callee_name", "qualname", "scopeid"),
true,
true),
}
}

Expand Down Expand Up @@ -686,4 +696,19 @@ impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> {
sub_span,
svec!(id.index.as_usize(), id.krate, "", scope_id));
}

pub fn macro_str(&mut self, span: Span, sub_span: Span, name: String, qualname: String) {
self.record_with_span(Macro, span, sub_span, svec!(name, qualname));
}

pub fn macro_use_str(&mut self,
span: Span,
sub_span: Span,
name: String,
qualname: String,
scope_id: NodeId) {
let scope_id = self.normalize_node_id(scope_id);
self.record_with_span(MacroUse, span, sub_span,
svec!(name, qualname, scope_id));
}
}
Loading