Allow #![doc(test(attr(..)))] at every level
This commit is contained in:
@@ -46,11 +46,6 @@ passes_attr_crate_level =
|
||||
.suggestion = to apply to the crate, use an inner attribute
|
||||
.note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
|
||||
passes_attr_mod_level =
|
||||
this attribute can only be applied at module level
|
||||
.suggestion = to apply to the crate, use an inner attribute at the crate level
|
||||
.note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-module-level> for more information
|
||||
|
||||
passes_attr_only_in_functions =
|
||||
`{$attr}` attribute can only be used on functions
|
||||
|
||||
|
||||
@@ -1252,7 +1252,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||
let bang_span = attr.span().lo() + BytePos(1);
|
||||
let sugg = (attr.style() == AttrStyle::Outer
|
||||
&& self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID)
|
||||
.then_some(errors::AttrCrateLevelSugg {
|
||||
.then_some(errors::AttrCrateLevelOnlySugg {
|
||||
attr: attr.span().with_lo(bang_span).with_hi(bang_span),
|
||||
});
|
||||
self.tcx.emit_node_span_lint(
|
||||
@@ -1266,46 +1266,13 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||
true
|
||||
}
|
||||
|
||||
/// Checks that an attribute is used at module level. Returns `true` if valid.
|
||||
fn check_attr_mod_level(
|
||||
&self,
|
||||
attr: &Attribute,
|
||||
meta: &MetaItemInner,
|
||||
hir_id: HirId,
|
||||
target: Target,
|
||||
) -> bool {
|
||||
if target != Target::Mod {
|
||||
// insert a bang between `#` and `[...`
|
||||
let bang_span = attr.span().lo() + BytePos(1);
|
||||
let sugg = (attr.style() == AttrStyle::Outer
|
||||
&& self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID)
|
||||
.then_some(errors::AttrCrateLevelSugg {
|
||||
attr: attr.span().with_lo(bang_span).with_hi(bang_span),
|
||||
});
|
||||
self.tcx.emit_node_span_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
meta.span(),
|
||||
errors::AttrModLevelOnly { sugg },
|
||||
);
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Checks that `doc(test(...))` attribute contains only valid attributes and are at the right place.
|
||||
fn check_test_attr(
|
||||
&self,
|
||||
attr: &Attribute,
|
||||
meta: &MetaItemInner,
|
||||
hir_id: HirId,
|
||||
target: Target,
|
||||
) {
|
||||
fn check_test_attr(&self, attr: &Attribute, meta: &MetaItemInner, hir_id: HirId) {
|
||||
if let Some(metas) = meta.meta_item_list() {
|
||||
for i_meta in metas {
|
||||
match (i_meta.name(), i_meta.meta_item()) {
|
||||
(Some(sym::attr), _) => {
|
||||
self.check_attr_mod_level(attr, meta, hir_id, target);
|
||||
// Allowed everywhere like `#[doc]`
|
||||
}
|
||||
(Some(sym::no_crate_inject), _) => {
|
||||
self.check_attr_crate_level(attr, meta, hir_id);
|
||||
@@ -1396,7 +1363,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
|
||||
Some(sym::test) => {
|
||||
self.check_test_attr(attr, meta, hir_id, target);
|
||||
self.check_test_attr(attr, meta, hir_id);
|
||||
}
|
||||
|
||||
Some(
|
||||
|
||||
@@ -1890,20 +1890,12 @@ pub(crate) struct UnusedVarTryIgnoreSugg {
|
||||
#[note]
|
||||
pub(crate) struct AttrCrateLevelOnly {
|
||||
#[subdiagnostic]
|
||||
pub sugg: Option<AttrCrateLevelSugg>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_attr_mod_level)]
|
||||
#[note]
|
||||
pub(crate) struct AttrModLevelOnly {
|
||||
#[subdiagnostic]
|
||||
pub sugg: Option<AttrCrateLevelSugg>,
|
||||
pub sugg: Option<AttrCrateLevelOnlySugg>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(passes_suggestion, applicability = "maybe-incorrect", code = "!", style = "verbose")]
|
||||
pub(crate) struct AttrCrateLevelSugg {
|
||||
pub(crate) struct AttrCrateLevelOnlySugg {
|
||||
#[primary_span]
|
||||
pub attr: Span,
|
||||
}
|
||||
|
||||
@@ -141,34 +141,6 @@ But if you include this:
|
||||
|
||||
it will not.
|
||||
|
||||
## At the module level
|
||||
|
||||
These forms of the `#[doc]` attribute are used on individual modules, to control how
|
||||
they are documented.
|
||||
|
||||
### `test(attr(...))`
|
||||
|
||||
This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For
|
||||
example, if you want your doctests to fail if they have dead code, you could add this:
|
||||
|
||||
```rust,no_run
|
||||
#![doc(test(attr(deny(dead_code))))]
|
||||
|
||||
mod my_mod {
|
||||
#![doc(test(attr(allow(dead_code))))] // but allow `dead_code` for this module
|
||||
}
|
||||
```
|
||||
|
||||
`test(attr(..))` attributes are appended to the parent module's, they do not replace the current
|
||||
list of attributes. In the previous example, both attributes would be present:
|
||||
|
||||
```rust,no_run
|
||||
// For every doctest in `my_mod`
|
||||
|
||||
#![deny(dead_code)] // from the crate-root
|
||||
#![allow(dead_code)] // from `my_mod`
|
||||
```
|
||||
|
||||
## At the item level
|
||||
|
||||
These forms of the `#[doc]` attribute are used on individual items, to control how
|
||||
@@ -300,3 +272,26 @@ To get around this limitation, we just add `#[doc(alias = "lib_name_do_something
|
||||
on the `do_something` method and then it's all good!
|
||||
Users can now look for `lib_name_do_something` in our crate directly and find
|
||||
`Obj::do_something`.
|
||||
|
||||
### `test(attr(...))`
|
||||
|
||||
This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For
|
||||
example, if you want your doctests to fail if they have dead code, you could add this:
|
||||
|
||||
```rust,no_run
|
||||
#![doc(test(attr(deny(dead_code))))]
|
||||
|
||||
mod my_mod {
|
||||
#![doc(test(attr(allow(dead_code))))] // but allow `dead_code` for this module
|
||||
}
|
||||
```
|
||||
|
||||
`test(attr(..))` attributes are appended to the parent module's, they do not replace the current
|
||||
list of attributes. In the previous example, both attributes would be present:
|
||||
|
||||
```rust,no_run
|
||||
// For every doctest in `my_mod`
|
||||
|
||||
#![deny(dead_code)] // from the crate-root
|
||||
#![allow(dead_code)] // from `my_mod`
|
||||
```
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
#![doc(masked)]
|
||||
//~^ ERROR this attribute can only be applied to an `extern crate` item
|
||||
|
||||
#[doc(test(attr(allow(warnings))))]
|
||||
//~^ ERROR can only be applied at module level
|
||||
//~| HELP to apply to the crate, use an inner attribute
|
||||
//~| SUGGESTION !
|
||||
#[doc(test(no_crate_inject))]
|
||||
//~^ ERROR can only be applied at the crate level
|
||||
//~| HELP to apply to the crate, use an inner attribute
|
||||
|
||||
@@ -1,30 +1,18 @@
|
||||
error: this attribute can only be applied at module level
|
||||
--> $DIR/invalid-doc-attr.rs:7:7
|
||||
|
|
||||
LL | #[doc(test(attr(allow(warnings))))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-module-level> for more information
|
||||
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||
help: to apply to the crate, use an inner attribute at the crate level
|
||||
|
|
||||
LL | #![doc(test(attr(allow(warnings))))]
|
||||
| +
|
||||
|
||||
error: this attribute can only be applied at the crate level
|
||||
--> $DIR/invalid-doc-attr.rs:11:7
|
||||
--> $DIR/invalid-doc-attr.rs:7:7
|
||||
|
|
||||
LL | #[doc(test(no_crate_inject))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||
help: to apply to the crate, use an inner attribute
|
||||
|
|
||||
LL | #![doc(test(no_crate_inject))]
|
||||
| +
|
||||
|
||||
error: this attribute can only be applied to a `use` item
|
||||
--> $DIR/invalid-doc-attr.rs:15:7
|
||||
--> $DIR/invalid-doc-attr.rs:11:7
|
||||
|
|
||||
LL | #[doc(inline)]
|
||||
| ^^^^^^ only applicable on `use` items
|
||||
@@ -35,7 +23,7 @@ LL | pub fn foo() {}
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
|
||||
|
||||
error: this attribute can only be applied at the crate level
|
||||
--> $DIR/invalid-doc-attr.rs:20:12
|
||||
--> $DIR/invalid-doc-attr.rs:16:12
|
||||
|
|
||||
LL | #![doc(test(no_crate_inject))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -43,7 +31,7 @@ LL | #![doc(test(no_crate_inject))]
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
|
||||
error: conflicting doc inlining attributes
|
||||
--> $DIR/invalid-doc-attr.rs:30:7
|
||||
--> $DIR/invalid-doc-attr.rs:26:7
|
||||
|
|
||||
LL | #[doc(inline)]
|
||||
| ^^^^^^ this attribute...
|
||||
@@ -53,7 +41,7 @@ LL | #[doc(no_inline)]
|
||||
= help: remove one of the conflicting attributes
|
||||
|
||||
error: this attribute can only be applied to an `extern crate` item
|
||||
--> $DIR/invalid-doc-attr.rs:36:7
|
||||
--> $DIR/invalid-doc-attr.rs:32:7
|
||||
|
|
||||
LL | #[doc(masked)]
|
||||
| ^^^^^^ only applicable on `extern crate` items
|
||||
@@ -64,7 +52,7 @@ LL | pub struct Masked;
|
||||
= note: read <https://doc.rust-lang.org/unstable-book/language-features/doc-masked.html> for more information
|
||||
|
||||
error: this attribute cannot be applied to an `extern crate self` item
|
||||
--> $DIR/invalid-doc-attr.rs:40:7
|
||||
--> $DIR/invalid-doc-attr.rs:36:7
|
||||
|
|
||||
LL | #[doc(masked)]
|
||||
| ^^^^^^ not applicable on `extern crate self` items
|
||||
@@ -81,7 +69,7 @@ LL | #![doc(masked)]
|
||||
= note: read <https://doc.rust-lang.org/unstable-book/language-features/doc-masked.html> for more information
|
||||
|
||||
error: this attribute can only be applied at the crate level
|
||||
--> $DIR/invalid-doc-attr.rs:23:11
|
||||
--> $DIR/invalid-doc-attr.rs:19:11
|
||||
|
|
||||
LL | #[doc(test(no_crate_inject))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -89,7 +77,7 @@ LL | #[doc(test(no_crate_inject))]
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
|
||||
|
||||
error: this attribute can only be applied to a `use` item
|
||||
--> $DIR/invalid-doc-attr.rs:25:11
|
||||
--> $DIR/invalid-doc-attr.rs:21:11
|
||||
|
|
||||
LL | #[doc(inline)]
|
||||
| ^^^^^^ only applicable on `use` items
|
||||
@@ -99,5 +87,5 @@ LL | pub fn baz() {}
|
||||
|
|
||||
= note: read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
error: aborting due to 9 previous errors
|
||||
|
||||
|
||||
@@ -9,8 +9,13 @@ macro_rules! mac {
|
||||
/// foo //~ ERROR unused doc comment
|
||||
mac!();
|
||||
|
||||
/// a //~ ERROR unused doc comment
|
||||
#[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment
|
||||
unsafe extern "C" { }
|
||||
|
||||
fn foo() {
|
||||
/// a //~ ERROR unused doc comment
|
||||
#[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment
|
||||
let x = 12;
|
||||
|
||||
/// multi-line //~ ERROR unused doc comment
|
||||
@@ -19,6 +24,7 @@ fn foo() {
|
||||
match x {
|
||||
/// c //~ ERROR unused doc comment
|
||||
1 => {},
|
||||
#[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -32,6 +38,7 @@ fn foo() {
|
||||
/// bar //~ ERROR unused doc comment
|
||||
mac!();
|
||||
|
||||
#[doc(test(attr(allow(dead_code))))] //~ ERROR unused doc comment
|
||||
let x = /** comment */ 47; //~ ERROR unused doc comment
|
||||
|
||||
/// dox //~ ERROR unused doc comment
|
||||
|
||||
@@ -12,7 +12,28 @@ LL | #![deny(unused_doc_comments)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless-comment.rs:32:5
|
||||
--> $DIR/useless-comment.rs:12:1
|
||||
|
|
||||
LL | /// a
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[doc(test(attr(allow(dead_code))))]
|
||||
LL | unsafe extern "C" { }
|
||||
| --------------------- rustdoc does not generate documentation for extern blocks
|
||||
|
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless-comment.rs:13:1
|
||||
|
|
||||
LL | #[doc(test(attr(allow(dead_code))))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | unsafe extern "C" { }
|
||||
| --------------------- rustdoc does not generate documentation for extern blocks
|
||||
|
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless-comment.rs:38:5
|
||||
|
|
||||
LL | /// bar
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ rustdoc does not generate documentation for macro invocations
|
||||
@@ -20,17 +41,28 @@ LL | /// bar
|
||||
= help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless-comment.rs:13:5
|
||||
--> $DIR/useless-comment.rs:17:5
|
||||
|
|
||||
LL | /// a
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #[doc(test(attr(allow(dead_code))))]
|
||||
LL | let x = 12;
|
||||
| ----------- rustdoc does not generate documentation for statements
|
||||
|
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless-comment.rs:16:5
|
||||
--> $DIR/useless-comment.rs:18:5
|
||||
|
|
||||
LL | #[doc(test(attr(allow(dead_code))))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let x = 12;
|
||||
| ----------- rustdoc does not generate documentation for statements
|
||||
|
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless-comment.rs:21:5
|
||||
|
|
||||
LL | / /// multi-line
|
||||
LL | | /// doc comment
|
||||
@@ -39,6 +71,7 @@ LL | | /// that is unused
|
||||
LL | / match x {
|
||||
LL | | /// c
|
||||
LL | | 1 => {},
|
||||
LL | | #[doc(test(attr(allow(dead_code))))]
|
||||
LL | | _ => {}
|
||||
LL | | }
|
||||
| |_____- rustdoc does not generate documentation for expressions
|
||||
@@ -46,7 +79,7 @@ LL | | }
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless-comment.rs:20:9
|
||||
--> $DIR/useless-comment.rs:25:9
|
||||
|
|
||||
LL | /// c
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -56,7 +89,17 @@ LL | 1 => {},
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless-comment.rs:25:5
|
||||
--> $DIR/useless-comment.rs:27:9
|
||||
|
|
||||
LL | #[doc(test(attr(allow(dead_code))))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | _ => {}
|
||||
| ------- rustdoc does not generate documentation for match arms
|
||||
|
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless-comment.rs:31:5
|
||||
|
|
||||
LL | /// foo
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -66,7 +109,7 @@ LL | unsafe {}
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless-comment.rs:28:5
|
||||
--> $DIR/useless-comment.rs:34:5
|
||||
|
|
||||
LL | #[doc = "foo"]
|
||||
| ^^^^^^^^^^^^^^
|
||||
@@ -77,7 +120,7 @@ LL | 3;
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless-comment.rs:29:5
|
||||
--> $DIR/useless-comment.rs:35:5
|
||||
|
|
||||
LL | #[doc = "bar"]
|
||||
| ^^^^^^^^^^^^^^
|
||||
@@ -87,7 +130,17 @@ LL | 3;
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless-comment.rs:35:13
|
||||
--> $DIR/useless-comment.rs:41:5
|
||||
|
|
||||
LL | #[doc(test(attr(allow(dead_code))))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let x = /** comment */ 47;
|
||||
| -------------------------- rustdoc does not generate documentation for statements
|
||||
|
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless-comment.rs:42:13
|
||||
|
|
||||
LL | let x = /** comment */ 47;
|
||||
| ^^^^^^^^^^^^^^ -- rustdoc does not generate documentation for expressions
|
||||
@@ -95,7 +148,7 @@ LL | let x = /** comment */ 47;
|
||||
= help: use `/* */` for a plain comment
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless-comment.rs:37:5
|
||||
--> $DIR/useless-comment.rs:44:5
|
||||
|
|
||||
LL | /// dox
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -106,5 +159,5 @@ LL | | }
|
||||
|
|
||||
= help: use `//` for a plain comment
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
error: aborting due to 15 previous errors
|
||||
|
||||
|
||||
@@ -10,4 +10,42 @@ mod test {
|
||||
#![doc(test(attr(allow(warnings))))]
|
||||
}
|
||||
|
||||
#[doc(test(attr(allow(dead_code))))]
|
||||
static S: u32 = 5;
|
||||
|
||||
#[doc(test(attr(allow(dead_code))))]
|
||||
const C: u32 = 5;
|
||||
|
||||
#[doc(test(attr(deny(dead_code))))]
|
||||
struct A {
|
||||
#[doc(test(attr(allow(dead_code))))]
|
||||
field: u32
|
||||
}
|
||||
|
||||
#[doc(test(attr(deny(dead_code))))]
|
||||
union U {
|
||||
#[doc(test(attr(allow(dead_code))))]
|
||||
field: u32,
|
||||
field2: u64,
|
||||
}
|
||||
|
||||
#[doc(test(attr(deny(dead_code))))]
|
||||
enum Enum {
|
||||
#[doc(test(attr(allow(dead_code))))]
|
||||
Variant1,
|
||||
}
|
||||
|
||||
#[doc(test(attr(deny(dead_code))))]
|
||||
impl A {
|
||||
#[doc(test(attr(deny(dead_code))))]
|
||||
fn method() {}
|
||||
}
|
||||
|
||||
#[doc(test(attr(deny(dead_code))))]
|
||||
trait MyTrait {
|
||||
#[doc(test(attr(deny(dead_code))))]
|
||||
fn my_trait_fn();
|
||||
}
|
||||
|
||||
#[doc(test(attr(deny(dead_code))))]
|
||||
pub fn foo() {}
|
||||
|
||||
Reference in New Issue
Block a user