Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5e1cbfa
remove const-fn-feature-flags test
sasurau4 Nov 26, 2020
d4ee2f6
Move const ip in ui test to unit test
sasurau4 Nov 26, 2020
f17e648
lint-docs: Move free functions into methods of LintExtractor.
ehuss Nov 28, 2020
d2d91b4
lint-docs: Add --validate flag to validate lint docs separately.
ehuss Nov 28, 2020
ddfb581
Move `src/test/rustdoc` intra-doc link tests into a subdirectory
jyn514 Nov 29, 2020
872acb0
Move `src/test/rustdoc-ui` intra-doc tests into a subdirectory
jyn514 Nov 29, 2020
228510b
lint-docs: Add some extra detail to the error message.
ehuss Nov 28, 2020
a90fdfc
lint-docs: Use strip-prefix to simplify.
ehuss Nov 29, 2020
95a6427
Add -Z normalize-docs and enable it for compiler docs
jyn514 Nov 29, 2020
be554c4
Make ui test that are run-pass and do not test the compiler itself li…
CDirkx Nov 22, 2020
ccbb0f5
Add support for stable-const-since in docs on items (standalone or as…
CraftSpider Nov 30, 2020
4eb64c8
update Miri
RalfJung Nov 30, 2020
1c367c0
Update with status for various NetBSD ports.
he32 Nov 30, 2020
36e6aa0
Stop adding '*' at the end of type names for Ref and Slice when compu…
nanguye Nov 18, 2020
9ba8d6e
Update books
ehuss Dec 1, 2020
b565fe2
Rollup merge of #79038 - CDirkx:move-ui-tests, r=dtolnay
m-ou-se Dec 1, 2020
08b1717
Rollup merge of #79184 - nanguye2496:nanguye2496/fix_slice_and_str_ty…
m-ou-se Dec 1, 2020
bf3f4c8
Rollup merge of #79227 - sasurau4:test/move-cell-test-to-lib-core, r=…
m-ou-se Dec 1, 2020
2404409
Rollup merge of #79444 - sasurau4:test/move-const-ip, r=matklad
m-ou-se Dec 1, 2020
36ce8db
Rollup merge of #79522 - ehuss:lint-check-validate, r=Mark-Simulacrum
m-ou-se Dec 1, 2020
99e075f
Rollup merge of #79525 - jyn514:feature-gate-normalize, r=GuillaumeGomez
m-ou-se Dec 1, 2020
f45e695
Rollup merge of #79527 - jyn514:intra-doc-tests, r=Manishearth
m-ou-se Dec 1, 2020
33d7b8c
Rollup merge of #79548 - CraftSpider:76998, r=jyn514
m-ou-se Dec 1, 2020
1bc1a18
Rollup merge of #79568 - RalfJung:miri, r=RalfJung
m-ou-se Dec 1, 2020
2891f3f
Rollup merge of #79573 - he32:master, r=jonas-schievink
m-ou-se Dec 1, 2020
c06a00e
Rollup merge of #79583 - ehuss:update-books, r=ehuss
m-ou-se Dec 1, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions compiler/rustc_lint_defs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => (
Expand Down
1 change: 1 addition & 0 deletions src/bootstrap/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ impl<'a> Builder<'a> {
test::TheBook,
test::UnstableBook,
test::RustcBook,
test::LintDocs,
test::RustcGuide,
test::EmbeddedBook,
test::EditionGuide,
Expand Down
5 changes: 5 additions & 0 deletions src/bootstrap/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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,
});
}

Expand Down Expand Up @@ -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.
Expand Down
33 changes: 33 additions & 0 deletions src/bootstrap/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
}
}
203 changes: 113 additions & 90 deletions src/tools/lint-docs/src/groups.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::Lint;
use crate::{Lint, LintExtractor};
use std::collections::{BTreeMap, BTreeSet};
use std::error::Error;
use std::fmt::Write;
use std::fs;
use std::path::Path;
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"),
Expand All @@ -15,100 +15,123 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"),
];

/// Updates the documentation of lint groups.
pub(crate) fn generate_group_docs(
lints: &[Lint],
rustc: crate::Rustc<'_>,
out_path: &Path,
) -> Result<(), Box<dyn Error>> {
let groups = collect_groups(rustc)?;
let groups_path = out_path.join("groups.md");
let contents = fs::read_to_string(&groups_path)
.map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?;
let new_contents = contents.replace("{{groups-table}}", &make_groups_table(lints, &groups)?);
// Delete the output because rustbuild uses hard links in its copies.
let _ = fs::remove_file(&groups_path);
fs::write(&groups_path, new_contents)
.map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?;
Ok(())
}

type LintGroups = BTreeMap<String, BTreeSet<String>>;

