diff --git a/src/doc/book/documentation.md b/src/doc/book/documentation.md index 8d1e58ac17397..42cf07aa9c042 100644 --- a/src/doc/book/documentation.md +++ b/src/doc/book/documentation.md @@ -241,17 +241,16 @@ Here's the full algorithm rustdoc uses to preprocess examples: `unused_variables`, `unused_assignments`, `unused_mut`, `unused_attributes`, and `dead_code`. Small examples often trigger these lints. -3. If the example does not contain `extern crate`, then `extern crate - ;` is inserted (note the lack of `#[macro_use]`). +3. If the example does not contain `extern crate`, then `#[macro_use] + extern crate ;` is inserted if the example is either for + a macro definition, or contains the crate name. 4. Finally, if the example does not contain `fn main`, the remainder of the text is wrapped in `fn main() { your_code }`. This generated `fn main` can be a problem! If you have `extern crate` or a `mod` statements in the example code that are referred to by `use` statements, they will fail to resolve unless you include at least `fn main() {}` to inhibit step 4. -`#[macro_use] extern crate` also does not work except at the crate root, so when -testing macros an explicit `main` is always required. It doesn't have to clutter -up your docs, though -- keep reading! +These additions don't have to clutter up your docs, though -- keep reading! Sometimes this algorithm isn't enough, though. For example, all of these code samples with `///` we've been talking about? The raw text: @@ -356,17 +355,11 @@ Here’s an example of documenting a macro: /// # Examples /// /// ``` -/// # #[macro_use] extern crate foo; -/// # fn main() { /// panic_unless!(1 + 1 == 2, “Math is broken.”); -/// # } /// ``` /// /// ```should_panic -/// # #[macro_use] extern crate foo; -/// # fn main() { /// panic_unless!(true == false, “I’m broken.”); -/// # } /// ``` #[macro_export] macro_rules! panic_unless { @@ -375,11 +368,6 @@ macro_rules! panic_unless { # fn main() {} ``` -You’ll note three things: we need to add our own `extern crate` line, so that -we can add the `#[macro_use]` attribute. Second, we’ll need to add our own -`main()` as well (for reasons discussed above). Finally, a judicious use of -`#` to comment out those two things, so they don’t show up in the output. - Another case where the use of `#` is handy is when you want to ignore error handling. Lets say you want the following, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 3baf22b38ef68..f31273328c769 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -258,7 +258,7 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { stripped_filtered_line(l).unwrap_or(l) }).collect::>().join("\n"); let krate = krate.as_ref().map(|s| &**s); - let test = test::maketest(&test, krate, false, + let test = test::maketest(&test, krate, false, false, &Default::default()); s.push_str(&format!("{}", Escape(&test))); }); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 81fd1128afac8..d35a64410e03c 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -175,12 +175,12 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { } fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, - externs: core::Externs, + externs: core::Externs, for_macro: bool, should_panic: bool, no_run: bool, as_test_harness: bool, compile_fail: bool, opts: &TestOptions) { // the test harness wants its own `main` & top level functions, so // never wrap the test in `fn main() { ... }` - let test = maketest(test, Some(cratename), as_test_harness, opts); + let test = maketest(test, Some(cratename), for_macro, as_test_harness, opts); let input = config::Input::Str { name: driver::anon_src(), input: test.to_owned(), @@ -312,7 +312,7 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec, libs: SearchPaths, } } -pub fn maketest(s: &str, cratename: Option<&str>, dont_insert_main: bool, +pub fn maketest(s: &str, cratename: Option<&str>, for_macro: bool, dont_insert_main: bool, opts: &TestOptions) -> String { let (crate_attrs, everything_else) = partition_source(s); @@ -331,8 +331,8 @@ pub fn maketest(s: &str, cratename: Option<&str>, dont_insert_main: bool, // compiler. if !s.contains("extern crate") && !opts.no_crate_inject && cratename != Some("std") { if let Some(cratename) = cratename { - if s.contains(cratename) { - prog.push_str(&format!("extern crate {};\n", cratename)); + if for_macro || s.contains(cratename) { + prog.push_str(&format!("#[macro_use] extern crate {};\n", cratename)); } } } @@ -381,6 +381,7 @@ pub struct Collector { libs: SearchPaths, externs: core::Externs, cnt: usize, + for_macro: bool, use_headers: bool, current_header: Option, cratename: String, @@ -397,6 +398,7 @@ impl Collector { libs: libs, externs: externs, cnt: 0, + for_macro: false, use_headers: use_headers, current_header: None, cratename: cratename, @@ -419,6 +421,7 @@ impl Collector { let externs = self.externs.clone(); let cratename = self.cratename.to_string(); let opts = self.opts.clone(); + let for_macro = self.for_macro; debug!("Creating test {}: {}", name, test); self.tests.push(testing::TestDescAndFn { desc: testing::TestDesc { @@ -433,6 +436,7 @@ impl Collector { cfgs, libs, externs, + for_macro, should_panic, no_run, as_test_harness, @@ -472,6 +476,10 @@ impl DocFolder for Collector { let pushed = current_name.map(|name| self.names.push(name)).is_some(); if let Some(doc) = item.doc_value() { + self.for_macro = match item.inner { + clean::MacroItem(_) => true, + _ => false, + }; self.cnt = 0; markdown::find_testable_code(doc, &mut *self); } diff --git a/src/test/run-make/issue-22131/Makefile b/src/test/run-make/rustdoc-doctests/Makefile similarity index 73% rename from src/test/run-make/issue-22131/Makefile rename to src/test/run-make/rustdoc-doctests/Makefile index 1e8568626a6a1..f74b871521aff 100644 --- a/src/test/run-make/issue-22131/Makefile +++ b/src/test/run-make/rustdoc-doctests/Makefile @@ -3,5 +3,4 @@ all: foo.rs $(RUSTC) --cfg 'feature="bar"' --crate-type lib foo.rs $(HOST_RPATH_ENV) '$(RUSTDOC)' --test --cfg 'feature="bar"' \ - -L $(TMPDIR) foo.rs |\ - grep -q 'test foo_0 ... ok' + -L $(TMPDIR) foo.rs diff --git a/src/test/run-make/issue-22131/foo.rs b/src/test/run-make/rustdoc-doctests/foo.rs similarity index 75% rename from src/test/run-make/issue-22131/foo.rs rename to src/test/run-make/rustdoc-doctests/foo.rs index 50c63abc0d4e5..950a305862aa1 100644 --- a/src/test/run-make/issue-22131/foo.rs +++ b/src/test/run-make/rustdoc-doctests/foo.rs @@ -13,3 +13,18 @@ /// ``` #[cfg(feature = "bar")] pub fn foo() -> i32 { 1 } + +/// ``` +/// assert_eq!(mymacro!(), 5); +/// ``` +#[macro_export] +macro_rules! mymacro { + () => { 5 }; +} + +/// ``` +/// assert_eq!(foo::foo2(), 5); +/// ``` +pub fn foo2() -> i32 { + 5 +}