Rollup merge of #99142 - notriddle:notriddle/doctest-multiline-crate-attributes, r=GuillaumeGomez

fix(doctest): treat fatal parse errors as incomplete attributes

Fixes #99089
This commit is contained in:
Matthias Krüger 2022-07-11 22:39:07 +02:00 committed by GitHub
commit 24d241a884
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 23 deletions

View File

@ -726,31 +726,58 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool {
// Empty content so nothing to check in here...
return true;
}
rustc_span::create_session_if_not_set_then(edition, |_| {
let filename = FileName::anon_source_code(source);
let sess = ParseSess::with_silent_emitter(None);
let mut parser = match maybe_new_parser_from_source_str(&sess, filename, source.to_owned())
{
Ok(p) => p,
Err(_) => {
debug!("Cannot build a parser to check mod attr so skipping...");
return true;
rustc_driver::catch_fatal_errors(|| {
rustc_span::create_session_if_not_set_then(edition, |_| {
use rustc_errors::emitter::EmitterWriter;
use rustc_errors::Handler;
use rustc_span::source_map::FilePathMapping;
let filename = FileName::anon_source_code(source);
// Any errors in parsing should also appear when the doctest is compiled for real, so just
// send all the errors that librustc_ast emits directly into a `Sink` instead of stderr.
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
let fallback_bundle =
rustc_errors::fallback_fluent_bundle(rustc_errors::DEFAULT_LOCALE_RESOURCES, false);
let emitter = EmitterWriter::new(
box io::sink(),
None,
None,
fallback_bundle,
false,
false,
false,
None,
false,
);
let handler = Handler::with_emitter(false, None, box emitter);
let sess = ParseSess::with_span_handler(handler, sm);
let mut parser =
match maybe_new_parser_from_source_str(&sess, filename, source.to_owned()) {
Ok(p) => p,
Err(_) => {
debug!("Cannot build a parser to check mod attr so skipping...");
return true;
}
};
// If a parsing error happened, it's very likely that the attribute is incomplete.
if let Err(e) = parser.parse_attribute(InnerAttrPolicy::Permitted) {
e.cancel();
return false;
}
};
// If a parsing error happened, it's very likely that the attribute is incomplete.
if parser.parse_attribute(InnerAttrPolicy::Permitted).is_err() {
return false;
}
// We now check if there is an unclosed delimiter for the attribute. To do so, we look at
// the `unclosed_delims` and see if the opening square bracket was closed.
parser
.unclosed_delims()
.get(0)
.map(|unclosed| {
unclosed.unclosed_span.map(|s| s.lo()).unwrap_or(BytePos(0)) != BytePos(2)
})
.unwrap_or(true)
// We now check if there is an unclosed delimiter for the attribute. To do so, we look at
// the `unclosed_delims` and see if the opening square bracket was closed.
parser
.unclosed_delims()
.get(0)
.map(|unclosed| {
unclosed.unclosed_span.map(|s| s.lo()).unwrap_or(BytePos(0)) != BytePos(2)
})
.unwrap_or(true)
})
})
.unwrap_or(false)
}
fn partition_source(s: &str, edition: Edition) -> (String, String, String) {

View File

@ -0,0 +1,10 @@
// compile-flags:--test --test-args=--test-threads=1
// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
// check-pass
/// ```
/// #![deprecated(since = "5.2", note = "foo was rarely used. \
/// Users should instead use bar")]
/// ```
pub fn f() {}

View File

@ -0,0 +1,6 @@
running 1 test
test $DIR/doctest-multiline-crate-attribute.rs - f (line 6) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME