Rollup merge of #48106 - QuietMisdreavus:teleporting-crates, r=GuillaumeGomez

rustdoc: move manual "extern crate" statements outside automatic "fn main"s in doctests

Gated on https://github.com/rust-lang/rust/pull/48095 - I based the branch atop that so i could show off the change in one of its tests, the actual change in this PR is just the last commit

There are a handful of unfortunate assumptions in the way rustdoc processes `extern crate` statements in doctests:

1. In the absence of an `extern crate` statement in the test, if the test also uses the local crate name, it will automatically insert an `extern crate cratename;` statement into the test.
2. If the doctest *does* include an `extern crate` statement, rustdoc will not automatically insert one, on the assumption that doing so would introduce a duplicate import.
3. If a doctest does not have the substring `fn main` outside a comment, rustdoc will wrap the whole doctest in a generated `fn main` so it can be compiled.

In short, whenever you write a doctest like this...

```rust
//! extern crate my_crate;
//! my_crate::some_cool_thing();
```

...rustdoc will turn it into (something like) this:

```rust
fn main() {
extern crate my_crate;
my_crate::some_cool_thing();
}
```

This creates issues when compiled, because now `my_crate` isn't even properly in scope! This forces people who want to have multiple crates in their doctests (or an explicit `extern crate` statement) to also manually include their own `fn main`, so rustdoc doesn't put their imports in the wrong place.

This PR just taps into another processing step rustdoc does to doctests: Whenever you add an `#![inner_attribute]` to the beginning of a doctest, rustdoc will actually splice those out and put it before the generated `fn main`. Now, we can just do the same with `extern crate`s at the beginning, too, and get a much nicer experience.

Now, the above example will be converted into this:

```rust
extern crate my_crate;
fn main() {
my_crate::some_cool_thing();
}
```
This commit is contained in:
Guillaume Gomez 2018-02-21 16:29:47 +01:00 committed by GitHub
commit f0343cbd1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 5 additions and 2 deletions

View File

@ -325,6 +325,8 @@ Erroneous code example:
extern crate core; extern crate core;
struct core; struct core;
fn main() {}
``` ```
There are two possible solutions: There are two possible solutions:

View File

@ -414,7 +414,8 @@ fn partition_source(s: &str) -> (String, String) {
for line in s.lines() { for line in s.lines() {
let trimline = line.trim(); let trimline = line.trim();
let header = trimline.is_whitespace() || let header = trimline.is_whitespace() ||
trimline.starts_with("#!["); trimline.starts_with("#![") ||
trimline.starts_with("extern crate");
if !header || after_header { if !header || after_header {
after_header = true; after_header = true;
after.push_str(line); after.push_str(line);
@ -814,8 +815,8 @@ use asdf::qwop;
assert_eq!(2+2, 4);"; assert_eq!(2+2, 4);";
let expected = let expected =
"#![allow(unused)] "#![allow(unused)]
fn main() {
extern crate asdf; extern crate asdf;
fn main() {
use asdf::qwop; use asdf::qwop;
assert_eq!(2+2, 4); assert_eq!(2+2, 4);
}".to_string(); }".to_string();