提交 f34e49dd 编写于 作者: J Jeffrey Seyfried

With `--test`, make `#[test]` functions `pub` in `InvocationCollector`

and expand the `__test_reexports` in the correct scope.
上级 0613dac0
......@@ -43,6 +43,16 @@ fn next_node_id(&mut self) -> ast::NodeId {
self.session.next_node_id()
}
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
let mark = Mark::fresh();
let module = self.module_map[&id];
self.expansion_data.insert(mark.as_u32(), ExpansionData {
module: module,
def_index: module.def_id().unwrap().index,
});
mark
}
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
self.collect_def_ids(mark, expansion);
self.current_module = self.expansion_data[&mark.as_u32()].module;
......
......@@ -303,6 +303,6 @@ fn is_cfg(attr: &ast::Attribute) -> bool {
attr.check_name("cfg")
}
fn is_test_or_bench(attr: &ast::Attribute) -> bool {
pub fn is_test_or_bench(attr: &ast::Attribute) -> bool {
attr.check_name("test") || attr.check_name("bench")
}
......@@ -656,6 +656,7 @@ pub enum SyntaxExtension {
pub trait Resolver {
fn next_node_id(&mut self) -> ast::NodeId;
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
fn add_macro(&mut self, scope: Mark, def: ast::MacroDef);
......@@ -671,6 +672,7 @@ pub trait Resolver {
impl Resolver for DummyResolver {
fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID }
fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef) {}
......
......@@ -16,7 +16,7 @@
use attr::{self, HasAttrs};
use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
use syntax_pos::{self, Span, ExpnId};
use config::StripUnconfigured;
use config::{is_test_or_bench, StripUnconfigured};
use ext::base::*;
use feature_gate::{self, Features};
use fold;
......@@ -612,7 +612,7 @@ fn fold_block(&mut self, block: P<Block>) -> P<Block> {
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
let item = configure!(self, item);
let (item, attr) = self.classify_item(item);
let (mut item, attr) = self.classify_item(item);
if let Some(attr) = attr {
let item = Annotatable::Item(fully_configure!(self, item, noop_fold_item));
return self.collect_attr(attr, item, ExpansionKind::Items).make_items();
......@@ -669,6 +669,13 @@ fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
self.cx.current_expansion.module = orig_module;
return result;
}
// Ensure that test functions are accessible from the test harness.
ast::ItemKind::Fn(..) if self.cx.ecfg.should_test => {
if item.attrs.iter().any(|attr| is_test_or_bench(attr)) {
item = item.map(|mut item| { item.vis = ast::Visibility::Public; item });
}
noop_fold_item(item, self)
}
_ => noop_fold_item(item, self),
}
}
......
......@@ -119,7 +119,7 @@ fn fold_item(&mut self, i: P<ast::Item>) -> SmallVector<P<ast::Item>> {
}
debug!("current path: {}", path_name_i(&self.cx.path));
let i = if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) {
if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) {
match i.node {
ast::ItemKind::Fn(_, ast::Unsafety::Unsafe, _, _, _, _) => {
let diag = self.cx.span_diagnostic;
......@@ -136,54 +136,37 @@ fn fold_item(&mut self, i: P<ast::Item>) -> SmallVector<P<ast::Item>> {
};
self.cx.testfns.push(test);
self.tests.push(i.ident);
// debug!("have {} test/bench functions",
// cx.testfns.len());
// Make all tests public so we can call them from outside
// the module (note that the tests are re-exported and must
// be made public themselves to avoid privacy errors).
i.map(|mut i| {
i.vis = ast::Visibility::Public;
i
})
}
}
} else {
i
};
}
let mut item = i.unwrap();
// We don't want to recurse into anything other than mods, since
// mods or tests inside of functions will break things
let res = match i.node {
ast::ItemKind::Mod(..) => fold::noop_fold_item(i, self),
_ => SmallVector::one(i),
};
if let ast::ItemKind::Mod(module) = item.node {
let tests = mem::replace(&mut self.tests, Vec::new());
let tested_submods = mem::replace(&mut self.tested_submods, Vec::new());
let mut mod_folded = fold::noop_fold_mod(module, self);
let tests = mem::replace(&mut self.tests, tests);
let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
if !tests.is_empty() || !tested_submods.is_empty() {
let (it, sym) = mk_reexport_mod(&mut self.cx, item.id, tests, tested_submods);
mod_folded.items.push(it);
if !self.cx.path.is_empty() {
self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
} else {
debug!("pushing nothing, sym: {:?}", sym);
self.cx.toplevel_reexport = Some(sym);
}
}
item.node = ast::ItemKind::Mod(mod_folded);
}
if ident.name != keywords::Invalid.name() {
self.cx.path.pop();
}
res
}
fn fold_mod(&mut self, m: ast::Mod) -> ast::Mod {
let tests = mem::replace(&mut self.tests, Vec::new());
let tested_submods = mem::replace(&mut self.tested_submods, Vec::new());
let mut mod_folded = fold::noop_fold_mod(m, self);
let tests = mem::replace(&mut self.tests, tests);
let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
if !tests.is_empty() || !tested_submods.is_empty() {
let (it, sym) = mk_reexport_mod(&mut self.cx, tests, tested_submods);
mod_folded.items.push(it);
if !self.cx.path.is_empty() {
self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
} else {
debug!("pushing nothing, sym: {:?}", sym);
self.cx.toplevel_reexport = Some(sym);
}
}
mod_folded
SmallVector::one(P(item))
}
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
......@@ -239,7 +222,7 @@ fn fold_item(&mut self, i: P<ast::Item>) -> SmallVector<P<ast::Item>> {
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
}
fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
fn mk_reexport_mod(cx: &mut TestCtxt, parent: ast::NodeId, tests: Vec<ast::Ident>,
tested_submods: Vec<(ast::Ident, ast::Ident)>) -> (P<ast::Item>, ast::Ident) {
let super_ = token::str_to_ident("super");
......@@ -257,6 +240,8 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
};
let sym = token::gensym_ident("__test_reexports");
let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent };
cx.ext_cx.current_expansion.mark = cx.ext_cx.resolver.get_module_scope(parent);
let it = cx.ext_cx.monotonic_expander().fold_item(P(ast::Item {
ident: sym.clone(),
attrs: Vec::new(),
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册