diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 7826ac94718..be0af8be7b2 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -683,7 +683,7 @@ impl Step for RustdocUi { target: self.target, mode: "ui", suite: "rustdoc-ui", - path: None, + path: Some("src/test/rustdoc-ui"), compare_mode: None, }) } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 68b65f9b4a1..9c4683e0946 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -778,6 +778,9 @@ fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum) let push = builder.levels.push(&krate.attrs); builder.levels.register_id(hir::CRATE_HIR_ID); + for macro_def in &krate.exported_macros { + builder.levels.register_id(macro_def.hir_id); + } intravisit::walk_crate(&mut builder, krate); builder.levels.pop(push); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f91cb469e46..e434623d4a1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3408,6 +3408,7 @@ pub struct Span { pub locol: usize, pub hiline: usize, pub hicol: usize, + pub original: syntax_pos::Span, } impl Span { @@ -3416,8 +3417,13 @@ impl Span { filename: FileName::Anon(0), loline: 0, locol: 0, hiline: 0, hicol: 0, + original: syntax_pos::DUMMY_SP, } } + + pub fn span(&self) -> syntax_pos::Span { + self.original + } } impl Clean for syntax_pos::Span { @@ -3436,6 +3442,7 @@ impl Clean for syntax_pos::Span { locol: lo.col.to_usize(), hiline: hi.line, hicol: hi.col.to_usize(), + original: *self, } } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 9e108e605c8..2c382a1c175 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -321,7 +321,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if let Ok(res) = self.resolve(path_str, ns, ¤t_item, parent_node) { res } else { - resolution_failure(cx, &item.attrs, path_str, &dox, link_range); + resolution_failure(cx, &item, path_str, &dox, link_range); // This could just be a normal link or a broken link // we could potentially check if something is // "intra-doc-link-like" and warn in that case. @@ -332,7 +332,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if let Ok(res) = self.resolve(path_str, ns, ¤t_item, parent_node) { res } else { - resolution_failure(cx, &item.attrs, path_str, &dox, link_range); + resolution_failure(cx, &item, path_str, &dox, link_range); // This could just be a normal link. continue; } @@ -357,7 +357,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { }; if candidates.is_empty() { - resolution_failure(cx, &item.attrs, path_str, &dox, link_range); + resolution_failure(cx, &item, path_str, &dox, link_range); // this could just be a normal link continue; } @@ -368,7 +368,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } else { ambiguity_error( cx, - &item.attrs, + &item, path_str, &dox, link_range, @@ -381,7 +381,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if let Some(res) = macro_resolve(cx, path_str) { (res, None) } else { - resolution_failure(cx, &item.attrs, path_str, &dox, link_range); + resolution_failure(cx, &item, path_str, &dox, link_range); continue } } @@ -452,16 +452,24 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option { /// line containing the failure as a note as well. fn resolution_failure( cx: &DocContext<'_>, - attrs: &Attributes, + item: &Item, path_str: &str, dox: &str, link_range: Option>, ) { + 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; + } + }; + let attrs = &item.attrs; let sp = span_of_attrs(attrs); let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, - hir::CRATE_HIR_ID, + hir_id, sp, &format!("`[{}]` cannot be resolved, ignoring it...", path_str), ); @@ -495,12 +503,20 @@ fn resolution_failure( fn ambiguity_error( cx: &DocContext<'_>, - attrs: &Attributes, + item: &Item, path_str: &str, dox: &str, link_range: Option>, candidates: PerNS>, ) { + 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; + } + }; + let attrs = &item.attrs; let sp = span_of_attrs(attrs); let mut msg = format!("`{}` is ", path_str); @@ -532,7 +548,7 @@ fn ambiguity_error( let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, - hir::CRATE_HIR_ID, + hir_id, sp, &msg, ); diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 99aca063471..d9af33ac5b6 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -1,7 +1,6 @@ //! Contains information about "passes", used to modify crate information during the documentation //! process. -use rustc::hir; use rustc::hir::def_id::DefId; use rustc::lint as lint; use rustc::middle::privacy::AccessLevels; @@ -314,10 +313,13 @@ pub fn look_for_tests<'tcx>( item: &Item, check_missing_code: bool, ) { - if cx.as_local_hir_id(item.def_id).is_none() { - // If non-local, no need to check anything. - return; - } + 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, @@ -336,10 +338,11 @@ pub fn look_for_tests<'tcx>( find_testable_code(&dox, &mut tests, ErrorCodes::No); if check_missing_code == true && tests.found_tests == 0 { + let sp = span_of_attrs(&item.attrs).substitute_dummy(item.source.span()); let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::MISSING_DOC_CODE_EXAMPLES, - hir::CRATE_HIR_ID, - span_of_attrs(&item.attrs), + hir_id, + sp, "Missing code example in this documentation"); diag.emit(); } else if check_missing_code == false && @@ -347,7 +350,7 @@ pub fn look_for_tests<'tcx>( !cx.renderinfo.borrow().access_levels.is_doc_reachable(item.def_id) { let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::PRIVATE_DOC_TESTS, - hir::CRATE_HIR_ID, + hir_id, span_of_attrs(&item.attrs), "Documentation test in private item"); diag.emit(); diff --git a/src/test/rustdoc-ui/doc-without-codeblock.rs b/src/test/rustdoc-ui/doc-without-codeblock.rs index aa3f539ba32..4b2a91e9c81 100644 --- a/src/test/rustdoc-ui/doc-without-codeblock.rs +++ b/src/test/rustdoc-ui/doc-without-codeblock.rs @@ -1,6 +1,4 @@ -//~ ERROR Missing code example in this documentation - -#![deny(missing_doc_code_examples)] +#![deny(missing_doc_code_examples)] //~ ERROR Missing code example in this documentation /// Some docs. //~^ ERROR Missing code example in this documentation diff --git a/src/test/rustdoc-ui/doc-without-codeblock.stderr b/src/test/rustdoc-ui/doc-without-codeblock.stderr index 208bdedf24d..23c07c4d32d 100644 --- a/src/test/rustdoc-ui/doc-without-codeblock.stderr +++ b/src/test/rustdoc-ui/doc-without-codeblock.stderr @@ -1,25 +1,35 @@ error: Missing code example in this documentation + --> $DIR/doc-without-codeblock.rs:1:1 + | +LL | / #![deny(missing_doc_code_examples)] +LL | | +LL | | /// Some docs. +LL | | +... | +LL | | pub fn bar() {} +LL | | } + | |_^ | note: lint level defined here - --> $DIR/doc-without-codeblock.rs:3:9 + --> $DIR/doc-without-codeblock.rs:1:9 | LL | #![deny(missing_doc_code_examples)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: Missing code example in this documentation - --> $DIR/doc-without-codeblock.rs:5:1 + --> $DIR/doc-without-codeblock.rs:3:1 | LL | /// Some docs. | ^^^^^^^^^^^^^^ error: Missing code example in this documentation - --> $DIR/doc-without-codeblock.rs:9:1 + --> $DIR/doc-without-codeblock.rs:7:1 | LL | /// And then, the princess died. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Missing code example in this documentation - --> $DIR/doc-without-codeblock.rs:12:5 + --> $DIR/doc-without-codeblock.rs:10:5 | LL | /// Or maybe not because she saved herself! | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.rs b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs new file mode 100644 index 00000000000..ffe0ddcd8c9 --- /dev/null +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.rs @@ -0,0 +1,40 @@ +#![deny(missing_docs)] +#![deny(missing_doc_code_examples)] + +//! crate level doc +//! ``` +//! println!("hello"): +//! ``` + + +/// doc +/// +/// ``` +/// println!("hello"); +/// ``` +fn test() { +} + +#[allow(missing_docs)] +mod module1 { //~ ERROR +} + +#[allow(missing_doc_code_examples)] +/// doc +mod module2 { + + /// doc + pub fn test() {} +} + +/// doc +/// +/// ``` +/// println!("hello"); +/// ``` +pub mod module3 { + + /// doc + //~^ ERROR + pub fn test() {} +} diff --git a/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr new file mode 100644 index 00000000000..97a52a13e3f --- /dev/null +++ b/src/test/rustdoc-ui/lint-missing-doc-code-example.stderr @@ -0,0 +1,21 @@ +error: Missing code example in this documentation + --> $DIR/lint-missing-doc-code-example.rs:19:1 + | +LL | / mod module1 { +LL | | } + | |_^ + | +note: lint level defined here + --> $DIR/lint-missing-doc-code-example.rs:2:9 + | +LL | #![deny(missing_doc_code_examples)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Missing code example in this documentation + --> $DIR/lint-missing-doc-code-example.rs:37:3 + | +LL | /// doc + | ^^^^^^^ + +error: aborting due to 2 previous errors +