From 5e1cbfa53ebed513b6d062f0f27187ebd3ed320c Mon Sep 17 00:00:00 2001 From: Daiki Ihara Date: Thu, 26 Nov 2020 21:13:02 +0900 Subject: [PATCH 01/18] remove const-fn-feature-flags test --- src/test/ui/consts/const-fn-feature-flags.rs | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 src/test/ui/consts/const-fn-feature-flags.rs diff --git a/src/test/ui/consts/const-fn-feature-flags.rs b/src/test/ui/consts/const-fn-feature-flags.rs deleted file mode 100644 index 30e7e102b8635..0000000000000 --- a/src/test/ui/consts/const-fn-feature-flags.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass -// Test use of stabilized const fns in std formerly using individual feature gates. - -use std::cell::Cell; - -const CELL: Cell = Cell::new(42); - -fn main() { - let v = CELL.get(); - CELL.set(v+1); - - assert_eq!(CELL.get(), v); -} From d4ee2f6dc5ba9d9e978ac052079ae3f6a5d4551b Mon Sep 17 00:00:00 2001 From: Daiki Ihara Date: Thu, 26 Nov 2020 23:15:32 +0900 Subject: [PATCH 02/18] Move const ip in ui test to unit test --- library/std/src/net/ip/tests.rs | 6 ++++++ src/test/ui/consts/std/net/ip.rs | 13 ------------- 2 files changed, 6 insertions(+), 13 deletions(-) delete mode 100644 src/test/ui/consts/std/net/ip.rs diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index d9fbdd1b5e794..44fb3adf07023 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -936,4 +936,10 @@ fn ip_const() { const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); assert!(!IS_MULTICAST); + + const IS_IP_V4: bool = IP_ADDRESS.is_ipv4(); + assert!(IS_IP_V4); + + const IS_IP_V6: bool = IP_ADDRESS.is_ipv6(); + assert!(!IS_IP_V6); } diff --git a/src/test/ui/consts/std/net/ip.rs b/src/test/ui/consts/std/net/ip.rs deleted file mode 100644 index 6730946577d51..0000000000000 --- a/src/test/ui/consts/std/net/ip.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass - -use std::net::{IpAddr, Ipv4Addr}; - -fn main() { - const IP_ADDRESS : IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST); - - const IS_IP_V4 : bool = IP_ADDRESS.is_ipv4(); - assert!(IS_IP_V4); - - const IS_IP_V6 : bool = IP_ADDRESS.is_ipv6(); - assert!(!IS_IP_V6); -} From f17e6487b2315d3cc3826fb8badeb7d4959b3ffd Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 28 Nov 2020 11:25:42 -0800 Subject: [PATCH 03/18] lint-docs: Move free functions into methods of LintExtractor. This helps avoid needing to pass so many parameters around. --- src/tools/lint-docs/src/groups.rs | 192 ++++---- src/tools/lint-docs/src/lib.rs | 732 +++++++++++++++--------------- src/tools/lint-docs/src/main.rs | 15 +- 3 files changed, 470 insertions(+), 469 deletions(-) diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 6b32ebdc284f4..db667264d2fd7 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -1,9 +1,8 @@ -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; static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ @@ -15,100 +14,113 @@ 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> { - 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>; -/// Collects the group names from rustc. -fn collect_groups(rustc: crate::Rustc<'_>) -> Result> { - 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> { + 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> { + 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> { - 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> { + 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(); + } + Ok(result) } - Ok(result) } diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 6ca71dcaf3cd0..aafd33301ea87 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -7,6 +7,20 @@ use walkdir::WalkDir; mod groups; +pub struct LintExtractor<'a> { + /// Path to the `src` directory, where it will scan for `.rs` files to + /// find lint declarations. + pub src_path: &'a Path, + /// Path where to save the output. + pub out_path: &'a Path, + /// Path to the `rustc` executable. + pub rustc_path: &'a Path, + /// The target arch to build the docs for. + pub rustc_target: &'a str, + /// Verbose output. + pub verbose: bool, +} + struct Lint { name: String, doc: Vec, @@ -26,6 +40,28 @@ impl Lint { .filter(|line| line.starts_with("```rust")) .all(|line| line.contains(",ignore")) } + + /// Checks the doc style of the lint. + fn check_style(&self) -> Result<(), Box> { + for &expected in &["### Example", "### Explanation", "{{produces}}"] { + if expected == "{{produces}}" && self.is_ignored() { + continue; + } + if !self.doc_contains(expected) { + return Err(format!("lint docs should contain the line `{}`", expected).into()); + } + } + if let Some(first) = self.doc.first() { + if !first.starts_with(&format!("The `{}` lint", self.name)) { + return Err(format!( + "lint docs should start with the text \"The `{}` lint\" to introduce the lint", + self.name + ) + .into()); + } + } + Ok(()) + } } #[derive(Clone, Copy, PartialEq)] @@ -45,382 +81,374 @@ impl Level { } } -#[derive(Copy, Clone)] -pub struct Rustc<'a> { - pub path: &'a Path, - pub target: &'a str, -} - -/// Collects all lints, and writes the markdown documentation at the given directory. -pub fn extract_lint_docs( - src_path: &Path, - out_path: &Path, - rustc: Rustc<'_>, - verbose: bool, -) -> Result<(), Box> { - let mut lints = gather_lints(src_path)?; - for lint in &mut lints { - generate_output_example(lint, rustc, verbose).map_err(|e| { - format!( - "failed to test example in lint docs for `{}` in {}:{}: {}", - lint.name, - lint.path.display(), - lint.lineno, - e - ) - })?; +impl<'a> LintExtractor<'a> { + /// Collects all lints, and writes the markdown documentation at the given directory. + pub fn extract_lint_docs(&self) -> Result<(), Box> { + let mut lints = self.gather_lints()?; + for lint in &mut lints { + self.generate_output_example(lint).map_err(|e| { + format!( + "failed to test example in lint docs for `{}` in {}:{}: {}", + lint.name, + lint.path.display(), + lint.lineno, + e + ) + })?; + } + self.save_lints_markdown(&lints)?; + self.generate_group_docs(&lints)?; + Ok(()) } - save_lints_markdown(&lints, &out_path.join("listing"))?; - groups::generate_group_docs(&lints, rustc, out_path)?; - Ok(()) -} -/// Collects all lints from all files in the given directory. -fn gather_lints(src_path: &Path) -> Result, Box> { - let mut lints = Vec::new(); - for entry in WalkDir::new(src_path).into_iter().filter_map(|e| e.ok()) { - if !entry.path().extension().map_or(false, |ext| ext == "rs") { - continue; + /// Collects all lints from all files in the given directory. + fn gather_lints(&self) -> Result, Box> { + let mut lints = Vec::new(); + for entry in WalkDir::new(self.src_path).into_iter().filter_map(|e| e.ok()) { + if !entry.path().extension().map_or(false, |ext| ext == "rs") { + continue; + } + lints.extend(self.lints_from_file(entry.path())?); } - lints.extend(lints_from_file(entry.path())?); - } - if lints.is_empty() { - return Err("no lints were found!".into()); + if lints.is_empty() { + return Err("no lints were found!".into()); + } + Ok(lints) } - Ok(lints) -} -/// Collects all lints from the given file. -fn lints_from_file(path: &Path) -> Result, Box> { - let mut lints = Vec::new(); - let contents = fs::read_to_string(path) - .map_err(|e| format!("could not read {}: {}", path.display(), e))?; - let mut lines = contents.lines().enumerate(); - loop { - // Find a lint declaration. - let lint_start = loop { - match lines.next() { - Some((lineno, line)) => { - if line.trim().starts_with("declare_lint!") { - break lineno + 1; + /// Collects all lints from the given file. + fn lints_from_file(&self, path: &Path) -> Result, Box> { + let mut lints = Vec::new(); + let contents = fs::read_to_string(path) + .map_err(|e| format!("could not read {}: {}", path.display(), e))?; + let mut lines = contents.lines().enumerate(); + loop { + // Find a lint declaration. + let lint_start = loop { + match lines.next() { + Some((lineno, line)) => { + if line.trim().starts_with("declare_lint!") { + break lineno + 1; + } + } + None => return Ok(lints), + } + }; + // Read the lint. + let mut doc_lines = Vec::new(); + let (doc, name) = loop { + match lines.next() { + Some((lineno, line)) => { + let line = line.trim(); + if line.starts_with("/// ") { + doc_lines.push(line.trim()[4..].to_string()); + } else if line.starts_with("///") { + doc_lines.push("".to_string()); + } else if line.starts_with("// ") { + // Ignore comments. + continue; + } else { + let name = lint_name(line).map_err(|e| { + format!( + "could not determine lint name in {}:{}: {}, line was `{}`", + path.display(), + lineno, + e, + line + ) + })?; + if doc_lines.is_empty() { + return Err(format!( + "did not find doc lines for lint `{}` in {}", + name, + path.display() + ) + .into()); + } + break (doc_lines, name); + } + } + None => { + return Err(format!( + "unexpected EOF for lint definition at {}:{}", + path.display(), + lint_start + ) + .into()); } } - None => return Ok(lints), + }; + // These lints are specifically undocumented. This should be reserved + // for internal rustc-lints only. + if name == "deprecated_in_future" { + continue; } - }; - // Read the lint. - let mut doc_lines = Vec::new(); - let (doc, name) = loop { - match lines.next() { - Some((lineno, line)) => { - let line = line.trim(); - if line.starts_with("/// ") { - doc_lines.push(line.trim()[4..].to_string()); - } else if line.starts_with("///") { - doc_lines.push("".to_string()); - } else if line.starts_with("// ") { - // Ignore comments. - continue; - } else { - let name = lint_name(line).map_err(|e| { - format!( - "could not determine lint name in {}:{}: {}, line was `{}`", - path.display(), - lineno, - e, - line - ) - })?; - if doc_lines.is_empty() { + // Read the level. + let level = loop { + match lines.next() { + // Ignore comments. + Some((_, line)) if line.trim().starts_with("// ") => {} + Some((lineno, line)) => match line.trim() { + "Allow," => break Level::Allow, + "Warn," => break Level::Warn, + "Deny," => break Level::Deny, + _ => { return Err(format!( - "did not find doc lines for lint `{}` in {}", - name, - path.display() + "unexpected lint level `{}` in {}:{}", + line, + path.display(), + lineno ) .into()); } - break (doc_lines, name); - } - } - None => { - return Err(format!( - "unexpected EOF for lint definition at {}:{}", - path.display(), - lint_start - ) - .into()); - } - } - }; - // These lints are specifically undocumented. This should be reserved - // for internal rustc-lints only. - if name == "deprecated_in_future" { - continue; - } - // Read the level. - let level = loop { - match lines.next() { - // Ignore comments. - Some((_, line)) if line.trim().starts_with("// ") => {} - Some((lineno, line)) => match line.trim() { - "Allow," => break Level::Allow, - "Warn," => break Level::Warn, - "Deny," => break Level::Deny, - _ => { + }, + None => { return Err(format!( - "unexpected lint level `{}` in {}:{}", - line, + "expected lint level in {}:{}, got EOF", path.display(), - lineno + lint_start ) .into()); } - }, - None => { - return Err(format!( - "expected lint level in {}:{}, got EOF", - path.display(), - lint_start - ) - .into()); } - } - }; - // The rest of the lint definition is ignored. - assert!(!doc.is_empty()); - lints.push(Lint { name, doc, level, path: PathBuf::from(path), lineno: lint_start }); - } -} - -/// Extracts the lint name (removing the visibility modifier, and checking validity). -fn lint_name(line: &str) -> Result { - // Skip over any potential `pub` visibility. - match line.trim().split(' ').next_back() { - Some(name) => { - if !name.ends_with(',') { - return Err("lint name should end with comma"); - } - let name = &name[..name.len() - 1]; - if !name.chars().all(|ch| ch.is_uppercase() || ch == '_') || name.is_empty() { - return Err("lint name did not have expected format"); - } - Ok(name.to_lowercase().to_string()) + }; + // The rest of the lint definition is ignored. + assert!(!doc.is_empty()); + lints.push(Lint { name, doc, level, path: PathBuf::from(path), lineno: lint_start }); } - None => Err("could not find lint name"), - } -} - -/// Mutates the lint definition to replace the `{{produces}}` marker with the -/// actual output from the compiler. -fn generate_output_example( - lint: &mut Lint, - rustc: Rustc<'_>, - verbose: bool, -) -> Result<(), Box> { - // Explicit list of lints that are allowed to not have an example. Please - // try to avoid adding to this list. - if matches!( - lint.name.as_str(), - "unused_features" // broken lint - | "unstable_features" // deprecated - ) { - return Ok(()); - } - if lint.doc_contains("[rustdoc book]") && !lint.doc_contains("{{produces}}") { - // Rustdoc lints are documented in the rustdoc book, don't check these. - return Ok(()); } - check_style(lint)?; - // 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() { - replace_produces(lint, rustc, verbose)?; - } - Ok(()) -} -/// Checks the doc style of the lint. -fn check_style(lint: &Lint) -> Result<(), Box> { - for &expected in &["### Example", "### Explanation", "{{produces}}"] { - if expected == "{{produces}}" && lint.is_ignored() { - continue; + /// Mutates the lint definition to replace the `{{produces}}` marker with the + /// actual output from the compiler. + fn generate_output_example(&self, lint: &mut Lint) -> Result<(), Box> { + // Explicit list of lints that are allowed to not have an example. Please + // try to avoid adding to this list. + if matches!( + lint.name.as_str(), + "unused_features" // broken lint + | "unstable_features" // deprecated + ) { + return Ok(()); } - if !lint.doc_contains(expected) { - return Err(format!("lint docs should contain the line `{}`", expected).into()); + if lint.doc_contains("[rustdoc book]") && !lint.doc_contains("{{produces}}") { + // Rustdoc lints are documented in the rustdoc book, don't check these. + return Ok(()); } - } - if let Some(first) = lint.doc.first() { - if !first.starts_with(&format!("The `{}` lint", lint.name)) { - return Err(format!( - "lint docs should start with the text \"The `{}` lint\" to introduce the lint", - lint.name - ) - .into()); + 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)?; } + Ok(()) } - Ok(()) -} -/// Mutates the lint docs to replace the `{{produces}}` marker with the actual -/// output from the compiler. -fn replace_produces( - lint: &mut Lint, - rustc: Rustc<'_>, - verbose: bool, -) -> Result<(), Box> { - let mut lines = lint.doc.iter_mut(); - loop { - // Find start of example. - let options = loop { - match lines.next() { - Some(line) if line.starts_with("```rust") => { - break line[7..].split(',').collect::>(); + /// Mutates the lint docs to replace the `{{produces}}` marker with the actual + /// output from the compiler. + fn replace_produces(&self, lint: &mut Lint) -> Result<(), Box> { + let mut lines = lint.doc.iter_mut(); + loop { + // Find start of example. + let options = loop { + match lines.next() { + Some(line) if line.starts_with("```rust") => { + break line[7..].split(',').collect::>(); + } + Some(line) if line.contains("{{produces}}") => { + return Err("lint marker {{{{produces}}}} found, \ + but expected to immediately follow a rust code block" + .into()); + } + Some(_) => {} + None => return Ok(()), } - Some(line) if line.contains("{{produces}}") => { - return Err("lint marker {{{{produces}}}} found, \ - but expected to immediately follow a rust code block" + }; + // Find the end of example. + let mut example = Vec::new(); + loop { + match lines.next() { + Some(line) if line == "```" => break, + Some(line) => example.push(line), + None => { + return Err(format!( + "did not find end of example triple ticks ```, docs were:\n{:?}", + lint.doc + ) .into()); - } - Some(_) => {} - None => return Ok(()), - } - }; - // Find the end of example. - let mut example = Vec::new(); - loop { - match lines.next() { - Some(line) if line == "```" => break, - Some(line) => example.push(line), - None => { - return Err(format!( - "did not find end of example triple ticks ```, docs were:\n{:?}", - lint.doc - ) - .into()); + } } } - } - // Find the {{produces}} line. - loop { - match lines.next() { - Some(line) if line.is_empty() => {} - Some(line) if line == "{{produces}}" => { - let output = - generate_lint_output(&lint.name, &example, &options, rustc, verbose)?; - line.replace_range( - .., - &format!( - "This will produce:\n\ - \n\ - ```text\n\ - {}\ - ```", - output - ), - ); - break; + // Find the {{produces}} line. + loop { + match lines.next() { + Some(line) if line.is_empty() => {} + Some(line) if line == "{{produces}}" => { + let output = self.generate_lint_output(&lint.name, &example, &options)?; + line.replace_range( + .., + &format!( + "This will produce:\n\ + \n\ + ```text\n\ + {}\ + ```", + output + ), + ); + break; + } + // No {{produces}} after example, find next example. + Some(_line) => break, + None => return Ok(()), } - // No {{produces}} after example, find next example. - Some(_line) => break, - None => return Ok(()), } } } -} -/// Runs the compiler against the example, and extracts the output. -fn generate_lint_output( - name: &str, - example: &[&mut String], - options: &[&str], - rustc: Rustc<'_>, - verbose: bool, -) -> Result> { - if verbose { - eprintln!("compiling lint {}", name); - } - let tempdir = tempfile::TempDir::new()?; - let tempfile = tempdir.path().join("lint_example.rs"); - let mut source = String::new(); - let needs_main = !example.iter().any(|line| line.contains("fn main")); - // Remove `# ` prefix for hidden lines. - let unhidden = - example.iter().map(|line| if line.starts_with("# ") { &line[2..] } else { line }); - let mut lines = unhidden.peekable(); - while let Some(line) = lines.peek() { - if line.starts_with("#!") { + /// Runs the compiler against the example, and extracts the output. + fn generate_lint_output( + &self, + name: &str, + example: &[&mut String], + options: &[&str], + ) -> Result> { + if self.verbose { + eprintln!("compiling lint {}", name); + } + let tempdir = tempfile::TempDir::new()?; + let tempfile = tempdir.path().join("lint_example.rs"); + let mut source = String::new(); + let needs_main = !example.iter().any(|line| line.contains("fn main")); + // Remove `# ` prefix for hidden lines. + let unhidden = + example.iter().map(|line| if line.starts_with("# ") { &line[2..] } else { line }); + let mut lines = unhidden.peekable(); + while let Some(line) = lines.peek() { + if line.starts_with("#!") { + source.push_str(line); + source.push('\n'); + lines.next(); + } else { + break; + } + } + if needs_main { + source.push_str("fn main() {\n"); + } + for line in lines { source.push_str(line); - source.push('\n'); - lines.next(); + source.push('\n') + } + if needs_main { + source.push_str("}\n"); + } + fs::write(&tempfile, source) + .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; + let mut cmd = Command::new(self.rustc_path); + if options.contains(&"edition2015") { + cmd.arg("--edition=2015"); } else { - break; + cmd.arg("--edition=2018"); + } + cmd.arg("--error-format=json"); + cmd.arg("--target").arg(self.rustc_target); + if options.contains(&"test") { + cmd.arg("--test"); + } + cmd.arg("lint_example.rs"); + cmd.current_dir(tempdir.path()); + let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; + let stderr = std::str::from_utf8(&output.stderr).unwrap(); + let msgs = stderr + .lines() + .filter(|line| line.starts_with('{')) + .map(serde_json::from_str) + .collect::, _>>()?; + match msgs + .iter() + .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name)) + { + Some(msg) => { + let rendered = msg["rendered"].as_str().expect("rendered field should exist"); + Ok(rendered.to_string()) + } + None => { + match msgs.iter().find( + |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)), + ) { + Some(msg) => { + let rendered = msg["rendered"].as_str().expect("rendered field should exist"); + Ok(rendered.to_string()) + } + None => { + let rendered: Vec<&str> = + msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); + let non_json: Vec<&str> = + stderr.lines().filter(|line| !line.starts_with('{')).collect(); + Err(format!( + "did not find lint `{}` in output of example, got:\n{}\n{}", + name, + non_json.join("\n"), + rendered.join("\n") + ) + .into()) + } + } + } } } - if needs_main { - source.push_str("fn main() {\n"); - } - for line in lines { - source.push_str(line); - source.push('\n') - } - if needs_main { - source.push_str("}\n"); - } - fs::write(&tempfile, source) - .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; - let mut cmd = Command::new(rustc.path); - if options.contains(&"edition2015") { - cmd.arg("--edition=2015"); - } else { - cmd.arg("--edition=2018"); - } - cmd.arg("--error-format=json"); - cmd.arg("--target").arg(rustc.target); - if options.contains(&"test") { - cmd.arg("--test"); + + /// Saves the mdbook lint chapters at the given path. + fn save_lints_markdown(&self, lints: &[Lint]) -> Result<(), Box> { + self.save_level(lints, Level::Allow, ALLOWED_MD)?; + self.save_level(lints, Level::Warn, WARN_MD)?; + self.save_level(lints, Level::Deny, DENY_MD)?; + Ok(()) } - cmd.arg("lint_example.rs"); - cmd.current_dir(tempdir.path()); - let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; - let stderr = std::str::from_utf8(&output.stderr).unwrap(); - let msgs = stderr - .lines() - .filter(|line| line.starts_with('{')) - .map(serde_json::from_str) - .collect::, _>>()?; - match msgs - .iter() - .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name)) - { - Some(msg) => { - let rendered = msg["rendered"].as_str().expect("rendered field should exist"); - Ok(rendered.to_string()) + + fn save_level(&self, lints: &[Lint], level: Level, header: &str) -> Result<(), Box> { + let mut result = String::new(); + result.push_str(header); + let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect(); + these_lints.sort_unstable_by_key(|lint| &lint.name); + for lint in &these_lints { + write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap(); } - None => { - match msgs.iter().find( - |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)), - ) { - Some(msg) => { - let rendered = msg["rendered"].as_str().expect("rendered field should exist"); - Ok(rendered.to_string()) - } - None => { - let rendered: Vec<&str> = - msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); - let non_json: Vec<&str> = - stderr.lines().filter(|line| !line.starts_with('{')).collect(); - Err(format!( - "did not find lint `{}` in output of example, got:\n{}\n{}", - name, - non_json.join("\n"), - rendered.join("\n") - ) - .into()) - } + result.push('\n'); + for lint in &these_lints { + write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap(); + for line in &lint.doc { + result.push_str(line); + result.push('\n'); + } + result.push('\n'); + } + let out_path = self.out_path.join("listing").join(level.doc_filename()); + // Delete the output because rustbuild uses hard links in its copies. + let _ = fs::remove_file(&out_path); + fs::write(&out_path, result) + .map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?; + Ok(()) + } +} + +/// Extracts the lint name (removing the visibility modifier, and checking validity). +fn lint_name(line: &str) -> Result { + // Skip over any potential `pub` visibility. + match line.trim().split(' ').next_back() { + Some(name) => { + if !name.ends_with(',') { + return Err("lint name should end with comma"); } + let name = &name[..name.len() - 1]; + if !name.chars().all(|ch| ch.is_uppercase() || ch == '_') || name.is_empty() { + return Err("lint name did not have expected format"); + } + Ok(name.to_lowercase().to_string()) } + None => Err("could not find lint name"), } } @@ -442,41 +470,3 @@ static DENY_MD: &str = r#"# Deny-by-default lints These lints are all set to the 'deny' level by default. "#; - -/// Saves the mdbook lint chapters at the given path. -fn save_lints_markdown(lints: &[Lint], out_dir: &Path) -> Result<(), Box> { - save_level(lints, Level::Allow, out_dir, ALLOWED_MD)?; - save_level(lints, Level::Warn, out_dir, WARN_MD)?; - save_level(lints, Level::Deny, out_dir, DENY_MD)?; - Ok(()) -} - -fn save_level( - lints: &[Lint], - level: Level, - out_dir: &Path, - header: &str, -) -> Result<(), Box> { - let mut result = String::new(); - result.push_str(header); - let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect(); - these_lints.sort_unstable_by_key(|lint| &lint.name); - for lint in &these_lints { - write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap(); - } - result.push('\n'); - for lint in &these_lints { - write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap(); - for line in &lint.doc { - result.push_str(line); - result.push('\n'); - } - result.push('\n'); - } - let out_path = out_dir.join(level.doc_filename()); - // Delete the output because rustbuild uses hard links in its copies. - let _ = fs::remove_file(&out_path); - fs::write(&out_path, result) - .map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?; - Ok(()) -} diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs index 5db49007d375c..9b75ab45fca87 100644 --- a/src/tools/lint-docs/src/main.rs +++ b/src/tools/lint-docs/src/main.rs @@ -57,13 +57,12 @@ fn doit() -> Result<(), Box> { if rustc_target.is_none() { return Err("--rustc-target must be specified to the rustc target".into()); } - lint_docs::extract_lint_docs( - &src_path.unwrap(), - &out_path.unwrap(), - lint_docs::Rustc { - path: rustc_path.as_deref().unwrap(), - target: rustc_target.as_deref().unwrap(), - }, + let le = lint_docs::LintExtractor { + src_path: &src_path.unwrap(), + out_path: &out_path.unwrap(), + rustc_path: &rustc_path.unwrap(), + rustc_target: &rustc_target.unwrap(), verbose, - ) + }; + le.extract_lint_docs() } From d2d91b42a577e033387918addac937b3f9062f5e Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 28 Nov 2020 13:29:51 -0800 Subject: [PATCH 04/18] lint-docs: Add --validate flag to validate lint docs separately. --- compiler/rustc_lint_defs/src/lib.rs | 24 ++++++++++++---- src/bootstrap/builder.rs | 1 + src/bootstrap/doc.rs | 5 ++++ src/bootstrap/test.rs | 33 ++++++++++++++++++++++ src/tools/lint-docs/src/groups.rs | 27 ++++++++++++------ src/tools/lint-docs/src/lib.rs | 43 +++++++++++++++++++++++------ src/tools/lint-docs/src/main.rs | 5 +++- 7 files changed, 115 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index af9926400ca44..aec0fc253ca5e 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -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) => ( diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 508d785834fce..9336d7165ee75 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -413,6 +413,7 @@ impl<'a> Builder<'a> { test::TheBook, test::UnstableBook, test::RustcBook, + test::LintDocs, test::RustcGuide, test::EmbeddedBook, test::EditionGuide, diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index af7f7eff89418..bb0555c227d70 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -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. diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index e087e2b8ff153..611fecca0546b 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -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, + }); + } +} diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index db667264d2fd7..0a69b18a33254 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -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(", ")) diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index aafd33301ea87..dc878b718ad60 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -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() { - return Err(format!( - "did not find doc lines for lint `{}` in {}", - name, - path.display() - ) - .into()); + 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(()); } - lint.check_style()?; + 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(()) } diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs index 9b75ab45fca87..922e70402f274 100644 --- a/src/tools/lint-docs/src/main.rs +++ b/src/tools/lint-docs/src/main.rs @@ -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> { 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> { }; } "-v" | "--verbose" => verbose = true, + "--validate" => validate = true, s => return Err(format!("unexpected argument `{}`", s).into()), } } @@ -63,6 +65,7 @@ fn doit() -> Result<(), Box> { rustc_path: &rustc_path.unwrap(), rustc_target: &rustc_target.unwrap(), verbose, + validate, }; le.extract_lint_docs() } From ddfb581fb9e04595bc7cdb9d66792fdfdbec67ed Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 28 Nov 2020 20:25:41 -0500 Subject: [PATCH 05/18] Move `src/test/rustdoc` intra-doc link tests into a subdirectory They were starting to get unwieldy. --- .../rustdoc/intra-doc-link-mod-ambiguity.rs | 18 ------ .../anchors.rs} | 4 +- .../rustdoc/intra-doc/associated-defaults.rs | 27 ++++++++ .../rustdoc/intra-doc/associated-items.rs | 61 +++++++++++++++++++ .../auxiliary/intra-link-extern-crate.rs | 0 .../auxiliary/intra-link-pub-use.rs | 0 .../intra-link-reexport-additional-docs.rs | 0 .../auxiliary/intra-links-external-traits.rs | 0 .../{ => intra-doc}/auxiliary/my-core.rs | 0 .../auxiliary/proc-macro-macro.rs} | 1 - .../auxiliary/through-proc-macro-aux.rs | 0 .../{intra-links.rs => intra-doc/basic.rs} | 46 +++++++------- .../builtin-macros.rs} | 2 +- .../cross-crate}/additional_doc.rs | 0 .../cross-crate}/auxiliary/additional_doc.rs | 0 .../cross-crate}/auxiliary/hidden.rs | 0 .../cross-crate}/auxiliary/intra-doc-basic.rs | 0 .../auxiliary/intra-link-cross-crate-crate.rs | 0 .../cross-crate}/auxiliary/macro_inner.rs | 0 .../cross-crate}/auxiliary/module.rs | 0 .../cross-crate}/auxiliary/proc_macro.rs | 0 .../cross-crate}/auxiliary/submodule-inner.rs | 0 .../cross-crate}/auxiliary/submodule-outer.rs | 0 .../cross-crate}/auxiliary/traits.rs | 0 .../cross-crate}/basic.rs | 0 .../cross-crate/crate.rs} | 0 .../cross-crate}/hidden.rs | 0 .../cross-crate}/macro.rs | 0 .../cross-crate}/module.rs | 0 .../cross-crate}/submodule-inner.rs | 0 .../cross-crate}/submodule-outer.rs | 0 .../cross-crate}/traits.rs | 0 .../intra-doc/disambiguators-removed.rs | 51 ++++++++++++++++ .../enum-struct-field.rs} | 0 .../extern-crate.rs} | 0 src/test/rustdoc/intra-doc/extern-type.rs | 17 ++++++ .../external-traits.rs} | 0 .../generic-params.rs} | 0 .../in-bodies.rs} | 0 .../libstd-re-export.rs} | 0 src/test/rustdoc/intra-doc/mod-ambiguity.rs | 16 +++++ src/test/rustdoc/intra-doc/prim-assoc.rs | 5 ++ .../prim-methods-external-core.rs} | 2 +- .../prim-methods-local.rs} | 2 +- .../prim-methods.rs} | 2 +- src/test/rustdoc/intra-doc/prim-precedence.rs | 17 ++++++ .../primitive-non-default-impl.rs} | 6 +- .../private-failures-ignored.rs} | 0 .../private.rs} | 0 src/test/rustdoc/intra-doc/proc-macro.rs | 27 ++++++++ .../pub-use.rs} | 0 .../reexport-additional-docs.rs} | 0 .../{intra-link-self.rs => intra-doc/self.rs} | 0 .../{ => intra-doc}/through-proc-macro.rs | 0 .../trait-impl.rs} | 0 .../trait-item.rs} | 2 +- .../true-false.rs} | 0 .../rustdoc/intra-link-associated-defaults.rs | 27 -------- .../rustdoc/intra-link-associated-items.rs | 61 ------------------- .../intra-link-disambiguators-removed.rs | 51 ---------------- src/test/rustdoc/intra-link-extern-type.rs | 18 ------ src/test/rustdoc/intra-link-prim-assoc.rs | 5 -- .../rustdoc/intra-link-prim-precedence.rs | 17 ------ src/test/rustdoc/intra-link-proc-macro.rs | 27 -------- 64 files changed, 254 insertions(+), 258 deletions(-) delete mode 100644 src/test/rustdoc/intra-doc-link-mod-ambiguity.rs rename src/test/rustdoc/{intra-links-anchors.rs => intra-doc/anchors.rs} (50%) create mode 100644 src/test/rustdoc/intra-doc/associated-defaults.rs create mode 100644 src/test/rustdoc/intra-doc/associated-items.rs rename src/test/rustdoc/{ => intra-doc}/auxiliary/intra-link-extern-crate.rs (100%) rename src/test/rustdoc/{ => intra-doc}/auxiliary/intra-link-pub-use.rs (100%) rename src/test/rustdoc/{ => intra-doc}/auxiliary/intra-link-reexport-additional-docs.rs (100%) rename src/test/rustdoc/{ => intra-doc}/auxiliary/intra-links-external-traits.rs (100%) rename src/test/rustdoc/{ => intra-doc}/auxiliary/my-core.rs (100%) rename src/test/rustdoc/{auxiliary/intra-link-proc-macro-macro.rs => intra-doc/auxiliary/proc-macro-macro.rs} (93%) rename src/test/rustdoc/{ => intra-doc}/auxiliary/through-proc-macro-aux.rs (100%) rename src/test/rustdoc/{intra-links.rs => intra-doc/basic.rs} (52%) rename src/test/rustdoc/{intra-link-builtin-macros.rs => intra-doc/builtin-macros.rs} (66%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/additional_doc.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/additional_doc.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/hidden.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/intra-doc-basic.rs (100%) rename src/test/rustdoc/{ => intra-doc/cross-crate}/auxiliary/intra-link-cross-crate-crate.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/macro_inner.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/module.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/proc_macro.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/submodule-inner.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/submodule-outer.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/auxiliary/traits.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/basic.rs (100%) rename src/test/rustdoc/{intra-link-cross-crate-crate.rs => intra-doc/cross-crate/crate.rs} (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/hidden.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/macro.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/module.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/submodule-inner.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/submodule-outer.rs (100%) rename src/test/rustdoc/{intra-doc-crate => intra-doc/cross-crate}/traits.rs (100%) create mode 100644 src/test/rustdoc/intra-doc/disambiguators-removed.rs rename src/test/rustdoc/{intra-doc-link-enum-struct-field.rs => intra-doc/enum-struct-field.rs} (100%) rename src/test/rustdoc/{intra-link-extern-crate.rs => intra-doc/extern-crate.rs} (100%) create mode 100644 src/test/rustdoc/intra-doc/extern-type.rs rename src/test/rustdoc/{intra-links-external-traits.rs => intra-doc/external-traits.rs} (100%) rename src/test/rustdoc/{intra-doc-link-generic-params.rs => intra-doc/generic-params.rs} (100%) rename src/test/rustdoc/{intra-link-in-bodies.rs => intra-doc/in-bodies.rs} (100%) rename src/test/rustdoc/{intra-link-libstd-re-export.rs => intra-doc/libstd-re-export.rs} (100%) create mode 100644 src/test/rustdoc/intra-doc/mod-ambiguity.rs create mode 100644 src/test/rustdoc/intra-doc/prim-assoc.rs rename src/test/rustdoc/{intra-link-prim-methods-external-core.rs => intra-doc/prim-methods-external-core.rs} (90%) rename src/test/rustdoc/{intra-link-prim-methods-local.rs => intra-doc/prim-methods-local.rs} (92%) rename src/test/rustdoc/{intra-link-prim-methods.rs => intra-doc/prim-methods.rs} (88%) create mode 100644 src/test/rustdoc/intra-doc/prim-precedence.rs rename src/test/rustdoc/{intra-link-primitive-non-default-impl.rs => intra-doc/primitive-non-default-impl.rs} (88%) rename src/test/rustdoc/{intra-link-private.rs => intra-doc/private-failures-ignored.rs} (100%) rename src/test/rustdoc/{intra-doc-link-private.rs => intra-doc/private.rs} (100%) create mode 100644 src/test/rustdoc/intra-doc/proc-macro.rs rename src/test/rustdoc/{intra-link-pub-use.rs => intra-doc/pub-use.rs} (100%) rename src/test/rustdoc/{intra-link-reexport-additional-docs.rs => intra-doc/reexport-additional-docs.rs} (100%) rename src/test/rustdoc/{intra-link-self.rs => intra-doc/self.rs} (100%) rename src/test/rustdoc/{ => intra-doc}/through-proc-macro.rs (100%) rename src/test/rustdoc/{intra-link-trait-impl.rs => intra-doc/trait-impl.rs} (100%) rename src/test/rustdoc/{intra-link-trait-item.rs => intra-doc/trait-item.rs} (69%) rename src/test/rustdoc/{intra-doc-link-true-false.rs => intra-doc/true-false.rs} (100%) delete mode 100644 src/test/rustdoc/intra-link-associated-defaults.rs delete mode 100644 src/test/rustdoc/intra-link-associated-items.rs delete mode 100644 src/test/rustdoc/intra-link-disambiguators-removed.rs delete mode 100644 src/test/rustdoc/intra-link-extern-type.rs delete mode 100644 src/test/rustdoc/intra-link-prim-assoc.rs delete mode 100644 src/test/rustdoc/intra-link-prim-precedence.rs delete mode 100644 src/test/rustdoc/intra-link-proc-macro.rs diff --git a/src/test/rustdoc/intra-doc-link-mod-ambiguity.rs b/src/test/rustdoc/intra-doc-link-mod-ambiguity.rs deleted file mode 100644 index bd733e1023033..0000000000000 --- a/src/test/rustdoc/intra-doc-link-mod-ambiguity.rs +++ /dev/null @@ -1,18 +0,0 @@ -// ignore-tidy-linelength - -#![deny(broken_intra_doc_links)] - - -pub fn foo() { - -} - -pub mod foo {} -// @has intra_doc_link_mod_ambiguity/struct.A.html '//a/@href' '../intra_doc_link_mod_ambiguity/foo/index.html' -/// Module is [`module@foo`] -pub struct A; - - -// @has intra_doc_link_mod_ambiguity/struct.B.html '//a/@href' '../intra_doc_link_mod_ambiguity/fn.foo.html' -/// Function is [`fn@foo`] -pub struct B; diff --git a/src/test/rustdoc/intra-links-anchors.rs b/src/test/rustdoc/intra-doc/anchors.rs similarity index 50% rename from src/test/rustdoc/intra-links-anchors.rs rename to src/test/rustdoc/intra-doc/anchors.rs index f554e16b4f475..e4f0c737bdd33 100644 --- a/src/test/rustdoc/intra-links-anchors.rs +++ b/src/test/rustdoc/intra-doc/anchors.rs @@ -3,8 +3,8 @@ /// # Anchor! pub struct Something; -// @has intra_links_anchors/struct.SomeOtherType.html -// @has - '//a/@href' '../intra_links_anchors/struct.Something.html#Anchor!' +// @has anchors/struct.SomeOtherType.html +// @has - '//a/@href' '../anchors/struct.Something.html#Anchor!' /// I want... /// diff --git a/src/test/rustdoc/intra-doc/associated-defaults.rs b/src/test/rustdoc/intra-doc/associated-defaults.rs new file mode 100644 index 0000000000000..f99d9b5baea44 --- /dev/null +++ b/src/test/rustdoc/intra-doc/associated-defaults.rs @@ -0,0 +1,27 @@ +// ignore-tidy-linelength +#![deny(intra_doc_link_resolution_failure)] +#![feature(associated_type_defaults)] + +pub trait TraitWithDefault { + type T = usize; + fn f() -> Self::T { + 0 + } +} + +/// Link to [UsesDefaults::T] and [UsesDefaults::f] +// @has 'associated_defaults/struct.UsesDefaults.html' '//a[@href="../associated_defaults/struct.UsesDefaults.html#associatedtype.T"]' 'UsesDefaults::T' +// @has 'associated_defaults/struct.UsesDefaults.html' '//a[@href="../associated_defaults/struct.UsesDefaults.html#method.f"]' 'UsesDefaults::f' +pub struct UsesDefaults; +impl TraitWithDefault for UsesDefaults {} + +/// Link to [OverridesDefaults::T] and [OverridesDefaults::f] +// @has 'associated_defaults/struct.OverridesDefaults.html' '//a[@href="../associated_defaults/struct.OverridesDefaults.html#associatedtype.T"]' 'OverridesDefaults::T' +// @has 'associated_defaults/struct.OverridesDefaults.html' '//a[@href="../associated_defaults/struct.OverridesDefaults.html#method.f"]' 'OverridesDefaults::f' +pub struct OverridesDefaults; +impl TraitWithDefault for OverridesDefaults { + type T = bool; + fn f() -> bool { + true + } +} diff --git a/src/test/rustdoc/intra-doc/associated-items.rs b/src/test/rustdoc/intra-doc/associated-items.rs new file mode 100644 index 0000000000000..09dfbfcf68a32 --- /dev/null +++ b/src/test/rustdoc/intra-doc/associated-items.rs @@ -0,0 +1,61 @@ +// ignore-tidy-linelength +#![deny(intra_doc_link_resolution_failure)] + +/// [`std::collections::BTreeMap::into_iter`] +/// [`String::from`] is ambiguous as to which `From` impl +/// [Vec::into_iter()] uses a disambiguator +// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter' +// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from' +// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter' +pub fn foo() {} + +/// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input] +// @has 'associated_items/struct.MyStruct.html' '//a[@href="../associated_items/struct.MyStruct.html"]' 'MyStruct' +// @has 'associated_items/struct.MyStruct.html' '//a[@href="../associated_items/struct.MyStruct.html#method.method"]' 'link from struct' +// @has 'associated_items/struct.MyStruct.html' '//a[@href="../associated_items/struct.MyStruct.html#method.clone"]' 'MyStruct::clone' +// @has 'associated_items/struct.MyStruct.html' '//a[@href="../associated_items/struct.MyStruct.html#associatedtype.Input"]' 'MyStruct::Input' +pub struct MyStruct { foo: () } + +impl Clone for MyStruct { + fn clone(&self) -> Self { + MyStruct + } +} + +pub trait T { + type Input; + fn method(i: Self::Input); +} + +impl T for MyStruct { + type Input = usize; + + /// [link from method][MyStruct::method] on method + // @has 'associated_items/struct.MyStruct.html' '//a[@href="../associated_items/struct.MyStruct.html#method.method"]' 'link from method' + fn method(i: usize) { + } +} + +/// Ambiguity between which trait to use +pub trait T1 { + fn ambiguous_method(); +} + +pub trait T2 { + fn ambiguous_method(); +} + +/// Link to [S::ambiguous_method] +// FIXME: there is no way to disambiguate these. +// Since we have `#[deny(intra_doc_failure)]`, we still know it was one or the other. +pub struct S; + +impl T1 for S { + fn ambiguous_method() {} +} + +impl T2 for S { + fn ambiguous_method() {} +} + +fn main() {} diff --git a/src/test/rustdoc/auxiliary/intra-link-extern-crate.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs similarity index 100% rename from src/test/rustdoc/auxiliary/intra-link-extern-crate.rs rename to src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs diff --git a/src/test/rustdoc/auxiliary/intra-link-pub-use.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs similarity index 100% rename from src/test/rustdoc/auxiliary/intra-link-pub-use.rs rename to src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs diff --git a/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs similarity index 100% rename from src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs rename to src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs diff --git a/src/test/rustdoc/auxiliary/intra-links-external-traits.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs similarity index 100% rename from src/test/rustdoc/auxiliary/intra-links-external-traits.rs rename to src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs diff --git a/src/test/rustdoc/auxiliary/my-core.rs b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs similarity index 100% rename from src/test/rustdoc/auxiliary/my-core.rs rename to src/test/rustdoc/intra-doc/auxiliary/my-core.rs diff --git a/src/test/rustdoc/auxiliary/intra-link-proc-macro-macro.rs b/src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs similarity index 93% rename from src/test/rustdoc/auxiliary/intra-link-proc-macro-macro.rs rename to src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs index 04a431d99026e..5ba132f25b471 100644 --- a/src/test/rustdoc/auxiliary/intra-link-proc-macro-macro.rs +++ b/src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs @@ -3,7 +3,6 @@ // compile-flags: --crate-type proc-macro #![crate_type="proc-macro"] -#![crate_name="intra_link_proc_macro_macro"] extern crate proc_macro; diff --git a/src/test/rustdoc/auxiliary/through-proc-macro-aux.rs b/src/test/rustdoc/intra-doc/auxiliary/through-proc-macro-aux.rs similarity index 100% rename from src/test/rustdoc/auxiliary/through-proc-macro-aux.rs rename to src/test/rustdoc/intra-doc/auxiliary/through-proc-macro-aux.rs diff --git a/src/test/rustdoc/intra-links.rs b/src/test/rustdoc/intra-doc/basic.rs similarity index 52% rename from src/test/rustdoc/intra-links.rs rename to src/test/rustdoc/intra-doc/basic.rs index 751c10925c017..7760546e1fa1c 100644 --- a/src/test/rustdoc/intra-links.rs +++ b/src/test/rustdoc/intra-doc/basic.rs @@ -1,21 +1,21 @@ -// @has intra_links/index.html -// @has - '//a/@href' '../intra_links/struct.ThisType.html' -// @has - '//a/@href' '../intra_links/struct.ThisType.html#method.this_method' -// @has - '//a/@href' '../intra_links/enum.ThisEnum.html' -// @has - '//a/@href' '../intra_links/enum.ThisEnum.html#variant.ThisVariant' -// @has - '//a/@href' '../intra_links/trait.ThisTrait.html' -// @has - '//a/@href' '../intra_links/trait.ThisTrait.html#tymethod.this_associated_method' -// @has - '//a/@href' '../intra_links/trait.ThisTrait.html#associatedtype.ThisAssociatedType' -// @has - '//a/@href' '../intra_links/trait.ThisTrait.html#associatedconstant.THIS_ASSOCIATED_CONST' -// @has - '//a/@href' '../intra_links/trait.ThisTrait.html' -// @has - '//a/@href' '../intra_links/type.ThisAlias.html' -// @has - '//a/@href' '../intra_links/union.ThisUnion.html' -// @has - '//a/@href' '../intra_links/fn.this_function.html' -// @has - '//a/@href' '../intra_links/constant.THIS_CONST.html' -// @has - '//a/@href' '../intra_links/static.THIS_STATIC.html' -// @has - '//a/@href' '../intra_links/macro.this_macro.html' -// @has - '//a/@href' '../intra_links/trait.SoAmbiguous.html' -// @has - '//a/@href' '../intra_links/fn.SoAmbiguous.html' +// @has basic/index.html +// @has - '//a/@href' '../basic/struct.ThisType.html' +// @has - '//a/@href' '../basic/struct.ThisType.html#method.this_method' +// @has - '//a/@href' '../basic/enum.ThisEnum.html' +// @has - '//a/@href' '../basic/enum.ThisEnum.html#variant.ThisVariant' +// @has - '//a/@href' '../basic/trait.ThisTrait.html' +// @has - '//a/@href' '../basic/trait.ThisTrait.html#tymethod.this_associated_method' +// @has - '//a/@href' '../basic/trait.ThisTrait.html#associatedtype.ThisAssociatedType' +// @has - '//a/@href' '../basic/trait.ThisTrait.html#associatedconstant.THIS_ASSOCIATED_CONST' +// @has - '//a/@href' '../basic/trait.ThisTrait.html' +// @has - '//a/@href' '../basic/type.ThisAlias.html' +// @has - '//a/@href' '../basic/union.ThisUnion.html' +// @has - '//a/@href' '../basic/fn.this_function.html' +// @has - '//a/@href' '../basic/constant.THIS_CONST.html' +// @has - '//a/@href' '../basic/static.THIS_STATIC.html' +// @has - '//a/@href' '../basic/macro.this_macro.html' +// @has - '//a/@href' '../basic/trait.SoAmbiguous.html' +// @has - '//a/@href' '../basic/fn.SoAmbiguous.html' //! In this crate we would like to link to: //! //! * [`ThisType`](ThisType) @@ -46,7 +46,7 @@ macro_rules! this_macro { () => {}; } -// @has intra_links/struct.ThisType.html '//a/@href' '../intra_links/macro.this_macro.html' +// @has basic/struct.ThisType.html '//a/@href' '../basic/macro.this_macro.html' /// another link to [`this_macro!()`] pub struct ThisType; @@ -72,10 +72,10 @@ pub trait SoAmbiguous {} pub fn SoAmbiguous() {} -// @has intra_links/struct.SomeOtherType.html '//a/@href' '../intra_links/struct.ThisType.html' -// @has - '//a/@href' '../intra_links/struct.ThisType.html#method.this_method' -// @has - '//a/@href' '../intra_links/enum.ThisEnum.html' -// @has - '//a/@href' '../intra_links/enum.ThisEnum.html#variant.ThisVariant' +// @has basic/struct.SomeOtherType.html '//a/@href' '../basic/struct.ThisType.html' +// @has - '//a/@href' '../basic/struct.ThisType.html#method.this_method' +// @has - '//a/@href' '../basic/enum.ThisEnum.html' +// @has - '//a/@href' '../basic/enum.ThisEnum.html#variant.ThisVariant' /// Shortcut links for: /// * [`ThisType`] /// * [`ThisType::this_method`] diff --git a/src/test/rustdoc/intra-link-builtin-macros.rs b/src/test/rustdoc/intra-doc/builtin-macros.rs similarity index 66% rename from src/test/rustdoc/intra-link-builtin-macros.rs rename to src/test/rustdoc/intra-doc/builtin-macros.rs index 4d40eb3b88f1b..74216a587e1da 100644 --- a/src/test/rustdoc/intra-link-builtin-macros.rs +++ b/src/test/rustdoc/intra-doc/builtin-macros.rs @@ -1,3 +1,3 @@ -// @has intra_link_builtin_macros/index.html +// @has builtin_macros/index.html // @has - '//a/@href' 'https://doc.rust-lang.org/nightly/core/macro.cfg.html' //! [cfg] diff --git a/src/test/rustdoc/intra-doc-crate/additional_doc.rs b/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/additional_doc.rs rename to src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/additional_doc.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/auxiliary/additional_doc.rs rename to src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/hidden.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/auxiliary/hidden.rs rename to src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/intra-doc-basic.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/auxiliary/intra-doc-basic.rs rename to src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs diff --git a/src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs similarity index 100% rename from src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs rename to src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/macro_inner.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/auxiliary/macro_inner.rs rename to src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/module.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/auxiliary/module.rs rename to src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/proc_macro.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/auxiliary/proc_macro.rs rename to src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-inner.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/auxiliary/submodule-inner.rs rename to src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-outer.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/auxiliary/submodule-outer.rs rename to src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/traits.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/auxiliary/traits.rs rename to src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs diff --git a/src/test/rustdoc/intra-doc-crate/basic.rs b/src/test/rustdoc/intra-doc/cross-crate/basic.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/basic.rs rename to src/test/rustdoc/intra-doc/cross-crate/basic.rs diff --git a/src/test/rustdoc/intra-link-cross-crate-crate.rs b/src/test/rustdoc/intra-doc/cross-crate/crate.rs similarity index 100% rename from src/test/rustdoc/intra-link-cross-crate-crate.rs rename to src/test/rustdoc/intra-doc/cross-crate/crate.rs diff --git a/src/test/rustdoc/intra-doc-crate/hidden.rs b/src/test/rustdoc/intra-doc/cross-crate/hidden.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/hidden.rs rename to src/test/rustdoc/intra-doc/cross-crate/hidden.rs diff --git a/src/test/rustdoc/intra-doc-crate/macro.rs b/src/test/rustdoc/intra-doc/cross-crate/macro.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/macro.rs rename to src/test/rustdoc/intra-doc/cross-crate/macro.rs diff --git a/src/test/rustdoc/intra-doc-crate/module.rs b/src/test/rustdoc/intra-doc/cross-crate/module.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/module.rs rename to src/test/rustdoc/intra-doc/cross-crate/module.rs diff --git a/src/test/rustdoc/intra-doc-crate/submodule-inner.rs b/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/submodule-inner.rs rename to src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs diff --git a/src/test/rustdoc/intra-doc-crate/submodule-outer.rs b/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/submodule-outer.rs rename to src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs diff --git a/src/test/rustdoc/intra-doc-crate/traits.rs b/src/test/rustdoc/intra-doc/cross-crate/traits.rs similarity index 100% rename from src/test/rustdoc/intra-doc-crate/traits.rs rename to src/test/rustdoc/intra-doc/cross-crate/traits.rs diff --git a/src/test/rustdoc/intra-doc/disambiguators-removed.rs b/src/test/rustdoc/intra-doc/disambiguators-removed.rs new file mode 100644 index 0000000000000..aa0ced62aaf30 --- /dev/null +++ b/src/test/rustdoc/intra-doc/disambiguators-removed.rs @@ -0,0 +1,51 @@ +// ignore-tidy-linelength +#![deny(intra_doc_link_resolution_failure)] +// first try backticks +/// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`] +// @has disambiguators_removed/struct.AtDisambiguator.html +// @has - '//a[@href="../disambiguators_removed/trait.Name.html"][code]' "Name" +// @has - '//a[@href="../disambiguators_removed/fn.Name.html"][code]' "Name" +// @has - '//a[@href="../disambiguators_removed/macro.Name.html"][code]' "Name" +pub struct AtDisambiguator; + +/// fn: [`Name()`], macro: [`Name!`] +// @has disambiguators_removed/struct.SymbolDisambiguator.html +// @has - '//a[@href="../disambiguators_removed/fn.Name.html"][code]' "Name()" +// @has - '//a[@href="../disambiguators_removed/macro.Name.html"][code]' "Name!" +pub struct SymbolDisambiguator; + +// Now make sure that backticks aren't added if they weren't already there +/// [fn@Name] +// @has disambiguators_removed/trait.Name.html +// @has - '//a[@href="../disambiguators_removed/fn.Name.html"]' "Name" +// @!has - '//a[@href="../disambiguators_removed/fn.Name.html"][code]' "Name" + +// FIXME: this will turn !() into ! alone +/// [Name!()] +// @has - '//a[@href="../disambiguators_removed/macro.Name.html"]' "Name!" +pub trait Name {} + +#[allow(non_snake_case)] + +// Try collapsed reference links +/// [macro@Name][] +// @has disambiguators_removed/fn.Name.html +// @has - '//a[@href="../disambiguators_removed/macro.Name.html"]' "Name" + +// Try links that have the same text as a generated URL +/// Weird URL aligned [../disambiguators_removed/macro.Name.html][trait@Name] +// @has - '//a[@href="../disambiguators_removed/trait.Name.html"]' "../disambiguators_removed/macro.Name.html" +pub fn Name() {} + +#[macro_export] +// Rustdoc doesn't currently handle links that have weird interspersing of inline code blocks. +/// [fn@Na`m`e] +// @has disambiguators_removed/macro.Name.html +// @has - '//a[@href="../disambiguators_removed/fn.Name.html"]' "fn@Name" + +// It also doesn't handle any case where the code block isn't the whole link text: +/// [trait@`Name`] +// @has - '//a[@href="../disambiguators_removed/trait.Name.html"]' "trait@Name" +macro_rules! Name { + () => () +} diff --git a/src/test/rustdoc/intra-doc-link-enum-struct-field.rs b/src/test/rustdoc/intra-doc/enum-struct-field.rs similarity index 100% rename from src/test/rustdoc/intra-doc-link-enum-struct-field.rs rename to src/test/rustdoc/intra-doc/enum-struct-field.rs diff --git a/src/test/rustdoc/intra-link-extern-crate.rs b/src/test/rustdoc/intra-doc/extern-crate.rs similarity index 100% rename from src/test/rustdoc/intra-link-extern-crate.rs rename to src/test/rustdoc/intra-doc/extern-crate.rs diff --git a/src/test/rustdoc/intra-doc/extern-type.rs b/src/test/rustdoc/intra-doc/extern-type.rs new file mode 100644 index 0000000000000..e1934698d1fad --- /dev/null +++ b/src/test/rustdoc/intra-doc/extern-type.rs @@ -0,0 +1,17 @@ +#![feature(extern_types)] + +extern { + pub type ExternType; +} + +impl ExternType { + pub fn f(&self) { + + } +} + +// @has 'extern_type/foreigntype.ExternType.html' +// @has 'extern_type/fn.links_to_extern_type.html' \ +// 'href="../extern_type/foreigntype.ExternType.html#method.f"' +/// See also [ExternType::f] +pub fn links_to_extern_type() {} diff --git a/src/test/rustdoc/intra-links-external-traits.rs b/src/test/rustdoc/intra-doc/external-traits.rs similarity index 100% rename from src/test/rustdoc/intra-links-external-traits.rs rename to src/test/rustdoc/intra-doc/external-traits.rs diff --git a/src/test/rustdoc/intra-doc-link-generic-params.rs b/src/test/rustdoc/intra-doc/generic-params.rs similarity index 100% rename from src/test/rustdoc/intra-doc-link-generic-params.rs rename to src/test/rustdoc/intra-doc/generic-params.rs diff --git a/src/test/rustdoc/intra-link-in-bodies.rs b/src/test/rustdoc/intra-doc/in-bodies.rs similarity index 100% rename from src/test/rustdoc/intra-link-in-bodies.rs rename to src/test/rustdoc/intra-doc/in-bodies.rs diff --git a/src/test/rustdoc/intra-link-libstd-re-export.rs b/src/test/rustdoc/intra-doc/libstd-re-export.rs similarity index 100% rename from src/test/rustdoc/intra-link-libstd-re-export.rs rename to src/test/rustdoc/intra-doc/libstd-re-export.rs diff --git a/src/test/rustdoc/intra-doc/mod-ambiguity.rs b/src/test/rustdoc/intra-doc/mod-ambiguity.rs new file mode 100644 index 0000000000000..feb013b22be65 --- /dev/null +++ b/src/test/rustdoc/intra-doc/mod-ambiguity.rs @@ -0,0 +1,16 @@ +#![deny(broken_intra_doc_links)] + + +pub fn foo() { + +} + +pub mod foo {} +// @has mod_ambiguity/struct.A.html '//a/@href' '../mod_ambiguity/foo/index.html' +/// Module is [`module@foo`] +pub struct A; + + +// @has mod_ambiguity/struct.B.html '//a/@href' '../mod_ambiguity/fn.foo.html' +/// Function is [`fn@foo`] +pub struct B; diff --git a/src/test/rustdoc/intra-doc/prim-assoc.rs b/src/test/rustdoc/intra-doc/prim-assoc.rs new file mode 100644 index 0000000000000..d687cbd69bb18 --- /dev/null +++ b/src/test/rustdoc/intra-doc/prim-assoc.rs @@ -0,0 +1,5 @@ +// ignore-tidy-linelength +#![deny(broken_intra_doc_links)] + +//! [i32::MAX] +// @has prim_assoc/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX" diff --git a/src/test/rustdoc/intra-link-prim-methods-external-core.rs b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs similarity index 90% rename from src/test/rustdoc/intra-link-prim-methods-external-core.rs rename to src/test/rustdoc/intra-doc/prim-methods-external-core.rs index c8ef4c015997b..434e03389835f 100644 --- a/src/test/rustdoc/intra-link-prim-methods-external-core.rs +++ b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs @@ -9,7 +9,7 @@ #![no_core] #![crate_type = "rlib"] -// @has intra_link_prim_methods_external_core/index.html +// @has prim_methods_external_core/index.html // @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char' // @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8' diff --git a/src/test/rustdoc/intra-link-prim-methods-local.rs b/src/test/rustdoc/intra-doc/prim-methods-local.rs similarity index 92% rename from src/test/rustdoc/intra-link-prim-methods-local.rs rename to src/test/rustdoc/intra-doc/prim-methods-local.rs index d448acf7f9682..9888f29db5bac 100644 --- a/src/test/rustdoc/intra-link-prim-methods-local.rs +++ b/src/test/rustdoc/intra-doc/prim-methods-local.rs @@ -5,7 +5,7 @@ // ignore-tidy-linelength -// @has intra_link_prim_methods_local/index.html +// @has prim_methods_local/index.html // @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char' // @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8' diff --git a/src/test/rustdoc/intra-link-prim-methods.rs b/src/test/rustdoc/intra-doc/prim-methods.rs similarity index 88% rename from src/test/rustdoc/intra-link-prim-methods.rs rename to src/test/rustdoc/intra-doc/prim-methods.rs index 94c80c996c1e0..f19cff7d34afa 100644 --- a/src/test/rustdoc/intra-link-prim-methods.rs +++ b/src/test/rustdoc/intra-doc/prim-methods.rs @@ -2,7 +2,7 @@ // ignore-tidy-linelength -// @has intra_link_prim_methods/index.html +// @has prim_methods/index.html // @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char' // @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8' diff --git a/src/test/rustdoc/intra-doc/prim-precedence.rs b/src/test/rustdoc/intra-doc/prim-precedence.rs new file mode 100644 index 0000000000000..ed2c2cda7184d --- /dev/null +++ b/src/test/rustdoc/intra-doc/prim-precedence.rs @@ -0,0 +1,17 @@ +// ignore-tidy-linelength +#![deny(broken_intra_doc_links)] + +pub mod char { + /// [char] + // @has prim_precedence/char/struct.Inner.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html' + pub struct Inner; +} + +/// See [prim@char] +// @has prim_precedence/struct.MyString.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html' +pub struct MyString; + +/// See also [crate::char] and [mod@char] +// @has prim_precedence/struct.MyString2.html '//*[@href="../prim_precedence/char/index.html"]' 'crate::char' +// @has - '//*[@href="../prim_precedence/char/index.html"]' 'mod@char' +pub struct MyString2; diff --git a/src/test/rustdoc/intra-link-primitive-non-default-impl.rs b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs similarity index 88% rename from src/test/rustdoc/intra-link-primitive-non-default-impl.rs rename to src/test/rustdoc/intra-doc/primitive-non-default-impl.rs index 160b18a967b20..548eb090a3276 100644 --- a/src/test/rustdoc/intra-link-primitive-non-default-impl.rs +++ b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs @@ -2,7 +2,7 @@ // ignore-tidy-linelength -// @has intra_link_primitive_non_default_impl/fn.str_methods.html +// @has primitive_non_default_impl/fn.str_methods.html /// [`str::trim`] // @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim"]' 'str::trim' /// [`str::to_lowercase`] @@ -13,7 +13,7 @@ // @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.replace"]' 'str::replace' pub fn str_methods() {} -// @has intra_link_primitive_non_default_impl/fn.f32_methods.html +// @has primitive_non_default_impl/fn.f32_methods.html /// [f32::powi] // @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.powi"]' 'f32::powi' /// [f32::sqrt] @@ -22,7 +22,7 @@ pub fn str_methods() {} // @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.mul_add"]' 'f32::mul_add' pub fn f32_methods() {} -// @has intra_link_primitive_non_default_impl/fn.f64_methods.html +// @has primitive_non_default_impl/fn.f64_methods.html /// [`f64::powi`] // @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.powi"]' 'f64::powi' /// [`f64::sqrt`] diff --git a/src/test/rustdoc/intra-link-private.rs b/src/test/rustdoc/intra-doc/private-failures-ignored.rs similarity index 100% rename from src/test/rustdoc/intra-link-private.rs rename to src/test/rustdoc/intra-doc/private-failures-ignored.rs diff --git a/src/test/rustdoc/intra-doc-link-private.rs b/src/test/rustdoc/intra-doc/private.rs similarity index 100% rename from src/test/rustdoc/intra-doc-link-private.rs rename to src/test/rustdoc/intra-doc/private.rs diff --git a/src/test/rustdoc/intra-doc/proc-macro.rs b/src/test/rustdoc/intra-doc/proc-macro.rs new file mode 100644 index 0000000000000..ab4626ccfc3ab --- /dev/null +++ b/src/test/rustdoc/intra-doc/proc-macro.rs @@ -0,0 +1,27 @@ +// aux-build:proc-macro-macro.rs +// build-aux-docs +#![deny(broken_intra_doc_links)] + +extern crate proc_macro_macro; + + +pub use proc_macro_macro::{DeriveA, attr_a}; +use proc_macro_macro::{DeriveB, attr_b}; + +// @has proc_macro/struct.Foo.html +// @has - '//a/@href' '../proc_macro/derive.DeriveA.html' +// @has - '//a/@href' '../proc_macro/attr.attr_a.html' +// @has - '//a/@href' '../proc_macro/trait.DeriveTrait.html' +// @has - '//a/@href' '../proc_macro_macro/derive.DeriveB.html' +// @has - '//a/@href' '../proc_macro_macro/attr.attr_b.html' +/// Link to [DeriveA], [attr_a], [DeriveB], [attr_b], [DeriveTrait] +pub struct Foo; + +// @has proc_macro/struct.Bar.html +// @has - '//a/@href' '../proc_macro/derive.DeriveA.html' +// @has - '//a/@href' '../proc_macro/attr.attr_a.html' +/// Link to [deriveA](derive@DeriveA) [attr](macro@attr_a) +pub struct Bar; + +// this should not cause ambiguity errors +pub trait DeriveTrait {} diff --git a/src/test/rustdoc/intra-link-pub-use.rs b/src/test/rustdoc/intra-doc/pub-use.rs similarity index 100% rename from src/test/rustdoc/intra-link-pub-use.rs rename to src/test/rustdoc/intra-doc/pub-use.rs diff --git a/src/test/rustdoc/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/intra-doc/reexport-additional-docs.rs similarity index 100% rename from src/test/rustdoc/intra-link-reexport-additional-docs.rs rename to src/test/rustdoc/intra-doc/reexport-additional-docs.rs diff --git a/src/test/rustdoc/intra-link-self.rs b/src/test/rustdoc/intra-doc/self.rs similarity index 100% rename from src/test/rustdoc/intra-link-self.rs rename to src/test/rustdoc/intra-doc/self.rs diff --git a/src/test/rustdoc/through-proc-macro.rs b/src/test/rustdoc/intra-doc/through-proc-macro.rs similarity index 100% rename from src/test/rustdoc/through-proc-macro.rs rename to src/test/rustdoc/intra-doc/through-proc-macro.rs diff --git a/src/test/rustdoc/intra-link-trait-impl.rs b/src/test/rustdoc/intra-doc/trait-impl.rs similarity index 100% rename from src/test/rustdoc/intra-link-trait-impl.rs rename to src/test/rustdoc/intra-doc/trait-impl.rs diff --git a/src/test/rustdoc/intra-link-trait-item.rs b/src/test/rustdoc/intra-doc/trait-item.rs similarity index 69% rename from src/test/rustdoc/intra-link-trait-item.rs rename to src/test/rustdoc/intra-doc/trait-item.rs index 54270414c9dfe..de8585f4c9a78 100644 --- a/src/test/rustdoc/intra-link-trait-item.rs +++ b/src/test/rustdoc/intra-doc/trait-item.rs @@ -3,7 +3,7 @@ /// Link to [S::assoc_fn()] /// Link to [Default::default()] -// @has intra_link_trait_item/struct.S.html '//*[@href="../intra_link_trait_item/struct.S.html#method.assoc_fn"]' 'S::assoc_fn()' +// @has trait_item/struct.S.html '//*[@href="../trait_item/struct.S.html#method.assoc_fn"]' 'S::assoc_fn()' // @has - '//*[@href="https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default"]' 'Default::default()' pub struct S; diff --git a/src/test/rustdoc/intra-doc-link-true-false.rs b/src/test/rustdoc/intra-doc/true-false.rs similarity index 100% rename from src/test/rustdoc/intra-doc-link-true-false.rs rename to src/test/rustdoc/intra-doc/true-false.rs diff --git a/src/test/rustdoc/intra-link-associated-defaults.rs b/src/test/rustdoc/intra-link-associated-defaults.rs deleted file mode 100644 index 2051129b948f3..0000000000000 --- a/src/test/rustdoc/intra-link-associated-defaults.rs +++ /dev/null @@ -1,27 +0,0 @@ -// ignore-tidy-linelength -#![deny(intra_doc_link_resolution_failure)] -#![feature(associated_type_defaults)] - -pub trait TraitWithDefault { - type T = usize; - fn f() -> Self::T { - 0 - } -} - -/// Link to [UsesDefaults::T] and [UsesDefaults::f] -// @has 'intra_link_associated_defaults/struct.UsesDefaults.html' '//a[@href="../intra_link_associated_defaults/struct.UsesDefaults.html#associatedtype.T"]' 'UsesDefaults::T' -// @has 'intra_link_associated_defaults/struct.UsesDefaults.html' '//a[@href="../intra_link_associated_defaults/struct.UsesDefaults.html#method.f"]' 'UsesDefaults::f' -pub struct UsesDefaults; -impl TraitWithDefault for UsesDefaults {} - -/// Link to [OverridesDefaults::T] and [OverridesDefaults::f] -// @has 'intra_link_associated_defaults/struct.OverridesDefaults.html' '//a[@href="../intra_link_associated_defaults/struct.OverridesDefaults.html#associatedtype.T"]' 'OverridesDefaults::T' -// @has 'intra_link_associated_defaults/struct.OverridesDefaults.html' '//a[@href="../intra_link_associated_defaults/struct.OverridesDefaults.html#method.f"]' 'OverridesDefaults::f' -pub struct OverridesDefaults; -impl TraitWithDefault for OverridesDefaults { - type T = bool; - fn f() -> bool { - true - } -} diff --git a/src/test/rustdoc/intra-link-associated-items.rs b/src/test/rustdoc/intra-link-associated-items.rs deleted file mode 100644 index daf7075a91740..0000000000000 --- a/src/test/rustdoc/intra-link-associated-items.rs +++ /dev/null @@ -1,61 +0,0 @@ -// ignore-tidy-linelength -#![deny(intra_doc_link_resolution_failure)] - -/// [`std::collections::BTreeMap::into_iter`] -/// [`String::from`] is ambiguous as to which `From` impl -/// [Vec::into_iter()] uses a disambiguator -// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter' -// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from' -// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter' -pub fn foo() {} - -/// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input] -// @has 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_associated_items/struct.MyStruct.html"]' 'MyStruct' -// @has 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_associated_items/struct.MyStruct.html#method.method"]' 'link from struct' -// @has 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_associated_items/struct.MyStruct.html#method.clone"]' 'MyStruct::clone' -// @has 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_associated_items/struct.MyStruct.html#associatedtype.Input"]' 'MyStruct::Input' -pub struct MyStruct { foo: () } - -impl Clone for MyStruct { - fn clone(&self) -> Self { - MyStruct - } -} - -pub trait T { - type Input; - fn method(i: Self::Input); -} - -impl T for MyStruct { - type Input = usize; - - /// [link from method][MyStruct::method] on method - // @has 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_associated_items/struct.MyStruct.html#method.method"]' 'link from method' - fn method(i: usize) { - } -} - -/// Ambiguity between which trait to use -pub trait T1 { - fn ambiguous_method(); -} - -pub trait T2 { - fn ambiguous_method(); -} - -/// Link to [S::ambiguous_method] -// FIXME: there is no way to disambiguate these. -// Since we have `#[deny(intra_doc_failure)]`, we still know it was one or the other. -pub struct S; - -impl T1 for S { - fn ambiguous_method() {} -} - -impl T2 for S { - fn ambiguous_method() {} -} - -fn main() {} diff --git a/src/test/rustdoc/intra-link-disambiguators-removed.rs b/src/test/rustdoc/intra-link-disambiguators-removed.rs deleted file mode 100644 index 26d05b484b919..0000000000000 --- a/src/test/rustdoc/intra-link-disambiguators-removed.rs +++ /dev/null @@ -1,51 +0,0 @@ -// ignore-tidy-linelength -#![deny(intra_doc_link_resolution_failure)] -// first try backticks -/// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`] -// @has intra_link_disambiguators_removed/struct.AtDisambiguator.html -// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"][code]' "Name" -// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name" -// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"][code]' "Name" -pub struct AtDisambiguator; - -/// fn: [`Name()`], macro: [`Name!`] -// @has intra_link_disambiguators_removed/struct.SymbolDisambiguator.html -// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name()" -// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"][code]' "Name!" -pub struct SymbolDisambiguator; - -// Now make sure that backticks aren't added if they weren't already there -/// [fn@Name] -// @has intra_link_disambiguators_removed/trait.Name.html -// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"]' "Name" -// @!has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name" - -// FIXME: this will turn !() into ! alone -/// [Name!()] -// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"]' "Name!" -pub trait Name {} - -#[allow(non_snake_case)] - -// Try collapsed reference links -/// [macro@Name][] -// @has intra_link_disambiguators_removed/fn.Name.html -// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"]' "Name" - -// Try links that have the same text as a generated URL -/// Weird URL aligned [../intra_link_disambiguators_removed/macro.Name.html][trait@Name] -// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"]' "../intra_link_disambiguators_removed/macro.Name.html" -pub fn Name() {} - -#[macro_export] -// Rustdoc doesn't currently handle links that have weird interspersing of inline code blocks. -/// [fn@Na`m`e] -// @has intra_link_disambiguators_removed/macro.Name.html -// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"]' "fn@Name" - -// It also doesn't handle any case where the code block isn't the whole link text: -/// [trait@`Name`] -// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"]' "trait@Name" -macro_rules! Name { - () => () -} diff --git a/src/test/rustdoc/intra-link-extern-type.rs b/src/test/rustdoc/intra-link-extern-type.rs deleted file mode 100644 index 418e0d91ea7ef..0000000000000 --- a/src/test/rustdoc/intra-link-extern-type.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![feature(extern_types)] - -extern { - pub type ExternType; -} - -impl ExternType { - pub fn f(&self) { - - } -} - -// @has 'intra_link_extern_type/foreigntype.ExternType.html' -// @has 'intra_link_extern_type/fn.links_to_extern_type.html' \ -// 'href="../intra_link_extern_type/foreigntype.ExternType.html#method.f"' -/// See also [ExternType::f] -pub fn links_to_extern_type() { -} diff --git a/src/test/rustdoc/intra-link-prim-assoc.rs b/src/test/rustdoc/intra-link-prim-assoc.rs deleted file mode 100644 index c0066885e1991..0000000000000 --- a/src/test/rustdoc/intra-link-prim-assoc.rs +++ /dev/null @@ -1,5 +0,0 @@ -// ignore-tidy-linelength -#![deny(broken_intra_doc_links)] - -//! [i32::MAX] -// @has intra_link_prim_assoc/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX" diff --git a/src/test/rustdoc/intra-link-prim-precedence.rs b/src/test/rustdoc/intra-link-prim-precedence.rs deleted file mode 100644 index 0a4e57ef643e7..0000000000000 --- a/src/test/rustdoc/intra-link-prim-precedence.rs +++ /dev/null @@ -1,17 +0,0 @@ -// ignore-tidy-linelength -#![deny(broken_intra_doc_links)] - -pub mod char { - /// [char] - // @has intra_link_prim_precedence/char/struct.Inner.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html' - pub struct Inner; -} - -/// See [prim@char] -// @has intra_link_prim_precedence/struct.MyString.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html' -pub struct MyString; - -/// See also [crate::char] and [mod@char] -// @has intra_link_prim_precedence/struct.MyString2.html '//*[@href="../intra_link_prim_precedence/char/index.html"]' 'crate::char' -// @has - '//*[@href="../intra_link_prim_precedence/char/index.html"]' 'mod@char' -pub struct MyString2; diff --git a/src/test/rustdoc/intra-link-proc-macro.rs b/src/test/rustdoc/intra-link-proc-macro.rs deleted file mode 100644 index 7a8403255edb6..0000000000000 --- a/src/test/rustdoc/intra-link-proc-macro.rs +++ /dev/null @@ -1,27 +0,0 @@ -// aux-build:intra-link-proc-macro-macro.rs -// build-aux-docs -#![deny(broken_intra_doc_links)] - -extern crate intra_link_proc_macro_macro; - - -pub use intra_link_proc_macro_macro::{DeriveA, attr_a}; -use intra_link_proc_macro_macro::{DeriveB, attr_b}; - -// @has intra_link_proc_macro/struct.Foo.html -// @has - '//a/@href' '../intra_link_proc_macro/derive.DeriveA.html' -// @has - '//a/@href' '../intra_link_proc_macro/attr.attr_a.html' -// @has - '//a/@href' '../intra_link_proc_macro/trait.DeriveTrait.html' -// @has - '//a/@href' '../intra_link_proc_macro_macro/derive.DeriveB.html' -// @has - '//a/@href' '../intra_link_proc_macro_macro/attr.attr_b.html' -/// Link to [DeriveA], [attr_a], [DeriveB], [attr_b], [DeriveTrait] -pub struct Foo; - -// @has intra_link_proc_macro/struct.Bar.html -// @has - '//a/@href' '../intra_link_proc_macro/derive.DeriveA.html' -// @has - '//a/@href' '../intra_link_proc_macro/attr.attr_a.html' -/// Link to [deriveA](derive@DeriveA) [attr](macro@attr_a) -pub struct Bar; - -// this should not cause ambiguity errors -pub trait DeriveTrait {} From 872acb0c3589450a10f6fec97cd1a781e2d17794 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 28 Nov 2020 21:10:37 -0500 Subject: [PATCH 06/18] Move `src/test/rustdoc-ui` intra-doc tests into a subdirectory This also changes the builder to allow using `x.py test src/test/rustdoc-ui/intra-doc`; before, it would panic that no paths were found. --- src/bootstrap/test.rs | 33 +-------------- src/test/rustdoc-ui/.gitattributes | 1 - src/test/rustdoc-ui/intra-doc/.gitattributes | 1 + .../alias-ice.rs} | 0 .../alias-ice.stderr} | 4 +- .../ambiguity.rs} | 0 .../ambiguity.stderr} | 14 +++---- .../anchors.rs} | 0 .../anchors.stderr} | 10 ++--- .../auxiliary/intra-doc-broken.rs | 0 .../broken-reexport.rs} | 0 .../disambiguator-mismatch.rs} | 0 .../disambiguator-mismatch.stderr} | 24 +++++------ .../double-anchor.rs} | 0 .../double-anchor.stderr} | 2 +- .../errors.rs} | 0 .../errors.stderr} | 42 +++++++++---------- .../malformed-generics.rs} | 0 .../malformed-generics.stderr} | 32 +++++++------- .../prim-conflict.rs} | 0 .../prim-conflict.stderr} | 10 ++--- .../private.private.stderr} | 2 +- .../private.public.stderr} | 2 +- .../private.rs} | 0 .../span-ice-55723.rs} | 0 .../span-ice-55723.stderr} | 4 +- .../warning-crlf.rs} | 0 .../warning-crlf.stderr} | 8 ++-- .../warning.rs} | 0 .../warning.stderr} | 38 ++++++++--------- 30 files changed, 98 insertions(+), 129 deletions(-) delete mode 100644 src/test/rustdoc-ui/.gitattributes create mode 100644 src/test/rustdoc-ui/intra-doc/.gitattributes rename src/test/rustdoc-ui/{intra-doc-alias-ice.rs => intra-doc/alias-ice.rs} (100%) rename src/test/rustdoc-ui/{intra-doc-alias-ice.stderr => intra-doc/alias-ice.stderr} (82%) rename src/test/rustdoc-ui/{intra-links-ambiguity.rs => intra-doc/ambiguity.rs} (100%) rename src/test/rustdoc-ui/{intra-links-ambiguity.stderr => intra-doc/ambiguity.stderr} (90%) rename src/test/rustdoc-ui/{intra-links-anchors.rs => intra-doc/anchors.rs} (100%) rename src/test/rustdoc-ui/{intra-links-anchors.stderr => intra-doc/anchors.stderr} (81%) rename src/test/rustdoc-ui/{ => intra-doc}/auxiliary/intra-doc-broken.rs (100%) rename src/test/rustdoc-ui/{intra-doc-broken-reexport.rs => intra-doc/broken-reexport.rs} (100%) rename src/test/rustdoc-ui/{intra-links-disambiguator-mismatch.rs => intra-doc/disambiguator-mismatch.rs} (100%) rename src/test/rustdoc-ui/{intra-links-disambiguator-mismatch.stderr => intra-doc/disambiguator-mismatch.stderr} (80%) rename src/test/rustdoc-ui/{intra-link-double-anchor.rs => intra-doc/double-anchor.rs} (100%) rename src/test/rustdoc-ui/{intra-link-double-anchor.stderr => intra-doc/double-anchor.stderr} (85%) rename src/test/rustdoc-ui/{intra-link-errors.rs => intra-doc/errors.rs} (100%) rename src/test/rustdoc-ui/{intra-link-errors.stderr => intra-doc/errors.stderr} (83%) rename src/test/rustdoc-ui/{intra-link-malformed-generics.rs => intra-doc/malformed-generics.rs} (100%) rename src/test/rustdoc-ui/{intra-link-malformed-generics.stderr => intra-doc/malformed-generics.stderr} (73%) rename src/test/rustdoc-ui/{intra-link-prim-conflict.rs => intra-doc/prim-conflict.rs} (100%) rename src/test/rustdoc-ui/{intra-link-prim-conflict.stderr => intra-doc/prim-conflict.stderr} (84%) rename src/test/rustdoc-ui/{intra-links-private.private.stderr => intra-doc/private.private.stderr} (90%) rename src/test/rustdoc-ui/{intra-links-private.public.stderr => intra-doc/private.public.stderr} (89%) rename src/test/rustdoc-ui/{intra-links-private.rs => intra-doc/private.rs} (100%) rename src/test/rustdoc-ui/{intra-link-span-ice-55723.rs => intra-doc/span-ice-55723.rs} (100%) rename src/test/rustdoc-ui/{intra-link-span-ice-55723.stderr => intra-doc/span-ice-55723.stderr} (79%) rename src/test/rustdoc-ui/{intra-links-warning-crlf.rs => intra-doc/warning-crlf.rs} (100%) rename src/test/rustdoc-ui/{intra-links-warning-crlf.stderr => intra-doc/warning-crlf.stderr} (83%) rename src/test/rustdoc-ui/{intra-links-warning.rs => intra-doc/warning.rs} (100%) rename src/test/rustdoc-ui/{intra-links-warning.stderr => intra-doc/warning.stderr} (86%) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index e087e2b8ff153..dad36640dbf81 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -688,38 +688,6 @@ impl Step for RustdocJSNotStd { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub struct RustdocUi { - pub target: TargetSelection, - pub compiler: Compiler, -} - -impl Step for RustdocUi { - type Output = (); - const DEFAULT: bool = true; - const ONLY_HOSTS: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/test/rustdoc-ui") - } - - fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); - run.builder.ensure(RustdocUi { target: run.target, compiler }); - } - - fn run(self, builder: &Builder<'_>) { - builder.ensure(Compiletest { - compiler: self.compiler, - target: self.target, - mode: "ui", - suite: "rustdoc-ui", - path: "src/test/rustdoc-ui", - compare_mode: None, - }) - } -} - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Tidy; @@ -934,6 +902,7 @@ default_test!(Debuginfo { path: "src/test/debuginfo", mode: "debuginfo", suite: host_test!(UiFullDeps { path: "src/test/ui-fulldeps", mode: "ui", suite: "ui-fulldeps" }); host_test!(Rustdoc { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" }); +host_test!(RustdocUi { path: "src/test/rustdoc-ui", mode: "ui", suite: "rustdoc-ui" }); host_test!(Pretty { path: "src/test/pretty", mode: "pretty", suite: "pretty" }); diff --git a/src/test/rustdoc-ui/.gitattributes b/src/test/rustdoc-ui/.gitattributes deleted file mode 100644 index 2bcabdffb3d93..0000000000000 --- a/src/test/rustdoc-ui/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -intra-links-warning-crlf.rs eol=crlf diff --git a/src/test/rustdoc-ui/intra-doc/.gitattributes b/src/test/rustdoc-ui/intra-doc/.gitattributes new file mode 100644 index 0000000000000..6c125fac52f5e --- /dev/null +++ b/src/test/rustdoc-ui/intra-doc/.gitattributes @@ -0,0 +1 @@ +warning-crlf.rs eol=crlf diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.rs b/src/test/rustdoc-ui/intra-doc/alias-ice.rs similarity index 100% rename from src/test/rustdoc-ui/intra-doc-alias-ice.rs rename to src/test/rustdoc-ui/intra-doc/alias-ice.rs diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc/alias-ice.stderr similarity index 82% rename from src/test/rustdoc-ui/intra-doc-alias-ice.stderr rename to src/test/rustdoc-ui/intra-doc/alias-ice.stderr index 771fc2204f5f8..3db5fad4cfbdc 100644 --- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr +++ b/src/test/rustdoc-ui/intra-doc/alias-ice.stderr @@ -1,11 +1,11 @@ error: unresolved link to `TypeAlias::hoge` - --> $DIR/intra-doc-alias-ice.rs:5:30 + --> $DIR/alias-ice.rs:5:30 | LL | /// [broken cross-reference](TypeAlias::hoge) | ^^^^^^^^^^^^^^^ the type alias `TypeAlias` has no associated item named `hoge` | note: the lint level is defined here - --> $DIR/intra-doc-alias-ice.rs:1:9 + --> $DIR/alias-ice.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.rs b/src/test/rustdoc-ui/intra-doc/ambiguity.rs similarity index 100% rename from src/test/rustdoc-ui/intra-links-ambiguity.rs rename to src/test/rustdoc-ui/intra-doc/ambiguity.rs diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-doc/ambiguity.stderr similarity index 90% rename from src/test/rustdoc-ui/intra-links-ambiguity.stderr rename to src/test/rustdoc-ui/intra-doc/ambiguity.stderr index 936055da01cf7..7e967dc88bcdd 100644 --- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr +++ b/src/test/rustdoc-ui/intra-doc/ambiguity.stderr @@ -1,11 +1,11 @@ error: `true` is both a module and a builtin type - --> $DIR/intra-links-ambiguity.rs:38:6 + --> $DIR/ambiguity.rs:38:6 | LL | /// [true] | ^^^^ ambiguous link | note: the lint level is defined here - --> $DIR/intra-links-ambiguity.rs:1:9 + --> $DIR/ambiguity.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | /// [prim@true] | ^^^^^^^^^ error: `ambiguous` is both a struct and a function - --> $DIR/intra-links-ambiguity.rs:27:6 + --> $DIR/ambiguity.rs:27:6 | LL | /// [`ambiguous`] is ambiguous. | ^^^^^^^^^^^ ambiguous link @@ -34,7 +34,7 @@ LL | /// [`ambiguous()`] is ambiguous. | ^^^^^^^^^^^^^ error: `ambiguous` is both a struct and a function - --> $DIR/intra-links-ambiguity.rs:29:6 + --> $DIR/ambiguity.rs:29:6 | LL | /// [ambiguous] is ambiguous. | ^^^^^^^^^ ambiguous link @@ -49,7 +49,7 @@ LL | /// [ambiguous()] is ambiguous. | ^^^^^^^^^^^ error: `multi_conflict` is a struct, a function, and a macro - --> $DIR/intra-links-ambiguity.rs:31:6 + --> $DIR/ambiguity.rs:31:6 | LL | /// [`multi_conflict`] is a three-way conflict. | ^^^^^^^^^^^^^^^^ ambiguous link @@ -68,7 +68,7 @@ LL | /// [`multi_conflict!`] is a three-way conflict. | ^^^^^^^^^^^^^^^^^ error: `type_and_value` is both a module and a constant - --> $DIR/intra-links-ambiguity.rs:33:16 + --> $DIR/ambiguity.rs:33:16 | LL | /// Ambiguous [type_and_value]. | ^^^^^^^^^^^^^^ ambiguous link @@ -83,7 +83,7 @@ LL | /// Ambiguous [const@type_and_value]. | ^^^^^^^^^^^^^^^^^^^^ error: `foo::bar` is both an enum and a function - --> $DIR/intra-links-ambiguity.rs:35:42 + --> $DIR/ambiguity.rs:35:42 | LL | /// Ambiguous non-implied shortcut link [`foo::bar`]. | ^^^^^^^^^^ ambiguous link diff --git a/src/test/rustdoc-ui/intra-links-anchors.rs b/src/test/rustdoc-ui/intra-doc/anchors.rs similarity index 100% rename from src/test/rustdoc-ui/intra-links-anchors.rs rename to src/test/rustdoc-ui/intra-doc/anchors.rs diff --git a/src/test/rustdoc-ui/intra-links-anchors.stderr b/src/test/rustdoc-ui/intra-doc/anchors.stderr similarity index 81% rename from src/test/rustdoc-ui/intra-links-anchors.stderr rename to src/test/rustdoc-ui/intra-doc/anchors.stderr index 1825a4ad1fa6b..5b272d960d50f 100644 --- a/src/test/rustdoc-ui/intra-links-anchors.stderr +++ b/src/test/rustdoc-ui/intra-doc/anchors.stderr @@ -1,29 +1,29 @@ error: `Foo::f#hola` contains an anchor, but links to fields are already anchored - --> $DIR/intra-links-anchors.rs:25:15 + --> $DIR/anchors.rs:25:15 | LL | /// Or maybe [Foo::f#hola]. | ^^^^^^^^^^^ contains invalid anchor | note: the lint level is defined here - --> $DIR/intra-links-anchors.rs:1:9 + --> $DIR/anchors.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ error: `hello#people#!` contains multiple anchors - --> $DIR/intra-links-anchors.rs:31:28 + --> $DIR/anchors.rs:31:28 | LL | /// Another anchor error: [hello#people#!]. | ^^^^^^^^^^^^^^ contains invalid anchor error: `Enum::A#whatever` contains an anchor, but links to variants are already anchored - --> $DIR/intra-links-anchors.rs:37:28 + --> $DIR/anchors.rs:37:28 | LL | /// Damn enum's variants: [Enum::A#whatever]. | ^^^^^^^^^^^^^^^^ contains invalid anchor error: `u32#hello` contains an anchor, but links to builtin types are already anchored - --> $DIR/intra-links-anchors.rs:43:6 + --> $DIR/anchors.rs:43:6 | LL | /// [u32#hello] | ^^^^^^^^^ contains invalid anchor diff --git a/src/test/rustdoc-ui/auxiliary/intra-doc-broken.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/intra-doc-broken.rs similarity index 100% rename from src/test/rustdoc-ui/auxiliary/intra-doc-broken.rs rename to src/test/rustdoc-ui/intra-doc/auxiliary/intra-doc-broken.rs diff --git a/src/test/rustdoc-ui/intra-doc-broken-reexport.rs b/src/test/rustdoc-ui/intra-doc/broken-reexport.rs similarity index 100% rename from src/test/rustdoc-ui/intra-doc-broken-reexport.rs rename to src/test/rustdoc-ui/intra-doc/broken-reexport.rs diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs similarity index 100% rename from src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs rename to src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr similarity index 80% rename from src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr rename to src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr index 2e732baf6e01e..2f5f3daa29785 100644 --- a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr +++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr @@ -1,18 +1,18 @@ error: incompatible link kind for `S` - --> $DIR/intra-links-disambiguator-mismatch.rs:14:14 + --> $DIR/disambiguator-mismatch.rs:14:14 | LL | /// Link to [struct@S] | ^^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | note: the lint level is defined here - --> $DIR/intra-links-disambiguator-mismatch.rs:1:9 + --> $DIR/disambiguator-mismatch.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ = note: this link resolved to an enum, which is not a struct error: incompatible link kind for `S` - --> $DIR/intra-links-disambiguator-mismatch.rs:19:14 + --> $DIR/disambiguator-mismatch.rs:19:14 | LL | /// Link to [mod@S] | ^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` @@ -20,7 +20,7 @@ LL | /// Link to [mod@S] = note: this link resolved to an enum, which is not a module error: incompatible link kind for `S` - --> $DIR/intra-links-disambiguator-mismatch.rs:24:14 + --> $DIR/disambiguator-mismatch.rs:24:14 | LL | /// Link to [union@S] | ^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` @@ -28,7 +28,7 @@ LL | /// Link to [union@S] = note: this link resolved to an enum, which is not a union error: incompatible link kind for `S` - --> $DIR/intra-links-disambiguator-mismatch.rs:29:14 + --> $DIR/disambiguator-mismatch.rs:29:14 | LL | /// Link to [trait@S] | ^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` @@ -36,7 +36,7 @@ LL | /// Link to [trait@S] = note: this link resolved to an enum, which is not a trait error: incompatible link kind for `T` - --> $DIR/intra-links-disambiguator-mismatch.rs:34:14 + --> $DIR/disambiguator-mismatch.rs:34:14 | LL | /// Link to [struct@T] | ^^^^^^^^ help: to link to the trait, prefix with `trait@`: `trait@T` @@ -44,7 +44,7 @@ LL | /// Link to [struct@T] = note: this link resolved to a trait, which is not a struct error: incompatible link kind for `m` - --> $DIR/intra-links-disambiguator-mismatch.rs:39:14 + --> $DIR/disambiguator-mismatch.rs:39:14 | LL | /// Link to [derive@m] | ^^^^^^^^ help: to link to the macro, add an exclamation mark: `m!` @@ -52,7 +52,7 @@ LL | /// Link to [derive@m] = note: this link resolved to a macro, which is not a derive macro error: incompatible link kind for `s` - --> $DIR/intra-links-disambiguator-mismatch.rs:44:14 + --> $DIR/disambiguator-mismatch.rs:44:14 | LL | /// Link to [const@s] | ^^^^^^^ help: to link to the static, prefix with `static@`: `static@s` @@ -60,7 +60,7 @@ LL | /// Link to [const@s] = note: this link resolved to a static, which is not a constant error: incompatible link kind for `c` - --> $DIR/intra-links-disambiguator-mismatch.rs:49:14 + --> $DIR/disambiguator-mismatch.rs:49:14 | LL | /// Link to [static@c] | ^^^^^^^^ help: to link to the constant, prefix with `const@`: `const@c` @@ -68,7 +68,7 @@ LL | /// Link to [static@c] = note: this link resolved to a constant, which is not a static error: incompatible link kind for `c` - --> $DIR/intra-links-disambiguator-mismatch.rs:54:14 + --> $DIR/disambiguator-mismatch.rs:54:14 | LL | /// Link to [fn@c] | ^^^^ help: to link to the constant, prefix with `const@`: `const@c` @@ -76,7 +76,7 @@ LL | /// Link to [fn@c] = note: this link resolved to a constant, which is not a function error: incompatible link kind for `c` - --> $DIR/intra-links-disambiguator-mismatch.rs:59:14 + --> $DIR/disambiguator-mismatch.rs:59:14 | LL | /// Link to [c()] | ^^^ help: to link to the constant, prefix with `const@`: `const@c` @@ -84,7 +84,7 @@ LL | /// Link to [c()] = note: this link resolved to a constant, which is not a function error: incompatible link kind for `f` - --> $DIR/intra-links-disambiguator-mismatch.rs:64:14 + --> $DIR/disambiguator-mismatch.rs:64:14 | LL | /// Link to [const@f] | ^^^^^^^ help: to link to the function, add parentheses: `f()` diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.rs b/src/test/rustdoc-ui/intra-doc/double-anchor.rs similarity index 100% rename from src/test/rustdoc-ui/intra-link-double-anchor.rs rename to src/test/rustdoc-ui/intra-doc/double-anchor.rs diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.stderr b/src/test/rustdoc-ui/intra-doc/double-anchor.stderr similarity index 85% rename from src/test/rustdoc-ui/intra-link-double-anchor.stderr rename to src/test/rustdoc-ui/intra-doc/double-anchor.stderr index 3282ec8b79379..1cd9231eded4d 100644 --- a/src/test/rustdoc-ui/intra-link-double-anchor.stderr +++ b/src/test/rustdoc-ui/intra-doc/double-anchor.stderr @@ -1,5 +1,5 @@ warning: `with#anchor#error` contains multiple anchors - --> $DIR/intra-link-double-anchor.rs:5:18 + --> $DIR/double-anchor.rs:5:18 | LL | /// docs [label][with#anchor#error] | ^^^^^^^^^^^^^^^^^ contains invalid anchor diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-doc/errors.rs similarity index 100% rename from src/test/rustdoc-ui/intra-link-errors.rs rename to src/test/rustdoc-ui/intra-doc/errors.rs diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-doc/errors.stderr similarity index 83% rename from src/test/rustdoc-ui/intra-link-errors.stderr rename to src/test/rustdoc-ui/intra-doc/errors.stderr index be98cac94ece7..21c806108e3af 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-doc/errors.stderr @@ -1,95 +1,95 @@ error: unresolved link to `path::to::nonexistent::module` - --> $DIR/intra-link-errors.rs:7:6 + --> $DIR/errors.rs:7:6 | LL | /// [path::to::nonexistent::module] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope | note: the lint level is defined here - --> $DIR/intra-link-errors.rs:1:9 + --> $DIR/errors.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ error: unresolved link to `path::to::nonexistent::macro` - --> $DIR/intra-link-errors.rs:11:6 + --> $DIR/errors.rs:11:6 | LL | /// [path::to::nonexistent::macro!] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope error: unresolved link to `path::to::nonexistent::type` - --> $DIR/intra-link-errors.rs:15:6 + --> $DIR/errors.rs:15:6 | LL | /// [type@path::to::nonexistent::type] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope error: unresolved link to `std::io::not::here` - --> $DIR/intra-link-errors.rs:19:6 + --> $DIR/errors.rs:19:6 | LL | /// [std::io::not::here] | ^^^^^^^^^^^^^^^^^^ no item named `not` in module `io` error: unresolved link to `std::io::not::here` - --> $DIR/intra-link-errors.rs:23:6 + --> $DIR/errors.rs:23:6 | LL | /// [type@std::io::not::here] | ^^^^^^^^^^^^^^^^^^^^^^^ no item named `not` in module `io` error: unresolved link to `std::io::Error::x` - --> $DIR/intra-link-errors.rs:27:6 + --> $DIR/errors.rs:27:6 | LL | /// [std::io::Error::x] | ^^^^^^^^^^^^^^^^^ the struct `Error` has no field or associated item named `x` error: unresolved link to `std::io::ErrorKind::x` - --> $DIR/intra-link-errors.rs:31:6 + --> $DIR/errors.rs:31:6 | LL | /// [std::io::ErrorKind::x] | ^^^^^^^^^^^^^^^^^^^^^ the enum `ErrorKind` has no variant or associated item named `x` error: unresolved link to `f::A` - --> $DIR/intra-link-errors.rs:35:6 + --> $DIR/errors.rs:35:6 | LL | /// [f::A] | ^^^^ `f` is a function, not a module or type, and cannot have associated items error: unresolved link to `f::A` - --> $DIR/intra-link-errors.rs:39:6 + --> $DIR/errors.rs:39:6 | LL | /// [f::A!] | ^^^^^ `f` is a function, not a module or type, and cannot have associated items error: unresolved link to `S::A` - --> $DIR/intra-link-errors.rs:43:6 + --> $DIR/errors.rs:43:6 | LL | /// [S::A] | ^^^^ the struct `S` has no field or associated item named `A` error: unresolved link to `S::fmt` - --> $DIR/intra-link-errors.rs:47:6 + --> $DIR/errors.rs:47:6 | LL | /// [S::fmt] | ^^^^^^ the struct `S` has no field or associated item named `fmt` error: unresolved link to `E::D` - --> $DIR/intra-link-errors.rs:51:6 + --> $DIR/errors.rs:51:6 | LL | /// [E::D] | ^^^^ the enum `E` has no variant or associated item named `D` error: unresolved link to `u8::not_found` - --> $DIR/intra-link-errors.rs:55:6 + --> $DIR/errors.rs:55:6 | LL | /// [u8::not_found] | ^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found` error: unresolved link to `std::primitive::u8::not_found` - --> $DIR/intra-link-errors.rs:59:6 + --> $DIR/errors.rs:59:6 | LL | /// [std::primitive::u8::not_found] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found` error: unresolved link to `Vec::into_iter` - --> $DIR/intra-link-errors.rs:63:6 + --> $DIR/errors.rs:63:6 | LL | /// [type@Vec::into_iter] | ^^^^^^^^^^^^^^^^^^^ @@ -98,7 +98,7 @@ LL | /// [type@Vec::into_iter] | help: to link to the associated function, add parentheses: `Vec::into_iter()` error: unresolved link to `S` - --> $DIR/intra-link-errors.rs:68:6 + --> $DIR/errors.rs:68:6 | LL | /// [S!] | ^^ @@ -107,7 +107,7 @@ LL | /// [S!] | help: to link to the struct, prefix with `struct@`: `struct@S` error: unresolved link to `S::h` - --> $DIR/intra-link-errors.rs:78:6 + --> $DIR/errors.rs:78:6 | LL | /// [type@S::h] | ^^^^^^^^^ @@ -116,7 +116,7 @@ LL | /// [type@S::h] | help: to link to the associated function, add parentheses: `S::h()` error: unresolved link to `T::g` - --> $DIR/intra-link-errors.rs:86:6 + --> $DIR/errors.rs:86:6 | LL | /// [type@T::g] | ^^^^^^^^^ @@ -125,13 +125,13 @@ LL | /// [type@T::g] | help: to link to the associated function, add parentheses: `T::g()` error: unresolved link to `T::h` - --> $DIR/intra-link-errors.rs:91:6 + --> $DIR/errors.rs:91:6 | LL | /// [T::h!] | ^^^^^ the trait `T` has no macro named `h` error: unresolved link to `m` - --> $DIR/intra-link-errors.rs:98:6 + --> $DIR/errors.rs:98:6 | LL | /// [m()] | ^^^ diff --git a/src/test/rustdoc-ui/intra-link-malformed-generics.rs b/src/test/rustdoc-ui/intra-doc/malformed-generics.rs similarity index 100% rename from src/test/rustdoc-ui/intra-link-malformed-generics.rs rename to src/test/rustdoc-ui/intra-doc/malformed-generics.rs diff --git a/src/test/rustdoc-ui/intra-link-malformed-generics.stderr b/src/test/rustdoc-ui/intra-doc/malformed-generics.stderr similarity index 73% rename from src/test/rustdoc-ui/intra-link-malformed-generics.stderr rename to src/test/rustdoc-ui/intra-doc/malformed-generics.stderr index fe5d4cd1bbffa..2e1b22807bc39 100644 --- a/src/test/rustdoc-ui/intra-link-malformed-generics.stderr +++ b/src/test/rustdoc-ui/intra-doc/malformed-generics.stderr @@ -1,89 +1,89 @@ error: unresolved link to `Vec<` - --> $DIR/intra-link-malformed-generics.rs:3:6 + --> $DIR/malformed-generics.rs:3:6 | LL | //! [Vec<] | ^^^^ unbalanced angle brackets | note: the lint level is defined here - --> $DIR/intra-link-malformed-generics.rs:1:9 + --> $DIR/malformed-generics.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ error: unresolved link to `Vec $DIR/intra-link-malformed-generics.rs:4:6 + --> $DIR/malformed-generics.rs:4:6 | LL | //! [Vec` - --> $DIR/intra-link-malformed-generics.rs:5:6 + --> $DIR/malformed-generics.rs:5:6 | LL | //! [Vec] | ^^^^^^^^^^ unbalanced angle brackets error: unresolved link to `Vec>>` - --> $DIR/intra-link-malformed-generics.rs:6:6 + --> $DIR/malformed-generics.rs:6:6 | LL | //! [Vec>>] | ^^^^^^^^^^^^ unbalanced angle brackets error: unresolved link to `Vec>>` - --> $DIR/intra-link-malformed-generics.rs:7:6 + --> $DIR/malformed-generics.rs:7:6 | LL | //! [Vec>>] | ^^^^^^^^ unbalanced angle brackets error: unresolved link to ` $DIR/intra-link-malformed-generics.rs:8:6 + --> $DIR/malformed-generics.rs:8:6 | LL | //! [ $DIR/intra-link-malformed-generics.rs:9:6 + --> $DIR/malformed-generics.rs:9:6 | LL | //! [Vec::<] | ^^^^^^ unbalanced angle brackets error: unresolved link to `` - --> $DIR/intra-link-malformed-generics.rs:10:6 + --> $DIR/malformed-generics.rs:10:6 | LL | //! [] | ^^^ missing type for generic parameters error: unresolved link to `` - --> $DIR/intra-link-malformed-generics.rs:11:6 + --> $DIR/malformed-generics.rs:11:6 | LL | //! [] | ^^^^^^^^^^^^^^^^ missing type for generic parameters error: unresolved link to `Vec::new` - --> $DIR/intra-link-malformed-generics.rs:12:6 + --> $DIR/malformed-generics.rs:12:6 | LL | //! [Vec::new()] | ^^^^^^^^^^^^^ has invalid path separator error: unresolved link to `Vec<>` - --> $DIR/intra-link-malformed-generics.rs:13:6 + --> $DIR/malformed-generics.rs:13:6 | LL | //! [Vec<>] | ^^^^^^^^ too many angle brackets error: unresolved link to `Vec<>` - --> $DIR/intra-link-malformed-generics.rs:14:6 + --> $DIR/malformed-generics.rs:14:6 | LL | //! [Vec<>] | ^^^^^ empty angle brackets error: unresolved link to `Vec<<>>` - --> $DIR/intra-link-malformed-generics.rs:15:6 + --> $DIR/malformed-generics.rs:15:6 | LL | //! [Vec<<>>] | ^^^^^^^ too many angle brackets error: unresolved link to `::into_iter` - --> $DIR/intra-link-malformed-generics.rs:18:6 + --> $DIR/malformed-generics.rs:18:6 | LL | //! [::into_iter] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported @@ -91,7 +91,7 @@ LL | //! [::into_iter] = note: see https://github.com/rust-lang/rust/issues/74563 for more information error: unresolved link to ` as IntoIterator>::iter` - --> $DIR/intra-link-malformed-generics.rs:19:6 + --> $DIR/malformed-generics.rs:19:6 | LL | //! [ as IntoIterator>::iter] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.rs b/src/test/rustdoc-ui/intra-doc/prim-conflict.rs similarity index 100% rename from src/test/rustdoc-ui/intra-link-prim-conflict.rs rename to src/test/rustdoc-ui/intra-doc/prim-conflict.rs diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.stderr b/src/test/rustdoc-ui/intra-doc/prim-conflict.stderr similarity index 84% rename from src/test/rustdoc-ui/intra-link-prim-conflict.stderr rename to src/test/rustdoc-ui/intra-doc/prim-conflict.stderr index 43587a80021af..01275f8d9afb0 100644 --- a/src/test/rustdoc-ui/intra-link-prim-conflict.stderr +++ b/src/test/rustdoc-ui/intra-doc/prim-conflict.stderr @@ -1,11 +1,11 @@ error: `char` is both a module and a builtin type - --> $DIR/intra-link-prim-conflict.rs:4:6 + --> $DIR/prim-conflict.rs:4:6 | LL | /// [char] | ^^^^ ambiguous link | note: the lint level is defined here - --> $DIR/intra-link-prim-conflict.rs:1:9 + --> $DIR/prim-conflict.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | /// [prim@char] | ^^^^^^^^^ error: `char` is both a module and a builtin type - --> $DIR/intra-link-prim-conflict.rs:10:6 + --> $DIR/prim-conflict.rs:10:6 | LL | /// [type@char] | ^^^^^^^^^ ambiguous link @@ -34,7 +34,7 @@ LL | /// [prim@char] | ^^^^^^^^^ error: incompatible link kind for `char` - --> $DIR/intra-link-prim-conflict.rs:19:6 + --> $DIR/prim-conflict.rs:19:6 | LL | /// [struct@char] | ^^^^^^^^^^^ help: to link to the module, prefix with `mod@`: `mod@char` @@ -42,7 +42,7 @@ LL | /// [struct@char] = note: this link resolved to a module, which is not a struct error: incompatible link kind for `char` - --> $DIR/intra-link-prim-conflict.rs:26:10 + --> $DIR/prim-conflict.rs:26:10 | LL | //! [struct@char] | ^^^^^^^^^^^ help: to link to the builtin type, prefix with `prim@`: `prim@char` diff --git a/src/test/rustdoc-ui/intra-links-private.private.stderr b/src/test/rustdoc-ui/intra-doc/private.private.stderr similarity index 90% rename from src/test/rustdoc-ui/intra-links-private.private.stderr rename to src/test/rustdoc-ui/intra-doc/private.private.stderr index eeef24b479747..6e11ec3e87bf9 100644 --- a/src/test/rustdoc-ui/intra-links-private.private.stderr +++ b/src/test/rustdoc-ui/intra-doc/private.private.stderr @@ -1,5 +1,5 @@ warning: public documentation for `DocMe` links to private item `DontDocMe` - --> $DIR/intra-links-private.rs:5:11 + --> $DIR/private.rs:5:11 | LL | /// docs [DontDocMe] | ^^^^^^^^^ this item is private diff --git a/src/test/rustdoc-ui/intra-links-private.public.stderr b/src/test/rustdoc-ui/intra-doc/private.public.stderr similarity index 89% rename from src/test/rustdoc-ui/intra-links-private.public.stderr rename to src/test/rustdoc-ui/intra-doc/private.public.stderr index 3f7b17586f19e..3a6a4b664522a 100644 --- a/src/test/rustdoc-ui/intra-links-private.public.stderr +++ b/src/test/rustdoc-ui/intra-doc/private.public.stderr @@ -1,5 +1,5 @@ warning: public documentation for `DocMe` links to private item `DontDocMe` - --> $DIR/intra-links-private.rs:5:11 + --> $DIR/private.rs:5:11 | LL | /// docs [DontDocMe] | ^^^^^^^^^ this item is private diff --git a/src/test/rustdoc-ui/intra-links-private.rs b/src/test/rustdoc-ui/intra-doc/private.rs similarity index 100% rename from src/test/rustdoc-ui/intra-links-private.rs rename to src/test/rustdoc-ui/intra-doc/private.rs diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.rs b/src/test/rustdoc-ui/intra-doc/span-ice-55723.rs similarity index 100% rename from src/test/rustdoc-ui/intra-link-span-ice-55723.rs rename to src/test/rustdoc-ui/intra-doc/span-ice-55723.rs diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr similarity index 79% rename from src/test/rustdoc-ui/intra-link-span-ice-55723.stderr rename to src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr index d8afa9e7efd59..10ca14e850fd7 100644 --- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr +++ b/src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr @@ -1,11 +1,11 @@ error: unresolved link to `i` - --> $DIR/intra-link-span-ice-55723.rs:9:10 + --> $DIR/span-ice-55723.rs:9:10 | LL | /// (arr[i]) | ^ no item named `i` in scope | note: the lint level is defined here - --> $DIR/intra-link-span-ice-55723.rs:1:9 + --> $DIR/span-ice-55723.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.rs b/src/test/rustdoc-ui/intra-doc/warning-crlf.rs similarity index 100% rename from src/test/rustdoc-ui/intra-links-warning-crlf.rs rename to src/test/rustdoc-ui/intra-doc/warning-crlf.rs diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr b/src/test/rustdoc-ui/intra-doc/warning-crlf.stderr similarity index 83% rename from src/test/rustdoc-ui/intra-links-warning-crlf.stderr rename to src/test/rustdoc-ui/intra-doc/warning-crlf.stderr index 67c48378fd2f4..01e4282003766 100644 --- a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr +++ b/src/test/rustdoc-ui/intra-doc/warning-crlf.stderr @@ -1,5 +1,5 @@ warning: unresolved link to `error` - --> $DIR/intra-links-warning-crlf.rs:7:6 + --> $DIR/warning-crlf.rs:7:6 | LL | /// [error] | ^^^^^ no item named `error` in scope @@ -8,7 +8,7 @@ LL | /// [error] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error1` - --> $DIR/intra-links-warning-crlf.rs:12:11 + --> $DIR/warning-crlf.rs:12:11 | LL | /// docs [error1] | ^^^^^^ no item named `error1` in scope @@ -16,7 +16,7 @@ LL | /// docs [error1] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error2` - --> $DIR/intra-links-warning-crlf.rs:15:11 + --> $DIR/warning-crlf.rs:15:11 | LL | /// docs [error2] | ^^^^^^ no item named `error2` in scope @@ -24,7 +24,7 @@ LL | /// docs [error2] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` - --> $DIR/intra-links-warning-crlf.rs:23:20 + --> $DIR/warning-crlf.rs:23:20 | LL | * It also has an [error]. | ^^^^^ no item named `error` in scope diff --git a/src/test/rustdoc-ui/intra-links-warning.rs b/src/test/rustdoc-ui/intra-doc/warning.rs similarity index 100% rename from src/test/rustdoc-ui/intra-links-warning.rs rename to src/test/rustdoc-ui/intra-doc/warning.rs diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-doc/warning.stderr similarity index 86% rename from src/test/rustdoc-ui/intra-links-warning.stderr rename to src/test/rustdoc-ui/intra-doc/warning.stderr index 0b074e9d53e3d..430d18165a005 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-doc/warning.stderr @@ -1,5 +1,5 @@ warning: unresolved link to `Foo::baz` - --> $DIR/intra-links-warning.rs:3:23 + --> $DIR/warning.rs:3:23 | LL | //! Test with [Foo::baz], [Bar::foo], ... | ^^^^^^^^ the struct `Foo` has no field or associated item named `baz` @@ -7,37 +7,37 @@ LL | //! Test with [Foo::baz], [Bar::foo], ... = note: `#[warn(broken_intra_doc_links)]` on by default warning: unresolved link to `Bar::foo` - --> $DIR/intra-links-warning.rs:3:35 + --> $DIR/warning.rs:3:35 | LL | //! Test with [Foo::baz], [Bar::foo], ... | ^^^^^^^^ no item named `Bar` in scope warning: unresolved link to `Uniooon::X` - --> $DIR/intra-links-warning.rs:6:13 + --> $DIR/warning.rs:6:13 | LL | //! , [Uniooon::X] and [Qux::Z]. | ^^^^^^^^^^ no item named `Uniooon` in scope warning: unresolved link to `Qux::Z` - --> $DIR/intra-links-warning.rs:6:30 + --> $DIR/warning.rs:6:30 | LL | //! , [Uniooon::X] and [Qux::Z]. | ^^^^^^ no item named `Qux` in scope warning: unresolved link to `Uniooon::X` - --> $DIR/intra-links-warning.rs:10:14 + --> $DIR/warning.rs:10:14 | LL | //! , [Uniooon::X] and [Qux::Z]. | ^^^^^^^^^^ no item named `Uniooon` in scope warning: unresolved link to `Qux::Z` - --> $DIR/intra-links-warning.rs:10:31 + --> $DIR/warning.rs:10:31 | LL | //! , [Uniooon::X] and [Qux::Z]. | ^^^^^^ no item named `Qux` in scope warning: unresolved link to `Qux:Y` - --> $DIR/intra-links-warning.rs:14:13 + --> $DIR/warning.rs:14:13 | LL | /// [Qux:Y] | ^^^^^ no item named `Qux:Y` in scope @@ -45,7 +45,7 @@ LL | /// [Qux:Y] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarA` - --> $DIR/intra-links-warning.rs:21:10 + --> $DIR/warning.rs:21:10 | LL | /// bar [BarA] bar | ^^^^ no item named `BarA` in scope @@ -53,7 +53,7 @@ LL | /// bar [BarA] bar = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarB` - --> $DIR/intra-links-warning.rs:27:9 + --> $DIR/warning.rs:27:9 | LL | * bar [BarB] bar | ^^^^ no item named `BarB` in scope @@ -61,7 +61,7 @@ LL | * bar [BarB] bar = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarC` - --> $DIR/intra-links-warning.rs:34:6 + --> $DIR/warning.rs:34:6 | LL | bar [BarC] bar | ^^^^ no item named `BarC` in scope @@ -69,7 +69,7 @@ LL | bar [BarC] bar = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarD` - --> $DIR/intra-links-warning.rs:45:1 + --> $DIR/warning.rs:45:1 | LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarF` - --> $DIR/intra-links-warning.rs:50:9 + --> $DIR/warning.rs:50:9 | LL | #[doc = $f] | ^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | f!("Foo\nbar [BarF] bar\nbaz"); = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: unresolved link to `error` - --> $DIR/intra-links-warning.rs:58:30 + --> $DIR/warning.rs:58:30 | LL | * time to introduce a link [error]*/ | ^^^^^ no item named `error` in scope @@ -107,7 +107,7 @@ LL | * time to introduce a link [error]*/ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` - --> $DIR/intra-links-warning.rs:64:30 + --> $DIR/warning.rs:64:30 | LL | * time to introduce a link [error] | ^^^^^ no item named `error` in scope @@ -115,7 +115,7 @@ LL | * time to introduce a link [error] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` - --> $DIR/intra-links-warning.rs:68:1 + --> $DIR/warning.rs:68:1 | LL | #[doc = "single line [error]"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -128,7 +128,7 @@ LL | #[doc = "single line [error]"] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` - --> $DIR/intra-links-warning.rs:71:1 + --> $DIR/warning.rs:71:1 | LL | #[doc = "single line with \"escaping\" [error]"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -141,7 +141,7 @@ LL | #[doc = "single line with \"escaping\" [error]"] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` - --> $DIR/intra-links-warning.rs:74:1 + --> $DIR/warning.rs:74:1 | LL | / /// Item docs. LL | | #[doc="Hello there!"] @@ -156,7 +156,7 @@ LL | | /// [error] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error1` - --> $DIR/intra-links-warning.rs:80:11 + --> $DIR/warning.rs:80:11 | LL | /// docs [error1] | ^^^^^^ no item named `error1` in scope @@ -164,7 +164,7 @@ LL | /// docs [error1] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error2` - --> $DIR/intra-links-warning.rs:82:11 + --> $DIR/warning.rs:82:11 | LL | /// docs [error2] | ^^^^^^ no item named `error2` in scope From 228510b0ec9447df6ee84450f8e3fc9b5a018745 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 28 Nov 2020 13:35:36 -0800 Subject: [PATCH 07/18] lint-docs: Add some extra detail to the error message. This will hopefully help users figure out what was wrong and how to fix it. --- src/tools/lint-docs/src/main.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs index 922e70402f274..2055fed2b480c 100644 --- a/src/tools/lint-docs/src/main.rs +++ b/src/tools/lint-docs/src/main.rs @@ -4,6 +4,19 @@ use std::path::PathBuf; fn main() { if let Err(e) = doit() { eprintln!("error: {}", e); + eprintln!( + " +This error was generated by the lint-docs tool. +This tool extracts documentation for lints from the source code and places +them in the rustc book. See the declare_lint! documentation +https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/macro.declare_lint.html +for an example of the format of documentation this tool expects. + +To re-run these tests, run: ./x.py test --keep-stage=0 src/tools/lint-docs +The --keep-stage flag should be used if you have already built the compiler +and are only modifying the doc comments to avoid rebuilding the compiler. +" + ); std::process::exit(1); } } From a90fdfc70178038599bfc7247aedc83bfe2e88f0 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 29 Nov 2020 07:57:55 -0800 Subject: [PATCH 08/18] lint-docs: Use strip-prefix to simplify. --- src/tools/lint-docs/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index dc878b718ad60..326b794809854 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -142,8 +142,8 @@ impl<'a> LintExtractor<'a> { match lines.next() { Some((lineno, line)) => { let line = line.trim(); - if line.starts_with("/// ") { - doc_lines.push(line.trim()[4..].to_string()); + if let Some(text) = line.strip_prefix("/// ") { + doc_lines.push(text.trim().to_string()); } else if line.starts_with("///") { doc_lines.push("".to_string()); } else if line.starts_with("// ") { @@ -347,8 +347,7 @@ impl<'a> LintExtractor<'a> { let mut source = String::new(); let needs_main = !example.iter().any(|line| line.contains("fn main")); // Remove `# ` prefix for hidden lines. - let unhidden = - example.iter().map(|line| if line.starts_with("# ") { &line[2..] } else { line }); + let unhidden = example.iter().map(|line| line.strip_prefix("# ").unwrap_or(line)); let mut lines = unhidden.peekable(); while let Some(line) = lines.peek() { if line.starts_with("#!") { From 95a6427d2c4d4ad53931d1f7e8932a61ba0e9601 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 28 Nov 2020 19:19:41 -0500 Subject: [PATCH 09/18] Add -Z normalize-docs and enable it for compiler docs --- compiler/rustc_session/src/options.rs | 2 ++ src/bootstrap/builder.rs | 1 + src/bootstrap/doc.rs | 1 + src/librustdoc/clean/mod.rs | 7 +++++-- src/test/rustdoc/normalize-assoc-item.rs | 2 +- 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index b438be0696ac1..66c709b408098 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -996,6 +996,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"), no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED], "prevent automatic injection of the profiler_builtins crate"), + normalize_docs: bool = (false, parse_bool, [TRACKED], + "normalize associated items in rustdoc when generating documentation"), osx_rpath_install_name: bool = (false, parse_bool, [TRACKED], "pass `-install_name @rpath/...` to the macOS linker (default: no)"), panic_abort_tests: bool = (false, parse_bool, [TRACKED], diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 508d785834fce..4e84e3ea59b38 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -730,6 +730,7 @@ impl<'a> Builder<'a> { .env("CFG_RELEASE_CHANNEL", &self.config.channel) .env("RUSTDOC_REAL", self.rustdoc(compiler)) .env("RUSTC_BOOTSTRAP", "1") + .arg("-Znormalize_docs") .arg("-Winvalid_codeblock_attributes"); if self.config.deny_warnings { cmd.arg("-Dwarnings"); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index af7f7eff89418..919c3a8b5749b 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -527,6 +527,7 @@ impl Step for Rustc { cargo.rustdocflag("--document-private-items"); cargo.rustdocflag("--enable-index-page"); cargo.rustdocflag("-Zunstable-options"); + cargo.rustdocflag("-Znormalize-docs"); compile::rustc_cargo(builder, &mut cargo, target); // Only include compiler crates, no dependencies of those, such as `libc`. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 13643fbf3d3fb..a136e69f9a617 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1503,9 +1503,12 @@ impl Clean for hir::Ty<'_> { } /// Returns `None` if the type could not be normalized -#[allow(unreachable_code, unused_variables)] fn normalize(cx: &DocContext<'tcx>, ty: Ty<'_>) -> Option> { - return None; // HACK: low-churn fix for #79459 while we wait for a trait normalization fix + // HACK: low-churn fix for #79459 while we wait for a trait normalization fix + if !cx.tcx.sess.opts.debugging_opts.normalize_docs { + return None; + } + use crate::rustc_trait_selection::infer::TyCtxtInferExt; use crate::rustc_trait_selection::traits::query::normalize::AtExt; use rustc_middle::traits::ObligationCause; diff --git a/src/test/rustdoc/normalize-assoc-item.rs b/src/test/rustdoc/normalize-assoc-item.rs index 70b3c66fd2b86..ad1a868ee32b8 100644 --- a/src/test/rustdoc/normalize-assoc-item.rs +++ b/src/test/rustdoc/normalize-assoc-item.rs @@ -1,7 +1,7 @@ // ignore-tidy-linelength // aux-build:normalize-assoc-item.rs // build-aux-docs -// ignore-test +// compile-flags:-Znormalize-docs pub trait Trait { type X; From be554c4101df2a9ac65d40962ee37ece85d517bf Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 22 Nov 2020 09:08:04 +0100 Subject: [PATCH 10/18] Make ui test that are run-pass and do not test the compiler itself library tests --- library/alloc/tests/str.rs | 96 +++++++- library/core/tests/ascii.rs | 53 ++++ library/core/tests/atomic.rs | 79 ++++++ library/core/tests/bool.rs | 84 +++++++ library/core/tests/cmp.rs | 71 ++++++ library/core/tests/iter.rs | 12 + library/core/tests/lib.rs | 4 + library/core/tests/macros.rs | 14 ++ library/core/tests/num/wrapping.rs | 233 ++++++++++++++++++ library/core/tests/ops.rs | 33 +++ library/core/tests/option.rs | 10 + library/core/tests/ptr.rs | 13 + library/core/tests/result.rs | 38 +++ library/core/tests/unicode.rs | 5 + library/std/tests/env.rs | 61 +++++ .../sleep.rs => library/std/tests/thread.rs | 15 +- src/test/ui/assert-eq-trailing-comma.rs | 5 - src/test/ui/assert-escape.rs | 5 - src/test/ui/assert-ne-trailing-comma.rs | 5 - src/test/ui/atomic-access-bool.rs | 24 -- src/test/ui/atomic-alignment.rs | 38 --- src/test/ui/atomic-compare_exchange.rs | 31 --- src/test/ui/bool-not.rs | 6 - src/test/ui/bool.rs | 72 ------ src/test/ui/char_unicode.rs | 10 - src/test/ui/cmp-default.rs | 73 ------ src/test/ui/consts/ascii_ctype.rs | 53 ---- src/test/ui/consts/const-str-ptr.rs | 17 -- src/test/ui/deref-mut-on-ref.rs | 15 -- src/test/ui/deref-on-ref.rs | 19 -- src/test/ui/env-home-dir.rs | 50 ---- src/test/ui/extend-for-unit.rs | 12 - src/test/ui/offset_from.rs | 13 - src/test/ui/option-ext.rs | 10 - src/test/ui/result-opt-conversions.rs | 47 ---- src/test/ui/utf8.rs | 50 ---- src/test/ui/utf8_chars.rs | 31 --- src/test/ui/wrapping-int-api.rs | 225 ----------------- 38 files changed, 812 insertions(+), 820 deletions(-) create mode 100644 library/core/tests/macros.rs create mode 100644 library/core/tests/unicode.rs rename src/test/ui/sleep.rs => library/std/tests/thread.rs (60%) delete mode 100644 src/test/ui/assert-eq-trailing-comma.rs delete mode 100644 src/test/ui/assert-escape.rs delete mode 100644 src/test/ui/assert-ne-trailing-comma.rs delete mode 100644 src/test/ui/atomic-access-bool.rs delete mode 100644 src/test/ui/atomic-alignment.rs delete mode 100644 src/test/ui/atomic-compare_exchange.rs delete mode 100644 src/test/ui/bool-not.rs delete mode 100644 src/test/ui/bool.rs delete mode 100644 src/test/ui/char_unicode.rs delete mode 100644 src/test/ui/cmp-default.rs delete mode 100644 src/test/ui/consts/ascii_ctype.rs delete mode 100644 src/test/ui/consts/const-str-ptr.rs delete mode 100644 src/test/ui/deref-mut-on-ref.rs delete mode 100644 src/test/ui/deref-on-ref.rs delete mode 100644 src/test/ui/env-home-dir.rs delete mode 100644 src/test/ui/extend-for-unit.rs delete mode 100644 src/test/ui/offset_from.rs delete mode 100644 src/test/ui/option-ext.rs delete mode 100644 src/test/ui/result-opt-conversions.rs delete mode 100644 src/test/ui/utf8.rs delete mode 100644 src/test/ui/utf8_chars.rs delete mode 100644 src/test/ui/wrapping-int-api.rs diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 834dd4656ff76..b13019146568c 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; use std::cmp::Ordering::{Equal, Greater, Less}; -use std::str::from_utf8; +use std::str::{from_utf8, from_utf8_unchecked}; #[test] fn test_le() { @@ -1971,3 +1971,97 @@ fn test_str_escapes() { "; assert_eq!(x, r"\\"); // extraneous whitespace stripped } + +#[test] +fn const_str_ptr() { + const A: [u8; 2] = ['h' as u8, 'i' as u8]; + const B: &'static [u8; 2] = &A; + const C: *const u8 = B as *const u8; + + unsafe { + let foo = &A as *const u8; + assert_eq!(foo, C); + assert_eq!(from_utf8_unchecked(&A), "hi"); + assert_eq!(*C, A[0]); + assert_eq!(*(&B[0] as *const u8), A[0]); + } +} + +#[test] +fn utf8() { + let yen: char = '¥'; // 0xa5 + let c_cedilla: char = 'ç'; // 0xe7 + let thorn: char = 'þ'; // 0xfe + let y_diaeresis: char = 'ÿ'; // 0xff + let pi: char = 'Π'; // 0x3a0 + + assert_eq!(yen as isize, 0xa5); + assert_eq!(c_cedilla as isize, 0xe7); + assert_eq!(thorn as isize, 0xfe); + assert_eq!(y_diaeresis as isize, 0xff); + assert_eq!(pi as isize, 0x3a0); + + assert_eq!(pi as isize, '\u{3a0}' as isize); + assert_eq!('\x0a' as isize, '\n' as isize); + + let bhutan: String = "འབྲུག་ཡུལ།".to_string(); + let japan: String = "日本".to_string(); + let uzbekistan: String = "Ўзбекистон".to_string(); + let austria: String = "Österreich".to_string(); + + let bhutan_e: String = + "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string(); + let japan_e: String = "\u{65e5}\u{672c}".to_string(); + let uzbekistan_e: String = + "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string(); + let austria_e: String = "\u{d6}sterreich".to_string(); + + let oo: char = 'Ö'; + assert_eq!(oo as isize, 0xd6); + + fn check_str_eq(a: String, b: String) { + let mut i: isize = 0; + for ab in a.bytes() { + println!("{}", i); + println!("{}", ab); + let bb: u8 = b.as_bytes()[i as usize]; + println!("{}", bb); + assert_eq!(ab, bb); + i += 1; + } + } + + check_str_eq(bhutan, bhutan_e); + check_str_eq(japan, japan_e); + check_str_eq(uzbekistan, uzbekistan_e); + check_str_eq(austria, austria_e); +} + +#[test] +fn utf8_chars() { + // Chars of 1, 2, 3, and 4 bytes + let chs: Vec = vec!['e', 'é', '€', '\u{10000}']; + let s: String = chs.iter().cloned().collect(); + let schs: Vec = s.chars().collect(); + + assert_eq!(s.len(), 10); + assert_eq!(s.chars().count(), 4); + assert_eq!(schs.len(), 4); + assert_eq!(schs.iter().cloned().collect::(), s); + + assert!((from_utf8(s.as_bytes()).is_ok())); + // invalid prefix + assert!((!from_utf8(&[0x80]).is_ok())); + // invalid 2 byte prefix + assert!((!from_utf8(&[0xc0]).is_ok())); + assert!((!from_utf8(&[0xc0, 0x10]).is_ok())); + // invalid 3 byte prefix + assert!((!from_utf8(&[0xe0]).is_ok())); + assert!((!from_utf8(&[0xe0, 0x10]).is_ok())); + assert!((!from_utf8(&[0xe0, 0xff, 0x10]).is_ok())); + // invalid 4 byte prefix + assert!((!from_utf8(&[0xf0]).is_ok())); + assert!((!from_utf8(&[0xf0, 0x10]).is_ok())); + assert!((!from_utf8(&[0xf0, 0xff, 0x10]).is_ok())); + assert!((!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok())); +} diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index 3244bbc2d670d..66c25e449df2b 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -408,3 +408,56 @@ fn ascii_const() { const BYTE_IS_ASCII: bool = 97u8.is_ascii(); assert!(BYTE_IS_ASCII); } + +#[test] +fn ascii_ctype_const() { + macro_rules! suite { + ( $( $fn:ident => [$a:ident, $A:ident, $nine:ident, $dot:ident, $space:ident]; )* ) => { + $( + mod $fn { + const CHAR_A_LOWER: bool = 'a'.$fn(); + const CHAR_A_UPPER: bool = 'A'.$fn(); + const CHAR_NINE: bool = '9'.$fn(); + const CHAR_DOT: bool = '.'.$fn(); + const CHAR_SPACE: bool = ' '.$fn(); + + const U8_A_LOWER: bool = b'a'.$fn(); + const U8_A_UPPER: bool = b'A'.$fn(); + const U8_NINE: bool = b'9'.$fn(); + const U8_DOT: bool = b'.'.$fn(); + const U8_SPACE: bool = b' '.$fn(); + + pub fn run() { + assert_eq!(CHAR_A_LOWER, $a); + assert_eq!(CHAR_A_UPPER, $A); + assert_eq!(CHAR_NINE, $nine); + assert_eq!(CHAR_DOT, $dot); + assert_eq!(CHAR_SPACE, $space); + + assert_eq!(U8_A_LOWER, $a); + assert_eq!(U8_A_UPPER, $A); + assert_eq!(U8_NINE, $nine); + assert_eq!(U8_DOT, $dot); + assert_eq!(U8_SPACE, $space); + } + } + )* + + $( $fn::run(); )* + } + } + + suite! { + // 'a' 'A' '9' '.' ' ' + is_ascii_alphabetic => [true, true, false, false, false]; + is_ascii_uppercase => [false, true, false, false, false]; + is_ascii_lowercase => [true, false, false, false, false]; + is_ascii_alphanumeric => [true, true, true, false, false]; + is_ascii_digit => [false, false, true, false, false]; + is_ascii_hexdigit => [true, true, true, false, false]; + is_ascii_punctuation => [false, false, false, true, false]; + is_ascii_graphic => [true, true, true, true, false]; + is_ascii_whitespace => [false, false, false, false, true]; + is_ascii_control => [false, false, false, false, false]; + } +} diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index acbd913982c1f..75528ebb54eaf 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -101,3 +101,82 @@ fn static_init() { assert!(S_INT.fetch_add(1, SeqCst) == 0); assert!(S_UINT.fetch_add(1, SeqCst) == 0); } + +#[test] +fn atomic_access_bool() { + static mut ATOMIC: AtomicBool = AtomicBool::new(false); + + unsafe { + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.store(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_or(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_and(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.fetch_nand(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_xor(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + } +} + +#[test] +fn atomic_alignment() { + use std::mem::{align_of, size_of}; + + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::>(), size_of::>()); + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "16")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "16")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "32")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "32")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "64")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "64")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "128")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "128")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::(), size_of::()); +} + +#[test] +fn atomic_compare_exchange() { + use Ordering::*; + + static ATOMIC: AtomicIsize = AtomicIsize::new(0); + + ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); + ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok(); +} diff --git a/library/core/tests/bool.rs b/library/core/tests/bool.rs index e89eb2c7f94d5..e40f0482aee3e 100644 --- a/library/core/tests/bool.rs +++ b/library/core/tests/bool.rs @@ -1,3 +1,87 @@ +use core::cmp::Ordering::{Equal, Greater, Less}; +use core::ops::{BitAnd, BitOr, BitXor}; + +#[test] +fn test_bool() { + assert_eq!(false.eq(&true), false); + assert_eq!(false == false, true); + assert_eq!(false != true, true); + assert_eq!(false.ne(&false), false); + + assert_eq!(false.bitand(false), false); + assert_eq!(true.bitand(false), false); + assert_eq!(false.bitand(true), false); + assert_eq!(true.bitand(true), true); + + assert_eq!(false & false, false); + assert_eq!(true & false, false); + assert_eq!(false & true, false); + assert_eq!(true & true, true); + + assert_eq!(false.bitor(false), false); + assert_eq!(true.bitor(false), true); + assert_eq!(false.bitor(true), true); + assert_eq!(true.bitor(true), true); + + assert_eq!(false | false, false); + assert_eq!(true | false, true); + assert_eq!(false | true, true); + assert_eq!(true | true, true); + + assert_eq!(false.bitxor(false), false); + assert_eq!(true.bitxor(false), true); + assert_eq!(false.bitxor(true), true); + assert_eq!(true.bitxor(true), false); + + assert_eq!(false ^ false, false); + assert_eq!(true ^ false, true); + assert_eq!(false ^ true, true); + assert_eq!(true ^ true, false); + + assert_eq!(!true, false); + assert_eq!(!false, true); + + let s = false.to_string(); + assert_eq!(s, "false"); + let s = true.to_string(); + assert_eq!(s, "true"); + + assert!(true > false); + assert!(!(false > true)); + + assert!(false < true); + assert!(!(true < false)); + + assert!(false <= false); + assert!(false >= false); + assert!(true <= true); + assert!(true >= true); + + assert!(false <= true); + assert!(!(false >= true)); + assert!(true >= false); + assert!(!(true <= false)); + + assert_eq!(true.cmp(&true), Equal); + assert_eq!(false.cmp(&false), Equal); + assert_eq!(true.cmp(&false), Greater); + assert_eq!(false.cmp(&true), Less); +} + +#[test] +pub fn test_bool_not() { + if !false { + assert!((true)); + } else { + assert!((false)); + } + if !true { + assert!((false)); + } else { + assert!((true)); + } +} + #[test] fn test_bool_to_option() { assert_eq!(false.then_some(0), None); diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs index 835289daf715a..11cf7add07ada 100644 --- a/library/core/tests/cmp.rs +++ b/library/core/tests/cmp.rs @@ -132,3 +132,74 @@ fn ordering_const() { const THEN: Ordering = Equal.then(ORDERING); assert_eq!(THEN, Greater); } + +#[test] +fn cmp_default() { + // Test default methods in PartialOrd and PartialEq + + #[derive(Debug)] + struct Fool(bool); + + impl PartialEq for Fool { + fn eq(&self, other: &Fool) -> bool { + let Fool(this) = *self; + let Fool(other) = *other; + this != other + } + } + + struct Int(isize); + + impl PartialEq for Int { + fn eq(&self, other: &Int) -> bool { + let Int(this) = *self; + let Int(other) = *other; + this == other + } + } + + impl PartialOrd for Int { + fn partial_cmp(&self, other: &Int) -> Option { + let Int(this) = *self; + let Int(other) = *other; + this.partial_cmp(&other) + } + } + + struct RevInt(isize); + + impl PartialEq for RevInt { + fn eq(&self, other: &RevInt) -> bool { + let RevInt(this) = *self; + let RevInt(other) = *other; + this == other + } + } + + impl PartialOrd for RevInt { + fn partial_cmp(&self, other: &RevInt) -> Option { + let RevInt(this) = *self; + let RevInt(other) = *other; + other.partial_cmp(&this) + } + } + + assert!(Int(2) > Int(1)); + assert!(Int(2) >= Int(1)); + assert!(Int(1) >= Int(1)); + assert!(Int(1) < Int(2)); + assert!(Int(1) <= Int(2)); + assert!(Int(1) <= Int(1)); + + assert!(RevInt(2) < RevInt(1)); + assert!(RevInt(2) <= RevInt(1)); + assert!(RevInt(1) <= RevInt(1)); + assert!(RevInt(1) > RevInt(2)); + assert!(RevInt(1) >= RevInt(2)); + assert!(RevInt(1) >= RevInt(1)); + + assert_eq!(Fool(true), Fool(false)); + assert!(Fool(true) != Fool(true)); + assert!(Fool(false) != Fool(false)); + assert_eq!(Fool(false), Fool(true)); +} diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 6b8a989fa426f..ec4b49da384c3 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -3493,3 +3493,15 @@ fn test_flatten_non_fused_inner() { assert_eq!(iter.next(), Some(1)); assert_eq!(iter.next(), None); } + +#[test] +pub fn extend_for_unit() { + let mut x = 0; + { + let iter = (0..5).map(|_| { + x += 1; + }); + ().extend(iter); + } + assert_eq!(x, 5); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 1efb3b7411898..106c9fe5da3e6 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -8,6 +8,7 @@ #![feature(bound_cloned)] #![feature(box_syntax)] #![feature(cell_update)] +#![feature(cfg_target_has_atomic)] #![feature(const_assume)] #![feature(const_cell_into_inner)] #![feature(core_intrinsics)] @@ -63,6 +64,7 @@ #![feature(int_bits_const)] #![feature(nonzero_leading_trailing_zeros)] #![feature(const_option)] +#![feature(integer_atomics)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; @@ -82,6 +84,7 @@ mod hash; mod intrinsics; mod iter; mod lazy; +mod macros; mod manually_drop; mod mem; mod nonzero; @@ -98,3 +101,4 @@ mod str_lossy; mod task; mod time; mod tuple; +mod unicode; diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs new file mode 100644 index 0000000000000..482f3c1c99840 --- /dev/null +++ b/library/core/tests/macros.rs @@ -0,0 +1,14 @@ +#[test] +fn assert_eq_trailing_comma() { + assert_eq!(1, 1,); +} + +#[test] +fn assert_escape() { + assert!(r#"☃\backslash"#.contains("\\")); +} + +#[test] +fn assert_ne_trailing_comma() { + assert_ne!(1, 2,); +} diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs index 5d4ecb2669a96..01defab2b38f0 100644 --- a/library/core/tests/num/wrapping.rs +++ b/library/core/tests/num/wrapping.rs @@ -74,3 +74,236 @@ wrapping_test!(u64, u64::MIN, u64::MAX); #[cfg(not(target_os = "emscripten"))] wrapping_test!(u128, u128::MIN, u128::MAX); wrapping_test!(usize, usize::MIN, usize::MAX); + +// Don't warn about overflowing ops on 32-bit platforms +#[cfg_attr(target_pointer_width = "32", allow(const_err))] +fn wrapping_int_api() { + assert_eq!(i8::MAX.wrapping_add(1), i8::MIN); + assert_eq!(i16::MAX.wrapping_add(1), i16::MIN); + assert_eq!(i32::MAX.wrapping_add(1), i32::MIN); + assert_eq!(i64::MAX.wrapping_add(1), i64::MIN); + assert_eq!(isize::MAX.wrapping_add(1), isize::MIN); + + assert_eq!(i8::MIN.wrapping_sub(1), i8::MAX); + assert_eq!(i16::MIN.wrapping_sub(1), i16::MAX); + assert_eq!(i32::MIN.wrapping_sub(1), i32::MAX); + assert_eq!(i64::MIN.wrapping_sub(1), i64::MAX); + assert_eq!(isize::MIN.wrapping_sub(1), isize::MAX); + + assert_eq!(u8::MAX.wrapping_add(1), u8::MIN); + assert_eq!(u16::MAX.wrapping_add(1), u16::MIN); + assert_eq!(u32::MAX.wrapping_add(1), u32::MIN); + assert_eq!(u64::MAX.wrapping_add(1), u64::MIN); + assert_eq!(usize::MAX.wrapping_add(1), usize::MIN); + + assert_eq!(u8::MIN.wrapping_sub(1), u8::MAX); + assert_eq!(u16::MIN.wrapping_sub(1), u16::MAX); + assert_eq!(u32::MIN.wrapping_sub(1), u32::MAX); + assert_eq!(u64::MIN.wrapping_sub(1), u64::MAX); + assert_eq!(usize::MIN.wrapping_sub(1), usize::MAX); + + assert_eq!((0xfe_u8 as i8).wrapping_mul(16), (0xe0_u8 as i8)); + assert_eq!((0xfedc_u16 as i16).wrapping_mul(16), (0xedc0_u16 as i16)); + assert_eq!((0xfedc_ba98_u32 as i32).wrapping_mul(16), (0xedcb_a980_u32 as i32)); + assert_eq!( + (0xfedc_ba98_7654_3217_u64 as i64).wrapping_mul(16), + (0xedcb_a987_6543_2170_u64 as i64) + ); + + match () { + #[cfg(target_pointer_width = "32")] + () => { + assert_eq!((0xfedc_ba98_u32 as isize).wrapping_mul(16), (0xedcb_a980_u32 as isize)); + } + #[cfg(target_pointer_width = "64")] + () => { + assert_eq!( + (0xfedc_ba98_7654_3217_u64 as isize).wrapping_mul(16), + (0xedcb_a987_6543_2170_u64 as isize) + ); + } + } + + assert_eq!((0xfe as u8).wrapping_mul(16), (0xe0 as u8)); + assert_eq!((0xfedc as u16).wrapping_mul(16), (0xedc0 as u16)); + assert_eq!((0xfedc_ba98 as u32).wrapping_mul(16), (0xedcb_a980 as u32)); + assert_eq!((0xfedc_ba98_7654_3217 as u64).wrapping_mul(16), (0xedcb_a987_6543_2170 as u64)); + + match () { + #[cfg(target_pointer_width = "32")] + () => { + assert_eq!((0xfedc_ba98 as usize).wrapping_mul(16), (0xedcb_a980 as usize)); + } + #[cfg(target_pointer_width = "64")] + () => { + assert_eq!( + (0xfedc_ba98_7654_3217 as usize).wrapping_mul(16), + (0xedcb_a987_6543_2170 as usize) + ); + } + } + + macro_rules! check_mul_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_mul($f), ($e) * $f); + }; + } + macro_rules! check_mul_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_mul($f), $e); + }; + } + + check_mul_no_wrap!(0xfe_u8 as i8, -1); + check_mul_no_wrap!(0xfedc_u16 as i16, -1); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_mul_no_wrap!(0xfe_u8 as i8, -2); + check_mul_no_wrap!(0xfedc_u16 as i16, -2); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, -2); + + check_mul_no_wrap!(0xfe_u8 as i8, 2); + check_mul_no_wrap!(0xfedc_u16 as i16, 2); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, 2); + + check_mul_wraps!(0x80_u8 as i8, -1); + check_mul_wraps!(0x8000_u16 as i16, -1); + check_mul_wraps!(0x8000_0000_u32 as i32, -1); + check_mul_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_mul_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_mul_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_div_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_div($f), ($e) / $f); + }; + } + macro_rules! check_div_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_div($f), $e); + }; + } + + check_div_no_wrap!(0xfe_u8 as i8, -1); + check_div_no_wrap!(0xfedc_u16 as i16, -1); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_div_no_wrap!(0xfe_u8 as i8, -2); + check_div_no_wrap!(0xfedc_u16 as i16, -2); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); + + check_div_no_wrap!(0xfe_u8 as i8, 2); + check_div_no_wrap!(0xfedc_u16 as i16, 2); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); + + check_div_wraps!(-128 as i8, -1); + check_div_wraps!(0x8000_u16 as i16, -1); + check_div_wraps!(0x8000_0000_u32 as i32, -1); + check_div_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_div_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_div_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_rem_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_rem($f), ($e) % $f); + }; + } + macro_rules! check_rem_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_rem($f), 0); + }; + } + + check_rem_no_wrap!(0xfe_u8 as i8, -1); + check_rem_no_wrap!(0xfedc_u16 as i16, -1); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_rem_no_wrap!(0xfe_u8 as i8, -2); + check_rem_no_wrap!(0xfedc_u16 as i16, -2); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); + + check_rem_no_wrap!(0xfe_u8 as i8, 2); + check_rem_no_wrap!(0xfedc_u16 as i16, 2); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); + + check_rem_wraps!(0x80_u8 as i8, -1); + check_rem_wraps!(0x8000_u16 as i16, -1); + check_rem_wraps!(0x8000_0000_u32 as i32, -1); + check_rem_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_rem_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_rem_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_neg_no_wrap { + ($e:expr) => { + assert_eq!(($e).wrapping_neg(), -($e)); + }; + } + macro_rules! check_neg_wraps { + ($e:expr) => { + assert_eq!(($e).wrapping_neg(), ($e)); + }; + } + + check_neg_no_wrap!(0xfe_u8 as i8); + check_neg_no_wrap!(0xfedc_u16 as i16); + check_neg_no_wrap!(0xfedc_ba98_u32 as i32); + check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64); + check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize); + + check_neg_wraps!(0x80_u8 as i8); + check_neg_wraps!(0x8000_u16 as i16); + check_neg_wraps!(0x8000_0000_u32 as i32); + check_neg_wraps!(0x8000_0000_0000_0000_u64 as i64); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_neg_wraps!(0x8000_0000_u32 as isize); + } + #[cfg(target_pointer_width = "64")] + () => { + check_neg_wraps!(0x8000_0000_0000_0000_u64 as isize); + } + } +} diff --git a/library/core/tests/ops.rs b/library/core/tests/ops.rs index e9d595e65e2b2..53e5539fad91c 100644 --- a/library/core/tests/ops.rs +++ b/library/core/tests/ops.rs @@ -1,4 +1,5 @@ use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; +use core::ops::{Deref, DerefMut}; // Test the Range structs and syntax. @@ -197,3 +198,35 @@ fn range_structural_match() { _ => unreachable!(), } } + +// Test Deref implementations + +#[test] +fn deref_mut_on_ref() { + // Test that `&mut T` implements `DerefMut` + + fn inc + DerefMut>(mut t: T) { + *t += 1; + } + + let mut x: isize = 5; + inc(&mut x); + assert_eq!(x, 6); +} + +#[test] +fn deref_on_ref() { + // Test that `&T` and `&mut T` implement `Deref` + + fn deref>(t: T) -> U { + *t + } + + let x: isize = 3; + let y = deref(&x); + assert_eq!(y, 3); + + let mut x: isize = 4; + let y = deref(&mut x); + assert_eq!(y, 4); +} diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index ae814efec2086..5388b4756245a 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -402,3 +402,13 @@ fn test_unwrap_drop() { assert_eq!(x.get(), 0); } + +#[test] +pub fn option_ext() { + let thing = "{{ f }}"; + let f = thing.find("{{"); + + if f.is_none() { + println!("None!"); + } +} diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 1970b17e26721..57c2fb06c16dd 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -400,3 +400,16 @@ fn align_offset_weird_strides() { } assert!(!x); } + +#[test] +fn offset_from() { + let mut a = [0; 5]; + let ptr1: *mut i32 = &mut a[1]; + let ptr2: *mut i32 = &mut a[3]; + unsafe { + assert_eq!(ptr2.offset_from(ptr1), 2); + assert_eq!(ptr1.offset_from(ptr2), -2); + assert_eq!(ptr1.offset(2), ptr2); + assert_eq!(ptr2.offset(-2), ptr1); + } +} diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index 39ea4831b9b86..81660870e95e4 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -320,3 +320,41 @@ fn result_const() { const IS_ERR: bool = RESULT.is_err(); assert!(!IS_ERR) } + +#[test] +fn result_opt_conversions() { + #[derive(Copy, Clone, Debug, PartialEq)] + struct BadNumErr; + + fn try_num(x: i32) -> Result { + if x <= 5 { Ok(x + 1) } else { Err(BadNumErr) } + } + + type ResOpt = Result, BadNumErr>; + type OptRes = Option>; + + let mut x: ResOpt = Ok(Some(5)); + let mut y: OptRes = Some(Ok(5)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Ok(None); + y = None; + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Err(BadNumErr); + y = Some(Err(BadNumErr)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + let res: Result, BadNumErr> = (0..10) + .map(|x| { + let y = try_num(x)?; + Ok(if y % 2 == 0 { Some(y - 1) } else { None }) + }) + .filter_map(Result::transpose) + .collect(); + + assert_eq!(res, Err(BadNumErr)) +} diff --git a/library/core/tests/unicode.rs b/library/core/tests/unicode.rs new file mode 100644 index 0000000000000..c28ea859115e1 --- /dev/null +++ b/library/core/tests/unicode.rs @@ -0,0 +1,5 @@ +#[test] +pub fn version() { + let (major, _minor, _update) = core::unicode::UNICODE_VERSION; + assert!(major >= 10); +} diff --git a/library/std/tests/env.rs b/library/std/tests/env.rs index c94fc41178dfe..0e55ec648c9c5 100644 --- a/library/std/tests/env.rs +++ b/library/std/tests/env.rs @@ -1,5 +1,6 @@ use std::env::*; use std::ffi::{OsStr, OsString}; +use std::path::PathBuf; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; @@ -76,3 +77,63 @@ fn test_env_set_var() { assert!(vars_os().any(|(k, v)| { &*k == &*n && &*v == "VALUE" })); } + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)] +#[allow(deprecated)] +fn env_home_dir() { + fn var_to_os_string(var: Result) -> Option { + match var { + Ok(var) => Some(OsString::from(var)), + Err(VarError::NotUnicode(var)) => Some(var), + _ => None, + } + } + + cfg_if::cfg_if! { + if #[cfg(unix)] { + let oldhome = var_to_os_string(var("HOME")); + + set_var("HOME", "/home/MountainView"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + remove_var("HOME"); + if cfg!(target_os = "android") { + assert!(home_dir().is_none()); + } else { + // When HOME is not set, some platforms return `None`, + // but others return `Some` with a default. + // Just check that it is not "/home/MountainView". + assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + } + + if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } + } else if #[cfg(windows)] { + let oldhome = var_to_os_string(var("HOME")); + let olduserprofile = var_to_os_string(var("USERPROFILE")); + + remove_var("HOME"); + remove_var("USERPROFILE"); + + assert!(home_dir().is_some()); + + set_var("HOME", "/home/MountainView"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + remove_var("HOME"); + + set_var("USERPROFILE", "/home/MountainView"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + set_var("HOME", "/home/MountainView"); + set_var("USERPROFILE", "/home/PaloAlto"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + remove_var("HOME"); + remove_var("USERPROFILE"); + + if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } + if let Some(olduserprofile) = olduserprofile { set_var("USERPROFILE", olduserprofile); } + } + } +} diff --git a/src/test/ui/sleep.rs b/library/std/tests/thread.rs similarity index 60% rename from src/test/ui/sleep.rs rename to library/std/tests/thread.rs index f3f8d7259c44e..754b264c6ad93 100644 --- a/src/test/ui/sleep.rs +++ b/library/std/tests/thread.rs @@ -1,17 +1,16 @@ -// run-pass -// ignore-emscripten no threads support - -use std::thread::{self, sleep}; -use std::time::Duration; use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::Duration; -fn main() { +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn sleep() { let finished = Arc::new(Mutex::new(false)); let t_finished = finished.clone(); thread::spawn(move || { - sleep(Duration::new(u64::MAX, 0)); + thread::sleep(Duration::new(u64::MAX, 0)); *t_finished.lock().unwrap() = true; }); - sleep(Duration::from_millis(100)); + thread::sleep(Duration::from_millis(100)); assert_eq!(*finished.lock().unwrap(), false); } diff --git a/src/test/ui/assert-eq-trailing-comma.rs b/src/test/ui/assert-eq-trailing-comma.rs deleted file mode 100644 index 7071f80d7f7ba..0000000000000 --- a/src/test/ui/assert-eq-trailing-comma.rs +++ /dev/null @@ -1,5 +0,0 @@ -// run-pass - -fn main() { - assert_eq!(1, 1,); -} diff --git a/src/test/ui/assert-escape.rs b/src/test/ui/assert-escape.rs deleted file mode 100644 index 00e51d42cab9e..0000000000000 --- a/src/test/ui/assert-escape.rs +++ /dev/null @@ -1,5 +0,0 @@ -// run-pass - -fn main() { - assert!(r#"☃\backslash"#.contains("\\")); -} diff --git a/src/test/ui/assert-ne-trailing-comma.rs b/src/test/ui/assert-ne-trailing-comma.rs deleted file mode 100644 index 03308db9a1fee..0000000000000 --- a/src/test/ui/assert-ne-trailing-comma.rs +++ /dev/null @@ -1,5 +0,0 @@ -// run-pass - -fn main() { - assert_ne!(1, 2,); -} diff --git a/src/test/ui/atomic-access-bool.rs b/src/test/ui/atomic-access-bool.rs deleted file mode 100644 index e9d48bb3b43d8..0000000000000 --- a/src/test/ui/atomic-access-bool.rs +++ /dev/null @@ -1,24 +0,0 @@ -// run-pass - -#![allow(stable_features)] -#![feature(atomic_access)] -use std::sync::atomic::AtomicBool; -use std::sync::atomic::Ordering::*; - -static mut ATOMIC: AtomicBool = AtomicBool::new(false); - -fn main() { - unsafe { - assert_eq!(*ATOMIC.get_mut(), false); - ATOMIC.store(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_or(false, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_and(false, SeqCst); - assert_eq!(*ATOMIC.get_mut(), false); - ATOMIC.fetch_nand(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_xor(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), false); - } -} diff --git a/src/test/ui/atomic-alignment.rs b/src/test/ui/atomic-alignment.rs deleted file mode 100644 index 5bda90d2eab02..0000000000000 --- a/src/test/ui/atomic-alignment.rs +++ /dev/null @@ -1,38 +0,0 @@ -// run-pass - -#![feature(cfg_target_has_atomic)] -#![feature(integer_atomics)] - -use std::mem::{align_of, size_of}; -use std::sync::atomic::*; - -fn main() { - #[cfg(target_has_atomic = "8")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "ptr")] - assert_eq!(align_of::>(), size_of::>()); - #[cfg(target_has_atomic = "8")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "8")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "16")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "16")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "32")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "32")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "64")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "64")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "128")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "128")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "ptr")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "ptr")] - assert_eq!(align_of::(), size_of::()); -} diff --git a/src/test/ui/atomic-compare_exchange.rs b/src/test/ui/atomic-compare_exchange.rs deleted file mode 100644 index 9b327eef3c894..0000000000000 --- a/src/test/ui/atomic-compare_exchange.rs +++ /dev/null @@ -1,31 +0,0 @@ -// run-pass - -#![allow(stable_features)] - -#![feature(extended_compare_and_swap)] -use std::sync::atomic::AtomicIsize; -use std::sync::atomic::Ordering::*; - -static ATOMIC: AtomicIsize = AtomicIsize::new(0); - -fn main() { - // Make sure codegen can emit all the intrinsics correctly - ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); - ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok(); -} diff --git a/src/test/ui/bool-not.rs b/src/test/ui/bool-not.rs deleted file mode 100644 index 84713d6818a3e..0000000000000 --- a/src/test/ui/bool-not.rs +++ /dev/null @@ -1,6 +0,0 @@ -// run-pass - -pub fn main() { - if !false { assert!((true)); } else { assert!((false)); } - if !true { assert!((false)); } else { assert!((true)); } -} diff --git a/src/test/ui/bool.rs b/src/test/ui/bool.rs deleted file mode 100644 index 92f36c8fd25ad..0000000000000 --- a/src/test/ui/bool.rs +++ /dev/null @@ -1,72 +0,0 @@ -// run-pass -// Basic boolean tests - - -use std::cmp::Ordering::{Equal, Greater, Less}; -use std::ops::{BitAnd, BitOr, BitXor}; - -fn main() { - assert_eq!(false.eq(&true), false); - assert_eq!(false == false, true); - assert_eq!(false != true, true); - assert_eq!(false.ne(&false), false); - - assert_eq!(false.bitand(false), false); - assert_eq!(true.bitand(false), false); - assert_eq!(false.bitand(true), false); - assert_eq!(true.bitand(true), true); - - assert_eq!(false & false, false); - assert_eq!(true & false, false); - assert_eq!(false & true, false); - assert_eq!(true & true, true); - - assert_eq!(false.bitor(false), false); - assert_eq!(true.bitor(false), true); - assert_eq!(false.bitor(true), true); - assert_eq!(true.bitor(true), true); - - assert_eq!(false | false, false); - assert_eq!(true | false, true); - assert_eq!(false | true, true); - assert_eq!(true | true, true); - - assert_eq!(false.bitxor(false), false); - assert_eq!(true.bitxor(false), true); - assert_eq!(false.bitxor(true), true); - assert_eq!(true.bitxor(true), false); - - assert_eq!(false ^ false, false); - assert_eq!(true ^ false, true); - assert_eq!(false ^ true, true); - assert_eq!(true ^ true, false); - - assert_eq!(!true, false); - assert_eq!(!false, true); - - let s = false.to_string(); - assert_eq!(s, "false"); - let s = true.to_string(); - assert_eq!(s, "true"); - - assert!(true > false); - assert!(!(false > true)); - - assert!(false < true); - assert!(!(true < false)); - - assert!(false <= false); - assert!(false >= false); - assert!(true <= true); - assert!(true >= true); - - assert!(false <= true); - assert!(!(false >= true)); - assert!(true >= false); - assert!(!(true <= false)); - - assert_eq!(true.cmp(&true), Equal); - assert_eq!(false.cmp(&false), Equal); - assert_eq!(true.cmp(&false), Greater); - assert_eq!(false.cmp(&true), Less); -} diff --git a/src/test/ui/char_unicode.rs b/src/test/ui/char_unicode.rs deleted file mode 100644 index 65dda47066f4e..0000000000000 --- a/src/test/ui/char_unicode.rs +++ /dev/null @@ -1,10 +0,0 @@ -// run-pass - -/// Tests access to the Unicode version constant. -pub fn main() { - check(std::char::UNICODE_VERSION); -} - -pub fn check(unicode_version: (u8, u8, u8)) { - assert!(unicode_version.0 >= 10); -} diff --git a/src/test/ui/cmp-default.rs b/src/test/ui/cmp-default.rs deleted file mode 100644 index bb5c39f5cdea9..0000000000000 --- a/src/test/ui/cmp-default.rs +++ /dev/null @@ -1,73 +0,0 @@ -// run-pass - -use std::cmp::Ordering; - -// Test default methods in PartialOrd and PartialEq -// -#[derive(Debug)] -struct Fool(bool); - -impl PartialEq for Fool { - fn eq(&self, other: &Fool) -> bool { - let Fool(this) = *self; - let Fool(other) = *other; - this != other - } -} - -struct Int(isize); - -impl PartialEq for Int { - fn eq(&self, other: &Int) -> bool { - let Int(this) = *self; - let Int(other) = *other; - this == other - } -} - -impl PartialOrd for Int { - fn partial_cmp(&self, other: &Int) -> Option { - let Int(this) = *self; - let Int(other) = *other; - this.partial_cmp(&other) - } -} - -struct RevInt(isize); - -impl PartialEq for RevInt { - fn eq(&self, other: &RevInt) -> bool { - let RevInt(this) = *self; - let RevInt(other) = *other; - this == other - } -} - -impl PartialOrd for RevInt { - fn partial_cmp(&self, other: &RevInt) -> Option { - let RevInt(this) = *self; - let RevInt(other) = *other; - other.partial_cmp(&this) - } -} - -pub fn main() { - assert!(Int(2) > Int(1)); - assert!(Int(2) >= Int(1)); - assert!(Int(1) >= Int(1)); - assert!(Int(1) < Int(2)); - assert!(Int(1) <= Int(2)); - assert!(Int(1) <= Int(1)); - - assert!(RevInt(2) < RevInt(1)); - assert!(RevInt(2) <= RevInt(1)); - assert!(RevInt(1) <= RevInt(1)); - assert!(RevInt(1) > RevInt(2)); - assert!(RevInt(1) >= RevInt(2)); - assert!(RevInt(1) >= RevInt(1)); - - assert_eq!(Fool(true), Fool(false)); - assert!(Fool(true) != Fool(true)); - assert!(Fool(false) != Fool(false)); - assert_eq!(Fool(false), Fool(true)); -} diff --git a/src/test/ui/consts/ascii_ctype.rs b/src/test/ui/consts/ascii_ctype.rs deleted file mode 100644 index ef2f7322f2718..0000000000000 --- a/src/test/ui/consts/ascii_ctype.rs +++ /dev/null @@ -1,53 +0,0 @@ -// run-pass - -macro_rules! suite { - ( $( $fn:ident => [$a:ident, $A:ident, $nine:ident, $dot:ident, $space:ident]; )* ) => { - $( - mod $fn { - const CHAR_A_LOWER: bool = 'a'.$fn(); - const CHAR_A_UPPER: bool = 'A'.$fn(); - const CHAR_NINE: bool = '9'.$fn(); - const CHAR_DOT: bool = '.'.$fn(); - const CHAR_SPACE: bool = ' '.$fn(); - - const U8_A_LOWER: bool = b'a'.$fn(); - const U8_A_UPPER: bool = b'A'.$fn(); - const U8_NINE: bool = b'9'.$fn(); - const U8_DOT: bool = b'.'.$fn(); - const U8_SPACE: bool = b' '.$fn(); - - pub fn run() { - assert_eq!(CHAR_A_LOWER, $a); - assert_eq!(CHAR_A_UPPER, $A); - assert_eq!(CHAR_NINE, $nine); - assert_eq!(CHAR_DOT, $dot); - assert_eq!(CHAR_SPACE, $space); - - assert_eq!(U8_A_LOWER, $a); - assert_eq!(U8_A_UPPER, $A); - assert_eq!(U8_NINE, $nine); - assert_eq!(U8_DOT, $dot); - assert_eq!(U8_SPACE, $space); - } - } - )* - - fn main() { - $( $fn::run(); )* - } - } -} - -suite! { - // 'a' 'A' '9' '.' ' ' - is_ascii_alphabetic => [true, true, false, false, false]; - is_ascii_uppercase => [false, true, false, false, false]; - is_ascii_lowercase => [true, false, false, false, false]; - is_ascii_alphanumeric => [true, true, true, false, false]; - is_ascii_digit => [false, false, true, false, false]; - is_ascii_hexdigit => [true, true, true, false, false]; - is_ascii_punctuation => [false, false, false, true, false]; - is_ascii_graphic => [true, true, true, true, false]; - is_ascii_whitespace => [false, false, false, false, true]; - is_ascii_control => [false, false, false, false, false]; -} diff --git a/src/test/ui/consts/const-str-ptr.rs b/src/test/ui/consts/const-str-ptr.rs deleted file mode 100644 index 56fd9d9f55ffc..0000000000000 --- a/src/test/ui/consts/const-str-ptr.rs +++ /dev/null @@ -1,17 +0,0 @@ -// run-pass -#![allow(unused_imports)] -use std::{str, string}; - -const A: [u8; 2] = ['h' as u8, 'i' as u8]; -const B: &'static [u8; 2] = &A; -const C: *const u8 = B as *const u8; - -pub fn main() { - unsafe { - let foo = &A as *const u8; - assert_eq!(foo, C); - assert_eq!(str::from_utf8_unchecked(&A), "hi"); - assert_eq!(*C, A[0]); - assert_eq!(*(&B[0] as *const u8), A[0]); - } -} diff --git a/src/test/ui/deref-mut-on-ref.rs b/src/test/ui/deref-mut-on-ref.rs deleted file mode 100644 index a6df5495a2775..0000000000000 --- a/src/test/ui/deref-mut-on-ref.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass -// Test that `&mut T` implements `DerefMut` - - -use std::ops::{Deref, DerefMut}; - -fn inc + DerefMut>(mut t: T) { - *t += 1; -} - -fn main() { - let mut x: isize = 5; - inc(&mut x); - assert_eq!(x, 6); -} diff --git a/src/test/ui/deref-on-ref.rs b/src/test/ui/deref-on-ref.rs deleted file mode 100644 index 973e61c9d59fa..0000000000000 --- a/src/test/ui/deref-on-ref.rs +++ /dev/null @@ -1,19 +0,0 @@ -// run-pass -// Test that `&T` and `&mut T` implement `Deref` - - -use std::ops::Deref; - -fn deref>(t: T) -> U { - *t -} - -fn main() { - let x: isize = 3; - let y = deref(&x); - assert_eq!(y, 3); - - let mut x: isize = 4; - let y = deref(&mut x); - assert_eq!(y, 4); -} diff --git a/src/test/ui/env-home-dir.rs b/src/test/ui/env-home-dir.rs deleted file mode 100644 index c597b4732d158..0000000000000 --- a/src/test/ui/env-home-dir.rs +++ /dev/null @@ -1,50 +0,0 @@ -// run-pass - -#![allow(unused_variables)] -#![allow(deprecated)] -// ignore-emscripten env vars don't work? -// ignore-sgx env vars cannot be modified - -use std::env::*; -use std::path::PathBuf; - -#[cfg(unix)] -fn main() { - let oldhome = var("HOME"); - - set_var("HOME", "/home/MountainView"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - remove_var("HOME"); - if cfg!(target_os = "android") { - assert!(home_dir().is_none()); - } else { - // When HOME is not set, some platforms return `None`, - // but others return `Some` with a default. - // Just check that it is not "/home/MountainView". - assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - } -} - -#[cfg(windows)] -fn main() { - let oldhome = var("HOME"); - let olduserprofile = var("USERPROFILE"); - - remove_var("HOME"); - remove_var("USERPROFILE"); - - assert!(home_dir().is_some()); - - set_var("HOME", "/home/MountainView"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - remove_var("HOME"); - - set_var("USERPROFILE", "/home/MountainView"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - set_var("HOME", "/home/MountainView"); - set_var("USERPROFILE", "/home/PaloAlto"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); -} diff --git a/src/test/ui/extend-for-unit.rs b/src/test/ui/extend-for-unit.rs deleted file mode 100644 index 01d743f70bc0a..0000000000000 --- a/src/test/ui/extend-for-unit.rs +++ /dev/null @@ -1,12 +0,0 @@ -// run-pass - -pub fn main() { - let mut x = 0; - { - let iter = (0..5).map(|_| { - x += 1; - }); - ().extend(iter); - } - assert_eq!(x, 5); -} diff --git a/src/test/ui/offset_from.rs b/src/test/ui/offset_from.rs deleted file mode 100644 index aa59c119706ea..0000000000000 --- a/src/test/ui/offset_from.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass - -fn main() { - let mut a = [0; 5]; - let ptr1: *mut i32 = &mut a[1]; - let ptr2: *mut i32 = &mut a[3]; - unsafe { - assert_eq!(ptr2.offset_from(ptr1), 2); - assert_eq!(ptr1.offset_from(ptr2), -2); - assert_eq!(ptr1.offset(2), ptr2); - assert_eq!(ptr2.offset(-2), ptr1); - } -} diff --git a/src/test/ui/option-ext.rs b/src/test/ui/option-ext.rs deleted file mode 100644 index 76d0cf43984b3..0000000000000 --- a/src/test/ui/option-ext.rs +++ /dev/null @@ -1,10 +0,0 @@ -// run-pass - -pub fn main() { - let thing = "{{ f }}"; - let f = thing.find("{{"); - - if f.is_none() { - println!("None!"); - } -} diff --git a/src/test/ui/result-opt-conversions.rs b/src/test/ui/result-opt-conversions.rs deleted file mode 100644 index 57f258aab654a..0000000000000 --- a/src/test/ui/result-opt-conversions.rs +++ /dev/null @@ -1,47 +0,0 @@ -// run-pass - -#[derive(Copy, Clone, Debug, PartialEq)] -struct BadNumErr; - -fn try_num(x: i32) -> Result { - if x <= 5 { - Ok(x + 1) - } else { - Err(BadNumErr) - } -} - -type ResOpt = Result, BadNumErr>; -type OptRes = Option>; - -fn main() { - let mut x: ResOpt = Ok(Some(5)); - let mut y: OptRes = Some(Ok(5)); - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - x = Ok(None); - y = None; - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - x = Err(BadNumErr); - y = Some(Err(BadNumErr)); - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - let res: Result, BadNumErr> = - (0..10) - .map(|x| { - let y = try_num(x)?; - Ok(if y % 2 == 0 { - Some(y - 1) - } else { - None - }) - }) - .filter_map(Result::transpose) - .collect(); - - assert_eq!(res, Err(BadNumErr)) -} diff --git a/src/test/ui/utf8.rs b/src/test/ui/utf8.rs deleted file mode 100644 index 75b6ddf7895c7..0000000000000 --- a/src/test/ui/utf8.rs +++ /dev/null @@ -1,50 +0,0 @@ -// run-pass - -pub fn main() { - let yen: char = '¥'; // 0xa5 - let c_cedilla: char = 'ç'; // 0xe7 - let thorn: char = 'þ'; // 0xfe - let y_diaeresis: char = 'ÿ'; // 0xff - let pi: char = 'Π'; // 0x3a0 - - assert_eq!(yen as isize, 0xa5); - assert_eq!(c_cedilla as isize, 0xe7); - assert_eq!(thorn as isize, 0xfe); - assert_eq!(y_diaeresis as isize, 0xff); - assert_eq!(pi as isize, 0x3a0); - - assert_eq!(pi as isize, '\u{3a0}' as isize); - assert_eq!('\x0a' as isize, '\n' as isize); - - let bhutan: String = "འབྲུག་ཡུལ།".to_string(); - let japan: String = "日本".to_string(); - let uzbekistan: String = "Ўзбекистон".to_string(); - let austria: String = "Österreich".to_string(); - - let bhutan_e: String = - "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string(); - let japan_e: String = "\u{65e5}\u{672c}".to_string(); - let uzbekistan_e: String = - "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string(); - let austria_e: String = "\u{d6}sterreich".to_string(); - - let oo: char = 'Ö'; - assert_eq!(oo as isize, 0xd6); - - fn check_str_eq(a: String, b: String) { - let mut i: isize = 0; - for ab in a.bytes() { - println!("{}", i); - println!("{}", ab); - let bb: u8 = b.as_bytes()[i as usize]; - println!("{}", bb); - assert_eq!(ab, bb); - i += 1; - } - } - - check_str_eq(bhutan, bhutan_e); - check_str_eq(japan, japan_e); - check_str_eq(uzbekistan, uzbekistan_e); - check_str_eq(austria, austria_e); -} diff --git a/src/test/ui/utf8_chars.rs b/src/test/ui/utf8_chars.rs deleted file mode 100644 index d764509813de1..0000000000000 --- a/src/test/ui/utf8_chars.rs +++ /dev/null @@ -1,31 +0,0 @@ -// run-pass - -use std::str; - -pub fn main() { - // Chars of 1, 2, 3, and 4 bytes - let chs: Vec = vec!['e', 'é', '€', '\u{10000}']; - let s: String = chs.iter().cloned().collect(); - let schs: Vec = s.chars().collect(); - - assert_eq!(s.len(), 10); - assert_eq!(s.chars().count(), 4); - assert_eq!(schs.len(), 4); - assert_eq!(schs.iter().cloned().collect::(), s); - - assert!((str::from_utf8(s.as_bytes()).is_ok())); - // invalid prefix - assert!((!str::from_utf8(&[0x80]).is_ok())); - // invalid 2 byte prefix - assert!((!str::from_utf8(&[0xc0]).is_ok())); - assert!((!str::from_utf8(&[0xc0, 0x10]).is_ok())); - // invalid 3 byte prefix - assert!((!str::from_utf8(&[0xe0]).is_ok())); - assert!((!str::from_utf8(&[0xe0, 0x10]).is_ok())); - assert!((!str::from_utf8(&[0xe0, 0xff, 0x10]).is_ok())); - // invalid 4 byte prefix - assert!((!str::from_utf8(&[0xf0]).is_ok())); - assert!((!str::from_utf8(&[0xf0, 0x10]).is_ok())); - assert!((!str::from_utf8(&[0xf0, 0xff, 0x10]).is_ok())); - assert!((!str::from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok())); -} diff --git a/src/test/ui/wrapping-int-api.rs b/src/test/ui/wrapping-int-api.rs deleted file mode 100644 index 6e2fc7f80b9c4..0000000000000 --- a/src/test/ui/wrapping-int-api.rs +++ /dev/null @@ -1,225 +0,0 @@ -// run-pass -// Test inherent wrapping_* methods for {i,u}{size,8,16,32,64}. - -// Don't warn about overflowing ops on 32-bit platforms -#![cfg_attr(target_pointer_width = "32", allow(const_err))] - -fn main() { - assert_eq!( i8::MAX.wrapping_add(1), i8::MIN); - assert_eq!( i16::MAX.wrapping_add(1), i16::MIN); - assert_eq!( i32::MAX.wrapping_add(1), i32::MIN); - assert_eq!( i64::MAX.wrapping_add(1), i64::MIN); - assert_eq!(isize::MAX.wrapping_add(1), isize::MIN); - - assert_eq!( i8::MIN.wrapping_sub(1), i8::MAX); - assert_eq!( i16::MIN.wrapping_sub(1), i16::MAX); - assert_eq!( i32::MIN.wrapping_sub(1), i32::MAX); - assert_eq!( i64::MIN.wrapping_sub(1), i64::MAX); - assert_eq!(isize::MIN.wrapping_sub(1), isize::MAX); - - assert_eq!( u8::MAX.wrapping_add(1), u8::MIN); - assert_eq!( u16::MAX.wrapping_add(1), u16::MIN); - assert_eq!( u32::MAX.wrapping_add(1), u32::MIN); - assert_eq!( u64::MAX.wrapping_add(1), u64::MIN); - assert_eq!(usize::MAX.wrapping_add(1), usize::MIN); - - assert_eq!( u8::MIN.wrapping_sub(1), u8::MAX); - assert_eq!( u16::MIN.wrapping_sub(1), u16::MAX); - assert_eq!( u32::MIN.wrapping_sub(1), u32::MAX); - assert_eq!( u64::MIN.wrapping_sub(1), u64::MAX); - assert_eq!(usize::MIN.wrapping_sub(1), usize::MAX); - - assert_eq!((0xfe_u8 as i8).wrapping_mul(16), - (0xe0_u8 as i8)); - assert_eq!((0xfedc_u16 as i16).wrapping_mul(16), - (0xedc0_u16 as i16)); - assert_eq!((0xfedc_ba98_u32 as i32).wrapping_mul(16), - (0xedcb_a980_u32 as i32)); - assert_eq!((0xfedc_ba98_7654_3217_u64 as i64).wrapping_mul(16), - (0xedcb_a987_6543_2170_u64 as i64)); - - match () { - #[cfg(target_pointer_width = "32")] - () => { - assert_eq!((0xfedc_ba98_u32 as isize).wrapping_mul(16), - (0xedcb_a980_u32 as isize)); - } - #[cfg(target_pointer_width = "64")] - () => { - assert_eq!((0xfedc_ba98_7654_3217_u64 as isize).wrapping_mul(16), - (0xedcb_a987_6543_2170_u64 as isize)); - } - } - - assert_eq!((0xfe as u8).wrapping_mul(16), - (0xe0 as u8)); - assert_eq!((0xfedc as u16).wrapping_mul(16), - (0xedc0 as u16)); - assert_eq!((0xfedc_ba98 as u32).wrapping_mul(16), - (0xedcb_a980 as u32)); - assert_eq!((0xfedc_ba98_7654_3217 as u64).wrapping_mul(16), - (0xedcb_a987_6543_2170 as u64)); - - match () { - #[cfg(target_pointer_width = "32")] - () => { - assert_eq!((0xfedc_ba98 as usize).wrapping_mul(16), - (0xedcb_a980 as usize)); - } - #[cfg(target_pointer_width = "64")] - () => { - assert_eq!((0xfedc_ba98_7654_3217 as usize).wrapping_mul(16), - (0xedcb_a987_6543_2170 as usize)); - } - } - - macro_rules! check_mul_no_wrap { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_mul($f), ($e) * $f); } - } - macro_rules! check_mul_wraps { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_mul($f), $e); } - } - - check_mul_no_wrap!(0xfe_u8 as i8, -1); - check_mul_no_wrap!(0xfedc_u16 as i16, -1); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_mul_no_wrap!(0xfe_u8 as i8, -2); - check_mul_no_wrap!(0xfedc_u16 as i16, -2); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, -2); - - check_mul_no_wrap!(0xfe_u8 as i8, 2); - check_mul_no_wrap!(0xfedc_u16 as i16, 2); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, 2); - - check_mul_wraps!(0x80_u8 as i8, -1); - check_mul_wraps!(0x8000_u16 as i16, -1); - check_mul_wraps!(0x8000_0000_u32 as i32, -1); - check_mul_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_mul_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_mul_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - macro_rules! check_div_no_wrap { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_div($f), ($e) / $f); } - } - macro_rules! check_div_wraps { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_div($f), $e); } - } - - check_div_no_wrap!(0xfe_u8 as i8, -1); - check_div_no_wrap!(0xfedc_u16 as i16, -1); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_div_no_wrap!(0xfe_u8 as i8, -2); - check_div_no_wrap!(0xfedc_u16 as i16, -2); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); - - check_div_no_wrap!(0xfe_u8 as i8, 2); - check_div_no_wrap!(0xfedc_u16 as i16, 2); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); - - check_div_wraps!(-128 as i8, -1); - check_div_wraps!(0x8000_u16 as i16, -1); - check_div_wraps!(0x8000_0000_u32 as i32, -1); - check_div_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_div_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_div_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - - macro_rules! check_rem_no_wrap { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_rem($f), ($e) % $f); } - } - macro_rules! check_rem_wraps { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_rem($f), 0); } - } - - check_rem_no_wrap!(0xfe_u8 as i8, -1); - check_rem_no_wrap!(0xfedc_u16 as i16, -1); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_rem_no_wrap!(0xfe_u8 as i8, -2); - check_rem_no_wrap!(0xfedc_u16 as i16, -2); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); - - check_rem_no_wrap!(0xfe_u8 as i8, 2); - check_rem_no_wrap!(0xfedc_u16 as i16, 2); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); - - check_rem_wraps!(0x80_u8 as i8, -1); - check_rem_wraps!(0x8000_u16 as i16, -1); - check_rem_wraps!(0x8000_0000_u32 as i32, -1); - check_rem_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_rem_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_rem_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - macro_rules! check_neg_no_wrap { - ($e:expr) => { assert_eq!(($e).wrapping_neg(), -($e)); } - } - macro_rules! check_neg_wraps { - ($e:expr) => { assert_eq!(($e).wrapping_neg(), ($e)); } - } - - check_neg_no_wrap!(0xfe_u8 as i8); - check_neg_no_wrap!(0xfedc_u16 as i16); - check_neg_no_wrap!(0xfedc_ba98_u32 as i32); - check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64); - check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize); - - check_neg_wraps!(0x80_u8 as i8); - check_neg_wraps!(0x8000_u16 as i16); - check_neg_wraps!(0x8000_0000_u32 as i32); - check_neg_wraps!(0x8000_0000_0000_0000_u64 as i64); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_neg_wraps!(0x8000_0000_u32 as isize); - } - #[cfg(target_pointer_width = "64")] - () => { - check_neg_wraps!(0x8000_0000_0000_0000_u64 as isize); - } - } - -} From ccbb0f5c1a1100b271f9945add665c692a2bf230 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Sun, 29 Nov 2020 21:00:14 -0500 Subject: [PATCH 11/18] Add support for stable-const-since in docs on items (standalone or assoc) --- src/librustdoc/clean/auto_trait.rs | 1 + src/librustdoc/clean/blanket_impl.rs | 1 + src/librustdoc/clean/inline.rs | 1 + src/librustdoc/clean/mod.rs | 3 + src/librustdoc/clean/types.rs | 11 +++- src/librustdoc/html/render/mod.rs | 90 ++++++++++++++++++++++------ src/test/rustdoc/const-display.rs | 10 ++++ 7 files changed, 99 insertions(+), 18 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index ff996b2a9254e..8feef9c259c13 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -124,6 +124,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { visibility: Inherited, def_id: self.cx.next_def_id(param_env_def_id.krate), stability: None, + const_stability: None, deprecation: None, kind: ImplItem(Impl { unsafety: hir::Unsafety::Normal, diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 5721927d0ec8d..33b5e84c5e074 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -113,6 +113,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { visibility: Inherited, def_id: self.cx.next_def_id(impl_def_id.krate), stability: None, + const_stability: None, deprecation: None, kind: ImplItem(Impl { unsafety: hir::Unsafety::Normal, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 61121c776f491..f3067360f0680 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -483,6 +483,7 @@ fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet) def_id: DefId::local(CRATE_DEF_INDEX), visibility: clean::Public, stability: None, + const_stability: None, deprecation: None, kind: clean::ImportItem(clean::Import::new_simple( item.ident.to_string(), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9e8ce45292417..a9e433bf45842 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2189,6 +2189,7 @@ fn clean_extern_crate( def_id: crate_def_id, visibility: krate.vis.clean(cx), stability: None, + const_stability: None, deprecation: None, kind: ExternCrateItem(name.clean(cx), path), }] @@ -2259,6 +2260,7 @@ impl Clean> for doctree::Import<'_> { def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: None, + const_stability: None, deprecation: None, kind: ImportItem(Import::new_simple( self.name.clean(cx), @@ -2279,6 +2281,7 @@ impl Clean> for doctree::Import<'_> { def_id: DefId::local(CRATE_DEF_INDEX), visibility: self.vis.clean(cx), stability: None, + const_stability: None, deprecation: None, kind: ImportItem(inner), }] diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2283b71a94fef..38d25d8d98e85 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -12,7 +12,7 @@ use rustc_ast::attr; use rustc_ast::util::comments::beautify_doc_string; use rustc_ast::{self as ast, AttrStyle}; use rustc_ast::{FloatTy, IntTy, UintTy}; -use rustc_attr::{Stability, StabilityLevel}; +use rustc_attr::{ConstStability, Stability, StabilityLevel}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_feature::UnstableFeatures; use rustc_hir as hir; @@ -87,6 +87,7 @@ crate struct Item { crate def_id: DefId, crate stability: Option, crate deprecation: Option, + crate const_stability: Option, } impl fmt::Debug for Item { @@ -155,6 +156,7 @@ impl Item { visibility: cx.tcx.visibility(def_id).clean(cx), stability: cx.tcx.lookup_stability(def_id).cloned(), deprecation: cx.tcx.lookup_deprecation(def_id).clean(cx), + const_stability: cx.tcx.lookup_const_stability(def_id).cloned(), } } @@ -262,6 +264,13 @@ impl Item { } } + crate fn const_stable_since(&self) -> Option { + match self.const_stability?.level { + StabilityLevel::Stable { since, .. } => Some(since.as_str()), + StabilityLevel::Unstable { .. } => None, + } + } + crate fn is_non_exhaustive(&self) -> bool { self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive)) } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index bbd4be88e6a8b..de620a35c80d7 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1692,13 +1692,13 @@ fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache) debug_assert!(!item.is_stripped()); // Write the breadcrumb trail header for the top write!(buf, "

