Rewrite empty_line_after_doc_comments and empty_line_after_outer_attr

This commit is contained in:
Alex Macleod 2024-08-24 17:43:34 +00:00
parent 30e0b69908
commit 3474df6a8e
73 changed files with 1563 additions and 872 deletions

View File

@ -1,52 +0,0 @@
use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::{is_present_in_source, without_block_comments, SpanRangeExt};
use rustc_ast::{AttrKind, AttrStyle};
use rustc_lint::EarlyContext;
use rustc_span::Span;
/// Check for empty lines after outer attributes.
///
/// Attributes and documentation comments are both considered outer attributes
/// by the AST. However, the average user likely considers them to be different.
/// Checking for empty lines after each of these attributes is split into two different
/// lints but can share the same logic.
pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
let mut iter = item.attrs.iter().peekable();
while let Some(attr) = iter.next() {
if (matches!(attr.kind, AttrKind::Normal(..)) || matches!(attr.kind, AttrKind::DocComment(..)))
&& attr.style == AttrStyle::Outer
&& is_present_in_source(cx, attr.span)
{
let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent());
let end_of_attr_to_next_attr_or_item = Span::new(
attr.span.hi(),
iter.peek().map_or(item.span.lo(), |next_attr| next_attr.span.lo()),
item.span.ctxt(),
item.span.parent(),
);
if let Some(snippet) = end_of_attr_to_next_attr_or_item.get_source_text(cx) {
let lines = snippet.split('\n').collect::<Vec<_>>();
let lines = without_block_comments(lines);
if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 {
let (lint_msg, lint_type) = match attr.kind {
AttrKind::DocComment(..) => (
"found an empty line after a doc comment. \
Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?",
EMPTY_LINE_AFTER_DOC_COMMENTS,
),
AttrKind::Normal(..) => (
"found an empty line after an outer attribute. \
Perhaps you forgot to add a `!` to make it an inner attribute?",
EMPTY_LINE_AFTER_OUTER_ATTR,
),
};
span_lint(cx, lint_type, begin_of_attr_to_item, lint_msg);
}
}
}
}
}

View File

