Correctly handle line comments in attributes and generate extern crates
outside of wrapping function
This commit is contained in:
parent
6f7e8d441a
commit
123ea25542
7 changed files with 98 additions and 25 deletions
|
@ -176,9 +176,24 @@ impl DocTestBuilder {
|
||||||
|
|
||||||
// Now push any outer attributes from the example, assuming they
|
// Now push any outer attributes from the example, assuming they
|
||||||
// are intended to be crate attributes.
|
// are intended to be crate attributes.
|
||||||
prog.push_str(&self.crate_attrs);
|
if !self.crate_attrs.is_empty() {
|
||||||
prog.push_str(&self.maybe_crate_attrs);
|
prog.push_str(&self.crate_attrs);
|
||||||
prog.push_str(&self.crates);
|
if !self.crate_attrs.ends_with('\n') {
|
||||||
|
prog.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !self.maybe_crate_attrs.is_empty() {
|
||||||
|
prog.push_str(&self.maybe_crate_attrs);
|
||||||
|
if !self.maybe_crate_attrs.ends_with('\n') {
|
||||||
|
prog.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !self.crates.is_empty() {
|
||||||
|
prog.push_str(&self.crates);
|
||||||
|
if !self.crates.ends_with('\n') {
|
||||||
|
prog.push('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Don't inject `extern crate std` because it's already injected by the
|
// Don't inject `extern crate std` because it's already injected by the
|
||||||
// compiler.
|
// compiler.
|
||||||
|
@ -276,7 +291,6 @@ const DOCTEST_CODE_WRAPPER: &str = "fn f(){";
|
||||||
fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceInfo, ()> {
|
fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceInfo, ()> {
|
||||||
use rustc_errors::DiagCtxt;
|
use rustc_errors::DiagCtxt;
|
||||||
use rustc_errors::emitter::{Emitter, HumanEmitter};
|
use rustc_errors::emitter::{Emitter, HumanEmitter};
|
||||||
// use rustc_parse::parser::ForceCollect;
|
|
||||||
use rustc_span::source_map::FilePathMapping;
|
use rustc_span::source_map::FilePathMapping;
|
||||||
|
|
||||||
let mut info =
|
let mut info =
|
||||||
|
@ -338,7 +352,8 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
|
||||||
info: &mut ParseSourceInfo,
|
info: &mut ParseSourceInfo,
|
||||||
crate_name: &Option<&str>,
|
crate_name: &Option<&str>,
|
||||||
is_top_level: bool,
|
is_top_level: bool,
|
||||||
) {
|
) -> bool {
|
||||||
|
let mut is_crate = false;
|
||||||
if !info.has_global_allocator
|
if !info.has_global_allocator
|
||||||
&& item.attrs.iter().any(|attr| attr.name_or_empty() == sym::global_allocator)
|
&& item.attrs.iter().any(|attr| attr.name_or_empty() == sym::global_allocator)
|
||||||
{
|
{
|
||||||
|
@ -354,12 +369,13 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
|
||||||
if let Some(ref body) = fn_item.body {
|
if let Some(ref body) = fn_item.body {
|
||||||
for stmt in &body.stmts {
|
for stmt in &body.stmts {
|
||||||
if let StmtKind::Item(ref item) = stmt.kind {
|
if let StmtKind::Item(ref item) = stmt.kind {
|
||||||
check_item(item, info, crate_name, false)
|
is_crate |= check_item(item, info, crate_name, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ItemKind::ExternCrate(original) => {
|
ast::ItemKind::ExternCrate(original) => {
|
||||||
|
is_crate = true;
|
||||||
if !info.found_extern_crate
|
if !info.found_extern_crate
|
||||||
&& let Some(crate_name) = crate_name
|
&& let Some(crate_name) = crate_name
|
||||||
{
|
{
|
||||||
|
@ -374,6 +390,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
is_crate
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut prev_span_hi = None;
|
let mut prev_span_hi = None;
|
||||||
|
@ -412,8 +429,11 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for stmt in &body.stmts {
|
for stmt in &body.stmts {
|
||||||
|
let mut is_crate = false;
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
StmtKind::Item(ref item) => check_item(&item, &mut info, crate_name, true),
|
StmtKind::Item(ref item) => {
|
||||||
|
is_crate = check_item(&item, &mut info, crate_name, true);
|
||||||
|
}
|
||||||
StmtKind::Expr(ref expr) if matches!(expr.kind, ast::ExprKind::Err(_)) => {
|
StmtKind::Expr(ref expr) if matches!(expr.kind, ast::ExprKind::Err(_)) => {
|
||||||
cancel_error_count(&psess);
|
cancel_error_count(&psess);
|
||||||
return Err(());
|
return Err(());
|
||||||
|
@ -450,15 +470,15 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
|
||||||
if info.everything_else.is_empty()
|
if info.everything_else.is_empty()
|
||||||
&& (!info.maybe_crate_attrs.is_empty() || !info.crate_attrs.is_empty())
|
&& (!info.maybe_crate_attrs.is_empty() || !info.crate_attrs.is_empty())
|
||||||
{
|
{
|
||||||
// We add potential backlines/comments into attributes if there are some.
|
// We add potential backlines/comments if there are some in items generated
|
||||||
push_to_s(
|
// before the wrapping function.
|
||||||
&mut info.maybe_crate_attrs,
|
push_to_s(&mut info.crates, source, span.shrink_to_lo(), &mut prev_span_hi);
|
||||||
source,
|
}
|
||||||
span.shrink_to_lo(),
|
if !is_crate {
|
||||||
&mut prev_span_hi,
|
push_to_s(&mut info.everything_else, source, span, &mut prev_span_hi);
|
||||||
);
|
} else {
|
||||||
|
push_to_s(&mut info.crates, source, span, &mut prev_span_hi);
|
||||||
}
|
}
|
||||||
push_to_s(&mut info.everything_else, source, span, &mut prev_span_hi);
|
|
||||||
}
|
}
|
||||||
Ok(info)
|
Ok(info)
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,8 +127,8 @@ fn make_test_manual_extern_crate() {
|
||||||
use asdf::qwop;
|
use asdf::qwop;
|
||||||
assert_eq!(2+2, 4);";
|
assert_eq!(2+2, 4);";
|
||||||
let expected = "#![allow(unused)]
|
let expected = "#![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);
|
||||||
}"
|
}"
|
||||||
|
@ -144,8 +144,8 @@ fn make_test_manual_extern_crate_with_macro_use() {
|
||||||
use asdf::qwop;
|
use asdf::qwop;
|
||||||
assert_eq!(2+2, 4);";
|
assert_eq!(2+2, 4);";
|
||||||
let expected = "#![allow(unused)]
|
let expected = "#![allow(unused)]
|
||||||
fn main() {
|
|
||||||
#[macro_use] extern crate asdf;
|
#[macro_use] extern crate asdf;
|
||||||
|
fn main() {
|
||||||
use asdf::qwop;
|
use asdf::qwop;
|
||||||
assert_eq!(2+2, 4);
|
assert_eq!(2+2, 4);
|
||||||
}"
|
}"
|
||||||
|
@ -197,6 +197,7 @@ fn make_test_crate_attrs() {
|
||||||
assert_eq!(2+2, 4);";
|
assert_eq!(2+2, 4);";
|
||||||
let expected = "#![allow(unused)]
|
let expected = "#![allow(unused)]
|
||||||
#![feature(sick_rad)]
|
#![feature(sick_rad)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
assert_eq!(2+2, 4);
|
assert_eq!(2+2, 4);
|
||||||
}"
|
}"
|
||||||
|
@ -277,10 +278,10 @@ fn make_test_issues_33731() {
|
||||||
assert_eq!(asdf::foo, 4);";
|
assert_eq!(asdf::foo, 4);";
|
||||||
|
|
||||||
let expected = "#![allow(unused)]
|
let expected = "#![allow(unused)]
|
||||||
|
extern crate hella_qwop;
|
||||||
#[allow(unused_extern_crates)]
|
#[allow(unused_extern_crates)]
|
||||||
extern crate r#asdf;
|
extern crate r#asdf;
|
||||||
fn main() {
|
fn main() {
|
||||||
extern crate hella_qwop;
|
|
||||||
assert_eq!(asdf::foo, 4);
|
assert_eq!(asdf::foo, 4);
|
||||||
}"
|
}"
|
||||||
.to_string();
|
.to_string();
|
||||||
|
@ -401,3 +402,26 @@ fn check_split_args() {
|
||||||
compare("a\n\t \rb", &["a", "b"]);
|
compare("a\n\t \rb", &["a", "b"]);
|
||||||
compare("a\n\t1 \rb", &["a", "1", "b"]);
|
compare("a\n\t1 \rb", &["a", "1", "b"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn comment_in_attrs() {
|
||||||
|
// if input already has a fn main, it should insert a space before it
|
||||||
|
let opts = default_global_opts("");
|
||||||
|
let input = "\
|
||||||
|
#![feature(rustdoc_internals)]
|
||||||
|
#![allow(internal_features)]
|
||||||
|
#![doc(rust_logo)]
|
||||||
|
//! This crate has the Rust(tm) branding on it.";
|
||||||
|
let expected = "\
|
||||||
|
#![allow(unused)]
|
||||||
|
#![feature(rustdoc_internals)]
|
||||||
|
#![allow(internal_features)]
|
||||||
|
#![doc(rust_logo)]
|
||||||
|
//! This crate has the Rust(tm) branding on it.
|
||||||
|
fn main() {
|
||||||
|
|
||||||
|
}"
|
||||||
|
.to_string();
|
||||||
|
let (output, len) = make_test(input, None, false, &opts, None);
|
||||||
|
assert_eq!((output, len), (expected, 2));
|
||||||
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@ fn main() {
|
||||||
|
|
||||||
let should_contain = &[
|
let should_contain = &[
|
||||||
"input.rs - foo (line 5)",
|
"input.rs - foo (line 5)",
|
||||||
"input.rs:7:15",
|
"input.rs:8:15",
|
||||||
"input.rs - bar (line 13)",
|
"input.rs - bar (line 13)",
|
||||||
"input.rs:15:15",
|
"input.rs:16:15",
|
||||||
"input.rs - bar (line 22)",
|
"input.rs - bar (line 22)",
|
||||||
"input.rs:24:15",
|
"input.rs:25:15",
|
||||||
];
|
];
|
||||||
for text in should_contain {
|
for text in should_contain {
|
||||||
assert!(output.contains(text), "output doesn't contains {:?}", text);
|
assert!(output.contains(text), "output doesn't contains {:?}", text);
|
||||||
|
|
|
@ -6,7 +6,7 @@ successes:
|
||||||
|
|
||||||
---- $DIR/display-output.rs - foo (line 9) stdout ----
|
---- $DIR/display-output.rs - foo (line 9) stdout ----
|
||||||
warning: unused variable: `x`
|
warning: unused variable: `x`
|
||||||
--> $DIR/display-output.rs:11:5
|
--> $DIR/display-output.rs:12:5
|
||||||
|
|
|
|
||||||
LL | let x = 12;
|
LL | let x = 12;
|
||||||
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
||||||
|
@ -19,13 +19,13 @@ LL | #![warn(unused)]
|
||||||
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
|
= note: `#[warn(unused_variables)]` implied by `#[warn(unused)]`
|
||||||
|
|
||||||
warning: unused variable: `x`
|
warning: unused variable: `x`
|
||||||
--> $DIR/display-output.rs:13:8
|
--> $DIR/display-output.rs:14:8
|
||||||
|
|
|
|
||||||
LL | fn foo(x: &dyn std::fmt::Display) {}
|
LL | fn foo(x: &dyn std::fmt::Display) {}
|
||||||
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
||||||
|
|
||||||
warning: function `foo` is never used
|
warning: function `foo` is never used
|
||||||
--> $DIR/display-output.rs:13:4
|
--> $DIR/display-output.rs:14:4
|
||||||
|
|
|
|
||||||
LL | fn foo(x: &dyn std::fmt::Display) {}
|
LL | fn foo(x: &dyn std::fmt::Display) {}
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
23
tests/rustdoc-ui/doctest/extern-crate.rs
Normal file
23
tests/rustdoc-ui/doctest/extern-crate.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
//@ check-pass
|
||||||
|
//@ compile-flags:--test --test-args=--test-threads=1
|
||||||
|
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
|
||||||
|
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||||
|
|
||||||
|
// This test ensures that crate imports are placed outside of the `main` function
|
||||||
|
// so they work all the time (even in 2015 edition).
|
||||||
|
|
||||||
|
/// ```rust
|
||||||
|
/// #![feature(test)]
|
||||||
|
///
|
||||||
|
/// extern crate test;
|
||||||
|
/// use test::Bencher;
|
||||||
|
///
|
||||||
|
/// #[bench]
|
||||||
|
/// fn bench_xor_1000_ints(b: &mut Bencher) {
|
||||||
|
/// b.iter(|| {
|
||||||
|
/// (0..1000).fold(0, |old, new| old ^ new);
|
||||||
|
/// });
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
pub fn foo() {}
|
6
tests/rustdoc-ui/doctest/extern-crate.stdout
Normal file
6
tests/rustdoc-ui/doctest/extern-crate.stdout
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
running 1 test
|
||||||
|
test $DIR/extern-crate.rs - foo (line 9) ... ok
|
||||||
|
|
||||||
|
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||||
|
|
|
@ -24,4 +24,4 @@
|
||||||
|
|
||||||
//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' ""
|
//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' ""
|
||||||
//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' ""
|
//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' ""
|
||||||
//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' ""
|
//@ matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' ""
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue