Auto merge of #12433 - J-ZhengLi:issue12197, r=dswij
fix [`missing_docs_in_private_items`] on some proc macros fixes: #12197 --- changelog: [`missing_docs_in_private_items`] support manually search for docs as fallback method
This commit is contained in:
commit
0b4b684b46
@ -8,6 +8,7 @@
|
|||||||
use clippy_utils::attrs::is_doc_hidden;
|
use clippy_utils::attrs::is_doc_hidden;
|
||||||
use clippy_utils::diagnostics::span_lint;
|
use clippy_utils::diagnostics::span_lint;
|
||||||
use clippy_utils::is_from_proc_macro;
|
use clippy_utils::is_from_proc_macro;
|
||||||
|
use clippy_utils::source::snippet_opt;
|
||||||
use rustc_ast::ast::{self, MetaItem, MetaItemKind};
|
use rustc_ast::ast::{self, MetaItem, MetaItemKind};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
@ -32,6 +33,13 @@
|
|||||||
"detects missing documentation for private members"
|
"detects missing documentation for private members"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! note_prev_span_then_ret {
|
||||||
|
($prev_span:expr, $span:expr) => {{
|
||||||
|
$prev_span = Some($span);
|
||||||
|
return;
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
pub struct MissingDoc {
|
pub struct MissingDoc {
|
||||||
/// Whether to **only** check for missing documentation in items visible within the current
|
/// Whether to **only** check for missing documentation in items visible within the current
|
||||||
/// crate. For example, `pub(crate)` items.
|
/// crate. For example, `pub(crate)` items.
|
||||||
@ -39,6 +47,8 @@ pub struct MissingDoc {
|
|||||||
/// Stack of whether #[doc(hidden)] is set
|
/// Stack of whether #[doc(hidden)] is set
|
||||||
/// at each level which has lint attributes.
|
/// at each level which has lint attributes.
|
||||||
doc_hidden_stack: Vec<bool>,
|
doc_hidden_stack: Vec<bool>,
|
||||||
|
/// Used to keep tracking of the previous item, field or variants etc, to get the search span.
|
||||||
|
prev_span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MissingDoc {
|
impl Default for MissingDoc {
|
||||||
@ -54,6 +64,7 @@ pub fn new(crate_items_only: bool) -> Self {
|
|||||||
Self {
|
Self {
|
||||||
crate_items_only,
|
crate_items_only,
|
||||||
doc_hidden_stack: vec![false],
|
doc_hidden_stack: vec![false],
|
||||||
|
prev_span: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +119,8 @@ fn check_missing_docs_attrs(
|
|||||||
|
|
||||||
let has_doc = attrs
|
let has_doc = attrs
|
||||||
.iter()
|
.iter()
|
||||||
.any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
|
.any(|a| a.doc_str().is_some() || Self::has_include(a.meta()))
|
||||||
|
|| matches!(self.search_span(sp), Some(span) if span_to_snippet_contains_docs(cx, span));
|
||||||
|
|
||||||
if !has_doc {
|
if !has_doc {
|
||||||
span_lint(
|
span_lint(
|
||||||
@ -119,6 +131,32 @@ fn check_missing_docs_attrs(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a span to search for doc comments manually.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```ignore
|
||||||
|
/// fn foo() { ... }
|
||||||
|
/// ^^^^^^^^^^^^^^^^ prev_span
|
||||||
|
/// ↑
|
||||||
|
/// | search_span |
|
||||||
|
/// ↓
|
||||||
|
/// fn bar() { ... }
|
||||||
|
/// ^^^^^^^^^^^^^^^^ cur_span
|
||||||
|
/// ```
|
||||||
|
fn search_span(&self, cur_span: Span) -> Option<Span> {
|
||||||
|
let prev_span = self.prev_span?;
|
||||||
|
let start_pos = if prev_span.contains(cur_span) {
|
||||||
|
// In case when the prev_span is an entire struct, or enum,
|
||||||
|
// and the current span is a field, or variant, we need to search from
|
||||||
|
// the starting pos of the previous span.
|
||||||
|
prev_span.lo()
|
||||||
|
} else {
|
||||||
|
prev_span.hi()
|
||||||
|
};
|
||||||
|
let search_span = cur_span.with_lo(start_pos).with_hi(cur_span.lo());
|
||||||
|
Some(search_span)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]);
|
impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]);
|
||||||
@ -138,6 +176,10 @@ fn check_crate(&mut self, cx: &LateContext<'tcx>) {
|
|||||||
self.check_missing_docs_attrs(cx, CRATE_DEF_ID, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate");
|
self.check_missing_docs_attrs(cx, CRATE_DEF_ID, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_crate_post(&mut self, _: &LateContext<'tcx>) {
|
||||||
|
self.prev_span = None;
|
||||||
|
}
|
||||||
|
|
||||||
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
|
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
|
||||||
match it.kind {
|
match it.kind {
|
||||||
hir::ItemKind::Fn(..) => {
|
hir::ItemKind::Fn(..) => {
|
||||||
@ -145,7 +187,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
|
|||||||
if it.ident.name == sym::main {
|
if it.ident.name == sym::main {
|
||||||
let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID;
|
let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID;
|
||||||
if at_root {
|
if at_root {
|
||||||
return;
|
note_prev_span_then_ret!(self.prev_span, it.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -164,7 +206,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
|
|||||||
| hir::ItemKind::ForeignMod { .. }
|
| hir::ItemKind::ForeignMod { .. }
|
||||||
| hir::ItemKind::GlobalAsm(..)
|
| hir::ItemKind::GlobalAsm(..)
|
||||||
| hir::ItemKind::Impl { .. }
|
| hir::ItemKind::Impl { .. }
|
||||||
| hir::ItemKind::Use(..) => return,
|
| hir::ItemKind::Use(..) => note_prev_span_then_ret!(self.prev_span, it.span),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
|
let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
|
||||||
@ -173,6 +215,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
|
|||||||
if !is_from_proc_macro(cx, it) {
|
if !is_from_proc_macro(cx, it) {
|
||||||
self.check_missing_docs_attrs(cx, it.owner_id.def_id, attrs, it.span, article, desc);
|
self.check_missing_docs_attrs(cx, it.owner_id.def_id, attrs, it.span, article, desc);
|
||||||
}
|
}
|
||||||
|
self.prev_span = Some(it.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
|
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
|
||||||
@ -182,16 +225,17 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::Tr
|
|||||||
if !is_from_proc_macro(cx, trait_item) {
|
if !is_from_proc_macro(cx, trait_item) {
|
||||||
self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, attrs, trait_item.span, article, desc);
|
self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, attrs, trait_item.span, article, desc);
|
||||||
}
|
}
|
||||||
|
self.prev_span = Some(trait_item.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
|
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
|
||||||
// If the method is an impl for a trait, don't doc.
|
// If the method is an impl for a trait, don't doc.
|
||||||
if let Some(cid) = cx.tcx.associated_item(impl_item.owner_id).impl_container(cx.tcx) {
|
if let Some(cid) = cx.tcx.associated_item(impl_item.owner_id).impl_container(cx.tcx) {
|
||||||
if cx.tcx.impl_trait_ref(cid).is_some() {
|
if cx.tcx.impl_trait_ref(cid).is_some() {
|
||||||
return;
|
note_prev_span_then_ret!(self.prev_span, impl_item.span);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return;
|
note_prev_span_then_ret!(self.prev_span, impl_item.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
|
let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
|
||||||
@ -199,6 +243,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
|
|||||||
if !is_from_proc_macro(cx, impl_item) {
|
if !is_from_proc_macro(cx, impl_item) {
|
||||||
self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, attrs, impl_item.span, article, desc);
|
self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, attrs, impl_item.span, article, desc);
|
||||||
}
|
}
|
||||||
|
self.prev_span = Some(impl_item.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) {
|
fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) {
|
||||||
@ -208,6 +253,7 @@ fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_
|
|||||||
self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field");
|
self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.prev_span = Some(sf.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
|
fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
|
||||||
@ -215,5 +261,13 @@ fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
|
|||||||
if !is_from_proc_macro(cx, v) {
|
if !is_from_proc_macro(cx, v) {
|
||||||
self.check_missing_docs_attrs(cx, v.def_id, attrs, v.span, "a", "variant");
|
self.check_missing_docs_attrs(cx, v.def_id, attrs, v.span, "a", "variant");
|
||||||
}
|
}
|
||||||
|
self.prev_span = Some(v.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn span_to_snippet_contains_docs(cx: &LateContext<'_>, search_span: Span) -> bool {
|
||||||
|
let Some(snippet) = snippet_opt(cx, search_span) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
snippet.lines().rev().any(|line| line.trim().starts_with("///"))
|
||||||
|
}
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::token::Star;
|
use syn::token::Star;
|
||||||
use syn::{
|
use syn::{
|
||||||
parse_macro_input, parse_quote, FnArg, ImplItem, ItemFn, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType,
|
parse_macro_input, parse_quote, FnArg, ImplItem, ItemFn, ItemImpl, ItemStruct, ItemTrait, Lifetime, Pat, PatIdent,
|
||||||
Signature, TraitItem, Type,
|
PatType, Signature, TraitItem, Type, Visibility,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
@ -101,9 +101,7 @@ pub fn fake_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
let mut item = parse_macro_input!(item as ItemFn);
|
let mut item = parse_macro_input!(item as ItemFn);
|
||||||
let span = item.block.brace_token.span;
|
let span = item.block.brace_token.span;
|
||||||
|
|
||||||
if item.sig.asyncness.is_some() {
|
item.sig.asyncness = None;
|
||||||
item.sig.asyncness = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let crate_name = quote! { fake_crate };
|
let crate_name = quote! { fake_crate };
|
||||||
let block = item.block;
|
let block = item.block;
|
||||||
@ -128,7 +126,7 @@ pub fn block_on<F: ::std::future::Future>(_fut: F) {}
|
|||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn fake_desugar_await(_args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn fake_desugar_await(_args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let mut async_fn = syn::parse_macro_input!(input as syn::ItemFn);
|
let mut async_fn = parse_macro_input!(input as syn::ItemFn);
|
||||||
|
|
||||||
for stmt in &mut async_fn.block.stmts {
|
for stmt in &mut async_fn.block.stmts {
|
||||||
if let syn::Stmt::Expr(syn::Expr::Match(syn::ExprMatch { expr: scrutinee, .. }), _) = stmt {
|
if let syn::Stmt::Expr(syn::Expr::Match(syn::ExprMatch { expr: scrutinee, .. }), _) = stmt {
|
||||||
@ -145,3 +143,23 @@ pub fn fake_desugar_await(_args: TokenStream, input: TokenStream) -> TokenStream
|
|||||||
|
|
||||||
quote!(#async_fn).into()
|
quote!(#async_fn).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn rewrite_struct(_args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
|
let mut item_struct = parse_macro_input!(input as syn::ItemStruct);
|
||||||
|
// remove struct attributes including doc comments.
|
||||||
|
item_struct.attrs = vec![];
|
||||||
|
if let Visibility::Public(token) = item_struct.vis {
|
||||||
|
// set vis to `pub(crate)` to trigger `missing_docs_in_private_items` lint.
|
||||||
|
let new_vis: Visibility = syn::parse_quote_spanned!(token.span() => pub(crate));
|
||||||
|
item_struct.vis = new_vis;
|
||||||
|
}
|
||||||
|
if let syn::Fields::Named(fields) = &mut item_struct.fields {
|
||||||
|
for field in &mut fields.named {
|
||||||
|
// remove all attributes from fields as well.
|
||||||
|
field.attrs = vec![];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quote!(#item_struct).into()
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//@needs-asm-support
|
//@needs-asm-support
|
||||||
//@aux-build: proc_macros.rs
|
//@aux-build: proc_macros.rs
|
||||||
|
//@aux-build: proc_macro_attr.rs
|
||||||
|
|
||||||
#![warn(clippy::missing_docs_in_private_items)]
|
#![warn(clippy::missing_docs_in_private_items)]
|
||||||
// When denying at the crate level, be sure to not get random warnings from the
|
// When denying at the crate level, be sure to not get random warnings from the
|
||||||
@ -8,6 +9,8 @@
|
|||||||
//! Some garbage docs for the crate here
|
//! Some garbage docs for the crate here
|
||||||
#![doc = "More garbage"]
|
#![doc = "More garbage"]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate proc_macro_attr;
|
||||||
extern crate proc_macros;
|
extern crate proc_macros;
|
||||||
|
|
||||||
use proc_macros::with_span;
|
use proc_macros::with_span;
|
||||||
@ -112,3 +115,12 @@ fn main() {}
|
|||||||
with_span!(span pub fn foo_pm() {});
|
with_span!(span pub fn foo_pm() {});
|
||||||
with_span!(span pub static FOO_PM: u32 = 0;);
|
with_span!(span pub static FOO_PM: u32 = 0;);
|
||||||
with_span!(span pub const FOO2_PM: u32 = 0;);
|
with_span!(span pub const FOO2_PM: u32 = 0;);
|
||||||
|
|
||||||
|
// issue #12197
|
||||||
|
// Undocumented field originated inside of spanned proc-macro attribute
|
||||||
|
/// Some dox for struct.
|
||||||
|
#[rewrite_struct]
|
||||||
|
pub struct Test {
|
||||||
|
/// Dox
|
||||||
|
a: u8,
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error: missing documentation for a type alias
|
error: missing documentation for a type alias
|
||||||
--> tests/ui/missing_doc.rs:16:1
|
--> tests/ui/missing_doc.rs:19:1
|
||||||
|
|
|
|
||||||
LL | type Typedef = String;
|
LL | type Typedef = String;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -8,19 +8,19 @@ LL | type Typedef = String;
|
|||||||
= help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]`
|
= help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]`
|
||||||
|
|
||||||
error: missing documentation for a module
|
error: missing documentation for a module
|
||||||
--> tests/ui/missing_doc.rs:19:1
|
--> tests/ui/missing_doc.rs:22:1
|
||||||
|
|
|
|
||||||
LL | mod module_no_dox {}
|
LL | mod module_no_dox {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: missing documentation for a function
|
error: missing documentation for a function
|
||||||
--> tests/ui/missing_doc.rs:25:1
|
--> tests/ui/missing_doc.rs:28:1
|
||||||
|
|
|
|
||||||
LL | fn foo3() {}
|
LL | fn foo3() {}
|
||||||
| ^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
error: missing documentation for an enum
|
error: missing documentation for an enum
|
||||||
--> tests/ui/missing_doc.rs:39:1
|
--> tests/ui/missing_doc.rs:42:1
|
||||||
|
|
|
|
||||||
LL | / enum Baz {
|
LL | / enum Baz {
|
||||||
LL | | BazA { a: isize, b: isize },
|
LL | | BazA { a: isize, b: isize },
|
||||||
@ -29,43 +29,43 @@ LL | | }
|
|||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: missing documentation for a variant
|
error: missing documentation for a variant
|
||||||
--> tests/ui/missing_doc.rs:40:5
|
--> tests/ui/missing_doc.rs:43:5
|
||||||
|
|
|
|
||||||
LL | BazA { a: isize, b: isize },
|
LL | BazA { a: isize, b: isize },
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: missing documentation for a struct field
|
error: missing documentation for a struct field
|
||||||
--> tests/ui/missing_doc.rs:40:12
|
--> tests/ui/missing_doc.rs:43:12
|
||||||
|
|
|
|
||||||
LL | BazA { a: isize, b: isize },
|
LL | BazA { a: isize, b: isize },
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: missing documentation for a struct field
|
error: missing documentation for a struct field
|
||||||
--> tests/ui/missing_doc.rs:40:22
|
--> tests/ui/missing_doc.rs:43:22
|
||||||
|
|
|
|
||||||
LL | BazA { a: isize, b: isize },
|
LL | BazA { a: isize, b: isize },
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: missing documentation for a variant
|
error: missing documentation for a variant
|
||||||
--> tests/ui/missing_doc.rs:41:5
|
--> tests/ui/missing_doc.rs:44:5
|
||||||
|
|
|
|
||||||
LL | BarB,
|
LL | BarB,
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: missing documentation for a constant
|
error: missing documentation for a constant
|
||||||
--> tests/ui/missing_doc.rs:65:1
|
--> tests/ui/missing_doc.rs:68:1
|
||||||
|
|
|
|
||||||
LL | const FOO: u32 = 0;
|
LL | const FOO: u32 = 0;
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: missing documentation for a static
|
error: missing documentation for a static
|
||||||
--> tests/ui/missing_doc.rs:74:1
|
--> tests/ui/missing_doc.rs:77:1
|
||||||
|
|
|
|
||||||
LL | static BAR: u32 = 0;
|
LL | static BAR: u32 = 0;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: missing documentation for a module
|
error: missing documentation for a module
|
||||||
--> tests/ui/missing_doc.rs:83:1
|
--> tests/ui/missing_doc.rs:86:1
|
||||||
|
|
|
|
||||||
LL | / mod internal_impl {
|
LL | / mod internal_impl {
|
||||||
LL | | /// dox
|
LL | | /// dox
|
||||||
@ -77,13 +77,13 @@ LL | | }
|
|||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: missing documentation for a function
|
error: missing documentation for a function
|
||||||
--> tests/ui/missing_doc.rs:88:5
|
--> tests/ui/missing_doc.rs:91:5
|
||||||
|
|
|
|
||||||
LL | fn undocumented3() {}
|
LL | fn undocumented3() {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: missing documentation for a function
|
error: missing documentation for a function
|
||||||
--> tests/ui/missing_doc.rs:94:9
|
--> tests/ui/missing_doc.rs:97:9
|
||||||
|
|
|
|
||||||
LL | fn also_undocumented2() {}
|
LL | fn also_undocumented2() {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
Loading…
Reference in New Issue
Block a user