Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new lint: suspicious_doc_comments #10497

Merged
merged 1 commit into from
Apr 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4925,6 +4925,7 @@ Released 2018-09-13
[`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
[`suspicious_assignment_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_assignment_formatting
[`suspicious_command_arg_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_command_arg_space
[`suspicious_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_doc_comments
[`suspicious_else_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_else_formatting
[`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
[`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
Expand Down
1 change: 1 addition & 0 deletions clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::strings::STR_TO_STRING_INFO,
crate::strings::TRIM_SPLIT_WHITESPACE_INFO,
crate::strlen_on_c_strings::STRLEN_ON_C_STRINGS_INFO,
crate::suspicious_doc_comments::SUSPICIOUS_DOC_COMMENTS_INFO,
crate::suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS_INFO,
crate::suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL_INFO,
crate::suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL_INFO,
Expand Down
2 changes: 2 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ mod slow_vector_initialization;
mod std_instead_of_core;
mod strings;
mod strlen_on_c_strings;
mod suspicious_doc_comments;
mod suspicious_operation_groupings;
mod suspicious_trait_impl;
mod suspicious_xor_used_as_pow;
Expand Down Expand Up @@ -958,6 +959,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(lines_filter_map_ok::LinesFilterMapOk));
store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule));
store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments));
// add lints here, do not remove this comment, it's used in `new_lint`
}

Expand Down
94 changes: 94 additions & 0 deletions clippy_lints/src/suspicious_doc_comments.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_then};
use if_chain::if_chain;
use rustc_ast::{token::CommentKind, AttrKind, AttrStyle, Attribute, Item};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
/// ### What it does
/// Detects the use of outer doc comments (`///`, `/**`) followed by a bang (`!`): `///!`
///
/// ### Why is this bad?
/// Triple-slash comments (known as "outer doc comments") apply to items that follow it.
/// An outer doc comment followed by a bang (i.e. `///!`) has no specific meaning.
///
/// The user most likely meant to write an inner doc comment (`//!`, `/*!`), which
/// applies to the parent item (i.e. the item that the comment is contained in,
/// usually a module or crate).
///
/// ### Known problems
/// Inner doc comments can only appear before items, so there are certain cases where the suggestion
/// made by this lint is not valid code. For example:
/// ```rs
/// fn foo() {}
/// ///!
/// fn bar() {}
/// ```
/// This lint detects the doc comment and suggests changing it to `//!`, but an inner doc comment
/// is not valid at that position.
///
/// ### Example
/// In this example, the doc comment is attached to the *function*, rather than the *module*.
/// ```rust
/// pub mod util {
/// ///! This module contains utility functions.
///
/// pub fn dummy() {}
/// }
/// ```
///
/// Use instead:
/// ```rust
/// pub mod util {
/// //! This module contains utility functions.
///
/// pub fn dummy() {}
/// }
/// ```
#[clippy::version = "1.70.0"]
pub SUSPICIOUS_DOC_COMMENTS,
suspicious,
"suspicious usage of (outer) doc comments"
}
declare_lint_pass!(SuspiciousDocComments => [SUSPICIOUS_DOC_COMMENTS]);

const WARNING: &str = "this is an outer doc comment and does not apply to the parent module or crate";
const HELP: &str = "use an inner doc comment to document the parent module or crate";

impl EarlyLintPass for SuspiciousDocComments {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
let replacements = collect_doc_comment_replacements(&item.attrs);

if let Some(((lo_span, _), (hi_span, _))) = replacements.first().zip(replacements.last()) {
let span = lo_span.to(*hi_span);

span_lint_and_then(cx, SUSPICIOUS_DOC_COMMENTS, span, WARNING, |diag| {
multispan_sugg_with_applicability(diag, HELP, Applicability::MaybeIncorrect, replacements);
});
}
}
}

fn collect_doc_comment_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> {
attrs
.iter()
.filter_map(|attr| {
if_chain! {
if let AttrKind::DocComment(com_kind, sym) = attr.kind;
if let AttrStyle::Outer = attr.style;
if let Some(com) = sym.as_str().strip_prefix('!');
then {
let sugg = match com_kind {
CommentKind::Line => format!("//!{com}"),
CommentKind::Block => format!("/*!{com}*/")
};
Some((attr.span, sugg))
} else {
None
}
}
})
.collect()
}
81 changes: 81 additions & 0 deletions tests/ui/suspicious_doc_comments.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// run-rustfix
#![allow(unused)]
#![warn(clippy::suspicious_doc_comments)]

//! Real module documentation.
//! Fake module documentation.
fn baz() {}

pub mod singleline_outer_doc {
//! This module contains useful functions.
pub fn bar() {}
}

pub mod singleline_inner_doc {
//! This module contains useful functions.
pub fn bar() {}
}

pub mod multiline_outer_doc {
/*! This module contains useful functions.
*/

pub fn bar() {}
}

pub mod multiline_inner_doc {
/*! This module contains useful functions.
*/

pub fn bar() {}
}

pub mod multiline_outer_doc2 {
//! This module
//! contains
//! useful functions.
pub fn bar() {}
}

pub mod multiline_outer_doc3 {
//! a
//! b
/// c
pub fn bar() {}
}

pub mod multiline_outer_doc4 {
//! a
/// b
pub fn bar() {}
}

pub mod multiline_outer_doc_gap {
//! a
//! b
pub fn bar() {}
}

pub mod multiline_outer_doc_commented {
/////! This outer doc comment was commented out.
pub fn bar() {}
}

pub mod outer_doc_macro {
//! Very cool macro
macro_rules! x {
() => {};
}
}

pub mod useless_outer_doc {
//! Huh.
use std::mem;
}

fn main() {}
81 changes: 81 additions & 0 deletions tests/ui/suspicious_doc_comments.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// run-rustfix
#![allow(unused)]
#![warn(clippy::suspicious_doc_comments)]

//! Real module documentation.
///! Fake module documentation.
fn baz() {}

pub mod singleline_outer_doc {
///! This module contains useful functions.

pub fn bar() {}
}

pub mod singleline_inner_doc {
//! This module contains useful functions.

pub fn bar() {}
}

pub mod multiline_outer_doc {
/**! This module contains useful functions.
*/

pub fn bar() {}
}

pub mod multiline_inner_doc {
/*! This module contains useful functions.
*/

pub fn bar() {}
}

pub mod multiline_outer_doc2 {
///! This module
///! contains
///! useful functions.

pub fn bar() {}
}

pub mod multiline_outer_doc3 {
///! a
///! b

/// c
pub fn bar() {}
}

pub mod multiline_outer_doc4 {
///! a
/// b
pub fn bar() {}
}

pub mod multiline_outer_doc_gap {
///! a

///! b
pub fn bar() {}
}

pub mod multiline_outer_doc_commented {
/////! This outer doc comment was commented out.
pub fn bar() {}
}

pub mod outer_doc_macro {
///! Very cool macro
macro_rules! x {
() => {};
}
}

pub mod useless_outer_doc {
///! Huh.
use std::mem;
}

fn main() {}
Loading