@ -4,7 +4,6 @@ mod blanket_clippy_restriction_lints;
mod deprecated_cfg_attr;
mod deprecated_semver;
mod duplicated_attributes;
mod empty_line_after;
mod inline_always;
mod mixed_attributes_style;
mod non_minimal_cfg;
@ -126,94 +125,6 @@ declare_clippy_lint! {
"use of `#[deprecated(since = \"x\")]` where x is not semver"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for empty lines after outer attributes
///
/// ### Why is this bad?
/// Most likely the attribute was meant to be an inner attribute using a '!'.
/// If it was meant to be an outer attribute, then the following item
/// should not be separated by empty lines.
///
/// ### Known problems
/// Can cause false positives.
///
/// From the clippy side it's difficult to detect empty lines between an attributes and the
/// following item because empty lines and comments are not part of the AST. The parsing
/// currently works for basic cases but is not perfect.
///
/// ### Example
/// ```no_run
/// #[allow(dead_code)]
///
/// fn not_quite_good_code() { }
/// ```
///
/// Use instead:
/// ```no_run
/// // Good (as inner attribute)
/// #![allow(dead_code)]
///
/// fn this_is_fine() { }
///
/// // or
///
/// // Good (as outer attribute)
/// #[allow(dead_code)]
/// fn this_is_fine_too() { }
/// ```
#[clippy::version = "pre 1.29.0"]
pub EMPTY_LINE_AFTER_OUTER_ATTR,
nursery,
"empty line after outer attribute"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for empty lines after documentation comments.
///
/// ### Why is this bad?
/// The documentation comment was most likely meant to be an inner attribute or regular comment.
/// If it was intended to be a documentation comment, then the empty line should be removed to
/// be more idiomatic.
///
/// ### Known problems
/// Only detects empty lines immediately following the documentation. If the doc comment is followed
/// by an attribute and then an empty line, this lint will not trigger. Use `empty_line_after_outer_attr`
/// in combination with this lint to detect both cases.
///
/// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`).
///
/// ### Example
/// ```no_run
/// /// Some doc comment with a blank line after it.
///
/// fn not_quite_good_code() { }
/// ```
///
/// Use instead:
/// ```no_run
/// /// Good (no blank line)
/// fn this_is_fine() { }
/// ```
///
/// ```no_run
/// // Good (convert to a regular comment)
///
/// fn this_is_fine_too() { }
/// ```
///
/// ```no_run
/// //! Good (convert to a comment on an inner attribute)
///
/// fn this_is_fine_as_well() { }
/// ```
#[clippy::version = "1.70.0"]
pub EMPTY_LINE_AFTER_DOC_COMMENTS,
nursery,
"empty line after documentation comments"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category.
@ -601,18 +512,12 @@ impl EarlyAttributes {
impl_lint_pass!(EarlyAttributes => [
DEPRECATED_CFG_ATTR,
EMPTY_LINE_AFTER_OUTER_ATTR,
EMPTY_LINE_AFTER_DOC_COMMENTS,
NON_MINIMAL_CFG,
DEPRECATED_CLIPPY_CFG_ATTR,
UNNECESSARY_CLIPPY_CFG,
]);
impl EarlyLintPass for EarlyAttributes {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
empty_line_after::check(cx, item);
}
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
deprecated_cfg_attr::check(cx, attr, &self.msrv);
deprecated_cfg_attr::check_clippy(cx, attr);

View File

@ -49,8 +49,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
crate::attrs::DEPRECATED_CLIPPY_CFG_ATTR_INFO,
crate::attrs::DEPRECATED_SEMVER_INFO,
crate::attrs::DUPLICATED_ATTRIBUTES_INFO,
crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
crate::attrs::INLINE_ALWAYS_INFO,
crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO,
crate::attrs::NON_MINIMAL_CFG_INFO,
@ -138,6 +136,8 @@ pub static LINTS: &[&crate::LintInfo] = &[
crate::doc::DOC_LINK_WITH_QUOTES_INFO,
crate::doc::DOC_MARKDOWN_INFO,
crate::doc::EMPTY_DOCS_INFO,
crate::doc::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
crate::doc::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
crate::doc::MISSING_ERRORS_DOC_INFO,
crate::doc::MISSING_PANICS_DOC_INFO,
crate::doc::MISSING_SAFETY_DOC_INFO,

View File

@ -0,0 +1,329 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{snippet_indent, SpanRangeExt};
use clippy_utils::tokenize_with_text;
use itertools::Itertools;
use rustc_ast::token::CommentKind;
use rustc_ast::{AttrKind, AttrStyle, Attribute};
use rustc_errors::{Applicability, Diag, SuggestionStyle};
use rustc_hir::{ItemKind, Node};
use rustc_lexer::TokenKind;
use rustc_lint::LateContext;
use rustc_span::{ExpnKind, InnerSpan, Span, SpanData};
use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR};
#[derive(Debug, PartialEq, Clone, Copy)]
enum StopKind {
Attr,
Doc(CommentKind),
}
impl StopKind {
fn is_doc(self) -> bool {
matches!(self, StopKind::Doc(_))
}
}
#[derive(Debug)]
struct Stop {
span: Span,
kind: StopKind,
first: usize,
last: usize,
}
impl Stop {
fn convert_to_inner(&self) -> (Span, String) {
let inner = match self.kind {
// #|[...]
StopKind::Attr => InnerSpan::new(1, 1),
// /// or /**
// ^ ^
StopKind::Doc(_) => InnerSpan::new(2, 3),
};
(self.span.from_inner(inner), "!".into())
}
fn comment_out(&self, cx: &LateContext<'_>, suggestions: &mut Vec<(Span, String)>) {
match self.kind {
StopKind::Attr => {
if cx.tcx.sess.source_map().is_multiline(self.span) {
suggestions.extend([
(self.span.shrink_to_lo(), "/* ".into()),
(self.span.shrink_to_hi(), " */".into()),
]);
} else {
suggestions.push((self.span.shrink_to_lo(), "// ".into()));
}
},
StopKind::Doc(CommentKind::Line) => suggestions.push((self.span.shrink_to_lo(), "// ".into())),
StopKind::Doc(CommentKind::Block) => {
// /** outer */ /*! inner */
// ^ ^
let asterisk = self.span.from_inner(InnerSpan::new(1, 2));
suggestions.push((asterisk, String::new()));
},
}
}
fn from_attr(cx: &LateContext<'_>, attr: &Attribute) -> Option<Self> {
let SpanData { lo, hi, .. } = attr.span.data();
let file = cx.tcx.sess.source_map().lookup_source_file(lo);
Some(Self {
span: attr.span,
kind: match attr.kind {
AttrKind::Normal(_) => StopKind::Attr,
AttrKind::DocComment(comment_kind, _) => StopKind::Doc(comment_kind),
},
first: file.lookup_line(file.relative_position(lo))?,
last: file.lookup_line(file.relative_position(hi))?,
})
}
}
/// Represents a set of attrs/doc comments separated by 1 or more empty lines
///
/// ```ignore
/// /// chunk 1 docs
/// // not an empty line so also part of chunk 1
/// #[chunk_1_attrs] // <-- prev_stop
///
/// /* gap */
///
/// /// chunk 2 docs // <-- next_stop
/// #[chunk_2_attrs]
/// ```
struct Gap<'a> {
/// The span of individual empty lines including the newline at the end of the line
empty_lines: Vec<Span>,
has_comment: bool,
next_stop: &'a Stop,
prev_stop: &'a Stop,
/// The chunk that includes [`prev_stop`](Self::prev_stop)
prev_chunk: &'a [Stop],
}
impl<'a> Gap<'a> {
fn new(cx: &LateContext<'_>, prev_chunk: &'a [Stop], next_chunk: &'a [Stop]) -> Option<Self> {
let prev_stop = prev_chunk.last()?;
let next_stop = next_chunk.first()?;
let gap_span = prev_stop.span.between(next_stop.span);
let gap_snippet = gap_span.get_source_text(cx)?;
let mut has_comment = false;
let mut empty_lines = Vec::new();
for (token, source, inner_span) in tokenize_with_text(&gap_snippet) {
match token {
TokenKind::BlockComment {
doc_style: None,
terminated: true,
}
| TokenKind::LineComment { doc_style: None } => has_comment = true,
TokenKind::Whitespace => {
let newlines = source.bytes().positions(|b| b == b'\n');
empty_lines.extend(
newlines
.tuple_windows()
.map(|(a, b)| InnerSpan::new(inner_span.start + a + 1, inner_span.start + b))
.map(|inner_span| gap_span.from_inner(inner_span)),
);
},
// Ignore cfg_attr'd out attributes as they may contain empty lines, could also be from macro
// shenanigans
_ => return None,
}
}
(!empty_lines.is_empty()).then_some(Self {
empty_lines,
has_comment,
next_stop,
prev_stop,
prev_chunk,
})
}
}
/// If the node the attributes/docs apply to is the first in the module/crate suggest converting
/// them to inner attributes/docs
fn suggest_inner(cx: &LateContext<'_>, diag: &mut Diag<'_, ()>, kind: StopKind, gaps: &[Gap<'_>]) {
let Some(owner) = cx.last_node_with_lint_attrs.as_owner() else {
return;
};
let parent_desc = match cx.tcx.parent_hir_node(owner.into()) {
Node::Item(item)
if let ItemKind::Mod(parent_mod) = item.kind
&& let [first, ..] = parent_mod.item_ids
&& first.owner_id == owner =>
{
"parent module"
},
Node::Crate(crate_mod)
if let Some(first) = crate_mod
.item_ids
.iter()
.map(|&id| cx.tcx.hir().item(id))
// skip prelude imports
.find(|item| !matches!(item.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
&& first.owner_id == owner =>
{
"crate"
},
_ => return,
};
diag.multipart_suggestion_verbose(
match kind {
StopKind::Attr => format!("if the attribute should apply to the {parent_desc} use an inner attribute"),
StopKind::Doc(_) => format!("if the comment should document the {parent_desc} use an inner doc comment"),
},
gaps.iter()
.flat_map(|gap| gap.prev_chunk)
.map(Stop::convert_to_inner)
.collect(),
Applicability::MaybeIncorrect,
);
}
fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool {
let Some(first_gap) = gaps.first() else {
return false;
};
let empty_lines = || gaps.iter().flat_map(|gap| gap.empty_lines.iter().copied());
let mut has_comment = false;
let mut has_attr = false;
for gap in gaps {
has_comment |= gap.has_comment;
if !has_attr {
has_attr = gap.prev_chunk.iter().any(|stop| stop.kind == StopKind::Attr);
}
}
let kind = first_gap.prev_stop.kind;
let (lint, kind_desc) = match kind {
StopKind::Attr => (EMPTY_LINE_AFTER_OUTER_ATTR, "outer attribute"),
StopKind::Doc(_) => (EMPTY_LINE_AFTER_DOC_COMMENTS, "doc comment"),
};
let (lines, are, them) = if empty_lines().nth(1).is_some() {
("lines", "are", "them")
} else {
("line", "is", "it")
};
span_lint_and_then(
cx,
lint,
first_gap.prev_stop.span.to(empty_lines().last().unwrap()),
format!("empty {lines} after {kind_desc}"),
|diag| {
if let Some(owner) = cx.last_node_with_lint_attrs.as_owner() {
let def_id = owner.to_def_id();
let def_descr = cx.tcx.def_descr(def_id);
diag.span_label(
cx.tcx.def_span(def_id),
match kind {
StopKind::Attr => format!("the attribute applies to this {def_descr}"),
StopKind::Doc(_) => format!("the comment documents this {def_descr}"),
},
);
}
diag.multipart_suggestion_with_style(
format!("if the empty {lines} {are} unintentional remove {them}"),
empty_lines().map(|empty_line| (empty_line, String::new())).collect(),
Applicability::MaybeIncorrect,
SuggestionStyle::HideCodeAlways,
);
if has_comment && kind.is_doc() {
// Likely doc comments that applied to some now commented out code
//
// /// Old docs for Foo
// // struct Foo;
let mut suggestions = Vec::new();
for stop in gaps.iter().flat_map(|gap| gap.prev_chunk) {
stop.comment_out(cx, &mut suggestions);
}
let name = match cx.tcx.hir().opt_name(cx.last_node_with_lint_attrs) {
Some(name) => format!("`{name}`"),
None => "this".into(),
};
diag.multipart_suggestion_verbose(
format!("if the doc comment should not document {name} comment it out"),
suggestions,
Applicability::MaybeIncorrect,
);
} else {
suggest_inner(cx, diag, kind, gaps);
}
if kind == StopKind::Doc(CommentKind::Line)
&& gaps
.iter()
.all(|gap| !gap.has_comment && gap.next_stop.kind == StopKind::Doc(CommentKind::Line))
{
// Commentless empty gaps between line doc comments, possibly intended to be part of the markdown
let indent = snippet_indent(cx, first_gap.prev_stop.span).unwrap_or_default();
diag.multipart_suggestion_verbose(
format!("if the documentation should include the empty {lines} include {them} in the comment"),
empty_lines()
.map(|empty_line| (empty_line, format!("{indent}///")))
.collect(),
Applicability::MaybeIncorrect,
);
}
},
);
kind.is_doc()
}
/// Returns `true` if [`EMPTY_LINE_AFTER_DOC_COMMENTS`] triggered, used to skip other doc comment
/// lints where they would be confusing
///
/// [`EMPTY_LINE_AFTER_OUTER_ATTR`] is also here to share an implementation but does not return
/// `true` if it triggers
pub(super) fn check(cx: &LateContext<'_>, attrs: &[Attribute]) -> bool {
let mut outer = attrs
.iter()
.filter(|attr| attr.style == AttrStyle::Outer && !attr.span.from_expansion())
.map(|attr| Stop::from_attr(cx, attr))
.collect::<Option<Vec<_>>>()
.unwrap_or_default();
if outer.is_empty() {
return false;
}
// Push a fake attribute Stop for the item itself so we check for gaps between the last outer
// attr/doc comment and the item they apply to
let span = cx.tcx.hir().span(cx.last_node_with_lint_attrs);
if !span.from_expansion()
&& let Ok(line) = cx.tcx.sess.source_map().lookup_line(span.lo())
{
outer.push(Stop {
span,
kind: StopKind::Attr,
first: line.line,
// last doesn't need to be accurate here, we don't compare it with anything
last: line.line,
});
}
let mut gaps = Vec::new();
let mut last = 0;
for pos in outer
.array_windows()
.positions(|[a, b]| b.first.saturating_sub(a.last) > 1)
{
// we want to be after the first stop in the window
let pos = pos + 1;
if let Some(gap) = Gap::new(cx, &outer[last..pos], &outer[pos..]) {
last = pos;
gaps.push(gap);
}
}
check_gaps(cx, &gaps)
}

View File

@ -22,7 +22,6 @@ pub(super) fn check(
range: Range<usize>,
mut span: Span,
containers: &[super::Container],
line_break_span: Span,
) {
if doc[range.clone()].contains('\t') {
// We don't do tab stops correctly.
@ -52,29 +51,6 @@ pub(super) fn check(
"doc list item without indentation"
};
span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| {
let snippet = clippy_utils::source::snippet(cx, line_break_span, "");
if snippet.chars().filter(|&c| c == '\n').count() > 1
&& let Some(doc_comment_start) = snippet.rfind('\n')
&& let doc_comment = snippet[doc_comment_start..].trim()
&& (doc_comment == "///" || doc_comment == "//!")
{
// suggest filling in a blank line
diag.span_suggestion_verbose(
line_break_span.shrink_to_lo(),
"if this should be its own paragraph, add a blank doc comment line",
format!("\n{doc_comment}"),
Applicability::MaybeIncorrect,
);
if ccount > 0 || blockquote_level > 0 {
diag.help("if this not intended to be a quote at all, escape it with `\\>`");
} else {
let indent = list_indentation - lcount;
diag.help(format!(
"if this is intended to be part of the list, indent {indent} spaces"
));
}
return;
}
if ccount == 0 && blockquote_level == 0 {
// simpler suggestion style for indentation
let indent = list_indentation - lcount;

View File

@ -32,6 +32,7 @@ use rustc_span::{sym, Span};
use std::ops::Range;
use url::Url;
mod empty_line_after;
mod link_with_quotes;
mod markdown;
mod missing_headers;
@ -455,7 +456,82 @@ declare_clippy_lint! {
"ensure that the first line of a documentation paragraph isn't too long"
}
#[derive(Clone)]
declare_clippy_lint! {
/// ### What it does
/// Checks for empty lines after outer attributes
///
/// ### Why is this bad?
/// The attribute may have meant to be an inner attribute (`#![attr]`). If
/// it was meant to be an outer attribute (`#[attr]`) then the empty line
/// should be removed
///
/// ### Example
/// ```no_run
/// #[allow(dead_code)]
///
/// fn not_quite_good_code() {}
/// ```
///
/// Use instead:
/// ```no_run
/// // Good (as inner attribute)
/// #![allow(dead_code)]
///
/// fn this_is_fine() {}
///
/// // or
///
/// // Good (as outer attribute)
/// #[allow(dead_code)]
/// fn this_is_fine_too() {}
/// ```
#[clippy::version = "pre 1.29.0"]
pub EMPTY_LINE_AFTER_OUTER_ATTR,
suspicious,
"empty line after outer attribute"
}
declare_clippy_lint! {
/// ### What it does
/// Checks for empty lines after doc comments.
///
/// ### Why is this bad?
/// The doc comment may have meant to be an inner doc comment, regular
/// comment or applied to some old code that is now commented out. If it was
/// intended to be a doc comment, then the empty line should be removed.
///
/// ### Example
/// ```no_run
/// /// Some doc comment with a blank line after it.
///
/// fn f() {}
///
/// /// Docs for `old_code`
/// // fn old_code() {}
///
/// fn new_code() {}
/// ```
///
/// Use instead:
/// ```no_run
/// //! Convert it to an inner doc comment
///
/// // Or a regular comment
///
/// /// Or remove the empty line
/// fn f() {}
///
/// // /// Docs for `old_code`
/// // fn old_code() {}
///
/// fn new_code() {}
/// ```
#[clippy::version = "1.70.0"]
pub EMPTY_LINE_AFTER_DOC_COMMENTS,
suspicious,
"empty line after doc comments"
}
pub struct Documentation {
valid_idents: FxHashSet<String>,
check_private_items: bool,
@ -482,6 +558,8 @@ impl_lint_pass!(Documentation => [
SUSPICIOUS_DOC_COMMENTS,
EMPTY_DOCS,
DOC_LAZY_CONTINUATION,
EMPTY_LINE_AFTER_OUTER_ATTR,
EMPTY_LINE_AFTER_DOC_COMMENTS,
TOO_LONG_FIRST_DOC_PARAGRAPH,
]);
@ -612,12 +690,10 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
Some(("fake".into(), "fake".into()))
}
if is_doc_hidden(attrs) {
if suspicious_doc_comments::check(cx, attrs) || empty_line_after::check(cx, attrs) || is_doc_hidden(attrs) {
return None;
}
suspicious_doc_comments::check(cx, attrs);
let (fragments, _) = attrs_to_doc_fragments(
attrs.iter().filter_map(|attr| {
if in_external_macro(cx.sess(), attr.span) {
@ -816,7 +892,6 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
range.end..next_range.start,
Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent()),
&containers[..],
span,
);
}
},

View File

@ -7,7 +7,7 @@ use rustc_span::Span;
use super::SUSPICIOUS_DOC_COMMENTS;
pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) {
pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) -> bool {
let replacements: Vec<_> = collect_doc_replacements(attrs);
if let Some((&(lo_span, _), &(hi_span, _))) = replacements.first().zip(replacements.last()) {
@ -24,6 +24,10 @@ pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) {
);
},
);
true
} else {
false
}
}

View File

@ -14,7 +14,6 @@ use rustc_span::sym;
/// - `hashmap.into_iter().map(|(_, v)| v)`
///
/// on `HashMaps` and `BTreeMaps` in std
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
map_type: &'tcx str, // iter / into_iter

View File

@ -183,15 +183,15 @@ pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool {
let mut iter = tokenize_with_text(src);
// Search for the token sequence [`#`, `[`, `cfg`]
while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) {
let mut iter = iter.by_ref().skip_while(|(t, _)| {
while iter.any(|(t, ..)| matches!(t, TokenKind::Pound)) {
let mut iter = iter.by_ref().skip_while(|(t, ..)| {
matches!(
t,
TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. }
)
});
if matches!(iter.next(), Some((TokenKind::OpenBracket, _)))
&& matches!(iter.next(), Some((TokenKind::Ident, "cfg")))
if matches!(iter.next(), Some((TokenKind::OpenBracket, ..)))
&& matches!(iter.next(), Some((TokenKind::Ident, "cfg", _)))
{
return true;
}

View File

@ -1194,8 +1194,8 @@ fn eq_span_tokens(
&& let Some(rsrc) = right.get_source_range(cx)
&& let Some(rsrc) = rsrc.as_str()
{
let pred = |t: &(_, _)| pred(t.0);
let map = |(_, x)| x;
let pred = |&(token, ..): &(TokenKind, _, _)| pred(token);
let map = |(_, source, _)| source;
let ltok = tokenize_with_text(lsrc).filter(pred).map(map);
let rtok = tokenize_with_text(rsrc).filter(pred).map(map);

View File

@ -121,7 +121,7 @@ use rustc_middle::ty::{
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{sym, Span};
use rustc_span::{sym, InnerSpan, Span};
use rustc_target::abi::Integer;
use visitors::Visitable;
@ -2949,13 +2949,14 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> ExprU
}
/// Tokenizes the input while keeping the text associated with each token.
pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str)> {
pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str, InnerSpan)> {
let mut pos = 0;
tokenize(s).map(move |t| {
let end = pos + t.len;
let range = pos as usize..end as usize;
let inner = InnerSpan::new(range.start, range.end);
pos = end;
(t.kind, s.get(range).unwrap_or_default())
(t.kind, s.get(range).unwrap_or_default(), inner)
})
}
@ -2979,8 +2980,8 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String {
let snippet = sm.span_to_snippet(span).unwrap_or_default();
let res = tokenize_with_text(&snippet)
.filter(|(t, _)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }))
.map(|(_, s)| s)
.filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }))
.map(|(_, s, _)| s)
.join("\n");
res
}
@ -3000,7 +3001,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
/// pat: Some(a)
/// else_body: return None
/// ```
///
/// And for this example:
/// ```ignore
/// let Some(FooBar { a, b }) = ex else { return None };
@ -3010,7 +3011,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
/// pat: Some(FooBar { a, b })
/// else_body: return None
/// ```
///
/// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because
/// the question mark operator is applicable here. Callers have to check whether we are in a
/// constant or not.

View File

@ -666,39 +666,6 @@ pub fn walk_span_to_context(span: Span, outer: SyntaxContext) -> Option<Span> {
(outer_span.ctxt() == outer).then_some(outer_span)
}
/// Removes block comments from the given `Vec` of lines.
///
/// # Examples
///
/// ```rust,ignore
/// without_block_comments(vec!["/*", "foo", "*/"]);
/// // => vec![]
///
/// without_block_comments(vec!["bar", "/*", "foo", "*/"]);
/// // => vec!["bar"]
/// ```
pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> {
let mut without = vec![];
let mut nest_level = 0;
for line in lines {
if line.contains("/*") {
nest_level += 1;
continue;
} else if line.contains("*/") {
nest_level -= 1;
continue;
}
if nest_level == 0 {
without.push(line);
}
}
without
}
/// Trims the whitespace from the start and the end of the span.
pub fn trim_span(sm: &SourceMap, span: Span) -> Span {
let data = span.data();
@ -776,7 +743,7 @@ pub fn str_literal_to_char_literal(
#[cfg(test)]
mod test {
use super::{reindent_multiline, without_block_comments};
use super::reindent_multiline;
#[test]
fn test_reindent_multiline_single_line() {
@ -844,29 +811,4 @@ mod test {
z
}".into(), true, Some(8)));
}
#[test]
fn test_without_block_comments_lines_without_block_comments() {
let result = without_block_comments(vec!["/*", "", "*/"]);
println!("result: {result:?}");
assert!(result.is_empty());
let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]);
assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]);
let result = without_block_comments(vec!["/* rust", "", "*/"]);
assert!(result.is_empty());
let result = without_block_comments(vec!["/* one-line comment */"]);
assert!(result.is_empty());
let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]);
assert!(result.is_empty());
let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]);
assert!(result.is_empty());
let result = without_block_comments(vec!["foo", "bar", "baz"]);
assert_eq!(result, vec!["foo", "bar", "baz"]);
}
}

