Skip to content

Commit f34e49d

Browse files
committed
With --test, make #[test] functions pub in InvocationCollector
and expand the `__test_reexports` in the correct scope.
1 parent 0613dac commit f34e49d

File tree

5 files changed

+49
-45
lines changed

5 files changed

+49
-45
lines changed

src/librustc_resolve/macros.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ impl<'a> base::Resolver for Resolver<'a> {
4343
self.session.next_node_id()
4444
}
4545

46+
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
47+
let mark = Mark::fresh();
48+
let module = self.module_map[&id];
49+
self.expansion_data.insert(mark.as_u32(), ExpansionData {
50+
module: module,
51+
def_index: module.def_id().unwrap().index,
52+
});
53+
mark
54+
}
55+
4656
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
4757
self.collect_def_ids(mark, expansion);
4858
self.current_module = self.expansion_data[&mark.as_u32()].module;

src/libsyntax/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,6 @@ fn is_cfg(attr: &ast::Attribute) -> bool {
303303
attr.check_name("cfg")
304304
}
305305

306-
fn is_test_or_bench(attr: &ast::Attribute) -> bool {
306+
pub fn is_test_or_bench(attr: &ast::Attribute) -> bool {
307307
attr.check_name("test") || attr.check_name("bench")
308308
}

src/libsyntax/ext/base.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,7 @@ pub type NamedSyntaxExtension = (Name, SyntaxExtension);
656656

657657
pub trait Resolver {
658658
fn next_node_id(&mut self) -> ast::NodeId;
659+
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
659660

660661
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
661662
fn add_macro(&mut self, scope: Mark, def: ast::MacroDef);
@@ -671,6 +672,7 @@ pub struct DummyResolver;
671672

672673
impl Resolver for DummyResolver {
673674
fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID }
675+
fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
674676

675677
fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
676678
fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef) {}

src/libsyntax/ext/expand.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use ext::placeholders::{placeholder, PlaceholderExpander};
1616
use attr::{self, HasAttrs};
1717
use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
1818
use syntax_pos::{self, Span, ExpnId};
19-
use config::StripUnconfigured;
19+
use config::{is_test_or_bench, StripUnconfigured};
2020
use ext::base::*;
2121
use feature_gate::{self, Features};
2222
use fold;
@@ -612,7 +612,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
612612
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
613613
let item = configure!(self, item);
614614

615-
let (item, attr) = self.classify_item(item);
615+
let (mut item, attr) = self.classify_item(item);
616616
if let Some(attr) = attr {
617617
let item = Annotatable::Item(fully_configure!(self, item, noop_fold_item));
618618
return self.collect_attr(attr, item, ExpansionKind::Items).make_items();
@@ -669,6 +669,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
669669
self.cx.current_expansion.module = orig_module;
670670
return result;
671671
}
672+
// Ensure that test functions are accessible from the test harness.
673+
ast::ItemKind::Fn(..) if self.cx.ecfg.should_test => {
674+
if item.attrs.iter().any(|attr| is_test_or_bench(attr)) {
675+
item = item.map(|mut item| { item.vis = ast::Visibility::Public; item });
676+
}
677+
noop_fold_item(item, self)
678+
}
672679
_ => noop_fold_item(item, self),
673680
}
674681
}

src/libsyntax/test.rs

Lines changed: 27 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
119119
}
120120
debug!("current path: {}", path_name_i(&self.cx.path));
121121

122-
let i = if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) {
122+
if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) {
123123
match i.node {
124124
ast::ItemKind::Fn(_, ast::Unsafety::Unsafe, _, _, _, _) => {
125125
let diag = self.cx.span_diagnostic;
@@ -136,54 +136,37 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
136136
};
137137
self.cx.testfns.push(test);
138138
self.tests.push(i.ident);
139-
// debug!("have {} test/bench functions",
140-
// cx.testfns.len());
141-
142-
// Make all tests public so we can call them from outside
143-
// the module (note that the tests are re-exported and must
144-
// be made public themselves to avoid privacy errors).
145-
i.map(|mut i| {
146-
i.vis = ast::Visibility::Public;
147-
i
148-
})
149139
}
150140
}
151-
} else {
152-
i
153-
};
141+
}
154142

143+
let mut item = i.unwrap();
155144
// We don't want to recurse into anything other than mods, since
156145
// mods or tests inside of functions will break things
157-
let res = match i.node {
158-
ast::ItemKind::Mod(..) => fold::noop_fold_item(i, self),
159-
_ => SmallVector::one(i),
160-
};
146+
if let ast::ItemKind::Mod(module) = item.node {
147+
let tests = mem::replace(&mut self.tests, Vec::new());
148+
let tested_submods = mem::replace(&mut self.tested_submods, Vec::new());
149+
let mut mod_folded = fold::noop_fold_mod(module, self);
150+
let tests = mem::replace(&mut self.tests, tests);
151+
let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
152+
153+
if !tests.is_empty() || !tested_submods.is_empty() {
154+
let (it, sym) = mk_reexport_mod(&mut self.cx, item.id, tests, tested_submods);
155+
mod_folded.items.push(it);
156+
157+
if !self.cx.path.is_empty() {
158+
self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
159+
} else {
160+
debug!("pushing nothing, sym: {:?}", sym);
161+
self.cx.toplevel_reexport = Some(sym);
162+
}
163+
}
164+
item.node = ast::ItemKind::Mod(mod_folded);
165+
}
161166
if ident.name != keywords::Invalid.name() {
162167
self.cx.path.pop();
163168
}
164-
res
165-
}
166-
167-
fn fold_mod(&mut self, m: ast::Mod) -> ast::Mod {
168-
let tests = mem::replace(&mut self.tests, Vec::new());
169-
let tested_submods = mem::replace(&mut self.tested_submods, Vec::new());
170-
let mut mod_folded = fold::noop_fold_mod(m, self);
171-
let tests = mem::replace(&mut self.tests, tests);
172-
let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
173-
174-
if !tests.is_empty() || !tested_submods.is_empty() {
175-
let (it, sym) = mk_reexport_mod(&mut self.cx, tests, tested_submods);
176-
mod_folded.items.push(it);
177-
178-
if !self.cx.path.is_empty() {
179-
self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
180-
} else {
181-
debug!("pushing nothing, sym: {:?}", sym);
182-
self.cx.toplevel_reexport = Some(sym);
183-
}
184-
}
185-
186-
mod_folded
169+
SmallVector::one(P(item))
187170
}
188171

189172
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
@@ -239,7 +222,7 @@ impl fold::Folder for EntryPointCleaner {
239222
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { mac }
240223
}
241224

242-
fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
225+
fn mk_reexport_mod(cx: &mut TestCtxt, parent: ast::NodeId, tests: Vec<ast::Ident>,
243226
tested_submods: Vec<(ast::Ident, ast::Ident)>) -> (P<ast::Item>, ast::Ident) {
244227
let super_ = token::str_to_ident("super");
245228

@@ -257,6 +240,8 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec<ast::Ident>,
257240
};
258241

259242
let sym = token::gensym_ident("__test_reexports");
243+
let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent };
244+
cx.ext_cx.current_expansion.mark = cx.ext_cx.resolver.get_module_scope(parent);
260245
let it = cx.ext_cx.monotonic_expander().fold_item(P(ast::Item {
261246
ident: sym.clone(),
262247
attrs: Vec::new(),

0 commit comments

Comments
 (0)