/// Collects the group names from rustc.
fn collect_groups(rustc: crate::Rustc<'_>) -> Result<LintGroups, Box<dyn Error>> {
let mut result = BTreeMap::new();
let mut cmd = Command::new(rustc.path);
cmd.arg("-Whelp");
let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
if !output.status.success() {
return Err(format!(
"failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n",
output.status,
std::str::from_utf8(&output.stderr).unwrap(),
std::str::from_utf8(&output.stdout).unwrap(),
)
.into());
impl<'a> LintExtractor<'a> {
/// Updates the documentation of lint groups.
pub(crate) fn generate_group_docs(&self, lints: &[Lint]) -> Result<(), Box<dyn Error>> {
let groups = self.collect_groups()?;
let groups_path = self.out_path.join("groups.md");
let contents = fs::read_to_string(&groups_path)
.map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?;
let new_contents =
contents.replace("{{groups-table}}", &self.make_groups_table(lints, &groups)?);
// Delete the output because rustbuild uses hard links in its copies.
let _ = fs::remove_file(&groups_path);
fs::write(&groups_path, new_contents)
.map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?;
Ok(())
}
let stdout = std::str::from_utf8(&output.stdout).unwrap();
let lines = stdout.lines();
let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1);
let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1);
for line in table_start {
if line.is_empty() {
break;

/// Collects the group names from rustc.
fn collect_groups(&self) -> Result<LintGroups, Box<dyn Error>> {
let mut result = BTreeMap::new();
let mut cmd = Command::new(self.rustc_path);
cmd.arg("-Whelp");
let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
if !output.status.success() {
return Err(format!(
"failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n",
output.status,
std::str::from_utf8(&output.stderr).unwrap(),
std::str::from_utf8(&output.stdout).unwrap(),
)
.into());
}
let mut parts = line.trim().splitn(2, ' ');
let name = parts.next().expect("name in group");
if name == "warnings" {
// This is special.
continue;
let stdout = std::str::from_utf8(&output.stdout).unwrap();
let lines = stdout.lines();
let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1);
let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1);
for line in table_start {
if line.is_empty() {
break;
}
let mut parts = line.trim().splitn(2, ' ');
let name = parts.next().expect("name in group");
if name == "warnings" {
// This is special.
continue;
}
let lints = parts
.next()
.ok_or_else(|| format!("expected lints following name, got `{}`", line))?;
let lints = lints.split(',').map(|l| l.trim().to_string()).collect();
assert!(result.insert(name.to_string(), lints).is_none());
}
let lints =
parts.next().ok_or_else(|| format!("expected lints following name, got `{}`", line))?;
let lints = lints.split(',').map(|l| l.trim().to_string()).collect();
assert!(result.insert(name.to_string(), lints).is_none());
}
if result.is_empty() {
return Err(
format!("expected at least one group in -Whelp output, got:\n{}", stdout).into()
);
if result.is_empty() {
return Err(
format!("expected at least one group in -Whelp output, got:\n{}", stdout).into()
);
}
Ok(result)
}
Ok(result)
}

fn make_groups_table(lints: &[Lint], groups: &LintGroups) -> Result<String, Box<dyn Error>> {
let mut result = String::new();
let mut to_link = Vec::new();
result.push_str("| Group | Description | Lints |\n");
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!("lint group `{}` does not have a description, please update the GROUP_DESCRIPTIONS list", group_name))?
.1;
to_link.extend(group_lints);
let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect();
write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", ")).unwrap();
}
result.push('\n');
result.push_str("[warn-by-default]: listing/warn-by-default.md\n");
for lint_name in to_link {
let lint_def =
lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| {
format!(
"`rustc -W help` defined lint `{}` but that lint does not appear to exist",
lint_name
)
})?;
write!(
result,
"[{}]: listing/{}#{}\n",
lint_name,
lint_def.level.doc_filename(),
lint_name
)
.unwrap();
fn make_groups_table(
&self,
lints: &[Lint],
groups: &LintGroups,
) -> Result<String, Box<dyn Error>> {
let mut result = String::new();
let mut to_link = Vec::new();
result.push_str("| Group | Description | Lints |\n");
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 = 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 in \
src/tools/lint-docs/src/groups.rs",
group_name
)
.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(", "))
.unwrap();
}
result.push('\n');
result.push_str("[warn-by-default]: listing/warn-by-default.md\n");
for lint_name in to_link {
let lint_def =
lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| {
format!(
"`rustc -W help` defined lint `{}` but that lint does not appear to exist",
lint_name
)
})?;
write!(
result,
"[{}]: listing/{}#{}\n",
lint_name,
lint_def.level.doc_filename(),
lint_name
)
.unwrap();
}
Ok(result)
}
Ok(result)
}
Loading