View File

@ -1,4 +1,4 @@
#[warn(clippy::disallowed_names)]
#![warn(clippy::disallowed_names)]
fn main() {
// `foo` is part of the default configuration

View File

@ -1,4 +1,4 @@
#[warn(clippy::disallowed_names)]
#![warn(clippy::disallowed_names)]
fn main() {
// `foo` is part of the default configuration

View File

@ -15,7 +15,6 @@ use proc_macros::{external, with_span};
#[warn(deref_nullptr)]
#[deny(deref_nullptr)]
#[forbid(deref_nullptr)]
fn main() {
external! {
#[allow(dead_code)]

View File

@ -36,7 +36,7 @@ LL | #[expect(dead_code)]
= help: try adding a reason at the end with `, reason = ".."`
error: `allow` attribute without specifying a reason
--> tests/ui/allow_attributes_without_reason.rs:47:5
--> tests/ui/allow_attributes_without_reason.rs:46:5
|
LL | #[allow(unused)]
| ^^^^^^^^^^^^^^^^
@ -44,7 +44,7 @@ LL | #[allow(unused)]
= help: try adding a reason at the end with `, reason = ".."`
error: `allow` attribute without specifying a reason
--> tests/ui/allow_attributes_without_reason.rs:47:5
--> tests/ui/allow_attributes_without_reason.rs:46:5
|
LL | #[allow(unused)]
| ^^^^^^^^^^^^^^^^

View File

@ -2,16 +2,16 @@
#![feature(rustc_private)]
#![feature(core_intrinsics)]
extern crate libc;
#[warn(clippy::cast_ptr_alignment)]
#[allow(
#![warn(clippy::cast_ptr_alignment)]
#![allow(
clippy::no_effect,
clippy::unnecessary_operation,
clippy::cast_lossless,
clippy::borrow_as_ptr
)]
extern crate libc;
fn main() {
/* These should be warned against */

View File

@ -1,5 +1,5 @@
#[allow(clippy::unnecessary_operation)]
#[allow(clippy::implicit_clone)]
#![allow(clippy::unnecessary_operation)]
#![allow(clippy::implicit_clone)]
fn main() {
let x = &Baz;

View File

@ -1,9 +1,7 @@
#![allow(clippy::assertions_on_constants, clippy::equatable_if_let, clippy::needless_if)]
#![warn(clippy::collapsible_if, clippy::collapsible_else_if)]
#[rustfmt::skip]
#[warn(clippy::collapsible_if)]
#[warn(clippy::collapsible_else_if)]
fn main() {
let x = "hello";
let y = "world";
@ -76,7 +74,6 @@ fn main() {
}
#[rustfmt::skip]
#[allow(dead_code)]
fn issue_7318() {
if true { println!("I've been resolved!")
}else if false {}

View File

@ -1,9 +1,7 @@
#![allow(clippy::assertions_on_constants, clippy::equatable_if_let, clippy::needless_if)]
#![warn(clippy::collapsible_if, clippy::collapsible_else_if)]
#[rustfmt::skip]
#[warn(clippy::collapsible_if)]
#[warn(clippy::collapsible_else_if)]
fn main() {
let x = "hello";
let y = "world";
@ -90,7 +88,6 @@ fn main() {
}
#[rustfmt::skip]
#[allow(dead_code)]
fn issue_7318() {
if true { println!("I've been resolved!")
}else{

View File

@ -1,5 +1,5 @@
error: this `else { if .. }` block can be collapsed
--> tests/ui/collapsible_else_if.rs:13:12
--> tests/ui/collapsible_else_if.rs:11:12
|
LL | } else {
| ____________^
@ -19,7 +19,7 @@ LL + }
|
error: this `else { if .. }` block can be collapsed
--> tests/ui/collapsible_else_if.rs:21:12
--> tests/ui/collapsible_else_if.rs:19:12
|
LL | } else {
| ____________^
@ -37,7 +37,7 @@ LL + }
|
error: this `else { if .. }` block can be collapsed
--> tests/ui/collapsible_else_if.rs:29:12
--> tests/ui/collapsible_else_if.rs:27:12
|
LL | } else {
| ____________^
@ -60,7 +60,7 @@ LL + }
|
error: this `else { if .. }` block can be collapsed
--> tests/ui/collapsible_else_if.rs:40:12
--> tests/ui/collapsible_else_if.rs:38:12
|
LL | } else {
| ____________^
@ -83,7 +83,7 @@ LL + }
|
error: this `else { if .. }` block can be collapsed
--> tests/ui/collapsible_else_if.rs:51:12
--> tests/ui/collapsible_else_if.rs:49:12
|
LL | } else {
| ____________^
@ -106,7 +106,7 @@ LL + }
|
error: this `else { if .. }` block can be collapsed
--> tests/ui/collapsible_else_if.rs:62:12
--> tests/ui/collapsible_else_if.rs:60:12
|
LL | } else {
| ____________^
@ -129,7 +129,7 @@ LL + }
|
error: this `else { if .. }` block can be collapsed
--> tests/ui/collapsible_else_if.rs:73:12
--> tests/ui/collapsible_else_if.rs:71:12
|
LL | } else {
| ____________^
@ -152,7 +152,7 @@ LL + }
|
error: this `else { if .. }` block can be collapsed
--> tests/ui/collapsible_else_if.rs:96:10
--> tests/ui/collapsible_else_if.rs:93:10
|
LL | }else{
| __________^

View File

@ -1,4 +1,4 @@
/// Test for https://github.com/rust-lang/rust-clippy/issues/1698
// Test for https://github.com/rust-lang/rust-clippy/issues/1698
pub trait Trait {
const CONSTANT: u8;

View File

@ -1,6 +1,4 @@
#[allow(dead_code)]
/// Test for https://github.com/rust-lang/rust-clippy/issues/478
// Test for https://github.com/rust-lang/rust-clippy/issues/478
enum Baz {
One,

View File

@ -1,4 +1,4 @@
/// Test for https://github.com/rust-lang/rust-clippy/issues/11230
// Test for https://github.com/rust-lang/rust-clippy/issues/11230
fn main() {
const A: &[for<'a> fn(&'a ())] = &[];

View File

@ -1,6 +1,6 @@
#![allow(clippy::all)]
/// Test for https://github.com/rust-lang/rust-clippy/issues/1588
// Test for https://github.com/rust-lang/rust-clippy/issues/1588
fn main() {
match 1 {

View File

@ -1,6 +1,6 @@
#![allow(clippy::all)]
/// Test for https://github.com/rust-lang/rust-clippy/issues/1969
// Test for https://github.com/rust-lang/rust-clippy/issues/1969
fn main() {}

View File

@ -1,8 +1,8 @@
#![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)]
/// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
///
/// Issue: https://github.com/rust-lang/rust-clippy/issues/2499
// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
//
// Issue: https://github.com/rust-lang/rust-clippy/issues/2499
fn f(s: &[u8]) -> bool {
let t = s[0] as char;

View File

@ -3,7 +3,6 @@
/// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
///
/// Issue: https://github.com/rust-lang/rust-clippy/issues/2594
fn spanless_hash_ice() {
let txt = "something";
let empty_header: [u8; 1] = [1; 1];

View File

@ -1,4 +1,4 @@
/// Test for https://github.com/rust-lang/rust-clippy/issues/2727
// Test for https://github.com/rust-lang/rust-clippy/issues/2727
pub fn f(new: fn()) {
new();

View File

@ -5,10 +5,10 @@
dead_code
)]
/// This should not compile-fail with:
///
/// error[E0277]: the trait bound `T: Foo` is not satisfied
// See rust-lang/rust-clippy#2760.
// This should not compile-fail with:
//
// error[E0277]: the trait bound `T: Foo` is not satisfied
// See https://github.com/rust-lang/rust-clippy/issues/2760
trait Foo {
type Bar;

View File

@ -1,4 +1,4 @@
/// Test for https://github.com/rust-lang/rust-clippy/issues/2862
// Test for https://github.com/rust-lang/rust-clippy/issues/2862
pub trait FooMap {
fn map<B, F: Fn() -> B>(&self, f: F) -> B;

View File

@ -1,6 +1,6 @@
#![allow(dead_code, clippy::extra_unused_lifetimes)]
/// Test for https://github.com/rust-lang/rust-clippy/issues/2865
// Test for https://github.com/rust-lang/rust-clippy/issues/2865
struct Ice {
size: String,

View File

@ -1,4 +1,4 @@
/// Test for https://github.com/rust-lang/rust-clippy/issues/3151
// Test for https://github.com/rust-lang/rust-clippy/issues/3151
#[derive(Clone)]
pub struct HashMap<V, S> {

View File

@ -2,7 +2,7 @@
#![allow(clippy::disallowed_names, clippy::equatable_if_let, clippy::needless_if)]
#![allow(unused)]
/// Test for https://github.com/rust-lang/rust-clippy/issues/3462
// Test for https://github.com/rust-lang/rust-clippy/issues/3462
enum Foo {
Bar,

View File

@ -1,4 +1,4 @@
/// Test for https://github.com/rust-lang/rust-clippy/issues/3747
// Test for https://github.com/rust-lang/rust-clippy/issues/3747
macro_rules! a {
( $pub:tt $($attr:tt)* ) => {

View File

@ -1,6 +1,6 @@
#![deny(clippy::all)]
/// Test for https://github.com/rust-lang/rust-clippy/issues/700
// Test for https://github.com/rust-lang/rust-clippy/issues/700
fn core() {}

View File

@ -1,6 +1,6 @@
#![deny(clippy::all)]
/// Test for https://github.com/rust-lang/rust-clippy/issues/1336
// Test for https://github.com/rust-lang/rust-clippy/issues/1336
#[allow(dead_code)]
struct Foo;

View File

@ -1,7 +1,7 @@
#![allow(clippy::comparison_chain)]
#![deny(clippy::if_same_then_else)]
/// Test for https://github.com/rust-lang/rust-clippy/issues/2426
// Test for https://github.com/rust-lang/rust-clippy/issues/2426
fn main() {}

View File

@ -1,6 +1,6 @@
#![deny(clippy::multiple_inherent_impl)]
/// Test for https://github.com/rust-lang/rust-clippy/issues/4578
// Test for https://github.com/rust-lang/rust-clippy/issues/4578
macro_rules! impl_foo {
($struct:ident) => {

View File

@ -1,6 +1,6 @@
#![allow(warnings)]
/// Test for https://github.com/rust-lang/rust-clippy/issues/825
// Test for https://github.com/rust-lang/rust-clippy/issues/825
// this should compile in a reasonable amount of time
fn rust_type_id(name: &str) {

View File

@ -1,6 +1,6 @@
#![deny(clippy::match_same_arms)]
/// Test for https://github.com/rust-lang/rust-clippy/issues/2427
// Test for https://github.com/rust-lang/rust-clippy/issues/2427
const PRICE_OF_SWEETS: u32 = 5;
const PRICE_OF_KINDNESS: u32 = 0;

View File

@ -1,4 +1,4 @@
/// Test for https://github.com/rust-lang/rust-clippy/issues/1346
// Test for https://github.com/rust-lang/rust-clippy/issues/1346
#[deny(warnings)]
fn cfg_return() -> i32 {

View File

@ -1,47 +0,0 @@
// https://github.com/rust-lang/rust-clippy/issues/12917
#![warn(clippy::doc_lazy_continuation)]
/// This is a constant.
///
/// The meaning of which should not be explained.
pub const A: i32 = 42;
/// This is another constant, no longer used.
///
/// This block of documentation has a long
/// explanation and derivation to explain
/// why it is what it is, and how it's used.
///
/// It is left here for historical reasons, and
/// for reference.
///
/// Reasons it's great:
/// - First reason
/// - Second reason
///
//pub const B: i32 = 1337;
/// This is yet another constant.
///
/// This has a similar fate as `B`.
///
/// Reasons it's useful:
/// 1. First reason
/// 2. Second reason
///
//pub const C: i32 = 8008;
/// This is still in use.
pub const D: i32 = 20;
/// > blockquote code path
///
/// bottom text
pub const E: i32 = 20;
/// > blockquote code path
///
#[repr(C)]
/// bottom text
pub struct Foo(i32);

View File

@ -1,43 +0,0 @@
// https://github.com/rust-lang/rust-clippy/issues/12917
#![warn(clippy::doc_lazy_continuation)]
/// This is a constant.
///
/// The meaning of which should not be explained.
pub const A: i32 = 42;
/// This is another constant, no longer used.
///
/// This block of documentation has a long
/// explanation and derivation to explain
/// why it is what it is, and how it's used.
///
/// It is left here for historical reasons, and
/// for reference.
///
/// Reasons it's great:
/// - First reason
/// - Second reason
//pub const B: i32 = 1337;
/// This is yet another constant.
///
/// This has a similar fate as `B`.
///
/// Reasons it's useful:
/// 1. First reason
/// 2. Second reason
//pub const C: i32 = 8008;
/// This is still in use.
pub const D: i32 = 20;
/// > blockquote code path
/// bottom text
pub const E: i32 = 20;
/// > blockquote code path
#[repr(C)]
/// bottom text
pub struct Foo(i32);

View File

@ -1,56 +0,0 @@
error: doc list item without indentation
--> tests/ui/doc/doc_lazy_blank_line.rs:23:5
|
LL | /// This is yet another constant.
| ^
|
= help: if this is intended to be part of the list, indent 3 spaces
= note: `-D clippy::doc-lazy-continuation` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]`
help: if this should be its own paragraph, add a blank doc comment line
|
LL ~ /// - Second reason
LL + ///
|
error: doc list item without indentation
--> tests/ui/doc/doc_lazy_blank_line.rs:32:5
|
LL | /// This is still in use.
| ^
|
= help: if this is intended to be part of the list, indent 4 spaces
help: if this should be its own paragraph, add a blank doc comment line
|
LL ~ /// 2. Second reason
LL + ///
|
error: doc quote line without `>` marker
--> tests/ui/doc/doc_lazy_blank_line.rs:37:5
|
LL | /// bottom text
| ^
|
= help: if this not intended to be a quote at all, escape it with `\>`
help: if this should be its own paragraph, add a blank doc comment line
|
LL ~ /// > blockquote code path
LL + ///
|
error: doc quote line without `>` marker
--> tests/ui/doc/doc_lazy_blank_line.rs:42:5
|
LL | /// bottom text
| ^
|
= help: if this not intended to be a quote at all, escape it with `\>`
help: if this should be its own paragraph, add a blank doc comment line
|
LL ~ /// > blockquote code path
LL + ///
|
error: aborting due to 4 previous errors

View File

@ -7,9 +7,8 @@ fn one() {}
/// 1. first line
/// lazy list continuations don't make warnings with this lint
///
//~^ ERROR: doc list item without indentation
/// because they don't have the
/// because they don't have the
//~^ ERROR: doc list item without indentation
fn two() {}
@ -20,9 +19,8 @@ fn three() {}
/// - first line
/// lazy list continuations don't make warnings with this lint
///
//~^ ERROR: doc list item without indentation
/// because they don't have the
/// because they don't have the
//~^ ERROR: doc list item without indentation
fn four() {}
@ -33,9 +31,8 @@ fn five() {}
/// - - first line
/// this will warn on the lazy continuation
///
//~^ ERROR: doc list item without indentation
/// and so should this
/// and so should this
//~^ ERROR: doc list item without indentation
fn six() {}

View File

@ -30,12 +30,11 @@ error: doc list item without indentation
LL | /// because they don't have the
| ^
|
= help: if this is intended to be part of the list, indent 3 spaces
help: if this should be its own paragraph, add a blank doc comment line
|
LL ~ /// lazy list continuations don't make warnings with this lint
LL + ///
= help: if this is supposed to be its own paragraph, add a blank line
help: indent this line
|
LL | /// because they don't have the
| +++
error: doc list item without indentation
--> tests/ui/doc/doc_lazy_list.rs:16:5
@ -67,12 +66,11 @@ error: doc list item without indentation
LL | /// because they don't have the
| ^
|
= help: if this is intended to be part of the list, indent 4 spaces
help: if this should be its own paragraph, add a blank doc comment line
|
LL ~ /// lazy list continuations don't make warnings with this lint
LL + ///
= help: if this is supposed to be its own paragraph, add a blank line
help: indent this line
|
LL | /// because they don't have the
| ++++
error: doc list item without indentation
--> tests/ui/doc/doc_lazy_list.rs:28:5
@ -104,12 +102,11 @@ error: doc list item without indentation
LL | /// and so should this
| ^^^^
|
= help: if this is intended to be part of the list, indent 2 spaces
help: if this should be its own paragraph, add a blank doc comment line
|
LL ~ /// this will warn on the lazy continuation
LL + ///
= help: if this is supposed to be its own paragraph, add a blank line
help: indent this line
|
LL | /// and so should this
| ++
error: doc list item without indentation
--> tests/ui/doc/doc_lazy_list.rs:56:5

View File

@ -1,5 +1,4 @@
#![warn(clippy::duplicate_underscore_argument)]
#[allow(dead_code, unused)]
fn join_the_dark_side(darth: i32, _darth: i32) {}
//~^ ERROR: `darth` already exists, having another argument having almost the same name ma

View File

@ -1,5 +1,5 @@
error: `darth` already exists, having another argument having almost the same name makes code comprehension and documentation more difficult
--> tests/ui/duplicate_underscore_argument.rs:4:23
--> tests/ui/duplicate_underscore_argument.rs:3:23
|
LL | fn join_the_dark_side(darth: i32, _darth: i32) {}
| ^^^^^

View File

@ -0,0 +1,135 @@
#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)]
//~vvv empty_line_after_doc_comments
/// Meant to be an
/// inner doc comment
/// for the crate
fn first_in_crate() {}
mod m {
//~vvv empty_line_after_doc_comments
/// Meant to be an
/// inner doc comment
/// for the module
fn first_in_module() {}
}
mod some_mod {
//! This doc comment should *NOT* produce a warning
mod some_inner_mod {
fn some_noop() {}
}
//~v empty_line_after_doc_comments
/// # Indented
/// Blank line
fn indented() {}
}
//~v empty_line_after_doc_comments
/// This should produce a warning
fn with_doc_and_newline() {}
// This should *NOT* produce a warning
#[crate_type = "lib"]
/// some comment
fn with_no_newline_and_comment() {}
//~v empty_line_after_doc_comments
/// This doc comment should produce a warning
/** This is also a doc comment and is part of the warning
*/
#[allow(non_camel_case_types)]
#[allow(missing_docs)]
#[allow(dead_code)]
fn three_attributes() {}
mod misattributed {
//~v empty_line_after_doc_comments
/// docs for `old_code`
// fn old_code() {}
fn new_code() {}
//~vv empty_line_after_doc_comments
/// Docs
/// for OldA
// struct OldA;
/// Docs
/// for OldB
// struct OldB;
/// Docs
/// for Multiple
#[allow(dead_code)]
struct Multiple;
}
mod block_comments {
//~v empty_line_after_doc_comments
/**
* Meant to be inner doc comment
*/
fn first_in_module() {}
//~v empty_line_after_doc_comments
/**
* Docs for `old_code`
*/
/* fn old_code() {} */
/**
* Docs for `new_code`
*/
fn new_code() {}
//~v empty_line_after_doc_comments
/// Docs for `old_code2`
/* fn old_code2() {} */
/// Docs for `new_code2`
fn new_code2() {}
}
// This should *NOT* produce a warning
#[doc = "
Returns the escaped value of the textual representation of
"]
pub fn function() -> bool {
true
}
// This should *NOT* produce a warning
#[derive(Clone, Copy)]
pub enum FooFighter {
Bar1,
Bar2,
Bar3,
Bar4,
}
/// Should not lint
// some line comment
/// gaps without an empty line
struct LineComment;
/// This should *NOT* produce a warning because the empty line is inside a block comment
/*
*/
pub struct EmptyInBlockComment;
/// This should *NOT* produce a warning
/* test */
pub struct BlockComment;
/// Ignore the empty line inside a cfg_attr'd out attribute
#[cfg_attr(any(), multiline(
foo = 1
bar = 2
))]
fn empty_line_in_cfg_attr() {}
fn main() {}

View File

@ -0,0 +1,144 @@
#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)]
//~vvv empty_line_after_doc_comments
//! Meant to be an
//! inner doc comment
//! for the crate
fn first_in_crate() {}
mod m {
//~vvv empty_line_after_doc_comments
//! Meant to be an
//! inner doc comment
//! for the module
fn first_in_module() {}
}
mod some_mod {
//! This doc comment should *NOT* produce a warning
mod some_inner_mod {
fn some_noop() {}
}
//~v empty_line_after_doc_comments
/// # Indented
///
/// Blank line
fn indented() {}
}
//~v empty_line_after_doc_comments
/// This should produce a warning
fn with_doc_and_newline() {}
// This should *NOT* produce a warning
#[crate_type = "lib"]
/// some comment
fn with_no_newline_and_comment() {}
//~v empty_line_after_doc_comments
/// This doc comment should produce a warning
/** This is also a doc comment and is part of the warning
*/
#[allow(non_camel_case_types)]
#[allow(missing_docs)]
#[allow(dead_code)]
fn three_attributes() {}
mod misattributed {
//~v empty_line_after_doc_comments
// /// docs for `old_code`
// fn old_code() {}
fn new_code() {}
//~vv empty_line_after_doc_comments
// /// Docs
// /// for OldA
// struct OldA;
// /// Docs
// /// for OldB
// struct OldB;
/// Docs
/// for Multiple
#[allow(dead_code)]
struct Multiple;
}
mod block_comments {
//~v empty_line_after_doc_comments
/*!
* Meant to be inner doc comment
*/
fn first_in_module() {}
//~v empty_line_after_doc_comments
/*
* Docs for `old_code`
*/
/* fn old_code() {} */
/**
* Docs for `new_code`
*/
fn new_code() {}
//~v empty_line_after_doc_comments
// /// Docs for `old_code2`
/* fn old_code2() {} */
/// Docs for `new_code2`
fn new_code2() {}
}
// This should *NOT* produce a warning
#[doc = "
Returns the escaped value of the textual representation of
"]
pub fn function() -> bool {
true
}
// This should *NOT* produce a warning
#[derive(Clone, Copy)]
pub enum FooFighter {
Bar1,
Bar2,
Bar3,
Bar4,
}
/// Should not lint
// some line comment
/// gaps without an empty line
struct LineComment;
/// This should *NOT* produce a warning because the empty line is inside a block comment
/*
*/
pub struct EmptyInBlockComment;
/// This should *NOT* produce a warning
/* test */
pub struct BlockComment;
/// Ignore the empty line inside a cfg_attr'd out attribute
#[cfg_attr(any(), multiline(
foo = 1
bar = 2
))]
fn empty_line_in_cfg_attr() {}
fn main() {}

View File

@ -0,0 +1,147 @@
#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)]
//~vvv empty_line_after_doc_comments
/// Meant to be an
/// inner doc comment
/// for the crate
fn first_in_crate() {}
mod m {
//~vvv empty_line_after_doc_comments
/// Meant to be an
/// inner doc comment
/// for the module
fn first_in_module() {}
}
mod some_mod {
//! This doc comment should *NOT* produce a warning
mod some_inner_mod {
fn some_noop() {}
}
//~v empty_line_after_doc_comments
/// # Indented
/// Blank line
fn indented() {}
}
//~v empty_line_after_doc_comments
/// This should produce a warning
fn with_doc_and_newline() {}
// This should *NOT* produce a warning
#[crate_type = "lib"]
/// some comment
fn with_no_newline_and_comment() {}
//~v empty_line_after_doc_comments
/// This doc comment should produce a warning
/** This is also a doc comment and is part of the warning
*/
#[allow(non_camel_case_types)]
#[allow(missing_docs)]
#[allow(dead_code)]
fn three_attributes() {}
mod misattributed {
//~v empty_line_after_doc_comments
/// docs for `old_code`
// fn old_code() {}
fn new_code() {}
//~vv empty_line_after_doc_comments
/// Docs
/// for OldA
// struct OldA;
/// Docs
/// for OldB
// struct OldB;
/// Docs
/// for Multiple
#[allow(dead_code)]
struct Multiple;
}
mod block_comments {
//~v empty_line_after_doc_comments
/**
* Meant to be inner doc comment
*/
fn first_in_module() {}
//~v empty_line_after_doc_comments
/**
* Docs for `old_code`
*/
/* fn old_code() {} */
/**
* Docs for `new_code`
*/
fn new_code() {}
//~v empty_line_after_doc_comments
/// Docs for `old_code2`
/* fn old_code2() {} */
/// Docs for `new_code2`
fn new_code2() {}
}
// This should *NOT* produce a warning
#[doc = "
Returns the escaped value of the textual representation of
"]
pub fn function() -> bool {
true
}
// This should *NOT* produce a warning
#[derive(Clone, Copy)]
pub enum FooFighter {
Bar1,
Bar2,
Bar3,
Bar4,
}
/// Should not lint
// some line comment
/// gaps without an empty line
struct LineComment;
/// This should *NOT* produce a warning because the empty line is inside a block comment
/*
*/
pub struct EmptyInBlockComment;
/// This should *NOT* produce a warning
/* test */
pub struct BlockComment;
/// Ignore the empty line inside a cfg_attr'd out attribute
#[cfg_attr(any(), multiline(
foo = 1
bar = 2
))]
fn empty_line_in_cfg_attr() {}
fn main() {}

View File

@ -0,0 +1,176 @@
error: empty line after doc comment
--> tests/ui/empty_line_after/doc_comments.rs:6:1
|
LL | / /// for the crate
LL | |
| |_
LL | fn first_in_crate() {}
| ------------------- the comment documents this function
|
= note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::empty_line_after_doc_comments)]`
= help: if the empty line is unintentional remove it
help: if the comment should document the crate use an inner doc comment
|
LL ~ //! Meant to be an
LL ~ //! inner doc comment
LL ~ //! for the crate
|
error: empty line after doc comment
--> tests/ui/empty_line_after/doc_comments.rs:14:5
|
LL | / /// for the module
LL | |
| |_
LL | fn first_in_module() {}
| -------------------- the comment documents this function
|
= help: if the empty line is unintentional remove it
help: if the comment should document the parent module use an inner doc comment
|
LL ~ //! Meant to be an
LL ~ //! inner doc comment
LL ~ //! for the module
|
error: empty line after doc comment
--> tests/ui/empty_line_after/doc_comments.rs:27:5
|
LL | / /// # Indented
LL | |
| |_
LL | /// Blank line
LL | fn indented() {}
| ------------- the comment documents this function
|
= help: if the empty line is unintentional remove it
help: if the documentation should include the empty line include it in the comment
|
LL | ///
|
error: empty line after doc comment
--> tests/ui/empty_line_after/doc_comments.rs:34:1
|
LL | / /// This should produce a warning
LL | |
| |_
LL | fn with_doc_and_newline() {}
| ------------------------- the comment documents this function
|
= help: if the empty line is unintentional remove it
error: empty lines after doc comment
--> tests/ui/empty_line_after/doc_comments.rs:44:1
|
LL | / /// This doc comment should produce a warning
LL | |
LL | | /** This is also a doc comment and is part of the warning
LL | | */
LL | |
| |_
...
LL | fn three_attributes() {}
| --------------------- the comment documents this function
|
= help: if the empty lines are unintentional remove them
error: empty line after doc comment
--> tests/ui/empty_line_after/doc_comments.rs:56:5
|
LL | / /// docs for `old_code`
LL | | // fn old_code() {}
LL | |
| |_
LL | fn new_code() {}
| ------------- the comment documents this function
|
= help: if the empty line is unintentional remove it
help: if the doc comment should not document `new_code` comment it out
|
LL | // /// docs for `old_code`
| ++
error: empty lines after doc comment
--> tests/ui/empty_line_after/doc_comments.rs:63:5
|
LL | / /// for OldA
LL | | // struct OldA;
LL | |
LL | | /// Docs
LL | | /// for OldB
LL | | // struct OldB;
LL | |
| |_
...
LL | struct Multiple;
| --------------- the comment documents this struct
|
= help: if the empty lines are unintentional remove them
help: if the doc comment should not document `Multiple` comment it out
|
LL ~ // /// Docs
LL ~ // /// for OldA
LL | // struct OldA;
LL |
LL ~ // /// Docs
LL ~ // /// for OldB
|
error: empty line after doc comment
--> tests/ui/empty_line_after/doc_comments.rs:78:5
|
LL | / /**
LL | | * Meant to be inner doc comment
LL | | */
LL | |
| |_
LL | fn first_in_module() {}
| -------------------- the comment documents this function
|
= help: if the empty line is unintentional remove it
help: if the comment should document the parent module use an inner doc comment
|
LL | /*!
| ~
error: empty line after doc comment
--> tests/ui/empty_line_after/doc_comments.rs:85:5
|
LL | / /**
LL | | * Docs for `old_code`
LL | | */
LL | | /* fn old_code() {} */
LL | |
| |_
...
LL | fn new_code() {}
| ------------- the comment documents this function
|
= help: if the empty line is unintentional remove it
help: if the doc comment should not document `new_code` comment it out
|
LL - /**
LL + /*
|
error: empty line after doc comment
--> tests/ui/empty_line_after/doc_comments.rs:96:5
|
LL | / /// Docs for `old_code2`
LL | | /* fn old_code2() {} */
LL | |
| |_
LL | /// Docs for `new_code2`
LL | fn new_code2() {}
| -------------- the comment documents this function
|
= help: if the empty line is unintentional remove it
help: if the doc comment should not document `new_code2` comment it out
|
LL | // /// Docs for `old_code2`
| ++
error: aborting due to 10 previous errors

View File

@ -0,0 +1,103 @@
//@aux-build:../auxiliary/proc_macro_attr.rs
#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)]
//~v empty_line_after_outer_attr
#[crate_type = "lib"]
fn first_in_crate() {}
#[macro_use]
extern crate proc_macro_attr;
//~v empty_line_after_outer_attr
#[inline]
/// some comment
fn with_one_newline_and_comment() {}
#[inline]
/// some comment
fn with_no_newline_and_comment() {}
//~v empty_line_after_outer_attr
#[inline]
fn with_one_newline() {}
#[rustfmt::skip]
mod two_lines {
//~v empty_line_after_outer_attr
#[crate_type = "lib"]
fn with_two_newlines() {}
}
//~v empty_line_after_outer_attr
#[doc = "doc attributes should be considered attributes"]
enum Baz {
One,
Two,
}
//~v empty_line_after_outer_attr
#[repr(C)]
struct Foo {
one: isize,
two: isize,
}
//~v empty_line_after_outer_attr
#[allow(dead_code)]
mod foo {}
//~v empty_line_after_outer_attr
#[inline]
// Still lint cases where the empty line does not immediately follow the attribute
fn comment_before_empty_line() {}
#[doc = "
Returns the escaped value of the textual representation of
"]
pub fn function() -> bool {
true
}
#[derive(Clone, Copy)]
pub enum FooFighter {
Bar1,
Bar2,
Bar3,
Bar4,
}
#[crate_type = "lib"]
/*
*/
pub struct EmptyLineInBlockComment;
#[crate_type = "lib"]
/* test */
pub struct BlockComment;
// See https://github.com/rust-lang/rust-clippy/issues/5567
#[rustfmt::skip]
#[fake_async_trait]
pub trait Bazz {
fn foo() -> Vec<u8> {
let _i = "";
vec![]
}
}
#[derive(Clone, Copy)]
#[dummy(string = "first line
second line
")]
pub struct Args;
fn main() {}

View File

@ -0,0 +1,106 @@
//@aux-build:../auxiliary/proc_macro_attr.rs
#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)]
//~v empty_line_after_outer_attr
#![crate_type = "lib"]
fn first_in_crate() {}
#[macro_use]
extern crate proc_macro_attr;
//~v empty_line_after_outer_attr
#[inline]
/// some comment
fn with_one_newline_and_comment() {}
#[inline]
/// some comment
fn with_no_newline_and_comment() {}
//~v empty_line_after_outer_attr
#[inline]
fn with_one_newline() {}
#[rustfmt::skip]
mod two_lines {
//~v empty_line_after_outer_attr
#![crate_type = "lib"]
fn with_two_newlines() {}
}
//~v empty_line_after_outer_attr
#[doc = "doc attributes should be considered attributes"]
enum Baz {
One,
Two,
}
//~v empty_line_after_outer_attr
#[repr(C)]
struct Foo {
one: isize,
two: isize,
}
//~v empty_line_after_outer_attr
#[allow(dead_code)]
mod foo {}
//~v empty_line_after_outer_attr
#[inline]
// Still lint cases where the empty line does not immediately follow the attribute
fn comment_before_empty_line() {}
#[doc = "
Returns the escaped value of the textual representation of
"]
pub fn function() -> bool {
true
}
#[derive(Clone, Copy)]
pub enum FooFighter {
Bar1,
Bar2,
Bar3,
Bar4,
}
#[crate_type = "lib"]
/*
*/
pub struct EmptyLineInBlockComment;
#[crate_type = "lib"]
/* test */
pub struct BlockComment;
// See https://github.com/rust-lang/rust-clippy/issues/5567
#[rustfmt::skip]
#[fake_async_trait]
pub trait Bazz {
fn foo() -> Vec<u8> {
let _i = "";
vec![]
}
}
#[derive(Clone, Copy)]
#[dummy(string = "first line
second line
")]
pub struct Args;
fn main() {}

View File

@ -0,0 +1,112 @@
//@aux-build:../auxiliary/proc_macro_attr.rs
#![warn(clippy::empty_line_after_outer_attr, clippy::empty_line_after_doc_comments)]
//~v empty_line_after_outer_attr
#[crate_type = "lib"]
fn first_in_crate() {}
#[macro_use]
extern crate proc_macro_attr;
//~v empty_line_after_outer_attr
#[inline]
/// some comment
fn with_one_newline_and_comment() {}
#[inline]
/// some comment
fn with_no_newline_and_comment() {}
//~v empty_line_after_outer_attr
#[inline]
fn with_one_newline() {}
#[rustfmt::skip]
mod two_lines {
//~v empty_line_after_outer_attr
#[crate_type = "lib"]
fn with_two_newlines() {}
}
//~v empty_line_after_outer_attr
#[doc = "doc attributes should be considered attributes"]
enum Baz {
One,
Two,
}
//~v empty_line_after_outer_attr
#[repr(C)]
struct Foo {
one: isize,
two: isize,
}
//~v empty_line_after_outer_attr
#[allow(dead_code)]
mod foo {}
//~v empty_line_after_outer_attr
#[inline]
// Still lint cases where the empty line does not immediately follow the attribute
fn comment_before_empty_line() {}
#[doc = "
Returns the escaped value of the textual representation of
"]
pub fn function() -> bool {
true
}
#[derive(Clone, Copy)]
pub enum FooFighter {
Bar1,
Bar2,
Bar3,
Bar4,
}
#[crate_type = "lib"]
/*
*/
pub struct EmptyLineInBlockComment;
#[crate_type = "lib"]
/* test */
pub struct BlockComment;
// See https://github.com/rust-lang/rust-clippy/issues/5567
#[rustfmt::skip]
#[fake_async_trait]
pub trait Bazz {
fn foo() -> Vec<u8> {
let _i = "";
vec![]
}
}
#[derive(Clone, Copy)]
#[dummy(string = "first line
second line
")]
pub struct Args;
fn main() {}

View File

@ -0,0 +1,103 @@
error: empty line after outer attribute
--> tests/ui/empty_line_after/outer_attribute.rs:5:1
|
LL | / #[crate_type = "lib"]
LL | |
| |_
LL | fn first_in_crate() {}
| ------------------- the attribute applies to this function
|
= note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]`
= help: if the empty line is unintentional remove it
help: if the attribute should apply to the crate use an inner attribute
|
LL | #![crate_type = "lib"]
| +
error: empty line after outer attribute
--> tests/ui/empty_line_after/outer_attribute.rs:13:1
|
LL | / #[inline]
LL | |
| |_
LL | /// some comment
LL | fn with_one_newline_and_comment() {}
| --------------------------------- the attribute applies to this function
|
= help: if the empty line is unintentional remove it
error: empty line after outer attribute
--> tests/ui/empty_line_after/outer_attribute.rs:23:1
|
LL | / #[inline]
LL | |
| |_
LL | fn with_one_newline() {}
| --------------------- the attribute applies to this function
|
= help: if the empty line is unintentional remove it
error: empty lines after outer attribute
--> tests/ui/empty_line_after/outer_attribute.rs:30:5
|
LL | / #[crate_type = "lib"]
LL | |
LL | |
| |_
LL | fn with_two_newlines() {}
| ---------------------- the attribute applies to this function
|
= help: if the empty lines are unintentional remove them
help: if the attribute should apply to the parent module use an inner attribute
|
LL | #![crate_type = "lib"]
| +
error: empty line after outer attribute
--> tests/ui/empty_line_after/outer_attribute.rs:37:1
|
LL | / #[doc = "doc attributes should be considered attributes"]
LL | |
| |_
LL | enum Baz {
| -------- the attribute applies to this enum
|
= help: if the empty line is unintentional remove it
error: empty line after outer attribute
--> tests/ui/empty_line_after/outer_attribute.rs:45:1
|
LL | / #[repr(C)]
LL | |
| |_
LL | struct Foo {
| ---------- the attribute applies to this struct
|
= help: if the empty line is unintentional remove it
error: empty line after outer attribute
--> tests/ui/empty_line_after/outer_attribute.rs:53:1
|
LL | / #[allow(dead_code)]
LL | |
| |_
LL | mod foo {}
| ------- the attribute applies to this module
|
= help: if the empty line is unintentional remove it
error: empty line after outer attribute
--> tests/ui/empty_line_after/outer_attribute.rs:58:1
|
LL | / #[inline]
LL | | // Still lint cases where the empty line does not immediately follow the attribute
LL | |
| |_
LL | fn comment_before_empty_line() {}
| ------------------------------ the attribute applies to this function
|
= help: if the empty line is unintentional remove it
error: aborting due to 8 previous errors

View File

@ -1,132 +0,0 @@
//@aux-build:proc_macro_attr.rs
#![warn(clippy::empty_line_after_doc_comments)]
#![allow(clippy::assertions_on_constants, clippy::duplicated_attributes)]
#![feature(custom_inner_attributes)]
#![rustfmt::skip]
#[macro_use]
extern crate proc_macro_attr;
mod some_mod {
//! This doc comment should *NOT* produce a warning
mod some_inner_mod {
fn some_noop() {}
}
}
/// This should produce a warning
fn with_doc_and_newline() { assert!(true)}
// This should *NOT* produce a warning
#[crate_type = "lib"]
/// some comment
fn with_one_newline_and_comment() { assert!(true) }
// This should *NOT* produce a warning
#[crate_type = "lib"]
/// some comment
fn with_no_newline_and_comment() { assert!(true) }
// This should *NOT* produce a warning
#[crate_type = "lib"]
fn with_one_newline() { assert!(true) }
// This should *NOT* produce a warning
#[crate_type = "lib"]
fn with_two_newlines() { assert!(true) }
// This should *NOT* produce a warning
#[crate_type = "lib"]
enum Baz {
One,
Two
}
// This should *NOT* produce a warning
#[crate_type = "lib"]
struct Foo {
one: isize,
two: isize
}
// This should *NOT* produce a warning
#[crate_type = "lib"]
mod foo {
}
/// This doc comment should produce a warning
/** This is also a doc comment and should produce a warning
*/
// This should *NOT* produce a warning
#[allow(non_camel_case_types)]
#[allow(missing_docs)]
#[allow(missing_docs)]
fn three_attributes() { assert!(true) }
// This should *NOT* produce a warning
#[doc = "
Returns the escaped value of the textual representation of
"]
pub fn function() -> bool {
true
}
// This should *NOT* produce a warning
#[derive(Clone, Copy)]
pub enum FooFighter {
Bar1,
Bar2,
Bar3,
Bar4
}
// This should *NOT* produce a warning because the empty line is inside a block comment
#[crate_type = "lib"]
/*
*/
pub struct S;
// This should *NOT* produce a warning
#[crate_type = "lib"]
/* test */
pub struct T;
// This should *NOT* produce a warning
// See https://github.com/rust-lang/rust-clippy/issues/5567
#[fake_async_trait]
pub trait Bazz {
fn foo() -> Vec<u8> {
let _i = "";
vec![]
}
}
#[derive(Clone, Copy)]
#[dummy(string = "first line
second line
")]
pub struct Args;
fn main() {}

View File

@ -1,37 +0,0 @@
error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?
--> tests/ui/empty_line_after_doc_comments.rs:18:1
|
LL | / /// This should produce a warning
LL | |
LL | | fn with_doc_and_newline() { assert!(true)}
| |_
|
= note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::empty_line_after_doc_comments)]`
error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?
--> tests/ui/empty_line_after_doc_comments.rs:68:1
|
LL | / /// This doc comment should produce a warning
LL | |
LL | | /** This is also a doc comment and should produce a warning
LL | | */
... |
LL | | #[allow(missing_docs)]
LL | | fn three_attributes() { assert!(true) }
| |_
error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?
--> tests/ui/empty_line_after_doc_comments.rs:70:1
|
LL | / /** This is also a doc comment and should produce a warning
LL | | */
LL | |
LL | | // This should *NOT* produce a warning
... |
LL | | #[allow(missing_docs)]
LL | | fn three_attributes() { assert!(true) }
| |_
error: aborting due to 3 previous errors

View File

@ -1,120 +0,0 @@
//@aux-build:proc_macro_attr.rs
#![warn(clippy::empty_line_after_outer_attr)]
#![allow(clippy::assertions_on_constants, clippy::duplicated_attributes)]
#![feature(custom_inner_attributes)]
#![rustfmt::skip]
#[macro_use]
extern crate proc_macro_attr;
// This should produce a warning
#[crate_type = "lib"]
/// some comment
fn with_one_newline_and_comment() { assert!(true) }
// This should not produce a warning
#[crate_type = "lib"]
/// some comment
fn with_no_newline_and_comment() { assert!(true) }
// This should produce a warning
#[crate_type = "lib"]
fn with_one_newline() { assert!(true) }
// This should produce a warning, too
#[crate_type = "lib"]
fn with_two_newlines() { assert!(true) }
// This should produce a warning
#[crate_type = "lib"]
enum Baz {
One,
Two
}
// This should produce a warning
#[crate_type = "lib"]
struct Foo {
one: isize,
two: isize
}
// This should produce a warning
#[crate_type = "lib"]
mod foo {
}
/// This doc comment should not produce a warning
/** This is also a doc comment and should not produce a warning
*/
// This should not produce a warning
#[allow(non_camel_case_types)]
#[allow(missing_docs)]
#[allow(missing_docs)]
fn three_attributes() { assert!(true) }
// This should not produce a warning
#[doc = "
Returns the escaped value of the textual representation of
"]
pub fn function() -> bool {
true
}
// This should not produce a warning
#[derive(Clone, Copy)]
pub enum FooFighter {
Bar1,
Bar2,
Bar3,
Bar4
}
// This should not produce a warning because the empty line is inside a block comment
#[crate_type = "lib"]
/*
*/
pub struct S;
// This should not produce a warning
#[crate_type = "lib"]
/* test */
pub struct T;
// This should not produce a warning
// See https://github.com/rust-lang/rust-clippy/issues/5567
#[fake_async_trait]
pub trait Bazz {
fn foo() -> Vec<u8> {
let _i = "";
vec![]
}
}
#[derive(Clone, Copy)]
#[dummy(string = "first line
second line
")]
pub struct Args;
fn main() {}

View File

@ -1,54 +0,0 @@
error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
--> tests/ui/empty_line_after_outer_attribute.rs:11:1
|
LL | / #[crate_type = "lib"]
LL | |
LL | | /// some comment
LL | | fn with_one_newline_and_comment() { assert!(true) }
| |_
|
= note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]`
error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
--> tests/ui/empty_line_after_outer_attribute.rs:23:1
|
LL | / #[crate_type = "lib"]
LL | |
LL | | fn with_one_newline() { assert!(true) }
| |_
error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
--> tests/ui/empty_line_after_outer_attribute.rs:28:1
|
LL | / #[crate_type = "lib"]
... |
LL | | fn with_two_newlines() { assert!(true) }
| |_
error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
--> tests/ui/empty_line_after_outer_attribute.rs:35:1
|
LL | / #[crate_type = "lib"]
LL | |
LL | | enum Baz {
| |_
error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
--> tests/ui/empty_line_after_outer_attribute.rs:43:1
|
LL | / #[crate_type = "lib"]
LL | |
LL | | struct Foo {
| |_
error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
--> tests/ui/empty_line_after_outer_attribute.rs:51:1
|
LL | / #[crate_type = "lib"]
LL | |
LL | | mod foo {
| |_
error: aborting due to 6 previous errors

View File

@ -1,4 +1,4 @@
#[warn(clippy::exit)]
#![warn(clippy::exit)]
fn not_main() {
if true {

View File

@ -1,4 +1,4 @@
#[warn(clippy::exit)]
#![warn(clippy::exit)]
fn also_not_main() {
std::process::exit(3);

View File

@ -1,4 +1,4 @@
#[warn(clippy::exit)]
#![warn(clippy::exit)]
fn main() {
if true {

View File

@ -5,8 +5,6 @@
clippy::unnecessary_literal_unwrap
)]
/// Checks implementation of the `EXPECT_FUN_CALL` lint
macro_rules! one {
() => {
1

View File

@ -5,8 +5,6 @@
clippy::unnecessary_literal_unwrap
)]
/// Checks implementation of the `EXPECT_FUN_CALL` lint
macro_rules! one {
() => {
1

View File

@ -1,5 +1,5 @@
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:37:26
--> tests/ui/expect_fun_call.rs:35:26
|
LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
@ -8,85 +8,85 @@ LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code
= help: to override `-D warnings` add `#[allow(clippy::expect_fun_call)]`
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:40:26
--> tests/ui/expect_fun_call.rs:38:26
|
LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:43:37
--> tests/ui/expect_fun_call.rs:41:37
|
LL | with_none_and_format_with_macro.expect(format!("Error {}: fake error", one!()).as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", one!()))`
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:53:25
--> tests/ui/expect_fun_call.rs:51:25
|
LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:56:25
--> tests/ui/expect_fun_call.rs:54:25
|
LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:68:17
--> tests/ui/expect_fun_call.rs:66:17
|
LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{} {}", 1, 2))`
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:89:21
--> tests/ui/expect_fun_call.rs:87:21
|
LL | Some("foo").expect(&get_string());
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:90:21
--> tests/ui/expect_fun_call.rs:88:21
|
LL | Some("foo").expect(get_string().as_ref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:91:21
--> tests/ui/expect_fun_call.rs:89:21
|
LL | Some("foo").expect(get_string().as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:93:21
--> tests/ui/expect_fun_call.rs:91:21
|
LL | Some("foo").expect(get_static_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_static_str()) })`
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:94:21
--> tests/ui/expect_fun_call.rs:92:21
|
LL | Some("foo").expect(get_non_static_str(&0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })`
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:98:16
--> tests/ui/expect_fun_call.rs:96:16
|
LL | Some(true).expect(&format!("key {}, {}", 1, 2));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))`
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:104:17
--> tests/ui/expect_fun_call.rs:102:17
|
LL | opt_ref.expect(&format!("{:?}", opt_ref));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{:?}", opt_ref))`
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:108:20
--> tests/ui/expect_fun_call.rs:106:20
|
LL | format_capture.expect(&format!("{error_code}"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}"))`
error: use of `expect` followed by a function call
--> tests/ui/expect_fun_call.rs:111:30
--> tests/ui/expect_fun_call.rs:109:30
|
LL | format_capture_and_value.expect(&format!("{error_code}, {}", 1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}, {}", 1))`

View File

@ -2,8 +2,6 @@
#![allow(clippy::redundant_pattern_matching)]
#![allow(clippy::if_same_then_else, clippy::equatable_if_let, clippy::needless_if)]
/// Tests for match_overlapping_arm
fn overlapping() {
const FOO: u64 = 2;

View File

@ -1,11 +1,11 @@
error: some ranges overlap
--> tests/ui/match_overlapping_arm.rs:11:9
--> tests/ui/match_overlapping_arm.rs:9:9
|
LL | 0..=10 => println!("0..=10"),
| ^^^^^^
|
note: overlaps with this
--> tests/ui/match_overlapping_arm.rs:13:9
--> tests/ui/match_overlapping_arm.rs:11:9
|
LL | 0..=11 => println!("0..=11"),
| ^^^^^^
@ -13,85 +13,85 @@ LL | 0..=11 => println!("0..=11"),
= help: to override `-D warnings` add `#[allow(clippy::match_overlapping_arm)]`
error: some ranges overlap
--> tests/ui/match_overlapping_arm.rs:18:9
--> tests/ui/match_overlapping_arm.rs:16:9
|
LL | 0..=5 => println!("0..=5"),
| ^^^^^
|
note: overlaps with this
--> tests/ui/match_overlapping_arm.rs:21:9
--> tests/ui/match_overlapping_arm.rs:19:9
|
LL | FOO..=11 => println!("FOO..=11"),
| ^^^^^^^^
error: some ranges overlap
--> tests/ui/match_overlapping_arm.rs:56:9
--> tests/ui/match_overlapping_arm.rs:54:9
|
LL | 0..11 => println!("0..11"),
| ^^^^^
|
note: overlaps with this
--> tests/ui/match_overlapping_arm.rs:58:9
--> tests/ui/match_overlapping_arm.rs:56:9
|
LL | 0..=11 => println!("0..=11"),
| ^^^^^^
error: some ranges overlap
--> tests/ui/match_overlapping_arm.rs:82:9
--> tests/ui/match_overlapping_arm.rs:80:9
|
LL | 0..=10 => println!("0..=10"),
| ^^^^^^
|
note: overlaps with this
--> tests/ui/match_overlapping_arm.rs:81:9
--> tests/ui/match_overlapping_arm.rs:79:9
|
LL | 5..14 => println!("5..14"),
| ^^^^^
error: some ranges overlap
--> tests/ui/match_overlapping_arm.rs:88:9
--> tests/ui/match_overlapping_arm.rs:86:9
|
LL | 0..7 => println!("0..7"),
| ^^^^
|
note: overlaps with this
--> tests/ui/match_overlapping_arm.rs:90:9
--> tests/ui/match_overlapping_arm.rs:88:9
|
LL | 0..=10 => println!("0..=10"),
| ^^^^^^
error: some ranges overlap
--> tests/ui/match_overlapping_arm.rs:101:9
--> tests/ui/match_overlapping_arm.rs:99:9
|
LL | ..=23 => println!("..=23"),
| ^^^^^
|
note: overlaps with this
--> tests/ui/match_overlapping_arm.rs:103:9
--> tests/ui/match_overlapping_arm.rs:101:9
|
LL | ..26 => println!("..26"),
| ^^^^
error: some ranges overlap
--> tests/ui/match_overlapping_arm.rs:111:9
--> tests/ui/match_overlapping_arm.rs:109:9
|
LL | 21..=30 => (),
| ^^^^^^^
|
note: overlaps with this
--> tests/ui/match_overlapping_arm.rs:113:9
--> tests/ui/match_overlapping_arm.rs:111:9
|
LL | 21..=40 => (),
| ^^^^^^^
error: some ranges overlap
--> tests/ui/match_overlapping_arm.rs:126:9
--> tests/ui/match_overlapping_arm.rs:124:9
|
LL | 0..=0x0000_0000_0000_00ff => (),
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: overlaps with this
--> tests/ui/match_overlapping_arm.rs:128:9
--> tests/ui/match_overlapping_arm.rs:126:9
|
LL | 0..=0x0000_0000_0000_ffff => (),
| ^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -1,7 +1,7 @@
use std::borrow::Cow;
#![warn(clippy::string_slice)]
#![allow(clippy::no_effect)]
#[warn(clippy::string_slice)]
#[allow(clippy::no_effect)]
use std::borrow::Cow;
fn main() {
&"Ölkanne"[1..];

View File

@ -1,5 +1,4 @@
#![warn(clippy::tabs_in_doc_comments)]
#[allow(dead_code)]
///
/// Struct to hold two strings:

View File

@ -1,5 +1,4 @@
#![warn(clippy::tabs_in_doc_comments)]
#[allow(dead_code)]
///
/// Struct to hold two strings:

View File

@ -1,5 +1,5 @@
error: using tabs in doc comments is not recommended
--> tests/ui/tabs_in_doc_comments.rs:6:5
--> tests/ui/tabs_in_doc_comments.rs:5:5
|
LL | /// - first one
| ^^^^ help: consider using four spaces per tab
@ -8,43 +8,43 @@ LL | /// - first one
= help: to override `-D warnings` add `#[allow(clippy::tabs_in_doc_comments)]`
error: using tabs in doc comments is not recommended
--> tests/ui/tabs_in_doc_comments.rs:6:13
--> tests/ui/tabs_in_doc_comments.rs:5:13
|
LL | /// - first one
| ^^^^^^^^ help: consider using four spaces per tab
error: using tabs in doc comments is not recommended
--> tests/ui/tabs_in_doc_comments.rs:7:5
--> tests/ui/tabs_in_doc_comments.rs:6:5
|
LL | /// - second one
| ^^^^ help: consider using four spaces per tab
error: using tabs in doc comments is not recommended
--> tests/ui/tabs_in_doc_comments.rs:7:14
--> tests/ui/tabs_in_doc_comments.rs:6:14
|
LL | /// - second one
| ^^^^ help: consider using four spaces per tab
error: using tabs in doc comments is not recommended
--> tests/ui/tabs_in_doc_comments.rs:10:9
--> tests/ui/tabs_in_doc_comments.rs:9:9
|
LL | /// - First String:
| ^^^^ help: consider using four spaces per tab
error: using tabs in doc comments is not recommended
--> tests/ui/tabs_in_doc_comments.rs:11:9
--> tests/ui/tabs_in_doc_comments.rs:10:9
|
LL | /// - needs to be inside here
| ^^^^^^^^ help: consider using four spaces per tab
error: using tabs in doc comments is not recommended
--> tests/ui/tabs_in_doc_comments.rs:14:9
--> tests/ui/tabs_in_doc_comments.rs:13:9
|
LL | /// - Second String:
| ^^^^ help: consider using four spaces per tab
error: using tabs in doc comments is not recommended
--> tests/ui/tabs_in_doc_comments.rs:15:9
--> tests/ui/tabs_in_doc_comments.rs:14:9
|
LL | /// - needs to be inside here
| ^^^^^^^^ help: consider using four spaces per tab