"); - if let Some(version) = item.stable_since() { - write!( - buf, - "{0}", - version - ); - } + render_stability_since_raw( + buf, + item.stable_since().as_deref(), + item.const_stable_since().as_deref(), + None, + None, + ); write!( buf, "\ @@ -2476,6 +2476,7 @@ fn render_implementor( AssocItemLink::Anchor(None), RenderMode::Normal, implementor.impl_item.stable_since().as_deref(), + implementor.impl_item.const_stable_since().as_deref(), false, Some(use_absolute), false, @@ -2506,6 +2507,7 @@ fn render_impls( assoc_link, RenderMode::Normal, containing_item.stable_since().as_deref(), + containing_item.const_stable_since().as_deref(), true, None, false, @@ -2756,6 +2758,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, assoc_link, RenderMode::Normal, implementor.impl_item.stable_since().as_deref(), + implementor.impl_item.const_stable_since().as_deref(), false, None, true, @@ -2898,10 +2901,40 @@ fn assoc_type( } } -fn render_stability_since_raw(w: &mut Buffer, ver: Option<&str>, containing_ver: Option<&str>) { +fn render_stability_since_raw( + w: &mut Buffer, + ver: Option<&str>, + const_ver: Option<&str>, + containing_ver: Option<&str>, + containing_const_ver: Option<&str>, +) { + let ver = ver.and_then(|inner| if !inner.is_empty() { Some(inner) } else { None }); + + let const_ver = const_ver.and_then(|inner| if !inner.is_empty() { Some(inner) } else { None }); + if let Some(v) = ver { - if containing_ver != ver && !v.is_empty() { - write!(w, "{0}", v) + if let Some(cv) = const_ver { + if const_ver != containing_const_ver { + write!( + w, + "{0} (const: {1})", + v, cv + ); + } else if ver != containing_ver { + write!( + w, + "{0}", + v + ); + } + } else { + if ver != containing_ver { + write!( + w, + "{0}", + v + ); + } } } } @@ -2910,7 +2943,9 @@ fn render_stability_since(w: &mut Buffer, item: &clean::Item, containing_item: & render_stability_since_raw( w, item.stable_since().as_deref(), + item.const_stable_since().as_deref(), containing_item.stable_since().as_deref(), + containing_item.const_stable_since().as_deref(), ) } @@ -3462,6 +3497,7 @@ fn render_assoc_items( AssocItemLink::Anchor(None), render_mode, containing_item.stable_since().as_deref(), + containing_item.const_stable_since().as_deref(), true, None, false, @@ -3654,6 +3690,7 @@ fn render_impl( link: AssocItemLink<'_>, render_mode: RenderMode, outer_version: Option<&str>, + outer_const_version: Option<&str>, show_def_docs: bool, use_absolute: Option, is_on_foreign_type: bool, @@ -3705,11 +3742,13 @@ fn render_impl( ); } write!(w, "", id); - let since = i.impl_item.stability.as_ref().and_then(|s| match s.level { - StabilityLevel::Stable { since } => Some(since.as_str()), - StabilityLevel::Unstable { .. } => None, - }); - render_stability_since_raw(w, since.as_deref(), outer_version); + render_stability_since_raw( + w, + i.impl_item.stable_since().as_deref(), + i.impl_item.const_stable_since().as_deref(), + outer_version, + outer_const_version, + ); write_srclink(cx, &i.impl_item, w, cache); write!(w, "

"); @@ -3746,6 +3785,7 @@ fn render_impl( render_mode: RenderMode, is_default_item: bool, outer_version: Option<&str>, + outer_const_version: Option<&str>, trait_: Option<&clean::Trait>, show_def_docs: bool, cache: &Cache, @@ -3775,7 +3815,13 @@ fn render_impl( write!(w, ""); render_assoc_item(w, item, link.anchor(&id), ItemType::Impl); write!(w, ""); - render_stability_since_raw(w, item.stable_since().as_deref(), outer_version); + render_stability_since_raw( + w, + item.stable_since().as_deref(), + item.const_stable_since().as_deref(), + outer_version, + outer_const_version, + ); write_srclink(cx, item, w, cache); write!(w, ""); } @@ -3791,7 +3837,13 @@ fn render_impl( write!(w, "

", id, item_type, extra_class); assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), ""); write!(w, ""); - render_stability_since_raw(w, item.stable_since().as_deref(), outer_version); + render_stability_since_raw( + w, + item.stable_since().as_deref(), + item.const_stable_since().as_deref(), + outer_version, + outer_const_version, + ); write_srclink(cx, item, w, cache); write!(w, "

"); } @@ -3854,6 +3906,7 @@ fn render_impl( render_mode, false, outer_version, + outer_const_version, trait_, show_def_docs, cache, @@ -3868,6 +3921,7 @@ fn render_impl( parent: &clean::Item, render_mode: RenderMode, outer_version: Option<&str>, + outer_const_version: Option<&str>, show_def_docs: bool, cache: &Cache, ) { @@ -3888,6 +3942,7 @@ fn render_impl( render_mode, true, outer_version, + outer_const_version, None, show_def_docs, cache, @@ -3909,6 +3964,7 @@ fn render_impl( &i.impl_item, render_mode, outer_version, + outer_const_version, show_def_docs, cache, ); diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs index b3fbe377f0b96..11ba68a388fba 100644 --- a/src/test/rustdoc/const-display.rs +++ b/src/test/rustdoc/const-display.rs @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + #![crate_name = "foo"] #![unstable(feature = "humans", @@ -17,6 +19,7 @@ pub const unsafe fn foo() -> u32 { 42 } pub const fn foo2() -> u32 { 42 } // @has 'foo/fn.bar2.html' '//pre' 'pub const fn bar2() -> u32' +// @has - //span '1.0.0 (const: 1.0.0)' #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn bar2() -> u32 { 42 } @@ -26,6 +29,7 @@ pub const fn bar2() -> u32 { 42 } pub const unsafe fn foo2_gated() -> u32 { 42 } // @has 'foo/fn.bar2_gated.html' '//pre' 'pub const unsafe fn bar2_gated() -> u32' +// @has - '//span[@class="since"]' '1.0.0 (const: 1.0.0)' #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const unsafe fn bar2_gated() -> u32 { 42 } @@ -40,4 +44,10 @@ impl Foo { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature="foo", issue = "none")] pub const unsafe fn gated() -> u32 { 42 } + + // @has 'foo/struct.Foo.html' '//h4[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32' + // @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)' + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.2.0")] + pub const fn stable_impl() -> u32 { 42 } } From 4eb64c842b73768b7c1b392fdab85996f622d4a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Nov 2020 16:37:40 +0100 Subject: [PATCH 12/18] update Miri --- Cargo.lock | 1 + src/tools/miri | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 18dfe890a0c1e..ce1f705bdffad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2131,6 +2131,7 @@ dependencies = [ "rustc-workspace-hack", "rustc_version", "shell-escape", + "smallvec 1.4.2", ] [[package]] diff --git a/src/tools/miri b/src/tools/miri index 746ea5b141baf..47acece7aa25d 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 746ea5b141baf1f86c2ad17753a37b135e0c1aa3 +Subproject commit 47acece7aa25d7b5edfae0bfd4b94e6e55a7b4b0 From 1c367c0a701807a4988d8a4247cc38a653d91abf Mon Sep 17 00:00:00 2001 From: Havard Eidnes Date: Mon, 30 Nov 2020 19:18:21 +0100 Subject: [PATCH 13/18] Update with status for various NetBSD ports. The NetBSD ports of rust to aarch64, armv7*, i686, and powerpc** all both build and run. *) Natively requires repeated successive build attempts (rustc is such a resource pig VM-consumption-wise), or run in a chroot on an aarch64 host where the available VM space is 4GB instead of the native 2GB. **) Powerpc either requires -latomic in a directory searched by default by 'ld' or to be built within pkgsrc which has a patch to tackle this. --- src/doc/rustc/src/platform-support.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 99e0a2b177fc0..96ffff0b67261 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -156,7 +156,7 @@ target | std | host | notes `aarch64-apple-tvos` | * | | ARM64 tvOS `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ? | | -`aarch64-unknown-netbsd` | ? | | +`aarch64-unknown-netbsd` | ✓ | ✓ | `aarch64-unknown-openbsd` | ✓ | ✓ | ARM64 OpenBSD `aarch64-unknown-redox` | ? | | ARM64 Redox OS `aarch64-uwp-windows-msvc` | ? | | @@ -166,7 +166,7 @@ target | std | host | notes `armv6-unknown-netbsd-eabihf` | ? | | `armv7-apple-ios` | ✓ | | ARMv7 iOS, Cortex-a8 `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD -`armv7-unknown-netbsd-eabihf` | ? | | +`armv7-unknown-netbsd-eabihf` | ✓ | ✓ | `armv7-wrs-vxworks-eabihf` | ? | | `armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat `armv7s-apple-ios` | ✓ | | @@ -177,7 +177,7 @@ target | std | host | notes `i686-pc-windows-msvc` | ✓ | | 32-bit Windows XP support `i686-unknown-uefi` | ? | | 32-bit UEFI `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku -`i686-unknown-netbsd` | ✓ | | NetBSD/i386 with SSE2 +`i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2 `i686-unknown-openbsd` | ✓ | ✓ | 32-bit OpenBSD `i686-uwp-windows-gnu` | ? | | `i686-uwp-windows-msvc` | ? | | @@ -193,7 +193,7 @@ target | std | host | notes `msp430-none-elf` | * | | 16-bit MSP430 microcontrollers `powerpc-unknown-linux-gnuspe` | ✓ | | PowerPC SPE Linux `powerpc-unknown-linux-musl` | ? | | -`powerpc-unknown-netbsd` | ? | | +`powerpc-unknown-netbsd` | ✓ | ✓ | `powerpc-wrs-vxworks` | ? | | `powerpc-wrs-vxworks-spe` | ? | | `powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2) From 36e6aa0aa686049736810d7444c1bfca8e14d38d Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 18 Nov 2020 13:42:36 -0800 Subject: [PATCH 14/18] Stop adding '*' at the end of type names for Ref and Slice when computing debug info for MSVC debuggers --- compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 896af8a9191c2..d1bbf74307c6b 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -94,7 +94,14 @@ pub fn push_debuginfo_type_name<'tcx>( push_debuginfo_type_name(tcx, inner_type, true, output, visited); if cpp_like_names { - output.push('*'); + // Slices and `&str` are treated like C++ pointers when computing debug + // info for MSVC debugger. However, adding '*' at the end of these types' names + // causes the .natvis engine for WinDbg to fail to display their data, so we opt these + // types out to aid debugging in MSVC. + match *inner_type.kind() { + ty::Slice(_) | ty::Str => {} + _ => output.push('*'), + } } } ty::Array(inner_type, len) => { From 36154e5b9b1e408627bf109b1b4954d7aad915cc Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Mon, 3 Aug 2020 12:45:27 -0500 Subject: [PATCH 15/18] Add json backend Respond to comments and start adding tests Fix re-exports and extern-crate Add expected output tests Add restricted paths Format Fix: associated methods missing in output Ignore stripped items Mark stripped items removing them creates dangling references Fix tests and update conversions Don't panic if JSON backend fails to create a file Fix attribute error in JSON testsuite Move rustdoc-json to rustdoc/ This way it doesn't have to build rustc twice. Eventually it should probably get its own suite, like rustdoc-js, but that can be fixed in a follow-up. Small cleanups Don't prettify json before printing This fully halves the size of the emitted JSON. Add comments [BREAKING CHANGE] rename version -> crate_version [BREAKING CHANGE] rename source -> span Use exhaustive matches Don't qualify imports for DefId Rename clean::{ItemEnum -> ItemKind}, clean::Item::{inner -> kind} Fix Visibility conversion clean::Visability was changed here: https://github.com/rust-lang/rust/pull/77820/files#diff-df9f90aae0b7769e1eb6ea6f1d73c1c3f649e1ac48a20e169662a8930eb427beL1467-R1509 More churn catchup Format --- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/clean/types.rs | 41 ++ src/librustdoc/json/conversions.rs | 596 ++++++++++++++++++ src/librustdoc/json/mod.rs | 223 ++++++- src/librustdoc/json/types.rs | 493 +++++++++++++++ src/test/rustdoc/rustdoc-json/Makefile | 6 + .../rustdoc-json/check_missing_items.py | 181 ++++++ src/test/rustdoc/rustdoc-json/compare.py | 107 ++++ .../rustdoc/rustdoc-json/structs.expected | 468 ++++++++++++++ src/test/rustdoc/rustdoc-json/structs.rs | 17 + 10 files changed, 2117 insertions(+), 17 deletions(-) create mode 100644 src/librustdoc/json/conversions.rs create mode 100644 src/librustdoc/json/types.rs create mode 100644 src/test/rustdoc/rustdoc-json/Makefile create mode 100644 src/test/rustdoc/rustdoc-json/check_missing_items.py create mode 100644 src/test/rustdoc/rustdoc-json/compare.py create mode 100644 src/test/rustdoc/rustdoc-json/structs.expected create mode 100644 src/test/rustdoc/rustdoc-json/structs.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9e8ce45292417..584adcf220d1e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2276,7 +2276,7 @@ impl Clean> for doctree::Import<'_> { name: None, attrs: self.attrs.clean(cx), source: self.span.clean(cx), - def_id: DefId::local(CRATE_DEF_INDEX), + def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: None, deprecation: None, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2283b71a94fef..281c0945380b0 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -328,6 +328,42 @@ crate enum ItemKind { } impl ItemKind { + /// Some items contain others such as structs (for their fields) and Enums + /// (for their variants). This method returns those contained items. + crate fn inner_items(&self) -> impl Iterator { + match self { + StructItem(s) => s.fields.iter(), + UnionItem(u) => u.fields.iter(), + VariantItem(Variant { kind: VariantKind::Struct(v) }) => v.fields.iter(), + EnumItem(e) => e.variants.iter(), + TraitItem(t) => t.items.iter(), + ImplItem(i) => i.items.iter(), + ModuleItem(m) => m.items.iter(), + ExternCrateItem(_, _) + | ImportItem(_) + | FunctionItem(_) + | TypedefItem(_, _) + | OpaqueTyItem(_) + | StaticItem(_) + | ConstantItem(_) + | TraitAliasItem(_) + | TyMethodItem(_) + | MethodItem(_, _) + | StructFieldItem(_) + | VariantItem(_) + | ForeignFunctionItem(_) + | ForeignStaticItem(_) + | ForeignTypeItem + | MacroItem(_) + | ProcMacroItem(_) + | PrimitiveItem(_) + | AssocConstItem(_, _) + | AssocTypeItem(_, _) + | StrippedItem(_) + | KeywordItem(_) => [].iter(), + } + } + crate fn is_type_alias(&self) -> bool { match *self { ItemKind::TypedefItem(_, _) | ItemKind::AssocTypeItem(_, _) => true, @@ -1604,6 +1640,11 @@ impl Path { crate fn last_name(&self) -> &str { self.segments.last().expect("segments were empty").name.as_str() } + + crate fn whole_name(&self) -> String { + String::from(if self.global { "::" } else { "" }) + + &self.segments.iter().map(|s| s.name.clone()).collect::>().join("::") + } } #[derive(Clone, PartialEq, Eq, Debug, Hash)] diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs new file mode 100644 index 0000000000000..80192623d54fe --- /dev/null +++ b/src/librustdoc/json/conversions.rs @@ -0,0 +1,596 @@ +//! These from impls are used to create the JSON types which get serialized. They're very close to +//! the `clean` types but with some fields removed or stringified to simplify the output and not +//! expose unstable compiler internals. + +use std::convert::From; + +use rustc_ast::ast; +use rustc_span::def_id::{DefId, CRATE_DEF_INDEX}; + +use crate::clean; +use crate::doctree; +use crate::formats::item_type::ItemType; +use crate::json::types::*; + +impl From for Item { + fn from(item: clean::Item) -> Self { + let item_type = ItemType::from(&item); + let clean::Item { + source, + name, + attrs, + kind: inner, + visibility, + def_id, + stability: _, + deprecation, + } = item; + Item { + id: def_id.into(), + crate_id: def_id.krate.as_u32(), + name, + stripped: match inner { + clean::StrippedItem(_) => true, + _ => false, + }, + source: source.into(), + visibility: visibility.into(), + docs: attrs.collapsed_doc_value().unwrap_or_default(), + links: attrs + .links + .into_iter() + .filter_map(|clean::ItemLink { link, did, .. }| did.map(|did| (link, did.into()))) + .collect(), + attrs: attrs + .other_attrs + .iter() + .map(rustc_ast_pretty::pprust::attribute_to_string) + .collect(), + deprecation: deprecation.map(Into::into), + kind: item_type.into(), + inner: inner.into(), + } + } +} + +impl From for Option { + fn from(span: clean::Span) -> Self { + let clean::Span { loline, locol, hiline, hicol, .. } = span; + match span.filename { + rustc_span::FileName::Real(name) => Some(Span { + filename: match name { + rustc_span::RealFileName::Named(path) => path, + rustc_span::RealFileName::Devirtualized { local_path, virtual_name: _ } => { + local_path + } + }, + begin: (loline, locol), + end: (hiline, hicol), + }), + _ => None, + } + } +} + +impl From for Deprecation { + fn from(deprecation: clean::Deprecation) -> Self { + let clean::Deprecation { since, note, is_since_rustc_version: _ } = deprecation; + Deprecation { since, note } + } +} + +impl From for Visibility { + fn from(v: clean::Visibility) -> Self { + use clean::Visibility::*; + match v { + Public => Visibility::Public, + Inherited => Visibility::Default, + Restricted(did, _) if did.index == CRATE_DEF_INDEX => Visibility::Crate, + Restricted(did, path) => Visibility::Restricted { + parent: did.into(), + path: path.to_string_no_crate_verbose(), + }, + } + } +} + +impl From for GenericArgs { + fn from(args: clean::GenericArgs) -> Self { + use clean::GenericArgs::*; + match args { + AngleBracketed { args, bindings } => GenericArgs::AngleBracketed { + args: args.into_iter().map(Into::into).collect(), + bindings: bindings.into_iter().map(Into::into).collect(), + }, + Parenthesized { inputs, output } => GenericArgs::Parenthesized { + inputs: inputs.into_iter().map(Into::into).collect(), + output: output.map(Into::into), + }, + } + } +} + +impl From for GenericArg { + fn from(arg: clean::GenericArg) -> Self { + use clean::GenericArg::*; + match arg { + Lifetime(l) => GenericArg::Lifetime(l.0), + Type(t) => GenericArg::Type(t.into()), + Const(c) => GenericArg::Const(c.into()), + } + } +} + +impl From for Constant { + fn from(constant: clean::Constant) -> Self { + let clean::Constant { type_, expr, value, is_literal } = constant; + Constant { type_: type_.into(), expr, value, is_literal } + } +} + +impl From for TypeBinding { + fn from(binding: clean::TypeBinding) -> Self { + TypeBinding { name: binding.name, binding: binding.kind.into() } + } +} + +impl From for TypeBindingKind { + fn from(kind: clean::TypeBindingKind) -> Self { + use clean::TypeBindingKind::*; + match kind { + Equality { ty } => TypeBindingKind::Equality(ty.into()), + Constraint { bounds } => { + TypeBindingKind::Constraint(bounds.into_iter().map(Into::into).collect()) + } + } + } +} + +impl From for Id { + fn from(did: DefId) -> Self { + Id(format!("{}:{}", did.krate.as_u32(), u32::from(did.index))) + } +} + +impl From for ItemEnum { + fn from(item: clean::ItemKind) -> Self { + use clean::ItemKind::*; + match item { + ModuleItem(m) => ItemEnum::ModuleItem(m.into()), + ExternCrateItem(c, a) => ItemEnum::ExternCrateItem { name: c, rename: a }, + ImportItem(i) => ItemEnum::ImportItem(i.into()), + StructItem(s) => ItemEnum::StructItem(s.into()), + UnionItem(u) => ItemEnum::StructItem(u.into()), + StructFieldItem(f) => ItemEnum::StructFieldItem(f.into()), + EnumItem(e) => ItemEnum::EnumItem(e.into()), + VariantItem(v) => ItemEnum::VariantItem(v.into()), + FunctionItem(f) => ItemEnum::FunctionItem(f.into()), + ForeignFunctionItem(f) => ItemEnum::FunctionItem(f.into()), + TraitItem(t) => ItemEnum::TraitItem(t.into()), + TraitAliasItem(t) => ItemEnum::TraitAliasItem(t.into()), + MethodItem(m, _) => ItemEnum::MethodItem(m.into()), + TyMethodItem(m) => ItemEnum::MethodItem(m.into()), + ImplItem(i) => ItemEnum::ImplItem(i.into()), + StaticItem(s) => ItemEnum::StaticItem(s.into()), + ForeignStaticItem(s) => ItemEnum::StaticItem(s.into()), + ForeignTypeItem => ItemEnum::ForeignTypeItem, + TypedefItem(t, _) => ItemEnum::TypedefItem(t.into()), + OpaqueTyItem(t) => ItemEnum::OpaqueTyItem(t.into()), + ConstantItem(c) => ItemEnum::ConstantItem(c.into()), + MacroItem(m) => ItemEnum::MacroItem(m.source), + ProcMacroItem(m) => ItemEnum::ProcMacroItem(m.into()), + AssocConstItem(t, s) => ItemEnum::AssocConstItem { type_: t.into(), default: s }, + AssocTypeItem(g, t) => ItemEnum::AssocTypeItem { + bounds: g.into_iter().map(Into::into).collect(), + default: t.map(Into::into), + }, + StrippedItem(inner) => (*inner).into(), + PrimitiveItem(_) | KeywordItem(_) => { + panic!("{:?} is not supported for JSON output", item) + } + } + } +} + +impl From for Module { + fn from(module: clean::Module) -> Self { + Module { + is_crate: module.is_crate, + items: module.items.into_iter().map(|i| i.def_id.into()).collect(), + } + } +} + +impl From for Struct { + fn from(struct_: clean::Struct) -> Self { + let clean::Struct { struct_type, generics, fields, fields_stripped } = struct_; + Struct { + struct_type: struct_type.into(), + generics: generics.into(), + fields_stripped, + fields: fields.into_iter().map(|i| i.def_id.into()).collect(), + impls: Vec::new(), // Added in JsonRenderer::item + } + } +} + +impl From for Struct { + fn from(struct_: clean::Union) -> Self { + let clean::Union { struct_type, generics, fields, fields_stripped } = struct_; + Struct { + struct_type: struct_type.into(), + generics: generics.into(), + fields_stripped, + fields: fields.into_iter().map(|i| i.def_id.into()).collect(), + impls: Vec::new(), // Added in JsonRenderer::item + } + } +} + +impl From for StructType { + fn from(struct_type: doctree::StructType) -> Self { + use doctree::StructType::*; + match struct_type { + Plain => StructType::Plain, + Tuple => StructType::Tuple, + Unit => StructType::Unit, + } + } +} + +fn stringify_header(header: &rustc_hir::FnHeader) -> String { + let mut s = String::from(header.unsafety.prefix_str()); + if header.asyncness == rustc_hir::IsAsync::Async { + s.push_str("async ") + } + if header.constness == rustc_hir::Constness::Const { + s.push_str("const ") + } + s +} + +impl From for Function { + fn from(function: clean::Function) -> Self { + let clean::Function { decl, generics, header, all_types: _, ret_types: _ } = function; + Function { + decl: decl.into(), + generics: generics.into(), + header: stringify_header(&header), + abi: header.abi.to_string(), + } + } +} + +impl From for Generics { + fn from(generics: clean::Generics) -> Self { + Generics { + params: generics.params.into_iter().map(Into::into).collect(), + where_predicates: generics.where_predicates.into_iter().map(Into::into).collect(), + } + } +} + +impl From for GenericParamDef { + fn from(generic_param: clean::GenericParamDef) -> Self { + GenericParamDef { name: generic_param.name, kind: generic_param.kind.into() } + } +} + +impl From for GenericParamDefKind { + fn from(kind: clean::GenericParamDefKind) -> Self { + use clean::GenericParamDefKind::*; + match kind { + Lifetime => GenericParamDefKind::Lifetime, + Type { did: _, bounds, default, synthetic: _ } => GenericParamDefKind::Type { + bounds: bounds.into_iter().map(Into::into).collect(), + default: default.map(Into::into), + }, + Const { did: _, ty } => GenericParamDefKind::Const(ty.into()), + } + } +} + +impl From for WherePredicate { + fn from(predicate: clean::WherePredicate) -> Self { + use clean::WherePredicate::*; + match predicate { + BoundPredicate { ty, bounds } => WherePredicate::BoundPredicate { + ty: ty.into(), + bounds: bounds.into_iter().map(Into::into).collect(), + }, + RegionPredicate { lifetime, bounds } => WherePredicate::RegionPredicate { + lifetime: lifetime.0, + bounds: bounds.into_iter().map(Into::into).collect(), + }, + EqPredicate { lhs, rhs } => { + WherePredicate::EqPredicate { lhs: lhs.into(), rhs: rhs.into() } + } + } + } +} + +impl From for GenericBound { + fn from(bound: clean::GenericBound) -> Self { + use clean::GenericBound::*; + match bound { + TraitBound(clean::PolyTrait { trait_, generic_params }, modifier) => { + GenericBound::TraitBound { + trait_: trait_.into(), + generic_params: generic_params.into_iter().map(Into::into).collect(), + modifier: modifier.into(), + } + } + Outlives(lifetime) => GenericBound::Outlives(lifetime.0), + } + } +} + +impl From for TraitBoundModifier { + fn from(modifier: rustc_hir::TraitBoundModifier) -> Self { + use rustc_hir::TraitBoundModifier::*; + match modifier { + None => TraitBoundModifier::None, + Maybe => TraitBoundModifier::Maybe, + MaybeConst => TraitBoundModifier::MaybeConst, + } + } +} + +impl From for Type { + fn from(ty: clean::Type) -> Self { + use clean::Type::*; + match ty { + ResolvedPath { path, param_names, did, is_generic: _ } => Type::ResolvedPath { + name: path.whole_name(), + id: did.into(), + args: path.segments.last().map(|args| Box::new(args.clone().args.into())), + param_names: param_names + .map(|v| v.into_iter().map(Into::into).collect()) + .unwrap_or_default(), + }, + Generic(s) => Type::Generic(s), + Primitive(p) => Type::Primitive(p.as_str().to_string()), + BareFunction(f) => Type::FunctionPointer(Box::new((*f).into())), + Tuple(t) => Type::Tuple(t.into_iter().map(Into::into).collect()), + Slice(t) => Type::Slice(Box::new((*t).into())), + Array(t, s) => Type::Array { type_: Box::new((*t).into()), len: s }, + ImplTrait(g) => Type::ImplTrait(g.into_iter().map(Into::into).collect()), + Never => Type::Never, + Infer => Type::Infer, + RawPointer(mutability, type_) => Type::RawPointer { + mutable: mutability == ast::Mutability::Mut, + type_: Box::new((*type_).into()), + }, + BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef { + lifetime: lifetime.map(|l| l.0), + mutable: mutability == ast::Mutability::Mut, + type_: Box::new((*type_).into()), + }, + QPath { name, self_type, trait_ } => Type::QualifiedPath { + name, + self_type: Box::new((*self_type).into()), + trait_: Box::new((*trait_).into()), + }, + } + } +} + +impl From for FunctionPointer { + fn from(bare_decl: clean::BareFunctionDecl) -> Self { + let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl; + FunctionPointer { + is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, + generic_params: generic_params.into_iter().map(Into::into).collect(), + decl: decl.into(), + abi: abi.to_string(), + } + } +} + +impl From for FnDecl { + fn from(decl: clean::FnDecl) -> Self { + let clean::FnDecl { inputs, output, c_variadic, attrs: _ } = decl; + FnDecl { + inputs: inputs.values.into_iter().map(|arg| (arg.name, arg.type_.into())).collect(), + output: match output { + clean::FnRetTy::Return(t) => Some(t.into()), + clean::FnRetTy::DefaultReturn => None, + }, + c_variadic, + } + } +} + +impl From for Trait { + fn from(trait_: clean::Trait) -> Self { + let clean::Trait { unsafety, items, generics, bounds, is_spotlight: _, is_auto } = trait_; + Trait { + is_auto, + is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, + items: items.into_iter().map(|i| i.def_id.into()).collect(), + generics: generics.into(), + bounds: bounds.into_iter().map(Into::into).collect(), + implementors: Vec::new(), // Added in JsonRenderer::item + } + } +} + +impl From for Impl { + fn from(impl_: clean::Impl) -> Self { + let clean::Impl { + unsafety, + generics, + provided_trait_methods, + trait_, + for_, + items, + polarity, + synthetic, + blanket_impl, + } = impl_; + Impl { + is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, + generics: generics.into(), + provided_trait_methods: provided_trait_methods.into_iter().collect(), + trait_: trait_.map(Into::into), + for_: for_.into(), + items: items.into_iter().map(|i| i.def_id.into()).collect(), + negative: polarity == Some(clean::ImplPolarity::Negative), + synthetic, + blanket_impl: blanket_impl.map(Into::into), + } + } +} + +impl From for Method { + fn from(function: clean::Function) -> Self { + let clean::Function { header, decl, generics, all_types: _, ret_types: _ } = function; + Method { + decl: decl.into(), + generics: generics.into(), + header: stringify_header(&header), + has_body: true, + } + } +} + +impl From for Enum { + fn from(enum_: clean::Enum) -> Self { + let clean::Enum { variants, generics, variants_stripped } = enum_; + Enum { + generics: generics.into(), + variants_stripped, + variants: variants.into_iter().map(|i| i.def_id.into()).collect(), + impls: Vec::new(), // Added in JsonRenderer::item + } + } +} + +impl From for Struct { + fn from(struct_: clean::VariantStruct) -> Self { + let clean::VariantStruct { struct_type, fields, fields_stripped } = struct_; + Struct { + struct_type: struct_type.into(), + generics: Default::default(), + fields_stripped, + fields: fields.into_iter().map(|i| i.def_id.into()).collect(), + impls: Vec::new(), + } + } +} + +impl From for Variant { + fn from(variant: clean::Variant) -> Self { + use clean::VariantKind::*; + match variant.kind { + CLike => Variant::Plain, + Tuple(t) => Variant::Tuple(t.into_iter().map(Into::into).collect()), + Struct(s) => Variant::Struct(s.fields.into_iter().map(|i| i.def_id.into()).collect()), + } + } +} + +impl From for Import { + fn from(import: clean::Import) -> Self { + use clean::ImportKind::*; + match import.kind { + Simple(s) => Import { + span: import.source.path.whole_name(), + name: s, + id: import.source.did.map(Into::into), + glob: false, + }, + Glob => Import { + span: import.source.path.whole_name(), + name: import.source.path.last_name().to_string(), + id: import.source.did.map(Into::into), + glob: true, + }, + } + } +} + +impl From for ProcMacro { + fn from(mac: clean::ProcMacro) -> Self { + ProcMacro { kind: mac.kind.into(), helpers: mac.helpers } + } +} + +impl From for MacroKind { + fn from(kind: rustc_span::hygiene::MacroKind) -> Self { + use rustc_span::hygiene::MacroKind::*; + match kind { + Bang => MacroKind::Bang, + Attr => MacroKind::Attr, + Derive => MacroKind::Derive, + } + } +} + +impl From for Typedef { + fn from(typedef: clean::Typedef) -> Self { + let clean::Typedef { type_, generics, item_type: _ } = typedef; + Typedef { type_: type_.into(), generics: generics.into() } + } +} + +impl From for OpaqueTy { + fn from(opaque: clean::OpaqueTy) -> Self { + OpaqueTy { + bounds: opaque.bounds.into_iter().map(Into::into).collect(), + generics: opaque.generics.into(), + } + } +} + +impl From for Static { + fn from(stat: clean::Static) -> Self { + Static { + type_: stat.type_.into(), + mutable: stat.mutability == ast::Mutability::Mut, + expr: stat.expr, + } + } +} + +impl From for TraitAlias { + fn from(alias: clean::TraitAlias) -> Self { + TraitAlias { + generics: alias.generics.into(), + params: alias.bounds.into_iter().map(Into::into).collect(), + } + } +} + +impl From for ItemKind { + fn from(kind: ItemType) -> Self { + use ItemType::*; + match kind { + Module => ItemKind::Module, + ExternCrate => ItemKind::ExternCrate, + Import => ItemKind::Import, + Struct => ItemKind::Struct, + Union => ItemKind::Union, + Enum => ItemKind::Enum, + Function => ItemKind::Function, + Typedef => ItemKind::Typedef, + OpaqueTy => ItemKind::OpaqueTy, + Static => ItemKind::Static, + Constant => ItemKind::Constant, + Trait => ItemKind::Trait, + Impl => ItemKind::Impl, + TyMethod | Method => ItemKind::Method, + StructField => ItemKind::StructField, + Variant => ItemKind::Variant, + Macro => ItemKind::Macro, + Primitive => ItemKind::Primitive, + AssocConst => ItemKind::AssocConst, + AssocType => ItemKind::AssocType, + ForeignType => ItemKind::ForeignType, + Keyword => ItemKind::Keyword, + TraitAlias => ItemKind::TraitAlias, + ProcAttribute => ItemKind::ProcAttribute, + ProcDerive => ItemKind::ProcDerive, + } + } +} diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 5eb1f7b1f7780..20a8de144adb3 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -1,47 +1,238 @@ +//! Rustdoc's JSON backend +//! +//! This module contains the logic for rendering a crate as JSON rather than the normal static HTML +//! output. See [the RFC](https://github.com/rust-lang/rfcs/pull/2963) and the [`types`] module +//! docs for usage and details. + +mod conversions; +pub mod types; + +use std::cell::RefCell; +use std::fs::File; +use std::path::PathBuf; +use std::rc::Rc; + +use rustc_data_structures::fx::FxHashMap; +use rustc_span::edition::Edition; + use crate::clean; use crate::config::{RenderInfo, RenderOptions}; use crate::error::Error; use crate::formats::cache::Cache; use crate::formats::FormatRenderer; - -use rustc_span::edition::Edition; +use crate::html::render::cache::ExternalLocation; #[derive(Clone)] -crate struct JsonRenderer {} +crate struct JsonRenderer { + /// A mapping of IDs that contains all local items for this crate which gets output as a top + /// level field of the JSON blob. + index: Rc>>, + /// The directory where the blob will be written to. + out_path: PathBuf, +} + +impl JsonRenderer { + fn get_trait_implementors( + &mut self, + id: rustc_span::def_id::DefId, + cache: &Cache, + ) -> Vec { + cache + .implementors + .get(&id) + .map(|implementors| { + implementors + .iter() + .map(|i| { + let item = &i.impl_item; + self.item(item.clone(), cache).unwrap(); + item.def_id.into() + }) + .collect() + }) + .unwrap_or_default() + } + + fn get_impls(&mut self, id: rustc_span::def_id::DefId, cache: &Cache) -> Vec { + cache + .impls + .get(&id) + .map(|impls| { + impls + .iter() + .filter_map(|i| { + let item = &i.impl_item; + if item.def_id.is_local() { + self.item(item.clone(), cache).unwrap(); + Some(item.def_id.into()) + } else { + None + } + }) + .collect() + }) + .unwrap_or_default() + } + + fn get_trait_items(&mut self, cache: &Cache) -> Vec<(types::Id, types::Item)> { + cache + .traits + .iter() + .filter_map(|(&id, trait_item)| { + // only need to synthesize items for external traits + if !id.is_local() { + trait_item.items.clone().into_iter().for_each(|i| self.item(i, cache).unwrap()); + Some(( + id.into(), + types::Item { + id: id.into(), + crate_id: id.krate.as_u32(), + name: cache + .paths + .get(&id) + .unwrap_or_else(|| { + cache + .external_paths + .get(&id) + .expect("Trait should either be in local or external paths") + }) + .0 + .last() + .map(Clone::clone), + stripped: false, + visibility: types::Visibility::Public, + kind: types::ItemKind::Trait, + inner: types::ItemEnum::TraitItem(trait_item.clone().into()), + source: None, + docs: Default::default(), + links: Default::default(), + attrs: Default::default(), + deprecation: Default::default(), + }, + )) + } else { + None + } + }) + .collect() + } +} impl FormatRenderer for JsonRenderer { fn init( - _krate: clean::Crate, - _options: RenderOptions, + krate: clean::Crate, + options: RenderOptions, _render_info: RenderInfo, _edition: Edition, _cache: &mut Cache, ) -> Result<(Self, clean::Crate), Error> { - unimplemented!() + debug!("Initializing json renderer"); + Ok(( + JsonRenderer { + index: Rc::new(RefCell::new(FxHashMap::default())), + out_path: options.output, + }, + krate, + )) } - fn item(&mut self, _item: clean::Item, _cache: &Cache) -> Result<(), Error> { - unimplemented!() + /// Inserts an item into the index. This should be used rather than directly calling insert on + /// the hashmap because certain items (traits and types) need to have their mappings for trait + /// implementations filled out before they're inserted. + fn item(&mut self, item: clean::Item, cache: &Cache) -> Result<(), Error> { + // Flatten items that recursively store other items + item.kind.inner_items().for_each(|i| self.item(i.clone(), cache).unwrap()); + + let id = item.def_id; + let mut new_item: types::Item = item.into(); + if let types::ItemEnum::TraitItem(ref mut t) = new_item.inner { + t.implementors = self.get_trait_implementors(id, cache) + } else if let types::ItemEnum::StructItem(ref mut s) = new_item.inner { + s.impls = self.get_impls(id, cache) + } else if let types::ItemEnum::EnumItem(ref mut e) = new_item.inner { + e.impls = self.get_impls(id, cache) + } + + self.index.borrow_mut().insert(id.into(), new_item); + Ok(()) } fn mod_item_in( &mut self, - _item: &clean::Item, - _item_name: &str, - _cache: &Cache, + item: &clean::Item, + _module_name: &str, + cache: &Cache, ) -> Result<(), Error> { - unimplemented!() + use clean::types::ItemKind::*; + if let ModuleItem(m) = &item.kind { + for item in &m.items { + match &item.kind { + // These don't have names so they don't get added to the output by default + ImportItem(_) => self.item(item.clone(), cache).unwrap(), + ExternCrateItem(_, _) => self.item(item.clone(), cache).unwrap(), + ImplItem(i) => { + i.items.iter().for_each(|i| self.item(i.clone(), cache).unwrap()) + } + _ => {} + } + } + } + self.item(item.clone(), cache).unwrap(); + Ok(()) } fn mod_item_out(&mut self, _item_name: &str) -> Result<(), Error> { - unimplemented!() + Ok(()) } - fn after_krate(&mut self, _krate: &clean::Crate, _cache: &Cache) -> Result<(), Error> { - unimplemented!() + fn after_krate(&mut self, krate: &clean::Crate, cache: &Cache) -> Result<(), Error> { + debug!("Done with crate"); + let mut index = (*self.index).clone().into_inner(); + index.extend(self.get_trait_items(cache)); + let output = types::Crate { + root: types::Id(String::from("0:0")), + crate_version: krate.version.clone(), + includes_private: cache.document_private, + index, + paths: cache + .paths + .clone() + .into_iter() + .chain(cache.external_paths.clone().into_iter()) + .map(|(k, (path, kind))| { + ( + k.into(), + types::ItemSummary { crate_id: k.krate.as_u32(), path, kind: kind.into() }, + ) + }) + .collect(), + external_crates: cache + .extern_locations + .iter() + .map(|(k, v)| { + ( + k.as_u32(), + types::ExternalCrate { + name: v.0.clone(), + html_root_url: match &v.2 { + ExternalLocation::Remote(s) => Some(s.clone()), + _ => None, + }, + }, + ) + }) + .collect(), + format_version: 1, + }; + let mut p = self.out_path.clone(); + p.push(output.index.get(&output.root).unwrap().name.clone().unwrap()); + p.set_extension("json"); + let file = File::create(&p).map_err(|error| Error { error: error.to_string(), file: p })?; + serde_json::ser::to_writer(&file, &output).unwrap(); + Ok(()) } fn after_run(&mut self, _diag: &rustc_errors::Handler) -> Result<(), Error> { - unimplemented!() + Ok(()) } } diff --git a/src/librustdoc/json/types.rs b/src/librustdoc/json/types.rs new file mode 100644 index 0000000000000..62705affafce1 --- /dev/null +++ b/src/librustdoc/json/types.rs @@ -0,0 +1,493 @@ +//! Rustdoc's JSON output interface +//! +//! These types are the public API exposed through the `--output-format json` flag. The [`Crate`] +//! struct is the root of the JSON blob and all other items are contained within. + +use std::path::PathBuf; + +use rustc_data_structures::fx::FxHashMap; +use serde::{Deserialize, Serialize}; + +/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information +/// about the language items in the local crate, as well as info about external items to allow +/// tools to find or link to them. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Crate { + /// The id of the root [`Module`] item of the local crate. + pub root: Id, + /// The version string given to `--crate-version`, if any. + pub crate_version: Option, + /// Whether or not the output includes private items. + pub includes_private: bool, + /// A collection of all items in the local crate as well as some external traits and their + /// items that are referenced locally. + pub index: FxHashMap, + /// Maps IDs to fully qualified paths and other info helpful for generating links. + pub paths: FxHashMap, + /// Maps `crate_id` of items to a crate name and html_root_url if it exists. + pub external_crates: FxHashMap, + /// A single version number to be used in the future when making backwards incompatible changes + /// to the JSON output. + pub format_version: u32, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ExternalCrate { + pub name: String, + pub html_root_url: Option, +} + +/// For external (not defined in the local crate) items, you don't get the same level of +/// information. This struct should contain enough to generate a link/reference to the item in +/// question, or can be used by a tool that takes the json output of multiple crates to find +/// the actual item definition with all the relevant info. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ItemSummary { + /// Can be used to look up the name and html_root_url of the crate this item came from in the + /// `external_crates` map. + pub crate_id: u32, + /// The list of path components for the fully qualified path of this item (e.g. + /// `["std", "io", "lazy", "Lazy"]` for `std::io::lazy::Lazy`). + pub path: Vec, + /// Whether this item is a struct, trait, macro, etc. + pub kind: ItemKind, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Item { + /// The unique identifier of this item. Can be used to find this item in various mappings. + pub id: Id, + /// This can be used as a key to the `external_crates` map of [`Crate`] to see which crate + /// this item came from. + pub crate_id: u32, + /// Some items such as impls don't have names. + pub name: Option, + /// Whether this item is meant to be omitted from the generated documentation due to `#doc(hidden)`, + /// because it is private, or because it was inlined. + pub stripped: bool, + /// The source location of this item (absent if it came from a macro expansion or inline + /// assembly). + pub source: Option, + /// By default all documented items are public, but you can tell rustdoc to output private items + /// so this field is needed to differentiate. + pub visibility: Visibility, + /// The full markdown docstring of this item. + pub docs: String, + /// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs + pub links: FxHashMap, + /// Stringified versions of the attributes on this item (e.g. `"#[inline]"`) + pub attrs: Vec, + pub deprecation: Option, + pub kind: ItemKind, + pub inner: ItemEnum, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Span { + /// The path to the source file for this span relative to the path `rustdoc` was invoked with. + pub filename: PathBuf, + /// Zero indexed Line and Column of the first character of the `Span` + pub begin: (usize, usize), + /// Zero indexed Line and Column of the last character of the `Span` + pub end: (usize, usize), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Deprecation { + pub since: Option, + pub note: Option, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Visibility { + Public, + /// For the most part items are private by default. The exceptions are associated items of + /// public traits and variants of public enums. + Default, + Crate, + /// For `pub(in path)` visibility. `parent` is the module it's restricted to and `path` is how + /// that module was referenced (like `"super::super"` or `"crate::foo::bar"`). + Restricted { + parent: Id, + path: String, + }, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum GenericArgs { + /// <'a, 32, B: Copy, C = u32> + AngleBracketed { args: Vec, bindings: Vec }, + /// Fn(A, B) -> C + Parenthesized { inputs: Vec, output: Option }, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum GenericArg { + Lifetime(String), + Type(Type), + Const(Constant), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Constant { + #[serde(rename = "type")] + pub type_: Type, + pub expr: String, + pub value: Option, + pub is_literal: bool, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TypeBinding { + pub name: String, + pub binding: TypeBindingKind, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum TypeBindingKind { + Equality(Type), + Constraint(Vec), +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct Id(pub String); + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum ItemKind { + Module, + ExternCrate, + Import, + Struct, + StructField, + Union, + Enum, + Variant, + Function, + Typedef, + OpaqueTy, + Constant, + Trait, + TraitAlias, + Method, + Impl, + Static, + ForeignType, + Macro, + ProcAttribute, + ProcDerive, + AssocConst, + AssocType, + Primitive, + Keyword, +} + +#[serde(untagged)] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum ItemEnum { + ModuleItem(Module), + ExternCrateItem { + name: String, + rename: Option, + }, + ImportItem(Import), + + StructItem(Struct), + StructFieldItem(Type), + EnumItem(Enum), + VariantItem(Variant), + + FunctionItem(Function), + + TraitItem(Trait), + TraitAliasItem(TraitAlias), + MethodItem(Method), + ImplItem(Impl), + + TypedefItem(Typedef), + OpaqueTyItem(OpaqueTy), + ConstantItem(Constant), + + StaticItem(Static), + + /// `type`s from an extern block + ForeignTypeItem, + + /// Declarative macro_rules! macro + MacroItem(String), + ProcMacroItem(ProcMacro), + + AssocConstItem { + #[serde(rename = "type")] + type_: Type, + /// e.g. `const X: usize = 5;` + default: Option, + }, + AssocTypeItem { + bounds: Vec, + /// e.g. `type X = usize;` + default: Option, + }, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Module { + pub is_crate: bool, + pub items: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Struct { + pub struct_type: StructType, + pub generics: Generics, + pub fields_stripped: bool, + pub fields: Vec, + pub impls: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Enum { + pub generics: Generics, + pub variants_stripped: bool, + pub variants: Vec, + pub impls: Vec, +} + +#[serde(rename_all = "snake_case")] +#[serde(tag = "variant_kind", content = "variant_inner")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Variant { + Plain, + Tuple(Vec), + Struct(Vec), +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum StructType { + Plain, + Tuple, + Unit, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Function { + pub decl: FnDecl, + pub generics: Generics, + pub header: String, + pub abi: String, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Method { + pub decl: FnDecl, + pub generics: Generics, + pub header: String, + pub has_body: bool, +} + +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct Generics { + pub params: Vec, + pub where_predicates: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct GenericParamDef { + pub name: String, + pub kind: GenericParamDefKind, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum GenericParamDefKind { + Lifetime, + Type { bounds: Vec, default: Option }, + Const(Type), +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum WherePredicate { + BoundPredicate { ty: Type, bounds: Vec }, + RegionPredicate { lifetime: String, bounds: Vec }, + EqPredicate { lhs: Type, rhs: Type }, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum GenericBound { + TraitBound { + #[serde(rename = "trait")] + trait_: Type, + /// Used for HRTBs + generic_params: Vec, + modifier: TraitBoundModifier, + }, + Outlives(String), +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum TraitBoundModifier { + None, + Maybe, + MaybeConst, +} + +#[serde(rename_all = "snake_case")] +#[serde(tag = "kind", content = "inner")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Type { + /// Structs, enums, and traits + ResolvedPath { + name: String, + id: Id, + args: Option>, + param_names: Vec, + }, + /// Parameterized types + Generic(String), + /// Fixed-size numeric types (plus int/usize/float), char, arrays, slices, and tuples + Primitive(String), + /// `extern "ABI" fn` + FunctionPointer(Box), + /// `(String, u32, Box)` + Tuple(Vec), + /// `[u32]` + Slice(Box), + /// [u32; 15] + Array { + #[serde(rename = "type")] + type_: Box, + len: String, + }, + /// `impl TraitA + TraitB + ...` + ImplTrait(Vec), + /// `!` + Never, + /// `_` + Infer, + /// `*mut u32`, `*u8`, etc. + RawPointer { + mutable: bool, + #[serde(rename = "type")] + type_: Box, + }, + /// `&'a mut String`, `&str`, etc. + BorrowedRef { + lifetime: Option, + mutable: bool, + #[serde(rename = "type")] + type_: Box, + }, + /// `::Name` or associated types like `T::Item` where `T: Iterator` + QualifiedPath { + name: String, + self_type: Box, + #[serde(rename = "trait")] + trait_: Box, + }, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct FunctionPointer { + pub is_unsafe: bool, + pub generic_params: Vec, + pub decl: FnDecl, + pub abi: String, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct FnDecl { + pub inputs: Vec<(String, Type)>, + pub output: Option, + pub c_variadic: bool, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Trait { + pub is_auto: bool, + pub is_unsafe: bool, + pub items: Vec, + pub generics: Generics, + pub bounds: Vec, + pub implementors: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct TraitAlias { + pub generics: Generics, + pub params: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Impl { + pub is_unsafe: bool, + pub generics: Generics, + pub provided_trait_methods: Vec, + #[serde(rename = "trait")] + pub trait_: Option, + #[serde(rename = "for")] + pub for_: Type, + pub items: Vec, + pub negative: bool, + pub synthetic: bool, + pub blanket_impl: Option, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Import { + /// The full path being imported. + pub span: String, + /// May be different from the last segment of `source` when renaming imports: + /// `use source as name;` + pub name: String, + /// The ID of the item being imported. + pub id: Option, // FIXME is this actually ever None? + /// Whether this import uses a glob: `use source::*;` + pub glob: bool, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ProcMacro { + pub kind: MacroKind, + pub helpers: Vec, +} + +#[serde(rename_all = "snake_case")] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum MacroKind { + /// A bang macro `foo!()`. + Bang, + /// An attribute macro `#[foo]`. + Attr, + /// A derive macro `#[derive(Foo)]` + Derive, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Typedef { + #[serde(rename = "type")] + pub type_: Type, + pub generics: Generics, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct OpaqueTy { + pub bounds: Vec, + pub generics: Generics, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Static { + #[serde(rename = "type")] + pub type_: Type, + pub mutable: bool, + pub expr: String, +} diff --git a/src/test/rustdoc/rustdoc-json/Makefile b/src/test/rustdoc/rustdoc-json/Makefile new file mode 100644 index 0000000000000..ad517ae95ebb6 --- /dev/null +++ b/src/test/rustdoc/rustdoc-json/Makefile @@ -0,0 +1,6 @@ +-include ../tools.mk + +tests: *.rs + $(RUSTDOC) $< -o $(TMPDIR) --output-format json + $(PYTHON) check_missing_items.py $(TMPDIR)/$(basename $<).json + $(PYTHON) compare.py $(basename $<).expected $(TMPDIR)/$(basename $<).json diff --git a/src/test/rustdoc/rustdoc-json/check_missing_items.py b/src/test/rustdoc/rustdoc-json/check_missing_items.py new file mode 100644 index 0000000000000..0004dc8fb147c --- /dev/null +++ b/src/test/rustdoc/rustdoc-json/check_missing_items.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python + +# This test ensures that every ID in the produced json actually resolves to an item either in +# `index` or `paths`. It DOES NOT check that the structure of the produced json is actually in +# any way correct, for example an empty map would pass. + +import sys +import json + +crate = json.load(open(sys.argv[1])) + + +def get_local_item(item_id): + if item_id in crate["index"]: + return crate["index"][item_id] + print("Missing local ID:", item_id) + sys.exit(1) + + +# local IDs have to be in `index`, external ones can sometimes be in `index` but otherwise have +# to be in `paths` +def valid_id(item_id): + return item_id in crate["index"] or item_id[0] != "0" and item_id in crate["paths"] + + +def check_generics(generics): + for param in generics["params"]: + check_generic_param(param) + for where_predicate in generics["where_predicates"]: + if "bound_predicate" in where_predicate: + pred = where_predicate["bound_predicate"] + check_type(pred["ty"]) + for bound in pred["bounds"]: + check_generic_bound(bound) + elif "region_predicate" in where_predicate: + pred = where_predicate["region_predicate"] + for bound in pred["bounds"]: + check_generic_bound(bound) + elif "eq_predicate" in where_predicate: + pred = where_predicate["eq_predicate"] + check_type(pred["rhs"]) + check_type(pred["lhs"]) + + +def check_generic_param(param): + if "type" in param["kind"]: + ty = param["kind"]["type"] + if ty["default"]: + check_type(ty["default"]) + for bound in ty["bounds"]: + check_generic_bound(bound) + elif "const" in param["kind"]: + check_type(param["kind"]["const"]) + + +def check_generic_bound(bound): + if "trait_bound" in bound: + for param in bound["trait_bound"]["generic_params"]: + check_generic_param(param) + check_type(bound["trait_bound"]["trait"]) + + +def check_decl(decl): + for (_name, ty) in decl["inputs"]: + check_type(ty) + if decl["output"]: + check_type(decl["output"]) + + +def check_type(ty): + if ty["kind"] == "resolved_path": + for bound in ty["inner"]["param_names"]: + check_generic_bound(bound) + args = ty["inner"]["args"] + if args: + if "angle_bracketed" in args: + for arg in args["angle_bracketed"]["args"]: + if "type" in arg: + check_type(arg["type"]) + elif "const" in arg: + check_type(arg["const"]["type"]) + for binding in args["angle_bracketed"]["bindings"]: + if "equality" in binding["binding"]: + check_type(binding["binding"]["equality"]) + elif "constraint" in binding["binding"]: + for bound in binding["binding"]["constraint"]: + check_generic_bound(bound) + elif "parenthesized" in args: + for ty in args["parenthesized"]["inputs"]: + check_type(ty) + if args["parenthesized"]["output"]: + check_type(args["parenthesized"]["output"]) + if not valid_id(ty["inner"]["id"]): + print("Type contained an invalid ID:", ty["inner"]["id"]) + sys.exit(1) + elif ty["kind"] == "tuple": + for ty in ty["inner"]: + check_type(ty) + elif ty["kind"] == "slice": + check_type(ty["inner"]) + elif ty["kind"] == "impl_trait": + for bound in ty["inner"]: + check_generic_bound(bound) + elif ty["kind"] in ("raw_pointer", "borrowed_ref", "array"): + check_type(ty["inner"]["type"]) + elif ty["kind"] == "function_pointer": + for param in ty["inner"]["generic_params"]: + check_generic_param(param) + check_decl(ty["inner"]["inner"]) + elif ty["kind"] == "qualified_path": + check_type(ty["inner"]["self_type"]) + check_type(ty["inner"]["trait"]) + + +work_list = set([crate["root"]]) +visited = work_list.copy() + +while work_list: + current = work_list.pop() + visited.add(current) + item = get_local_item(current) + # check intradoc links + for (_name, link) in item["links"].items(): + if not valid_id(link): + print("Intra-doc link contains invalid ID:", link) + + # check all fields that reference types such as generics as well as nested items + # (modules, structs, traits, and enums) + if item["kind"] == "module": + work_list |= set(item["inner"]["items"]) - visited + elif item["kind"] == "struct": + check_generics(item["inner"]["generics"]) + work_list |= (set(item["inner"]["fields"]) | set(item["inner"]["impls"])) - visited + elif item["kind"] == "struct_field": + check_type(item["inner"]) + elif item["kind"] == "enum": + check_generics(item["inner"]["generics"]) + work_list |= (set(item["inner"]["variants"]) | set(item["inner"]["impls"])) - visited + elif item["kind"] == "variant": + if item["inner"]["variant_kind"] == "tuple": + for ty in item["inner"]["variant_inner"]: + check_type(ty) + elif item["inner"]["variant_kind"] == "struct": + work_list |= set(item["inner"]["variant_inner"]) - visited + elif item["kind"] in ("function", "method"): + check_generics(item["inner"]["generics"]) + check_decl(item["inner"]["decl"]) + elif item["kind"] in ("static", "constant", "assoc_const"): + check_type(item["inner"]["type"]) + elif item["kind"] == "typedef": + check_type(item["inner"]["type"]) + check_generics(item["inner"]["generics"]) + elif item["kind"] == "opaque_ty": + check_generics(item["inner"]["generics"]) + for bound in item["inner"]["bounds"]: + check_generic_bound(bound) + elif item["kind"] == "trait_alias": + check_generics(item["inner"]["params"]) + for bound in item["inner"]["bounds"]: + check_generic_bound(bound) + elif item["kind"] == "trait": + check_generics(item["inner"]["generics"]) + for bound in item["inner"]["bounds"]: + check_generic_bound(bound) + work_list |= (set(item["inner"]["items"]) | set(item["inner"]["implementors"])) - visited + elif item["kind"] == "impl": + check_generics(item["inner"]["generics"]) + if item["inner"]["trait"]: + check_type(item["inner"]["trait"]) + if item["inner"]["blanket_impl"]: + check_type(item["inner"]["blanket_impl"]) + check_type(item["inner"]["for"]) + for assoc_item in item["inner"]["items"]: + if not valid_id(assoc_item): + print("Impl block referenced a missing ID:", assoc_item) + sys.exit(1) + elif item["kind"] == "assoc_type": + for bound in item["inner"]["bounds"]: + check_generic_bound(bound) + if item["inner"]["default"]: + check_type(item["inner"]["default"]) diff --git a/src/test/rustdoc/rustdoc-json/compare.py b/src/test/rustdoc/rustdoc-json/compare.py new file mode 100644 index 0000000000000..5daf8903e2030 --- /dev/null +++ b/src/test/rustdoc/rustdoc-json/compare.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python + +# This script can check that an expected json blob is a subset of what actually gets produced. +# The comparison is independent of the value of IDs (which are unstable) and instead uses their +# relative ordering to check them against eachother by looking them up in their respective blob's +# `index` or `paths` mappings. To add a new test run `rustdoc --output-format json -o . yourtest.rs` +# and then create `yourtest.expected` by stripping unnecessary details from `yourtest.json`. + +import copy +import sys +import json +import types + +# Used instead of the string ids when used as references. +# Not used as keys in `index` or `paths` +class ID(str): + pass + + +class SubsetException(Exception): + def __init__(self, msg, trace): + self.msg = msg + self.trace = msg + super().__init__("{}: {}".format(trace, msg)) + + +def check_subset(expected_main, actual_main): + expected_index = expected_main["index"] + expected_paths = expected_main["paths"] + actual_index = actual_main["index"] + actual_paths = actual_main["paths"] + already_checked = set() + + def _check_subset(expected, actual, trace): + expected_type = type(expected) + actual_type = type(actual) + if expected_type is not actual_type: + raise SubsetException( + "expected type `{}`, got `{}`".format(expected_type, actual_type), trace + ) + if expected_type in (str, int, bool) and expected != actual: + raise SubsetException("expected `{}`, got: `{}`".format(expected, actual), trace) + if expected_type is dict: + for key in expected: + if key not in actual: + raise SubsetException("Key `{}` not found in output".format(key), trace) + new_trace = copy.deepcopy(trace) + new_trace.append(key) + _check_subset(expected[key], actual[key], new_trace) + elif expected_type is list: + expected_elements = len(expected) + actual_elements = len(actual) + if expected_elements != actual_elements: + raise SubsetException( + "Found {} items, expected {}".format(expected_elements, actual_elements), trace + ) + for expected, actual in zip(expected, actual): + new_trace = copy.deepcopy(trace) + new_trace.append(expected) + _check_subset(expected, actual, new_trace) + elif expected_type is ID and expected not in already_checked: + already_checked.add(expected) + _check_subset(expected_index.get(expected, {}), actual_index.get(actual, {}), trace) + _check_subset(expected_paths.get(expected, {}), actual_paths.get(actual, {}), trace) + + _check_subset(expected_main["root"], actual_main["root"], []) + + +def rustdoc_object_hook(obj): + # No need to convert paths, index and external_crates keys to ids, since + # they are the target of resolution, and never a source itself. + if "id" in obj and obj["id"]: + obj["id"] = ID(obj["id"]) + if "root" in obj: + obj["root"] = ID(obj["root"]) + if "items" in obj: + obj["items"] = [ID(id) for id in obj["items"]] + if "variants" in obj: + obj["variants"] = [ID(id) for id in obj["variants"]] + if "fields" in obj: + obj["fields"] = [ID(id) for id in obj["fields"]] + if "impls" in obj: + obj["impls"] = [ID(id) for id in obj["impls"]] + if "implementors" in obj: + obj["implementors"] = [ID(id) for id in obj["implementors"]] + if "links" in obj: + obj["links"] = {s: ID(id) for s, id in obj["links"]} + if "variant_kind" in obj and obj["variant_kind"] == "struct": + obj["variant_inner"] = [ID(id) for id in obj["variant_inner"]] + return obj + + +def main(expected_fpath, actual_fpath): + print("checking that {} is a logical subset of {}".format(expected_fpath, actual_fpath)) + with open(expected_fpath) as expected_file: + expected_main = json.load(expected_file, object_hook=rustdoc_object_hook) + with open(actual_fpath) as actual_file: + actual_main = json.load(actual_file, object_hook=rustdoc_object_hook) + check_subset(expected_main, actual_main) + print("all checks passed") + + +if __name__ == "__main__": + if len(sys.argv) < 3: + print("Usage: `compare.py expected.json actual.json`") + else: + main(sys.argv[1], sys.argv[2]) diff --git a/src/test/rustdoc/rustdoc-json/structs.expected b/src/test/rustdoc/rustdoc-json/structs.expected new file mode 100644 index 0000000000000..45b23534bc77b --- /dev/null +++ b/src/test/rustdoc/rustdoc-json/structs.expected @@ -0,0 +1,468 @@ +{ + "root": "0:0", + "version": null, + "includes_private": false, + "index": { + "0:9": { + "crate_id": 0, + "name": "Unit", + "source": { + "filename": "structs.rs", + "begin": [ + 7, + 0 + ], + "end": [ + 7, + 16 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "unit", + "generics": { + "params": [], + "where_predicates": [] + }, + "fields_stripped": false, + "fields": [] + } + }, + "0:8": { + "crate_id": 0, + "name": "1", + "source": { + "filename": "structs.rs", + "begin": [ + 5, + 22 + ], + "end": [ + 5, + 28 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "resolved_path", + "inner": { + "name": "String", + "id": "5:5035", + "args": { + "angle_bracketed": { + "args": [], + "bindings": [] + } + }, + "param_names": [] + } + } + }, + "0:18": { + "crate_id": 0, + "name": "stuff", + "source": { + "filename": "structs.rs", + "begin": [ + 15, + 4 + ], + "end": [ + 15, + 17 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "resolved_path", + "inner": { + "name": "Vec", + "id": "5:4322", + "args": { + "angle_bracketed": { + "args": [ + { + "type": { + "kind": "generic", + "inner": "T" + } + } + ], + "bindings": [] + } + }, + "param_names": [] + } + } + }, + "0:11": { + "crate_id": 0, + "name": "WithPrimitives", + "source": { + "filename": "structs.rs", + "begin": [ + 9, + 0 + ], + "end": [ + 12, + 1 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "plain", + "generics": { + "params": [ + { + "name": "'a", + "kind": "lifetime" + } + ], + "where_predicates": [] + }, + "fields_stripped": true, + "fields": [ + "0:13", + "0:14" + ] + } + }, + "0:14": { + "crate_id": 0, + "name": "s", + "source": { + "filename": "structs.rs", + "begin": [ + 11, + 4 + ], + "end": [ + 11, + 14 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "borrowed_ref", + "inner": { + "lifetime": "'a", + "mutable": false, + "type": { + "kind": "primitive", + "inner": "str" + } + } + } + }, + "0:19": { + "crate_id": 0, + "name": "things", + "source": { + "filename": "structs.rs", + "begin": [ + 16, + 4 + ], + "end": [ + 16, + 25 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "resolved_path", + "inner": { + "name": "HashMap", + "id": "1:6600", + "args": { + "angle_bracketed": { + "args": [ + { + "type": { + "kind": "generic", + "inner": "U" + } + }, + { + "type": { + "kind": "generic", + "inner": "U" + } + } + ], + "bindings": [] + } + }, + "param_names": [] + } + } + }, + "0:15": { + "crate_id": 0, + "name": "WithGenerics", + "source": { + "filename": "structs.rs", + "begin": [ + 14, + 0 + ], + "end": [ + 17, + 1 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "plain", + "generics": { + "params": [ + { + "name": "T", + "kind": { + "type": { + "bounds": [], + "default": null + } + } + }, + { + "name": "U", + "kind": { + "type": { + "bounds": [], + "default": null + } + } + } + ], + "where_predicates": [] + }, + "fields_stripped": true, + "fields": [ + "0:18", + "0:19" + ] + } + }, + "0:0": { + "crate_id": 0, + "name": "structs", + "source": { + "filename": "structs.rs", + "begin": [ + 1, + 0 + ], + "end": [ + 17, + 1 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "module", + "inner": { + "is_crate": true, + "items": [ + "0:4", + "0:5", + "0:9", + "0:11", + "0:15" + ] + } + }, + "0:13": { + "crate_id": 0, + "name": "num", + "source": { + "filename": "structs.rs", + "begin": [ + 10, + 4 + ], + "end": [ + 10, + 12 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "primitive", + "inner": "u32" + } + }, + "0:5": { + "crate_id": 0, + "name": "Tuple", + "source": { + "filename": "structs.rs", + "begin": [ + 5, + 0 + ], + "end": [ + 5, + 30 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "tuple", + "generics": { + "params": [], + "where_predicates": [] + }, + "fields_stripped": true, + "fields": [ + "0:7", + "0:8" + ] + } + }, + "0:4": { + "crate_id": 0, + "name": "PlainEmpty", + "source": { + "filename": "structs.rs", + "begin": [ + 3, + 0 + ], + "end": [ + 3, + 24 + ] + }, + "visibility": "public", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct", + "inner": { + "struct_type": "plain", + "generics": { + "params": [], + "where_predicates": [] + }, + "fields_stripped": false, + "fields": [] + } + }, + "0:7": { + "crate_id": 0, + "name": "0", + "source": { + "filename": "structs.rs", + "begin": [ + 5, + 17 + ], + "end": [ + 5, + 20 + ] + }, + "visibility": "default", + "docs": "", + "links": {}, + "attrs": [], + "deprecation": null, + "kind": "struct_field", + "inner": { + "kind": "primitive", + "inner": "u32" + } + } + }, + "paths": { + "5:4322": { + "crate_id": 5, + "path": [ + "alloc", + "vec", + "Vec" + ], + "kind": "struct" + }, + "5:5035": { + "crate_id": 5, + "path": [ + "alloc", + "string", + "String" + ], + "kind": "struct" + }, + "1:6600": { + "crate_id": 1, + "path": [ + "std", + "collections", + "hash", + "map", + "HashMap" + ], + "kind": "struct" + } + }, + "external_crates": { + "1": { + "name": "std" + }, + "5": { + "name": "alloc" + } + }, + "format_version": 1 +} diff --git a/src/test/rustdoc/rustdoc-json/structs.rs b/src/test/rustdoc/rustdoc-json/structs.rs new file mode 100644 index 0000000000000..43fc4743503aa --- /dev/null +++ b/src/test/rustdoc/rustdoc-json/structs.rs @@ -0,0 +1,17 @@ +use std::collections::HashMap; + +pub struct PlainEmpty {} + +pub struct Tuple(u32, String); + +pub struct Unit; + +pub struct WithPrimitives<'a> { + num: u32, + s: &'a str, +} + +pub struct WithGenerics { + stuff: Vec, + things: HashMap, +} From 35cc34952f49f61abed1f72ce25597c8525c2121 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sun, 29 Nov 2020 16:16:25 +0000 Subject: [PATCH 16/18] Add tests for rustdoc json Move rustdoc/rustdoc-json to rustdoc-json Scaffold rustdoc-json test mode Implement run_rustdoc_json_test Fix up python Make tidy happy --- src/bootstrap/builder.rs | 1 + src/bootstrap/test.rs | 7 ++ src/test/{rustdoc => }/rustdoc-json/Makefile | 0 .../rustdoc-json/check_missing_items.py | 12 +++- .../{rustdoc => }/rustdoc-json/compare.py | 48 +++++++++---- .../rustdoc-json/structs.expected | 0 .../{rustdoc => }/rustdoc-json/structs.rs | 0 src/tools/compiletest/src/common.rs | 3 + src/tools/compiletest/src/main.rs | 2 +- src/tools/compiletest/src/runtest.rs | 67 ++++++++++++++++--- 10 files changed, 115 insertions(+), 25 deletions(-) rename src/test/{rustdoc => }/rustdoc-json/Makefile (100%) rename src/test/{rustdoc => }/rustdoc-json/check_missing_items.py (95%) rename src/test/{rustdoc => }/rustdoc-json/compare.py (69%) rename src/test/{rustdoc => }/rustdoc-json/structs.expected (100%) rename src/test/{rustdoc => }/rustdoc-json/structs.rs (100%) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 508d785834fce..edade298fd929 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -424,6 +424,7 @@ impl<'a> Builder<'a> { test::RustdocJSNotStd, test::RustdocTheme, test::RustdocUi, + test::RustdocJson, // Run bootstrap close to the end as it's unlikely to fail test::Bootstrap, // Run run-make last, since these won't pass without make on Windows diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index e087e2b8ff153..bd056fed78cc5 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -935,6 +935,12 @@ host_test!(UiFullDeps { path: "src/test/ui-fulldeps", mode: "ui", suite: "ui-ful host_test!(Rustdoc { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" }); +host_test!(RustdocJson { + path: "src/test/rustdoc-json", + mode: "rustdoc-json", + suite: "rustdoc-json" +}); + host_test!(Pretty { path: "src/test/pretty", mode: "pretty", suite: "pretty" }); default_test!(RunMake { path: "src/test/run-make", mode: "run-make", suite: "run-make" }); @@ -1032,6 +1038,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the || (mode == "run-make" && suite.ends_with("fulldeps")) || (mode == "ui" && is_rustdoc) || mode == "js-doc-test" + || mode == "rustdoc-json" { cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler)); } diff --git a/src/test/rustdoc/rustdoc-json/Makefile b/src/test/rustdoc-json/Makefile similarity index 100% rename from src/test/rustdoc/rustdoc-json/Makefile rename to src/test/rustdoc-json/Makefile diff --git a/src/test/rustdoc/rustdoc-json/check_missing_items.py b/src/test/rustdoc-json/check_missing_items.py similarity index 95% rename from src/test/rustdoc/rustdoc-json/check_missing_items.py rename to src/test/rustdoc-json/check_missing_items.py index 0004dc8fb147c..3a3bf7fa3ed58 100644 --- a/src/test/rustdoc/rustdoc-json/check_missing_items.py +++ b/src/test/rustdoc-json/check_missing_items.py @@ -130,12 +130,16 @@ def check_type(ty): work_list |= set(item["inner"]["items"]) - visited elif item["kind"] == "struct": check_generics(item["inner"]["generics"]) - work_list |= (set(item["inner"]["fields"]) | set(item["inner"]["impls"])) - visited + work_list |= ( + set(item["inner"]["fields"]) | set(item["inner"]["impls"]) + ) - visited elif item["kind"] == "struct_field": check_type(item["inner"]) elif item["kind"] == "enum": check_generics(item["inner"]["generics"]) - work_list |= (set(item["inner"]["variants"]) | set(item["inner"]["impls"])) - visited + work_list |= ( + set(item["inner"]["variants"]) | set(item["inner"]["impls"]) + ) - visited elif item["kind"] == "variant": if item["inner"]["variant_kind"] == "tuple": for ty in item["inner"]["variant_inner"]: @@ -162,7 +166,9 @@ def check_type(ty): check_generics(item["inner"]["generics"]) for bound in item["inner"]["bounds"]: check_generic_bound(bound) - work_list |= (set(item["inner"]["items"]) | set(item["inner"]["implementors"])) - visited + work_list |= ( + set(item["inner"]["items"]) | set(item["inner"]["implementors"]) + ) - visited elif item["kind"] == "impl": check_generics(item["inner"]["generics"]) if item["inner"]["trait"]: diff --git a/src/test/rustdoc/rustdoc-json/compare.py b/src/test/rustdoc-json/compare.py similarity index 69% rename from src/test/rustdoc/rustdoc-json/compare.py rename to src/test/rustdoc-json/compare.py index 5daf8903e2030..afc8066685c46 100644 --- a/src/test/rustdoc/rustdoc-json/compare.py +++ b/src/test/rustdoc-json/compare.py @@ -24,7 +24,7 @@ def __init__(self, msg, trace): super().__init__("{}: {}".format(trace, msg)) -def check_subset(expected_main, actual_main): +def check_subset(expected_main, actual_main, base_dir): expected_index = expected_main["index"] expected_paths = expected_main["paths"] actual_index = actual_main["index"] @@ -39,11 +39,24 @@ def _check_subset(expected, actual, trace): "expected type `{}`, got `{}`".format(expected_type, actual_type), trace ) if expected_type in (str, int, bool) and expected != actual: - raise SubsetException("expected `{}`, got: `{}`".format(expected, actual), trace) + if expected_type == str and actual.startswith(base_dir): + if actual.replace(base_dir + "/", "") != expected: + raise SubsetException( + "expected `{}`, got: `{}`".format( + expected, actual.replace(base_dir + "/", "") + ), + trace, + ) + else: + raise SubsetException( + "expected `{}`, got: `{}`".format(expected, actual), trace + ) if expected_type is dict: for key in expected: if key not in actual: - raise SubsetException("Key `{}` not found in output".format(key), trace) + raise SubsetException( + "Key `{}` not found in output".format(key), trace + ) new_trace = copy.deepcopy(trace) new_trace.append(key) _check_subset(expected[key], actual[key], new_trace) @@ -52,7 +65,10 @@ def _check_subset(expected, actual, trace): actual_elements = len(actual) if expected_elements != actual_elements: raise SubsetException( - "Found {} items, expected {}".format(expected_elements, actual_elements), trace + "Found {} items, expected {}".format( + expected_elements, actual_elements + ), + trace, ) for expected, actual in zip(expected, actual): new_trace = copy.deepcopy(trace) @@ -60,8 +76,12 @@ def _check_subset(expected, actual, trace): _check_subset(expected, actual, new_trace) elif expected_type is ID and expected not in already_checked: already_checked.add(expected) - _check_subset(expected_index.get(expected, {}), actual_index.get(actual, {}), trace) - _check_subset(expected_paths.get(expected, {}), actual_paths.get(actual, {}), trace) + _check_subset( + expected_index.get(expected, {}), actual_index.get(actual, {}), trace + ) + _check_subset( + expected_paths.get(expected, {}), actual_paths.get(actual, {}), trace + ) _check_subset(expected_main["root"], actual_main["root"], []) @@ -90,18 +110,22 @@ def rustdoc_object_hook(obj): return obj -def main(expected_fpath, actual_fpath): - print("checking that {} is a logical subset of {}".format(expected_fpath, actual_fpath)) +def main(expected_fpath, actual_fpath, base_dir): + print( + "checking that {} is a logical subset of {}".format( + expected_fpath, actual_fpath + ) + ) with open(expected_fpath) as expected_file: expected_main = json.load(expected_file, object_hook=rustdoc_object_hook) with open(actual_fpath) as actual_file: actual_main = json.load(actual_file, object_hook=rustdoc_object_hook) - check_subset(expected_main, actual_main) + check_subset(expected_main, actual_main, base_dir) print("all checks passed") if __name__ == "__main__": - if len(sys.argv) < 3: - print("Usage: `compare.py expected.json actual.json`") + if len(sys.argv) < 4: + print("Usage: `compare.py expected.json actual.json test-dir`") else: - main(sys.argv[1], sys.argv[2]) + main(sys.argv[1], sys.argv[2], sys.argv[3]) diff --git a/src/test/rustdoc/rustdoc-json/structs.expected b/src/test/rustdoc-json/structs.expected similarity index 100% rename from src/test/rustdoc/rustdoc-json/structs.expected rename to src/test/rustdoc-json/structs.expected diff --git a/src/test/rustdoc/rustdoc-json/structs.rs b/src/test/rustdoc-json/structs.rs similarity index 100% rename from src/test/rustdoc/rustdoc-json/structs.rs rename to src/test/rustdoc-json/structs.rs diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 24ef98cd784d8..eba02333c8cb2 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -17,6 +17,7 @@ pub enum Mode { DebugInfo, Codegen, Rustdoc, + RustdocJson, CodegenUnits, Incremental, RunMake, @@ -48,6 +49,7 @@ impl FromStr for Mode { "debuginfo" => Ok(DebugInfo), "codegen" => Ok(Codegen), "rustdoc" => Ok(Rustdoc), + "rustdoc-json" => Ok(RustdocJson), "codegen-units" => Ok(CodegenUnits), "incremental" => Ok(Incremental), "run-make" => Ok(RunMake), @@ -70,6 +72,7 @@ impl fmt::Display for Mode { DebugInfo => "debuginfo", Codegen => "codegen", Rustdoc => "rustdoc", + RustdocJson => "rustdoc-json", CodegenUnits => "codegen-units", Incremental => "incremental", RunMake => "run-make", diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 32347db5dbb1c..0541548aefd6d 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -68,7 +68,7 @@ pub fn parse_config(args: Vec) -> Config { "mode", "which sort of compile tests to run", "compile-fail | run-fail | run-pass-valgrind | pretty | debug-info | codegen | rustdoc \ - codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", + | rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", ) .reqopt( "", diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 1b9f0089dced0..88cb8544e47cc 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2,7 +2,7 @@ use crate::common::{expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT}; use crate::common::{output_base_dir, output_base_name, output_testname_unique}; -use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, Ui}; +use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, RustdocJson, Ui}; use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc}; use crate::common::{CompareMode, FailMode, PassMode}; use crate::common::{CompileFail, Pretty, RunFail, RunPassValgrind}; @@ -342,6 +342,7 @@ impl<'test> TestCx<'test> { DebugInfo => self.run_debuginfo_test(), Codegen => self.run_codegen_test(), Rustdoc => self.run_rustdoc_test(), + RustdocJson => self.run_rustdoc_json_test(), CodegenUnits => self.run_codegen_units_test(), Incremental => self.run_incremental_test(), RunMake => self.run_rmake_test(), @@ -1564,7 +1565,7 @@ impl<'test> TestCx<'test> { self.compose_and_run_compiler(rustc, None) } - fn document(&self, out_dir: &Path) -> ProcRes { + fn document(&self, out_dir: &Path, json: bool) -> ProcRes { if self.props.build_aux_docs { for rel_ab in &self.props.aux_builds { let aux_testpaths = self.compute_aux_test_paths(rel_ab); @@ -1578,7 +1579,7 @@ impl<'test> TestCx<'test> { }; // Create the directory for the stdout/stderr files. create_dir_all(aux_cx.output_base_dir()).unwrap(); - let auxres = aux_cx.document(out_dir); + let auxres = aux_cx.document(out_dir, json); if !auxres.status.success() { return auxres; } @@ -1600,6 +1601,10 @@ impl<'test> TestCx<'test> { .arg(&self.testpaths.file) .args(&self.props.compile_flags); + if json { + rustdoc.arg("--output-format").arg("json"); + } + if let Some(ref linker) = self.config.linker { rustdoc.arg(format!("-Clinker={}", linker)); } @@ -1887,7 +1892,9 @@ impl<'test> TestCx<'test> { } fn is_rustdoc(&self) -> bool { - self.config.src_base.ends_with("rustdoc-ui") || self.config.src_base.ends_with("rustdoc-js") + self.config.src_base.ends_with("rustdoc-ui") + || self.config.src_base.ends_with("rustdoc-js") + || self.config.src_base.ends_with("rustdoc-json") } fn make_compile_args( @@ -1968,8 +1975,8 @@ impl<'test> TestCx<'test> { rustc.arg(dir_opt); } - RunFail | RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RunMake - | CodegenUnits | JsDocTest | Assembly => { + RunFail | RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RustdocJson + | RunMake | CodegenUnits | JsDocTest | Assembly => { // do not use JSON output } } @@ -2329,7 +2336,7 @@ impl<'test> TestCx<'test> { let _ = fs::remove_dir_all(&out_dir); create_dir_all(&out_dir).unwrap(); - let proc_res = self.document(&out_dir); + let proc_res = self.document(&out_dir, false); if !proc_res.status.success() { self.fatal_proc_rec("rustdoc failed!", &proc_res); } @@ -2385,7 +2392,7 @@ impl<'test> TestCx<'test> { rustc.arg("-L").arg(&new_rustdoc.aux_output_dir_name()); new_rustdoc.build_all_auxiliary(&mut rustc); - let proc_res = new_rustdoc.document(&compare_dir); + let proc_res = new_rustdoc.document(&compare_dir, false); if !proc_res.status.success() { proc_res.fatal(Some("failed to run nightly rustdoc"), || ()); } @@ -2466,6 +2473,48 @@ impl<'test> TestCx<'test> { eprintln!("{}", String::from_utf8_lossy(&output.stderr)); } + fn run_rustdoc_json_test(&self) { + //FIXME: Add bless option. + + assert!(self.revision.is_none(), "revisions not relevant here"); + + let out_dir = self.output_base_dir(); + let _ = fs::remove_dir_all(&out_dir); + create_dir_all(&out_dir).unwrap(); + + let proc_res = self.document(&out_dir, true); + if !proc_res.status.success() { + self.fatal_proc_rec("rustdoc failed!", &proc_res); + } + + let root = self.config.find_rust_src_root().unwrap(); + let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap()); + json_out.set_extension("json"); + let res = self.cmd2procres( + Command::new(&self.config.docck_python) + .arg(root.join("src/test/rustdoc-json/check_missing_items.py")) + .arg(&json_out), + ); + + if !res.status.success() { + self.fatal_proc_rec("check_missing_items failed!", &res); + } + + let mut expected = self.testpaths.file.clone(); + expected.set_extension("expected"); + let res = self.cmd2procres( + Command::new(&self.config.docck_python) + .arg(root.join("src/test/rustdoc-json/compare.py")) + .arg(&expected) + .arg(&json_out) + .arg(&expected.parent().unwrap()), + ); + + if !res.status.success() { + self.fatal_proc_rec("compare failed!", &res); + } + } + fn get_lines>( &self, path: &P, @@ -3003,7 +3052,7 @@ impl<'test> TestCx<'test> { if let Some(nodejs) = &self.config.nodejs { let out_dir = self.output_base_dir(); - self.document(&out_dir); + self.document(&out_dir, false); let root = self.config.find_rust_src_root().unwrap(); let file_stem = From 97011ebd16351e50b0e8f9a1d97f4fe35b825dea Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Mon, 30 Nov 2020 20:24:48 +0000 Subject: [PATCH 17/18] Address review comments. Go back to CRATE_DEF_INDEX Minor niceness improvements Don't output hidden items Remove striped items from fields Add $TEST_BASE_DIR Small catch --- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/json/conversions.rs | 76 +++++++++++++------------- src/librustdoc/json/mod.rs | 18 +++--- src/librustdoc/json/types.rs | 3 - src/librustdoc/lib.rs | 1 + src/test/rustdoc-json/Makefile | 6 -- src/test/rustdoc-json/compare.py | 21 +++---- src/test/rustdoc-json/structs.expected | 42 +++++--------- src/tools/compiletest/src/runtest.rs | 14 ++--- 9 files changed, 80 insertions(+), 103 deletions(-) delete mode 100644 src/test/rustdoc-json/Makefile diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 584adcf220d1e..9e8ce45292417 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2276,7 +2276,7 @@ impl Clean> for doctree::Import<'_> { name: None, attrs: self.attrs.clean(cx), source: self.span.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), + def_id: DefId::local(CRATE_DEF_INDEX), visibility: self.vis.clean(cx), stability: None, deprecation: None, diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 80192623d54fe..4d57b33787963 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -12,43 +12,44 @@ use crate::doctree; use crate::formats::item_type::ItemType; use crate::json::types::*; -impl From for Item { +impl From for Option { fn from(item: clean::Item) -> Self { let item_type = ItemType::from(&item); let clean::Item { source, name, attrs, - kind: inner, + kind, visibility, def_id, stability: _, deprecation, } = item; - Item { - id: def_id.into(), - crate_id: def_id.krate.as_u32(), - name, - stripped: match inner { - clean::StrippedItem(_) => true, - _ => false, - }, - source: source.into(), - visibility: visibility.into(), - docs: attrs.collapsed_doc_value().unwrap_or_default(), - links: attrs - .links - .into_iter() - .filter_map(|clean::ItemLink { link, did, .. }| did.map(|did| (link, did.into()))) - .collect(), - attrs: attrs - .other_attrs - .iter() - .map(rustc_ast_pretty::pprust::attribute_to_string) - .collect(), - deprecation: deprecation.map(Into::into), - kind: item_type.into(), - inner: inner.into(), + match kind { + clean::StrippedItem(_) => None, + _ => Some(Item { + id: def_id.into(), + crate_id: def_id.krate.as_u32(), + name, + source: source.into(), + visibility: visibility.into(), + docs: attrs.collapsed_doc_value().unwrap_or_default(), + links: attrs + .links + .into_iter() + .filter_map(|clean::ItemLink { link, did, .. }| { + did.map(|did| (link, did.into())) + }) + .collect(), + attrs: attrs + .other_attrs + .iter() + .map(rustc_ast_pretty::pprust::attribute_to_string) + .collect(), + deprecation: deprecation.map(Into::into), + kind: item_type.into(), + inner: kind.into(), + }), } } } @@ -194,10 +195,7 @@ impl From for ItemEnum { impl From for Module { fn from(module: clean::Module) -> Self { - Module { - is_crate: module.is_crate, - items: module.items.into_iter().map(|i| i.def_id.into()).collect(), - } + Module { is_crate: module.is_crate, items: ids(module.items) } } } @@ -208,7 +206,7 @@ impl From for Struct { struct_type: struct_type.into(), generics: generics.into(), fields_stripped, - fields: fields.into_iter().map(|i| i.def_id.into()).collect(), + fields: ids(fields), impls: Vec::new(), // Added in JsonRenderer::item } } @@ -221,7 +219,7 @@ impl From for Struct { struct_type: struct_type.into(), generics: generics.into(), fields_stripped, - fields: fields.into_iter().map(|i| i.def_id.into()).collect(), + fields: ids(fields), impls: Vec::new(), // Added in JsonRenderer::item } } @@ -407,7 +405,7 @@ impl From for Trait { Trait { is_auto, is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe, - items: items.into_iter().map(|i| i.def_id.into()).collect(), + items: ids(items), generics: generics.into(), bounds: bounds.into_iter().map(Into::into).collect(), implementors: Vec::new(), // Added in JsonRenderer::item @@ -434,7 +432,7 @@ impl From for Impl { provided_trait_methods: provided_trait_methods.into_iter().collect(), trait_: trait_.map(Into::into), for_: for_.into(), - items: items.into_iter().map(|i| i.def_id.into()).collect(), + items: ids(items), negative: polarity == Some(clean::ImplPolarity::Negative), synthetic, blanket_impl: blanket_impl.map(Into::into), @@ -460,7 +458,7 @@ impl From for Enum { Enum { generics: generics.into(), variants_stripped, - variants: variants.into_iter().map(|i| i.def_id.into()).collect(), + variants: ids(variants), impls: Vec::new(), // Added in JsonRenderer::item } } @@ -473,7 +471,7 @@ impl From for Struct { struct_type: struct_type.into(), generics: Default::default(), fields_stripped, - fields: fields.into_iter().map(|i| i.def_id.into()).collect(), + fields: ids(fields), impls: Vec::new(), } } @@ -485,7 +483,7 @@ impl From for Variant { match variant.kind { CLike => Variant::Plain, Tuple(t) => Variant::Tuple(t.into_iter().map(Into::into).collect()), - Struct(s) => Variant::Struct(s.fields.into_iter().map(|i| i.def_id.into()).collect()), + Struct(s) => Variant::Struct(ids(s.fields)), } } } @@ -594,3 +592,7 @@ impl From for ItemKind { } } } + +fn ids(items: impl IntoIterator) -> Vec { + items.into_iter().filter(|x| !x.is_stripped()).map(|i| i.def_id.into()).collect() +} diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 20a8de144adb3..c080ad21c0f33 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -99,7 +99,6 @@ impl JsonRenderer { .0 .last() .map(Clone::clone), - stripped: false, visibility: types::Visibility::Public, kind: types::ItemKind::Trait, inner: types::ItemEnum::TraitItem(trait_item.clone().into()), @@ -144,16 +143,17 @@ impl FormatRenderer for JsonRenderer { item.kind.inner_items().for_each(|i| self.item(i.clone(), cache).unwrap()); let id = item.def_id; - let mut new_item: types::Item = item.into(); - if let types::ItemEnum::TraitItem(ref mut t) = new_item.inner { - t.implementors = self.get_trait_implementors(id, cache) - } else if let types::ItemEnum::StructItem(ref mut s) = new_item.inner { - s.impls = self.get_impls(id, cache) - } else if let types::ItemEnum::EnumItem(ref mut e) = new_item.inner { - e.impls = self.get_impls(id, cache) + if let Some(mut new_item) = item.into(): Option { + if let types::ItemEnum::TraitItem(ref mut t) = new_item.inner { + t.implementors = self.get_trait_implementors(id, cache) + } else if let types::ItemEnum::StructItem(ref mut s) = new_item.inner { + s.impls = self.get_impls(id, cache) + } else if let types::ItemEnum::EnumItem(ref mut e) = new_item.inner { + e.impls = self.get_impls(id, cache) + } + self.index.borrow_mut().insert(id.into(), new_item); } - self.index.borrow_mut().insert(id.into(), new_item); Ok(()) } diff --git a/src/librustdoc/json/types.rs b/src/librustdoc/json/types.rs index 62705affafce1..10bf2a2acc5b9 100644 --- a/src/librustdoc/json/types.rs +++ b/src/librustdoc/json/types.rs @@ -62,9 +62,6 @@ pub struct Item { pub crate_id: u32, /// Some items such as impls don't have names. pub name: Option, - /// Whether this item is meant to be omitted from the generated documentation due to `#doc(hidden)`, - /// because it is private, or because it was inlined. - pub stripped: bool, /// The source location of this item (absent if it came from a macro expansion or inline /// assembly). pub source: Option, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 751f230105392..80a9c3811cf66 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -14,6 +14,7 @@ #![feature(crate_visibility_modifier)] #![feature(never_type)] #![feature(once_cell)] +#![feature(type_ascription)] #![recursion_limit = "256"] #[macro_use] diff --git a/src/test/rustdoc-json/Makefile b/src/test/rustdoc-json/Makefile deleted file mode 100644 index ad517ae95ebb6..0000000000000 --- a/src/test/rustdoc-json/Makefile +++ /dev/null @@ -1,6 +0,0 @@ --include ../tools.mk - -tests: *.rs - $(RUSTDOC) $< -o $(TMPDIR) --output-format json - $(PYTHON) check_missing_items.py $(TMPDIR)/$(basename $<).json - $(PYTHON) compare.py $(basename $<).expected $(TMPDIR)/$(basename $<).json diff --git a/src/test/rustdoc-json/compare.py b/src/test/rustdoc-json/compare.py index afc8066685c46..422e48ea39a01 100644 --- a/src/test/rustdoc-json/compare.py +++ b/src/test/rustdoc-json/compare.py @@ -34,23 +34,18 @@ def check_subset(expected_main, actual_main, base_dir): def _check_subset(expected, actual, trace): expected_type = type(expected) actual_type = type(actual) + + if actual_type is str: + actual = actual.replace(base_dir, "$TEST_BASE_DIR") + if expected_type is not actual_type: raise SubsetException( "expected type `{}`, got `{}`".format(expected_type, actual_type), trace ) - if expected_type in (str, int, bool) and expected != actual: - if expected_type == str and actual.startswith(base_dir): - if actual.replace(base_dir + "/", "") != expected: - raise SubsetException( - "expected `{}`, got: `{}`".format( - expected, actual.replace(base_dir + "/", "") - ), - trace, - ) - else: - raise SubsetException( - "expected `{}`, got: `{}`".format(expected, actual), trace - ) + + + if expected_type in (int, bool, str) and expected != actual: + raise SubsetException("expected `{}`, got: `{}`".format(expected, actual), trace) if expected_type is dict: for key in expected: if key not in actual: diff --git a/src/test/rustdoc-json/structs.expected b/src/test/rustdoc-json/structs.expected index 45b23534bc77b..799829de3fd6c 100644 --- a/src/test/rustdoc-json/structs.expected +++ b/src/test/rustdoc-json/structs.expected @@ -7,7 +7,7 @@ "crate_id": 0, "name": "Unit", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 7, 0 @@ -37,7 +37,7 @@ "crate_id": 0, "name": "1", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 5, 22 @@ -72,7 +72,7 @@ "crate_id": 0, "name": "stuff", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 15, 4 @@ -114,7 +114,7 @@ "crate_id": 0, "name": "WithPrimitives", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 9, 0 @@ -141,18 +141,14 @@ ], "where_predicates": [] }, - "fields_stripped": true, - "fields": [ - "0:13", - "0:14" - ] + "fields_stripped": true } }, "0:14": { "crate_id": 0, "name": "s", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 11, 4 @@ -184,7 +180,7 @@ "crate_id": 0, "name": "things", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 16, 4 @@ -232,7 +228,7 @@ "crate_id": 0, "name": "WithGenerics", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 14, 0 @@ -273,18 +269,14 @@ ], "where_predicates": [] }, - "fields_stripped": true, - "fields": [ - "0:18", - "0:19" - ] + "fields_stripped": true } }, "0:0": { "crate_id": 0, "name": "structs", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 1, 0 @@ -315,7 +307,7 @@ "crate_id": 0, "name": "num", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 10, 4 @@ -340,7 +332,7 @@ "crate_id": 0, "name": "Tuple", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 5, 0 @@ -362,18 +354,14 @@ "params": [], "where_predicates": [] }, - "fields_stripped": true, - "fields": [ - "0:7", - "0:8" - ] + "fields_stripped": true } }, "0:4": { "crate_id": 0, "name": "PlainEmpty", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 3, 0 @@ -403,7 +391,7 @@ "crate_id": 0, "name": "0", "source": { - "filename": "structs.rs", + "filename": "$TEST_BASE_DIR/structs.rs", "begin": [ 5, 17 diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 88cb8544e47cc..e9089b4b15baa 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1565,7 +1565,7 @@ impl<'test> TestCx<'test> { self.compose_and_run_compiler(rustc, None) } - fn document(&self, out_dir: &Path, json: bool) -> ProcRes { + fn document(&self, out_dir: &Path) -> ProcRes { if self.props.build_aux_docs { for rel_ab in &self.props.aux_builds { let aux_testpaths = self.compute_aux_test_paths(rel_ab); @@ -1579,7 +1579,7 @@ impl<'test> TestCx<'test> { }; // Create the directory for the stdout/stderr files. create_dir_all(aux_cx.output_base_dir()).unwrap(); - let auxres = aux_cx.document(out_dir, json); + let auxres = aux_cx.document(out_dir); if !auxres.status.success() { return auxres; } @@ -1601,7 +1601,7 @@ impl<'test> TestCx<'test> { .arg(&self.testpaths.file) .args(&self.props.compile_flags); - if json { + if self.config.mode == RustdocJson { rustdoc.arg("--output-format").arg("json"); } @@ -2336,7 +2336,7 @@ impl<'test> TestCx<'test> { let _ = fs::remove_dir_all(&out_dir); create_dir_all(&out_dir).unwrap(); - let proc_res = self.document(&out_dir, false); + let proc_res = self.document(&out_dir); if !proc_res.status.success() { self.fatal_proc_rec("rustdoc failed!", &proc_res); } @@ -2392,7 +2392,7 @@ impl<'test> TestCx<'test> { rustc.arg("-L").arg(&new_rustdoc.aux_output_dir_name()); new_rustdoc.build_all_auxiliary(&mut rustc); - let proc_res = new_rustdoc.document(&compare_dir, false); + let proc_res = new_rustdoc.document(&compare_dir); if !proc_res.status.success() { proc_res.fatal(Some("failed to run nightly rustdoc"), || ()); } @@ -2482,7 +2482,7 @@ impl<'test> TestCx<'test> { let _ = fs::remove_dir_all(&out_dir); create_dir_all(&out_dir).unwrap(); - let proc_res = self.document(&out_dir, true); + let proc_res = self.document(&out_dir); if !proc_res.status.success() { self.fatal_proc_rec("rustdoc failed!", &proc_res); } @@ -3052,7 +3052,7 @@ impl<'test> TestCx<'test> { if let Some(nodejs) = &self.config.nodejs { let out_dir = self.output_base_dir(); - self.document(&out_dir, false); + self.document(&out_dir); let root = self.config.find_rust_src_root().unwrap(); let file_stem = From 9ba8d6e2347f80891f6aa1cd2afa223361465c3f Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 30 Nov 2020 17:25:23 -0800 Subject: [PATCH 18/18] Update books --- src/doc/book | 2 +- src/doc/embedded-book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book b/src/doc/book index 13e1c05420bca..a190438d77d28 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 13e1c05420bca86ecc79e4ba5b6d02de9bd53c62 +Subproject commit a190438d77d28041f24da4f6592e287fab073a61 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index ca8169e69b479..ba34b8a968f95 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit ca8169e69b479f615855d0eece7e318138fcfc00 +Subproject commit ba34b8a968f9531d38c4dc4411d5568b7c076bfe diff --git a/src/doc/nomicon b/src/doc/nomicon index 23c49f1d5ce47..d8383b65f7948 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 23c49f1d5ce4720bc5b7e3a920f47eccc8da6b63 +Subproject commit d8383b65f7948c2ca19191b3b4bd709b403aaf45 diff --git a/src/doc/reference b/src/doc/reference index a7de763c21329..a8afdca5d0715 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit a7de763c213292f5b44bf10acb87ffa38724814d +Subproject commit a8afdca5d0715b2257b6f8b9a032fd4dd7dae855 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 1886fda6981b7..236c734a2cb32 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 1886fda6981b723e4de637074455558f8bc1e83c +Subproject commit 236c734a2cb323541b3394f98682cb981b9ec086