mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Auto merge of #57882 - euclio:unused-doc-attributes, r=estebank
overhaul unused doc comments lint This PR contains a number of improvements to the `unused_doc_comments` lint. - Extends the span to cover the entire comment when using sugared doc comments. - Triggers the lint for all unused doc comments on a node, instead of just the first one. - Triggers the lint on macro expansions, and provides a help note explaining that doc comments must be expanded by the macro. - Adds a label pointing at the node that cannot be documented. Furthermore, this PR fixes any instances in rustc where a macro expansion was erroneously documented.
This commit is contained in:
commit
e1b8898cfb
@ -4515,7 +4515,7 @@ macro_rules! rev {
|
||||
)*}
|
||||
}
|
||||
|
||||
/// intra-sign conversions
|
||||
// intra-sign conversions
|
||||
try_from_upper_bounded!(u16, u8);
|
||||
try_from_upper_bounded!(u32, u16, u8);
|
||||
try_from_upper_bounded!(u64, u32, u16, u8);
|
||||
|
@ -122,15 +122,15 @@ impl fmt::Display for HirId {
|
||||
// hack to ensure that we don't try to access the private parts of `ItemLocalId` in this module
|
||||
mod item_local_id_inner {
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
/// An `ItemLocalId` uniquely identifies something within a given "item-like",
|
||||
/// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no
|
||||
/// guarantee that the numerical value of a given `ItemLocalId` corresponds to
|
||||
/// the node's position within the owning item in any way, but there is a
|
||||
/// guarantee that the `LocalItemId`s within an owner occupy a dense range of
|
||||
/// integers starting at zero, so a mapping that maps all or most nodes within
|
||||
/// an "item-like" to something else can be implement by a `Vec` instead of a
|
||||
/// tree or hash map.
|
||||
newtype_index! {
|
||||
/// An `ItemLocalId` uniquely identifies something within a given "item-like",
|
||||
/// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no
|
||||
/// guarantee that the numerical value of a given `ItemLocalId` corresponds to
|
||||
/// the node's position within the owning item in any way, but there is a
|
||||
/// guarantee that the `LocalItemId`s within an owner occupy a dense range of
|
||||
/// integers starting at zero, so a mapping that maps all or most nodes within
|
||||
/// an "item-like" to something else can be implement by a `Vec` instead of a
|
||||
/// tree or hash map.
|
||||
pub struct ItemLocalId { .. }
|
||||
}
|
||||
}
|
||||
|
@ -132,25 +132,24 @@ pub enum ScopeData {
|
||||
Remainder(FirstStatementIndex)
|
||||
}
|
||||
|
||||
/// Represents a subscope of `block` for a binding that is introduced
|
||||
/// by `block.stmts[first_statement_index]`. Such subscopes represent
|
||||
/// a suffix of the block. Note that each subscope does not include
|
||||
/// the initializer expression, if any, for the statement indexed by
|
||||
/// `first_statement_index`.
|
||||
///
|
||||
/// For example, given `{ let (a, b) = EXPR_1; let c = EXPR_2; ... }`:
|
||||
///
|
||||
/// * The subscope with `first_statement_index == 0` is scope of both
|
||||
/// `a` and `b`; it does not include EXPR_1, but does include
|
||||
/// everything after that first `let`. (If you want a scope that
|
||||
/// includes EXPR_1 as well, then do not use `Scope::Remainder`,
|
||||
/// but instead another `Scope` that encompasses the whole block,
|
||||
/// e.g., `Scope::Node`.
|
||||
///
|
||||
/// * The subscope with `first_statement_index == 1` is scope of `c`,
|
||||
/// and thus does not include EXPR_2, but covers the `...`.
|
||||
|
||||
newtype_index! {
|
||||
/// Represents a subscope of `block` for a binding that is introduced
|
||||
/// by `block.stmts[first_statement_index]`. Such subscopes represent
|
||||
/// a suffix of the block. Note that each subscope does not include
|
||||
/// the initializer expression, if any, for the statement indexed by
|
||||
/// `first_statement_index`.
|
||||
///
|
||||
/// For example, given `{ let (a, b) = EXPR_1; let c = EXPR_2; ... }`:
|
||||
///
|
||||
/// * The subscope with `first_statement_index == 0` is scope of both
|
||||
/// `a` and `b`; it does not include EXPR_1, but does include
|
||||
/// everything after that first `let`. (If you want a scope that
|
||||
/// includes EXPR_1 as well, then do not use `Scope::Remainder`,
|
||||
/// but instead another `Scope` that encompasses the whole block,
|
||||
/// e.g., `Scope::Node`.
|
||||
///
|
||||
/// * The subscope with `first_statement_index == 1` is scope of `c`,
|
||||
/// and thus does not include EXPR_2, but covers the `...`.
|
||||
pub struct FirstStatementIndex { .. }
|
||||
}
|
||||
|
||||
|
@ -1892,9 +1892,11 @@ pub mod tls {
|
||||
rayon_core::tlv::get()
|
||||
}
|
||||
|
||||
/// A thread local variable which stores a pointer to the current ImplicitCtxt
|
||||
#[cfg(not(parallel_compiler))]
|
||||
thread_local!(static TLV: Cell<usize> = Cell::new(0));
|
||||
thread_local! {
|
||||
/// A thread local variable which stores a pointer to the current ImplicitCtxt.
|
||||
static TLV: Cell<usize> = Cell::new(0);
|
||||
}
|
||||
|
||||
/// Sets TLV to `value` during the call to `f`.
|
||||
/// It is restored to its previous value after.
|
||||
@ -2011,10 +2013,11 @@ pub mod tls {
|
||||
})
|
||||
}
|
||||
|
||||
/// Stores a pointer to the GlobalCtxt if one is available.
|
||||
/// This is used to access the GlobalCtxt in the deadlock handler
|
||||
/// given to Rayon.
|
||||
scoped_thread_local!(pub static GCX_PTR: Lock<usize>);
|
||||
scoped_thread_local! {
|
||||
/// Stores a pointer to the GlobalCtxt if one is available.
|
||||
/// This is used to access the GlobalCtxt in the deadlock handler given to Rayon.
|
||||
pub static GCX_PTR: Lock<usize>
|
||||
}
|
||||
|
||||
/// Creates a TyCtxt and ImplicitCtxt based on the GCX_PTR thread local.
|
||||
/// This is used in the deadlock handler.
|
||||
|
@ -1512,42 +1512,42 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// "Universes" are used during type- and trait-checking in the
|
||||
/// presence of `for<..>` binders to control what sets of names are
|
||||
/// visible. Universes are arranged into a tree: the root universe
|
||||
/// contains names that are always visible. Each child then adds a new
|
||||
/// set of names that are visible, in addition to those of its parent.
|
||||
/// We say that the child universe "extends" the parent universe with
|
||||
/// new names.
|
||||
///
|
||||
/// To make this more concrete, consider this program:
|
||||
///
|
||||
/// ```
|
||||
/// struct Foo { }
|
||||
/// fn bar<T>(x: T) {
|
||||
/// let y: for<'a> fn(&'a u8, Foo) = ...;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The struct name `Foo` is in the root universe U0. But the type
|
||||
/// parameter `T`, introduced on `bar`, is in an extended universe U1
|
||||
/// -- i.e., within `bar`, we can name both `T` and `Foo`, but outside
|
||||
/// of `bar`, we cannot name `T`. Then, within the type of `y`, the
|
||||
/// region `'a` is in a universe U2 that extends U1, because we can
|
||||
/// name it inside the fn type but not outside.
|
||||
///
|
||||
/// Universes are used to do type- and trait-checking around these
|
||||
/// "forall" binders (also called **universal quantification**). The
|
||||
/// idea is that when, in the body of `bar`, we refer to `T` as a
|
||||
/// type, we aren't referring to any type in particular, but rather a
|
||||
/// kind of "fresh" type that is distinct from all other types we have
|
||||
/// actually declared. This is called a **placeholder** type, and we
|
||||
/// use universes to talk about this. In other words, a type name in
|
||||
/// universe 0 always corresponds to some "ground" type that the user
|
||||
/// declared, but a type name in a non-zero universe is a placeholder
|
||||
/// type -- an idealized representative of "types in general" that we
|
||||
/// use for checking generic functions.
|
||||
newtype_index! {
|
||||
/// "Universes" are used during type- and trait-checking in the
|
||||
/// presence of `for<..>` binders to control what sets of names are
|
||||
/// visible. Universes are arranged into a tree: the root universe
|
||||
/// contains names that are always visible. Each child then adds a new
|
||||
/// set of names that are visible, in addition to those of its parent.
|
||||
/// We say that the child universe "extends" the parent universe with
|
||||
/// new names.
|
||||
///
|
||||
/// To make this more concrete, consider this program:
|
||||
///
|
||||
/// ```
|
||||
/// struct Foo { }
|
||||
/// fn bar<T>(x: T) {
|
||||
/// let y: for<'a> fn(&'a u8, Foo) = ...;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The struct name `Foo` is in the root universe U0. But the type
|
||||
/// parameter `T`, introduced on `bar`, is in an extended universe U1
|
||||
/// -- i.e., within `bar`, we can name both `T` and `Foo`, but outside
|
||||
/// of `bar`, we cannot name `T`. Then, within the type of `y`, the
|
||||
/// region `'a` is in a universe U2 that extends U1, because we can
|
||||
/// name it inside the fn type but not outside.
|
||||
///
|
||||
/// Universes are used to do type- and trait-checking around these
|
||||
/// "forall" binders (also called **universal quantification**). The
|
||||
/// idea is that when, in the body of `bar`, we refer to `T` as a
|
||||
/// type, we aren't referring to any type in particular, but rather a
|
||||
/// kind of "fresh" type that is distinct from all other types we have
|
||||
/// actually declared. This is called a **placeholder** type, and we
|
||||
/// use universes to talk about this. In other words, a type name in
|
||||
/// universe 0 always corresponds to some "ground" type that the user
|
||||
/// declared, but a type name in a non-zero universe is a placeholder
|
||||
/// type -- an idealized representative of "types in general" that we
|
||||
/// use for checking generic functions.
|
||||
pub struct UniverseIndex {
|
||||
DEBUG_FORMAT = "U{}",
|
||||
}
|
||||
|
@ -1082,46 +1082,46 @@ impl<'a, 'gcx, 'tcx> ParamConst {
|
||||
}
|
||||
}
|
||||
|
||||
/// A [De Bruijn index][dbi] is a standard means of representing
|
||||
/// regions (and perhaps later types) in a higher-ranked setting. In
|
||||
/// particular, imagine a type like this:
|
||||
///
|
||||
/// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char)
|
||||
/// ^ ^ | | |
|
||||
/// | | | | |
|
||||
/// | +------------+ 0 | |
|
||||
/// | | |
|
||||
/// +--------------------------------+ 1 |
|
||||
/// | |
|
||||
/// +------------------------------------------+ 0
|
||||
///
|
||||
/// In this type, there are two binders (the outer fn and the inner
|
||||
/// fn). We need to be able to determine, for any given region, which
|
||||
/// fn type it is bound by, the inner or the outer one. There are
|
||||
/// various ways you can do this, but a De Bruijn index is one of the
|
||||
/// more convenient and has some nice properties. The basic idea is to
|
||||
/// count the number of binders, inside out. Some examples should help
|
||||
/// clarify what I mean.
|
||||
///
|
||||
/// Let's start with the reference type `&'b isize` that is the first
|
||||
/// argument to the inner function. This region `'b` is assigned a De
|
||||
/// Bruijn index of 0, meaning "the innermost binder" (in this case, a
|
||||
/// fn). The region `'a` that appears in the second argument type (`&'a
|
||||
/// isize`) would then be assigned a De Bruijn index of 1, meaning "the
|
||||
/// second-innermost binder". (These indices are written on the arrays
|
||||
/// in the diagram).
|
||||
///
|
||||
/// What is interesting is that De Bruijn index attached to a particular
|
||||
/// variable will vary depending on where it appears. For example,
|
||||
/// the final type `&'a char` also refers to the region `'a` declared on
|
||||
/// the outermost fn. But this time, this reference is not nested within
|
||||
/// any other binders (i.e., it is not an argument to the inner fn, but
|
||||
/// rather the outer one). Therefore, in this case, it is assigned a
|
||||
/// De Bruijn index of 0, because the innermost binder in that location
|
||||
/// is the outer fn.
|
||||
///
|
||||
/// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index
|
||||
newtype_index! {
|
||||
/// A [De Bruijn index][dbi] is a standard means of representing
|
||||
/// regions (and perhaps later types) in a higher-ranked setting. In
|
||||
/// particular, imagine a type like this:
|
||||
///
|
||||
/// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char)
|
||||
/// ^ ^ | | |
|
||||
/// | | | | |
|
||||
/// | +------------+ 0 | |
|
||||
/// | | |
|
||||
/// +--------------------------------+ 1 |
|
||||
/// | |
|
||||
/// +------------------------------------------+ 0
|
||||
///
|
||||
/// In this type, there are two binders (the outer fn and the inner
|
||||
/// fn). We need to be able to determine, for any given region, which
|
||||
/// fn type it is bound by, the inner or the outer one. There are
|
||||
/// various ways you can do this, but a De Bruijn index is one of the
|
||||
/// more convenient and has some nice properties. The basic idea is to
|
||||
/// count the number of binders, inside out. Some examples should help
|
||||
/// clarify what I mean.
|
||||
///
|
||||
/// Let's start with the reference type `&'b isize` that is the first
|
||||
/// argument to the inner function. This region `'b` is assigned a De
|
||||
/// Bruijn index of 0, meaning "the innermost binder" (in this case, a
|
||||
/// fn). The region `'a` that appears in the second argument type (`&'a
|
||||
/// isize`) would then be assigned a De Bruijn index of 1, meaning "the
|
||||
/// second-innermost binder". (These indices are written on the arrays
|
||||
/// in the diagram).
|
||||
///
|
||||
/// What is interesting is that De Bruijn index attached to a particular
|
||||
/// variable will vary depending on where it appears. For example,
|
||||
/// the final type `&'a char` also refers to the region `'a` declared on
|
||||
/// the outermost fn. But this time, this reference is not nested within
|
||||
/// any other binders (i.e., it is not an argument to the inner fn, but
|
||||
/// rather the outer one). Therefore, in this case, it is assigned a
|
||||
/// De Bruijn index of 0, because the innermost binder in that location
|
||||
/// is the outer fn.
|
||||
///
|
||||
/// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index
|
||||
pub struct DebruijnIndex {
|
||||
DEBUG_FORMAT = "DebruijnIndex({})",
|
||||
const INNERMOST = 0,
|
||||
|
@ -58,9 +58,10 @@ macro_rules! newtype_index {
|
||||
// ---- public rules ----
|
||||
|
||||
// Use default constants
|
||||
($v:vis struct $name:ident { .. }) => (
|
||||
($(#[$attrs:meta])* $v:vis struct $name:ident { .. }) => (
|
||||
newtype_index!(
|
||||
// Leave out derives marker so we can use its absence to ensure it comes first
|
||||
@attrs [$(#[$attrs])*]
|
||||
@type [$name]
|
||||
// shave off 256 indices at the end to allow space for packing these indices into enums
|
||||
@max [0xFFFF_FF00]
|
||||
@ -69,9 +70,10 @@ macro_rules! newtype_index {
|
||||
);
|
||||
|
||||
// Define any constants
|
||||
($v:vis struct $name:ident { $($tokens:tt)+ }) => (
|
||||
($(#[$attrs:meta])* $v:vis struct $name:ident { $($tokens:tt)+ }) => (
|
||||
newtype_index!(
|
||||
// Leave out derives marker so we can use its absence to ensure it comes first
|
||||
@attrs [$(#[$attrs])*]
|
||||
@type [$name]
|
||||
// shave off 256 indices at the end to allow space for packing these indices into enums
|
||||
@max [0xFFFF_FF00]
|
||||
@ -84,10 +86,12 @@ macro_rules! newtype_index {
|
||||
|
||||
// Base case, user-defined constants (if any) have already been defined
|
||||
(@derives [$($derives:ident,)*]
|
||||
@attrs [$(#[$attrs:meta])*]
|
||||
@type [$type:ident]
|
||||
@max [$max:expr]
|
||||
@vis [$v:vis]
|
||||
@debug_format [$debug_format:tt]) => (
|
||||
$(#[$attrs])*
|
||||
#[derive(Copy, PartialEq, Eq, Hash, PartialOrd, Ord, $($derives),*)]
|
||||
#[rustc_layout_scalar_valid_range_end($max)]
|
||||
$v struct $type {
|
||||
@ -317,7 +321,8 @@ macro_rules! newtype_index {
|
||||
|
||||
// By not including the @derives marker in this list nor in the default args, we can force it
|
||||
// to come first if it exists. When encodable isn't custom, add serialization traits by default.
|
||||
(@type [$type:ident]
|
||||
(@attrs [$(#[$attrs:meta])*]
|
||||
@type [$type:ident]
|
||||
@max [$max:expr]
|
||||
@vis [$v:vis]
|
||||
@debug_format [$debug_format:tt]
|
||||
@ -325,6 +330,7 @@ macro_rules! newtype_index {
|
||||
$($tokens:tt)*) => (
|
||||
newtype_index!(
|
||||
@derives [$($derives,)+ RustcEncodable,]
|
||||
@attrs [$(#[$attrs])*]
|
||||
@type [$type]
|
||||
@max [$max]
|
||||
@vis [$v]
|
||||
@ -335,7 +341,8 @@ macro_rules! newtype_index {
|
||||
|
||||
// The case where no derives are added, but encodable is overridden. Don't
|
||||
// derive serialization traits
|
||||
(@type [$type:ident]
|
||||
(@attrs [$(#[$attrs:meta])*]
|
||||
@type [$type:ident]
|
||||
@max [$max:expr]
|
||||
@vis [$v:vis]
|
||||
@debug_format [$debug_format:tt]
|
||||
@ -343,6 +350,7 @@ macro_rules! newtype_index {
|
||||
$($tokens:tt)*) => (
|
||||
newtype_index!(
|
||||
@derives []
|
||||
@attrs [$(#[$attrs])*]
|
||||
@type [$type]
|
||||
@max [$max]
|
||||
@vis [$v]
|
||||
@ -351,13 +359,15 @@ macro_rules! newtype_index {
|
||||
);
|
||||
|
||||
// The case where no derives are added, add serialization derives by default
|
||||
(@type [$type:ident]
|
||||
(@attrs [$(#[$attrs:meta])*]
|
||||
@type [$type:ident]
|
||||
@max [$max:expr]
|
||||
@vis [$v:vis]
|
||||
@debug_format [$debug_format:tt]
|
||||
$($tokens:tt)*) => (
|
||||
newtype_index!(
|
||||
@derives [RustcEncodable,]
|
||||
@attrs [$(#[$attrs])*]
|
||||
@type [$type]
|
||||
@max [$max]
|
||||
@vis [$v]
|
||||
@ -384,6 +394,7 @@ macro_rules! newtype_index {
|
||||
|
||||
// Rewrite final without comma to one that includes comma
|
||||
(@derives [$($derives:ident,)*]
|
||||
@attrs [$(#[$attrs:meta])*]
|
||||
@type [$type:ident]
|
||||
@max [$max:expr]
|
||||
@vis [$v:vis]
|
||||
@ -391,6 +402,7 @@ macro_rules! newtype_index {
|
||||
$name:ident = $constant:expr) => (
|
||||
newtype_index!(
|
||||
@derives [$($derives,)*]
|
||||
@attrs [$(#[$attrs])*]
|
||||
@type [$type]
|
||||
@max [$max]
|
||||
@vis [$v]
|
||||
@ -400,6 +412,7 @@ macro_rules! newtype_index {
|
||||
|
||||
// Rewrite final const without comma to one that includes comma
|
||||
(@derives [$($derives:ident,)*]
|
||||
@attrs [$(#[$attrs:meta])*]
|
||||
@type [$type:ident]
|
||||
@max [$_max:expr]
|
||||
@vis [$v:vis]
|
||||
@ -408,6 +421,7 @@ macro_rules! newtype_index {
|
||||
const $name:ident = $constant:expr) => (
|
||||
newtype_index!(
|
||||
@derives [$($derives,)*]
|
||||
@attrs [$(#[$attrs])*]
|
||||
@type [$type]
|
||||
@max [$max]
|
||||
@vis [$v]
|
||||
@ -417,6 +431,7 @@ macro_rules! newtype_index {
|
||||
|
||||
// Replace existing default for max
|
||||
(@derives [$($derives:ident,)*]
|
||||
@attrs [$(#[$attrs:meta])*]
|
||||
@type [$type:ident]
|
||||
@max [$_max:expr]
|
||||
@vis [$v:vis]
|
||||
@ -425,6 +440,7 @@ macro_rules! newtype_index {
|
||||
$($tokens:tt)*) => (
|
||||
newtype_index!(
|
||||
@derives [$($derives,)*]
|
||||
@attrs [$(#[$attrs])*]
|
||||
@type [$type]
|
||||
@max [$max]
|
||||
@vis [$v]
|
||||
@ -434,6 +450,7 @@ macro_rules! newtype_index {
|
||||
|
||||
// Replace existing default for debug_format
|
||||
(@derives [$($derives:ident,)*]
|
||||
@attrs [$(#[$attrs:meta])*]
|
||||
@type [$type:ident]
|
||||
@max [$max:expr]
|
||||
@vis [$v:vis]
|
||||
@ -442,6 +459,7 @@ macro_rules! newtype_index {
|
||||
$($tokens:tt)*) => (
|
||||
newtype_index!(
|
||||
@derives [$($derives,)*]
|
||||
@attrs [$(#[$attrs])*]
|
||||
@type [$type]
|
||||
@max [$max]
|
||||
@vis [$v]
|
||||
@ -451,6 +469,7 @@ macro_rules! newtype_index {
|
||||
|
||||
// Assign a user-defined constant
|
||||
(@derives [$($derives:ident,)*]
|
||||
@attrs [$(#[$attrs:meta])*]
|
||||
@type [$type:ident]
|
||||
@max [$max:expr]
|
||||
@vis [$v:vis]
|
||||
@ -462,6 +481,7 @@ macro_rules! newtype_index {
|
||||
pub const $name: $type = $type::from_u32_const($constant);
|
||||
newtype_index!(
|
||||
@derives [$($derives,)*]
|
||||
@attrs [$(#[$attrs])*]
|
||||
@type [$type]
|
||||
@max [$max]
|
||||
@vis [$v]
|
||||
|
@ -36,7 +36,7 @@ use syntax::tokenstream::{TokenTree, TokenStream};
|
||||
use syntax::ast;
|
||||
use syntax::ptr::P;
|
||||
use syntax::ast::Expr;
|
||||
use syntax::attr;
|
||||
use syntax::attr::{self, HasAttrs};
|
||||
use syntax::source_map::Spanned;
|
||||
use syntax::edition::Edition;
|
||||
use syntax::feature_gate::{AttributeGate, AttributeTemplate, AttributeType};
|
||||
@ -802,27 +802,81 @@ impl LintPass for UnusedDocComment {
|
||||
}
|
||||
|
||||
impl UnusedDocComment {
|
||||
fn warn_if_doc<'a, 'tcx,
|
||||
I: Iterator<Item=&'a ast::Attribute>,
|
||||
C: LintContext<'tcx>>(&self, mut attrs: I, cx: &C) {
|
||||
if let Some(attr) = attrs.find(|a| a.is_value_str() && a.check_name("doc")) {
|
||||
cx.struct_span_lint(UNUSED_DOC_COMMENTS, attr.span, "doc comment not used by rustdoc")
|
||||
.emit();
|
||||
fn warn_if_doc(
|
||||
&self,
|
||||
cx: &EarlyContext<'_>,
|
||||
node_span: Span,
|
||||
node_kind: &str,
|
||||
is_macro_expansion: bool,
|
||||
attrs: &[ast::Attribute]
|
||||
) {
|
||||
let mut attrs = attrs.into_iter().peekable();
|
||||
|
||||
// Accumulate a single span for sugared doc comments.
|
||||
let mut sugared_span: Option<Span> = None;
|
||||
|
||||
while let Some(attr) = attrs.next() {
|
||||
if attr.is_sugared_doc {
|
||||
sugared_span = Some(
|
||||
sugared_span.map_or_else(
|
||||
|| attr.span,
|
||||
|span| span.with_hi(attr.span.hi()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if attrs.peek().map(|next_attr| next_attr.is_sugared_doc).unwrap_or_default() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let span = sugared_span.take().unwrap_or_else(|| attr.span);
|
||||
|
||||
if attr.name() == "doc" {
|
||||
let mut err = cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, "unused doc comment");
|
||||
|
||||
err.span_label(
|
||||
node_span,
|
||||
format!("rustdoc does not generate documentation for {}", node_kind)
|
||||
);
|
||||
|
||||
if is_macro_expansion {
|
||||
err.help("to document an item produced by a macro, \
|
||||
the macro must produce the documentation as part of its expansion");
|
||||
}
|
||||
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EarlyLintPass for UnusedDocComment {
|
||||
fn check_local(&mut self, cx: &EarlyContext<'_>, decl: &ast::Local) {
|
||||
self.warn_if_doc(decl.attrs.iter(), cx);
|
||||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|
||||
if let ast::ItemKind::Mac(..) = item.node {
|
||||
self.warn_if_doc(cx, item.span, "macro expansions", true, &item.attrs);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
|
||||
let (kind, is_macro_expansion) = match stmt.node {
|
||||
ast::StmtKind::Local(..) => ("statements", false),
|
||||
ast::StmtKind::Item(..) => ("inner items", false),
|
||||
ast::StmtKind::Mac(..) => ("macro expansions", true),
|
||||
// expressions will be reported by `check_expr`.
|
||||
ast::StmtKind::Semi(..) |
|
||||
ast::StmtKind::Expr(..) => return,
|
||||
};
|
||||
|
||||
self.warn_if_doc(cx, stmt.span, kind, is_macro_expansion, stmt.node.attrs());
|
||||
}
|
||||
|
||||
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
|
||||
self.warn_if_doc(arm.attrs.iter(), cx);
|
||||
let arm_span = arm.pats[0].span.with_hi(arm.body.span.hi());
|
||||
self.warn_if_doc(cx, arm_span, "match arms", false, &arm.attrs);
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
|
||||
self.warn_if_doc(expr.attrs.iter(), cx);
|
||||
self.warn_if_doc(cx, expr.span, "expressions", false, &expr.attrs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,7 @@ macro_rules! pre_expansion_lint_passes {
|
||||
($macro:path, $args:tt) => (
|
||||
$macro!($args, [
|
||||
KeywordIdents: KeywordIdents,
|
||||
UnusedDocComment: UnusedDocComment,
|
||||
]);
|
||||
)
|
||||
}
|
||||
@ -77,7 +78,6 @@ macro_rules! early_lint_passes {
|
||||
UnusedImportBraces: UnusedImportBraces,
|
||||
UnsafeCode: UnsafeCode,
|
||||
AnonymousParameters: AnonymousParameters,
|
||||
UnusedDocComment: UnusedDocComment,
|
||||
EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns,
|
||||
NonCamelCaseTypes: NonCamelCaseTypes,
|
||||
DeprecatedAttr: DeprecatedAttr::new(),
|
||||
|
@ -116,14 +116,14 @@ impl RegionValueElements {
|
||||
}
|
||||
}
|
||||
|
||||
/// A single integer representing a `Location` in the MIR control-flow
|
||||
/// graph. Constructed efficiently from `RegionValueElements`.
|
||||
newtype_index! {
|
||||
/// A single integer representing a `Location` in the MIR control-flow
|
||||
/// graph. Constructed efficiently from `RegionValueElements`.
|
||||
pub struct PointIndex { DEBUG_FORMAT = "PointIndex({})" }
|
||||
}
|
||||
|
||||
/// A single integer representing a `ty::Placeholder`.
|
||||
newtype_index! {
|
||||
/// A single integer representing a `ty::Placeholder`.
|
||||
pub struct PlaceholderIndex { DEBUG_FORMAT = "PlaceholderIndex({})" }
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ pub(crate) mod indexes {
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
macro_rules! new_index {
|
||||
($Index:ident, $debug_name:expr) => {
|
||||
($(#[$attrs:meta])* $Index:ident, $debug_name:expr) => {
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct $Index(NonZeroUsize);
|
||||
|
||||
@ -44,17 +44,29 @@ pub(crate) mod indexes {
|
||||
}
|
||||
}
|
||||
|
||||
/// Index into MovePathData.move_paths
|
||||
new_index!(MovePathIndex, "mp");
|
||||
new_index!(
|
||||
/// Index into MovePathData.move_paths
|
||||
MovePathIndex,
|
||||
"mp"
|
||||
);
|
||||
|
||||
/// Index into MoveData.moves.
|
||||
new_index!(MoveOutIndex, "mo");
|
||||
new_index!(
|
||||
/// Index into MoveData.moves.
|
||||
MoveOutIndex,
|
||||
"mo"
|
||||
);
|
||||
|
||||
/// Index into MoveData.inits.
|
||||
new_index!(InitIndex, "in");
|
||||
new_index!(
|
||||
/// Index into MoveData.inits.
|
||||
InitIndex,
|
||||
"in"
|
||||
);
|
||||
|
||||
/// Index into Borrows.locations
|
||||
new_index!(BorrowIndex, "bw");
|
||||
new_index!(
|
||||
/// Index into Borrows.locations
|
||||
BorrowIndex,
|
||||
"bw"
|
||||
);
|
||||
}
|
||||
|
||||
pub use self::indexes::MovePathIndex;
|
||||
|
@ -11,15 +11,15 @@ use crate::sys::stdio;
|
||||
use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
|
||||
use crate::thread::LocalKey;
|
||||
|
||||
/// Stdout used by print! and println! macros
|
||||
thread_local! {
|
||||
/// Stdout used by print! and println! macros
|
||||
static LOCAL_STDOUT: RefCell<Option<Box<dyn Write + Send>>> = {
|
||||
RefCell::new(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Stderr used by eprint! and eprintln! macros, and panics
|
||||
thread_local! {
|
||||
/// Stderr used by eprint! and eprintln! macros, and panics
|
||||
static LOCAL_STDERR: RefCell<Option<Box<dyn Write + Send>>> = {
|
||||
RefCell::new(None)
|
||||
}
|
||||
|
@ -1,18 +1,43 @@
|
||||
#![feature(stmt_expr_attributes)]
|
||||
|
||||
#![deny(unused_doc_comments)]
|
||||
|
||||
macro_rules! mac {
|
||||
() => {}
|
||||
}
|
||||
|
||||
/// foo //~ ERROR unused doc comment
|
||||
mac!();
|
||||
|
||||
fn foo() {
|
||||
/// a //~ ERROR doc comment not used by rustdoc
|
||||
/// a //~ ERROR unused doc comment
|
||||
let x = 12;
|
||||
|
||||
/// b //~ doc comment not used by rustdoc
|
||||
/// multi-line //~ unused doc comment
|
||||
/// doc comment
|
||||
/// that is unused
|
||||
match x {
|
||||
/// c //~ ERROR doc comment not used by rustdoc
|
||||
/// c //~ ERROR unused doc comment
|
||||
1 => {},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
/// foo //~ ERROR doc comment not used by rustdoc
|
||||
/// foo //~ ERROR unused doc comment
|
||||
unsafe {}
|
||||
|
||||
#[doc = "foo"] //~ ERROR unused doc comment
|
||||
#[doc = "bar"] //~ ERROR unused doc comment
|
||||
3;
|
||||
|
||||
/// bar //~ ERROR unused doc comment
|
||||
mac!();
|
||||
|
||||
let x = /** comment */ 47; //~ ERROR unused doc comment
|
||||
|
||||
/// dox //~ ERROR unused doc comment
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -1,32 +1,98 @@
|
||||
error: doc comment not used by rustdoc
|
||||
--> $DIR/useless_comment.rs:4:5
|
||||
error: unused doc comment
|
||||
--> $DIR/useless_comment.rs:9:1
|
||||
|
|
||||
LL | /// a //~ ERROR doc comment not used by rustdoc
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | /// foo //~ ERROR unused doc comment
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | mac!();
|
||||
| ------- rustdoc does not generate documentation for macro expansions
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/useless_comment.rs:1:9
|
||||
--> $DIR/useless_comment.rs:3:9
|
||||
|
|
||||
LL | #![deny(unused_doc_comments)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
= help: to document an item produced by a macro, the macro must produce the documentation as part of its expansion
|
||||
|
||||
error: doc comment not used by rustdoc
|
||||
--> $DIR/useless_comment.rs:7:5
|
||||
error: unused doc comment
|
||||
--> $DIR/useless_comment.rs:13:5
|
||||
|
|
||||
LL | /// b //~ doc comment not used by rustdoc
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | /// a //~ ERROR unused doc comment
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let x = 12;
|
||||
| ----------- rustdoc does not generate documentation for statements
|
||||
|
||||
error: doc comment not used by rustdoc
|
||||
--> $DIR/useless_comment.rs:9:9
|
||||
error: unused doc comment
|
||||
--> $DIR/useless_comment.rs:16:5
|
||||
|
|
||||
LL | /// c //~ ERROR doc comment not used by rustdoc
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | / /// multi-line //~ unused doc comment
|
||||
LL | | /// doc comment
|
||||
LL | | /// that is unused
|
||||
| |______________________^
|
||||
LL | / match x {
|
||||
LL | | /// c //~ ERROR unused doc comment
|
||||
LL | | 1 => {},
|
||||
LL | | _ => {}
|
||||
LL | | }
|
||||
| |_____- rustdoc does not generate documentation for expressions
|
||||
|
||||
error: doc comment not used by rustdoc
|
||||
--> $DIR/useless_comment.rs:14:5
|
||||
error: unused doc comment
|
||||
--> $DIR/useless_comment.rs:20:9
|
||||
|
|
||||
LL | /// foo //~ ERROR doc comment not used by rustdoc
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | /// c //~ ERROR unused doc comment
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | 1 => {},
|
||||
| ------- rustdoc does not generate documentation for match arms
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: unused doc comment
|
||||
--> $DIR/useless_comment.rs:25:5
|
||||
|
|
||||
LL | /// foo //~ ERROR unused doc comment
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | unsafe {}
|
||||
| --------- rustdoc does not generate documentation for expressions
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless_comment.rs:28:5
|
||||
|
|
||||
LL | #[doc = "foo"] //~ ERROR unused doc comment
|
||||
| ^^^^^^^^^^^^^^
|
||||
LL | #[doc = "bar"] //~ ERROR unused doc comment
|
||||
LL | 3;
|
||||
| - rustdoc does not generate documentation for expressions
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless_comment.rs:29:5
|
||||
|
|
||||
LL | #[doc = "bar"] //~ ERROR unused doc comment
|
||||
| ^^^^^^^^^^^^^^
|
||||
LL | 3;
|
||||
| - rustdoc does not generate documentation for expressions
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless_comment.rs:32:5
|
||||
|
|
||||
LL | /// bar //~ ERROR unused doc comment
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | mac!();
|
||||
| ------- rustdoc does not generate documentation for macro expansions
|
||||
|
|
||||
= 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:35:13
|
||||
|
|
||||
LL | let x = /** comment */ 47; //~ ERROR unused doc comment
|
||||
| ^^^^^^^^^^^^^^ -- rustdoc does not generate documentation for expressions
|
||||
|
||||
error: unused doc comment
|
||||
--> $DIR/useless_comment.rs:37:5
|
||||
|
|
||||
LL | /// dox //~ ERROR unused doc comment
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | / {
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_____- rustdoc does not generate documentation for expressions
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user