From 617d10975ef1db8ab9fcf3b5720a147f36b69f41 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 27 Jul 2020 22:16:41 -0400 Subject: [PATCH 1/3] Separate `missing_doc_code_examples` from intra-doc links These two lints have no relation other than both being nightly-only. This allows stabilizing intra-doc links without stabilizing missing_doc_code_examples. --- .../passes/collect_intra_doc_links.rs | 4 +-- src/librustdoc/passes/mod.rs | 31 ++++++++++++------- .../passes/private_items_doc_tests.rs | 2 +- src/test/rustdoc-ui/lint-group.stderr | 26 ++++++++-------- 4 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 5187839423d..418238181e9 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -23,7 +23,7 @@ use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; use crate::html::markdown::markdown_links; -use crate::passes::{look_for_tests, Pass}; +use crate::passes::Pass; use super::span_of_attrs; @@ -508,8 +508,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new); trace!("got documentation '{}'", dox); - look_for_tests(&cx, &dox, &item, true); - // find item's parent to resolve `Self` in item's docs below let parent_name = self.cx.as_local_hir_id(item.def_id).and_then(|item_hir| { let parent_hir = self.cx.tcx.hir().get_parent_item(item_hir); diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 70366c90139..c604c804ddf 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -312,12 +312,7 @@ impl DocFolder for ImportStripper { } } -pub fn look_for_tests<'tcx>( - cx: &DocContext<'tcx>, - dox: &str, - item: &Item, - check_missing_code: bool, -) { +pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { let hir_id = match cx.as_local_hir_id(item.def_id) { Some(hir_id) => hir_id, None => { @@ -340,12 +335,24 @@ pub fn look_for_tests<'tcx>( find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None); - if check_missing_code && tests.found_tests == 0 { - let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span()); - cx.tcx.struct_span_lint_hir(lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id, sp, |lint| { - lint.build("missing code example in this documentation").emit() - }); - } else if !check_missing_code + if tests.found_tests == 0 { + use clean::ItemEnum::*; + + let should_report = match item.inner { + ExternCrateItem(_, _) | ImportItem(_) | PrimitiveItem(_) | KeywordItem(_) => false, + _ => true, + }; + if should_report { + debug!("reporting error for {:?} (hir_id={:?})", item, hir_id); + let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span()); + cx.tcx.struct_span_lint_hir( + lint::builtin::MISSING_DOC_CODE_EXAMPLES, + hir_id, + sp, + |lint| lint.build("missing code example in this documentation").emit(), + ); + } + } else if rustc_feature::UnstableFeatures::from_environment().is_nightly_build() && tests.found_tests > 0 && !cx.renderinfo.borrow().access_levels.is_public(item.def_id) { diff --git a/src/librustdoc/passes/private_items_doc_tests.rs b/src/librustdoc/passes/private_items_doc_tests.rs index aec5a6bd4e2..77ed578ca77 100644 --- a/src/librustdoc/passes/private_items_doc_tests.rs +++ b/src/librustdoc/passes/private_items_doc_tests.rs @@ -30,7 +30,7 @@ impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> { let cx = self.cx; let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new); - look_for_tests(&cx, &dox, &item, false); + look_for_tests(&cx, &dox, &item); self.fold_item_recur(item) } diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr index 14d72e9aad3..ad923c714da 100644 --- a/src/test/rustdoc-ui/lint-group.stderr +++ b/src/test/rustdoc-ui/lint-group.stderr @@ -1,3 +1,16 @@ +error: missing code example in this documentation + --> $DIR/lint-group.rs:16:1 + | +LL | /// wait, this doesn't have a doctest? + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-group.rs:7:9 + | +LL | #![deny(rustdoc)] + | ^^^^^^^ + = note: `#[deny(missing_doc_code_examples)]` implied by `#[deny(rustdoc)]` + error: documentation test in private item --> $DIR/lint-group.rs:19:1 | @@ -29,18 +42,5 @@ LL | #![deny(rustdoc)] = note: `#[deny(intra_doc_link_resolution_failure)]` implied by `#[deny(rustdoc)]` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` -error: missing code example in this documentation - --> $DIR/lint-group.rs:16:1 - | -LL | /// wait, this doesn't have a doctest? - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/lint-group.rs:7:9 - | -LL | #![deny(rustdoc)] - | ^^^^^^^ - = note: `#[deny(missing_doc_code_examples)]` implied by `#[deny(rustdoc)]` - error: aborting due to 3 previous errors From def61777083d938a75718d55ba6c6600d4923d6d Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 27 Jul 2020 23:03:56 -0400 Subject: [PATCH 2/3] Move `look_for_tests` to `private_items_doc_tests` --- src/librustdoc/passes/mod.rs | 55 ---------------- .../passes/private_items_doc_tests.rs | 62 ++++++++++++++++++- 2 files changed, 61 insertions(+), 56 deletions(-) diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index c604c804ddf..a21b5d10ed1 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -3,7 +3,6 @@ use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::middle::privacy::AccessLevels; -use rustc_session::lint; use rustc_span::{InnerSpan, Span, DUMMY_SP}; use std::mem; use std::ops::Range; @@ -12,7 +11,6 @@ use self::Condition::*; use crate::clean::{self, GetDefId, Item}; use crate::core::DocContext; use crate::fold::{DocFolder, StripItem}; -use crate::html::markdown::{find_testable_code, ErrorCodes, LangString}; mod collapse_docs; pub use self::collapse_docs::COLLAPSE_DOCS; @@ -312,59 +310,6 @@ impl DocFolder for ImportStripper { } } -pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { - let hir_id = match cx.as_local_hir_id(item.def_id) { - Some(hir_id) => hir_id, - None => { - // If non-local, no need to check anything. - return; - } - }; - - struct Tests { - found_tests: usize, - } - - impl crate::test::Tester for Tests { - fn add_test(&mut self, _: String, _: LangString, _: usize) { - self.found_tests += 1; - } - } - - let mut tests = Tests { found_tests: 0 }; - - find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None); - - if tests.found_tests == 0 { - use clean::ItemEnum::*; - - let should_report = match item.inner { - ExternCrateItem(_, _) | ImportItem(_) | PrimitiveItem(_) | KeywordItem(_) => false, - _ => true, - }; - if should_report { - debug!("reporting error for {:?} (hir_id={:?})", item, hir_id); - let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span()); - cx.tcx.struct_span_lint_hir( - lint::builtin::MISSING_DOC_CODE_EXAMPLES, - hir_id, - sp, - |lint| lint.build("missing code example in this documentation").emit(), - ); - } - } else if rustc_feature::UnstableFeatures::from_environment().is_nightly_build() - && tests.found_tests > 0 - && !cx.renderinfo.borrow().access_levels.is_public(item.def_id) - { - cx.tcx.struct_span_lint_hir( - lint::builtin::PRIVATE_DOC_TESTS, - hir_id, - span_of_attrs(&item.attrs).unwrap_or(item.source.span()), - |lint| lint.build("documentation test in private item").emit(), - ); - } -} - /// Returns a span encompassing all the given attributes. crate fn span_of_attrs(attrs: &clean::Attributes) -> Option { if attrs.doc_strings.is_empty() { diff --git a/src/librustdoc/passes/private_items_doc_tests.rs b/src/librustdoc/passes/private_items_doc_tests.rs index 77ed578ca77..b869e68da4c 100644 --- a/src/librustdoc/passes/private_items_doc_tests.rs +++ b/src/librustdoc/passes/private_items_doc_tests.rs @@ -1,7 +1,14 @@ +//! This pass is overloaded and runs two different lints. +//! +//! - MISSING_DOC_CODE_EXAMPLES: this looks for public items missing doc-tests +//! - PRIVATE_DOC_TESTS: this looks for private items with doc-tests. + use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; -use crate::passes::{look_for_tests, Pass}; +use super::{span_of_attrs, Pass}; +use crate::html::markdown::{find_testable_code, ErrorCodes, LangString}; +use rustc_session::lint; pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { name: "check-private-items-doc-tests", @@ -35,3 +42,56 @@ impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> { self.fold_item_recur(item) } } + +pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { + let hir_id = match cx.as_local_hir_id(item.def_id) { + Some(hir_id) => hir_id, + None => { + // If non-local, no need to check anything. + return; + } + }; + + struct Tests { + found_tests: usize, + } + + impl crate::test::Tester for Tests { + fn add_test(&mut self, _: String, _: LangString, _: usize) { + self.found_tests += 1; + } + } + + let mut tests = Tests { found_tests: 0 }; + + find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None); + + if tests.found_tests == 0 { + use ItemEnum::*; + + let should_report = match item.inner { + ExternCrateItem(_, _) | ImportItem(_) | PrimitiveItem(_) | KeywordItem(_) => false, + _ => true, + }; + if should_report { + debug!("reporting error for {:?} (hir_id={:?})", item, hir_id); + let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span()); + cx.tcx.struct_span_lint_hir( + lint::builtin::MISSING_DOC_CODE_EXAMPLES, + hir_id, + sp, + |lint| lint.build("missing code example in this documentation").emit(), + ); + } + } else if rustc_feature::UnstableFeatures::from_environment().is_nightly_build() + && tests.found_tests > 0 + && !cx.renderinfo.borrow().access_levels.is_public(item.def_id) + { + cx.tcx.struct_span_lint_hir( + lint::builtin::PRIVATE_DOC_TESTS, + hir_id, + span_of_attrs(&item.attrs).unwrap_or(item.source.span()), + |lint| lint.build("documentation test in private item").emit(), + ); + } +} From c3f5556c30e7af7a9fe139a2393b0fcdd27b9206 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 27 Jul 2020 23:05:01 -0400 Subject: [PATCH 3/3] private_items_doc_tests -> doc_test_lints --- .../passes/{private_items_doc_tests.rs => doc_test_lints.rs} | 2 +- src/librustdoc/passes/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/librustdoc/passes/{private_items_doc_tests.rs => doc_test_lints.rs} (100%) diff --git a/src/librustdoc/passes/private_items_doc_tests.rs b/src/librustdoc/passes/doc_test_lints.rs similarity index 100% rename from src/librustdoc/passes/private_items_doc_tests.rs rename to src/librustdoc/passes/doc_test_lints.rs index b869e68da4c..aced7d55281 100644 --- a/src/librustdoc/passes/private_items_doc_tests.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -3,10 +3,10 @@ //! - MISSING_DOC_CODE_EXAMPLES: this looks for public items missing doc-tests //! - PRIVATE_DOC_TESTS: this looks for private items with doc-tests. +use super::{span_of_attrs, Pass}; use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; -use super::{span_of_attrs, Pass}; use crate::html::markdown::{find_testable_code, ErrorCodes, LangString}; use rustc_session::lint; diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index a21b5d10ed1..0eebdbd87ed 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -33,8 +33,8 @@ pub use self::propagate_doc_cfg::PROPAGATE_DOC_CFG; mod collect_intra_doc_links; pub use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS; -mod private_items_doc_tests; -pub use self::private_items_doc_tests::CHECK_PRIVATE_ITEMS_DOC_TESTS; +mod doc_test_lints; +pub use self::doc_test_lints::CHECK_PRIVATE_ITEMS_DOC_TESTS; mod collect_trait_impls; pub use self::collect_trait_impls::COLLECT_TRAIT_IMPLS;