mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
lint-docs: Add --validate flag to validate lint docs separately.
This commit is contained in:
parent
f17e6487b2
commit
d2d91b42a5
@ -366,11 +366,25 @@ impl LintBuffer {
|
||||
/// ```
|
||||
///
|
||||
/// The `{{produces}}` tag will be automatically replaced with the output from
|
||||
/// the example by the build system. You can build and view the rustc book
|
||||
/// with `x.py doc --stage=1 src/doc/rustc --open`. If the lint example is too
|
||||
/// complex to run as a simple example (for example, it needs an extern
|
||||
/// crate), mark it with `ignore` and manually paste the expected output below
|
||||
/// the example.
|
||||
/// the example by the build system. If the lint example is too complex to run
|
||||
/// as a simple example (for example, it needs an extern crate), mark the code
|
||||
/// block with `ignore` and manually replace the `{{produces}}` line with the
|
||||
/// expected output in a `text` code block.
|
||||
///
|
||||
/// If this is a rustdoc-only lint, then only include a brief introduction
|
||||
/// with a link with the text `[rustdoc book]` so that the validator knows
|
||||
/// that this is for rustdoc only (see BROKEN_INTRA_DOC_LINKS as an example).
|
||||
///
|
||||
/// Commands to view and test the documentation:
|
||||
///
|
||||
/// * `./x.py doc --stage=1 src/doc/rustc --open`: Builds the rustc book and opens it.
|
||||
/// * `./x.py test src/tools/lint-docs`: Validates that the lint docs have the
|
||||
/// correct style, and that the code example actually emits the expected
|
||||
/// lint.
|
||||
///
|
||||
/// If you have already built the compiler, and you want to make changes to
|
||||
/// just the doc comments, then use the `--keep-stage=0` flag with the above
|
||||
/// commands to avoid rebuilding the compiler.
|
||||
#[macro_export]
|
||||
macro_rules! declare_lint {
|
||||
($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
|
||||
|
@ -413,6 +413,7 @@ impl<'a> Builder<'a> {
|
||||
test::TheBook,
|
||||
test::UnstableBook,
|
||||
test::RustcBook,
|
||||
test::LintDocs,
|
||||
test::RustcGuide,
|
||||
test::EmbeddedBook,
|
||||
test::EditionGuide,
|
||||
|
@ -726,6 +726,7 @@ fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()>
|
||||
pub struct RustcBook {
|
||||
pub compiler: Compiler,
|
||||
pub target: TargetSelection,
|
||||
pub validate: bool,
|
||||
}
|
||||
|
||||
impl Step for RustcBook {
|
||||
@ -742,6 +743,7 @@ impl Step for RustcBook {
|
||||
run.builder.ensure(RustcBook {
|
||||
compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
|
||||
target: run.target,
|
||||
validate: false,
|
||||
});
|
||||
}
|
||||
|
||||
@ -772,6 +774,9 @@ impl Step for RustcBook {
|
||||
if builder.config.verbose() {
|
||||
cmd.arg("--verbose");
|
||||
}
|
||||
if self.validate {
|
||||
cmd.arg("--validate");
|
||||
}
|
||||
// If the lib directories are in an unusual location (changed in
|
||||
// config.toml), then this needs to explicitly update the dylib search
|
||||
// path.
|
||||
|
@ -2115,3 +2115,36 @@ impl Step for TierCheck {
|
||||
try_run(builder, &mut cargo.into());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct LintDocs {
|
||||
pub compiler: Compiler,
|
||||
pub target: TargetSelection,
|
||||
}
|
||||
|
||||
impl Step for LintDocs {
|
||||
type Output = ();
|
||||
const DEFAULT: bool = true;
|
||||
const ONLY_HOSTS: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.path("src/tools/lint-docs")
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(LintDocs {
|
||||
compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
|
||||
target: run.target,
|
||||
});
|
||||
}
|
||||
|
||||
/// Tests that the lint examples in the rustc book generate the correct
|
||||
/// lints and have the expected format.
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
builder.ensure(crate::doc::RustcBook {
|
||||
compiler: self.compiler,
|
||||
target: self.target,
|
||||
validate: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ use std::fmt::Write;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
|
||||
/// Descriptions of rustc lint groups.
|
||||
static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
|
||||
("unused", "Lints that detect things being declared but not used, or excess syntax"),
|
||||
("rustdoc", "Rustdoc-specific lints"),
|
||||
@ -86,17 +87,27 @@ impl<'a> LintExtractor<'a> {
|
||||
result.push_str("|-------|-------------|-------|\n");
|
||||
result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n");
|
||||
for (group_name, group_lints) in groups {
|
||||
let description = GROUP_DESCRIPTIONS
|
||||
.iter()
|
||||
.find(|(n, _)| n == group_name)
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
let description = match GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name) {
|
||||
Some((_, desc)) => desc,
|
||||
None if self.validate => {
|
||||
return Err(format!(
|
||||
"lint group `{}` does not have a description, \
|
||||
please update the GROUP_DESCRIPTIONS list",
|
||||
please update the GROUP_DESCRIPTIONS list in \
|
||||
src/tools/lint-docs/src/groups.rs",
|
||||
group_name
|
||||
)
|
||||
})?
|
||||
.1;
|
||||
.into());
|
||||
}
|
||||
None => {
|
||||
eprintln!(
|
||||
"warning: lint group `{}` is missing from the GROUP_DESCRIPTIONS list\n\
|
||||
If this is a new lint group, please update the GROUP_DESCRIPTIONS in \
|
||||
src/tools/lint-docs/src/groups.rs",
|
||||
group_name
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
to_link.extend(group_lints);
|
||||
let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect();
|
||||
write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", "))
|
||||
|
@ -19,6 +19,8 @@ pub struct LintExtractor<'a> {
|
||||
pub rustc_target: &'a str,
|
||||
/// Verbose output.
|
||||
pub verbose: bool,
|
||||
/// Validate the style and the code example.
|
||||
pub validate: bool,
|
||||
}
|
||||
|
||||
struct Lint {
|
||||
@ -122,7 +124,7 @@ impl<'a> LintExtractor<'a> {
|
||||
let contents = fs::read_to_string(path)
|
||||
.map_err(|e| format!("could not read {}: {}", path.display(), e))?;
|
||||
let mut lines = contents.lines().enumerate();
|
||||
loop {
|
||||
'outer: loop {
|
||||
// Find a lint declaration.
|
||||
let lint_start = loop {
|
||||
match lines.next() {
|
||||
@ -158,12 +160,22 @@ impl<'a> LintExtractor<'a> {
|
||||
)
|
||||
})?;
|
||||
if doc_lines.is_empty() {
|
||||
if self.validate {
|
||||
return Err(format!(
|
||||
"did not find doc lines for lint `{}` in {}",
|
||||
name,
|
||||
path.display()
|
||||
)
|
||||
.into());
|
||||
} else {
|
||||
eprintln!(
|
||||
"warning: lint `{}` in {} does not define any doc lines, \
|
||||
these are required for the lint documentation",
|
||||
name,
|
||||
path.display()
|
||||
);
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
break (doc_lines, name);
|
||||
}
|
||||
@ -234,13 +246,26 @@ impl<'a> LintExtractor<'a> {
|
||||
// Rustdoc lints are documented in the rustdoc book, don't check these.
|
||||
return Ok(());
|
||||
}
|
||||
if self.validate {
|
||||
lint.check_style()?;
|
||||
}
|
||||
// Unfortunately some lints have extra requirements that this simple test
|
||||
// setup can't handle (like extern crates). An alternative is to use a
|
||||
// separate test suite, and use an include mechanism such as mdbook's
|
||||
// `{{#rustdoc_include}}`.
|
||||
if !lint.is_ignored() {
|
||||
self.replace_produces(lint)?;
|
||||
if let Err(e) = self.replace_produces(lint) {
|
||||
if self.validate {
|
||||
return Err(e);
|
||||
}
|
||||
eprintln!(
|
||||
"warning: the code example in lint `{}` in {} failed to \
|
||||
generate the expected output: {}",
|
||||
lint.name,
|
||||
lint.path.display(),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
if let Err(e) = doit() {
|
||||
println!("error: {}", e);
|
||||
eprintln!("error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,7 @@ fn doit() -> Result<(), Box<dyn Error>> {
|
||||
let mut rustc_path = None;
|
||||
let mut rustc_target = None;
|
||||
let mut verbose = false;
|
||||
let mut validate = false;
|
||||
while let Some(arg) = args.next() {
|
||||
match arg.as_str() {
|
||||
"--src" => {
|
||||
@ -42,6 +43,7 @@ fn doit() -> Result<(), Box<dyn Error>> {
|
||||
};
|
||||
}
|
||||
"-v" | "--verbose" => verbose = true,
|
||||
"--validate" => validate = true,
|
||||
s => return Err(format!("unexpected argument `{}`", s).into()),
|
||||
}
|
||||
}
|
||||
@ -63,6 +65,7 @@ fn doit() -> Result<(), Box<dyn Error>> {
|
||||
rustc_path: &rustc_path.unwrap(),
|
||||
rustc_target: &rustc_target.unwrap(),
|
||||
verbose,
|
||||
validate,
|
||||
};
|
||||
le.extract_lint_docs()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user