diff --git a/CHANGELOG.md b/CHANGELOG.md index fef25ad8635a..156b3efc3953 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4985,6 +4985,7 @@ Released 2018-09-13 [`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument [`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else +[`empty_docs`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_docs [`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop [`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum [`empty_line_after_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_doc_comments diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 481c44031cf7..27c14befd284 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -146,6 +146,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::drop_forget_ref::MEM_FORGET_INFO, crate::duplicate_mod::DUPLICATE_MOD_INFO, crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO, + crate::empty_docs::EMPTY_DOCS_INFO, crate::empty_drop::EMPTY_DROP_INFO, crate::empty_enum::EMPTY_ENUM_INFO, crate::empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO, diff --git a/clippy_lints/src/empty_docs.rs b/clippy_lints/src/empty_docs.rs new file mode 100644 index 000000000000..2d3050167c0e --- /dev/null +++ b/clippy_lints/src/empty_docs.rs @@ -0,0 +1,57 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use rustc_ast::ast::*; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Detects documentation that is empty. + /// ### Why is this bad? + /// It is unlikely that there is any reason to have empty documentation for an item + /// + /// ### Example + /// ```rust + /// /// + /// fn returns_true() -> bool { + /// true + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn returns_true() -> bool { + /// true + /// } + /// ``` + #[clippy::version = "1.74.0"] + pub EMPTY_DOCS, + suspicious, + "docstrings exist but documentation is empty" +} + +declare_lint_pass!(EmptyDocs => [EMPTY_DOCS]); + +fn trim_comment(comment: &str) -> String { + comment + .trim() + .split("\n") + .map(|comment| comment.trim().trim_matches('*').trim_matches('!')) + .collect::>() + .join("") +} + +impl EarlyLintPass for EmptyDocs { + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attribute: &Attribute) { + if let AttrKind::DocComment(_line, comment) = attribute.kind { + if trim_comment(comment.as_str()).len() == 0 { + span_lint_and_help( + cx, + EMPTY_DOCS, + attribute.span, + "empty doc comment", + None, + "consider removing or fill it", + ); + } + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0f35ec276657..f5ca122056b6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -115,6 +115,7 @@ mod double_parens; mod drop_forget_ref; mod duplicate_mod; mod else_if_without_else; +mod empty_docs; mod empty_drop; mod empty_enum; mod empty_structs_with_brackets; @@ -1123,6 +1124,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(msrv()))); store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter)); + store.register_early_pass(|| Box::new(empty_docs::EmptyDocs)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/tests/ui/empty_docs.rs b/tests/ui/empty_docs.rs new file mode 100644 index 000000000000..74f017755928 --- /dev/null +++ b/tests/ui/empty_docs.rs @@ -0,0 +1,26 @@ +#![allow(unused)] +#![warn(clippy::empty_docs)] + +pub mod outer_module { + + //! + //! valid doc comment + //!! + //!! valid doc comment + + /// + /// valid doc comment + /// + /// valid block doc comment + + /** + * + */ + + /** + * valid block doc comment + * + */ + + pub mod inner_module {} +} diff --git a/tests/ui/empty_docs.stderr b/tests/ui/empty_docs.stderr new file mode 100644 index 000000000000..02c592fa46b1 --- /dev/null +++ b/tests/ui/empty_docs.stderr @@ -0,0 +1,46 @@ +error: empty doc comment + --> $DIR/empty_docs.rs:11:5 + | +LL | /// + | ^^^ + | + = help: consider removing or fill it + = note: `-D clippy::empty-docs` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::empty_docs)]` + +error: empty doc comment + --> $DIR/empty_docs.rs:13:5 + | +LL | /// + | ^^^ + | + = help: consider removing or fill it + +error: empty doc comment + --> $DIR/empty_docs.rs:16:5 + | +LL | / /** +LL | | * +LL | | */ + | |_______^ + | + = help: consider removing or fill it + +error: empty doc comment + --> $DIR/empty_docs.rs:6:5 + | +LL | //! + | ^^^ + | + = help: consider removing or fill it + +error: empty doc comment + --> $DIR/empty_docs.rs:8:5 + | +LL | //!! + | ^^^^ + | + = help: consider removing or fill it + +error: aborting due to 5 previous errors +