Merge remote-tracking branch 'upstream/master' into rustup
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_ast::ast::{Expr, ExprKind};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
@@ -47,7 +47,7 @@ declare_lint_pass!(AsConversions => [AS_CONVERSIONS]);
|
||||
|
||||
impl EarlyLintPass for AsConversions {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
if in_external_macro(cx.sess, expr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -230,15 +230,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
||||
panic_span: None,
|
||||
};
|
||||
fpu.visit_expr(&body.value);
|
||||
lint_for_missing_headers(
|
||||
cx,
|
||||
item.def_id,
|
||||
item.span,
|
||||
sig,
|
||||
headers,
|
||||
Some(body_id),
|
||||
fpu.panic_span,
|
||||
);
|
||||
lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
|
||||
}
|
||||
},
|
||||
hir::ItemKind::Impl(ref impl_) => {
|
||||
@@ -278,15 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
|
||||
panic_span: None,
|
||||
};
|
||||
fpu.visit_expr(&body.value);
|
||||
lint_for_missing_headers(
|
||||
cx,
|
||||
item.def_id,
|
||||
item.span,
|
||||
sig,
|
||||
headers,
|
||||
Some(body_id),
|
||||
fpu.panic_span,
|
||||
);
|
||||
lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_ast::ast::{Expr, ExprKind};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
@@ -49,7 +49,7 @@ declare_lint_pass!(ElseIfWithoutElse => [ELSE_IF_WITHOUT_ELSE]);
|
||||
|
||||
impl EarlyLintPass for ElseIfWithoutElse {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, mut item: &Expr) {
|
||||
if in_external_macro(cx.sess(), item.span) {
|
||||
if in_external_macro(cx.sess, item.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
|
||||
hir_id: hir::HirId,
|
||||
) {
|
||||
too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold);
|
||||
too_many_lines::check_fn(cx, span, body, self.too_many_lines_threshold);
|
||||
too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold);
|
||||
not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, hir_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_span::Span;
|
||||
@@ -8,8 +9,16 @@ use clippy_utils::source::snippet_opt;
|
||||
|
||||
use super::TOO_MANY_LINES;
|
||||
|
||||
pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<'_>, too_many_lines_threshold: u64) {
|
||||
if in_external_macro(cx.sess(), span) {
|
||||
pub(super) fn check_fn(
|
||||
cx: &LateContext<'_>,
|
||||
kind: FnKind<'tcx>,
|
||||
span: Span,
|
||||
body: &'tcx hir::Body<'_>,
|
||||
too_many_lines_threshold: u64,
|
||||
) {
|
||||
// Closures must be contained in a parent body, which will be checked for `too_many_lines`.
|
||||
// Don't check closures for `too_many_lines` to avoid duplicated lints.
|
||||
if matches!(kind, FnKind::Closure) || in_external_macro(cx.sess(), span) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
@@ -48,7 +48,7 @@ declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
|
||||
|
||||
impl EarlyLintPass for IfNotElse {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
|
||||
if in_external_macro(cx.sess(), item.span) {
|
||||
if in_external_macro(cx.sess, item.span) {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::If(ref cond, _, Some(ref els)) = item.kind {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_ast::ast::{Block, ItemKind, StmtKind};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
@@ -54,7 +54,7 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]);
|
||||
|
||||
impl EarlyLintPass for ItemsAfterStatements {
|
||||
fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) {
|
||||
if in_external_macro(cx.sess(), item.span) {
|
||||
if in_external_macro(cx.sess, item.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ impl EarlyLintPass for ItemsAfterStatements {
|
||||
// lint on all further items
|
||||
for stmt in stmts {
|
||||
if let StmtKind::Item(ref it) = *stmt {
|
||||
if in_external_macro(cx.sess(), it.span) {
|
||||
if in_external_macro(cx.sess, it.span) {
|
||||
return;
|
||||
}
|
||||
if let ItemKind::MacroDef(..) = it.kind {
|
||||
|
||||
@@ -207,8 +207,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
|
||||
}
|
||||
}
|
||||
|
||||
if cx.access_levels.is_exported(visited_trait.def_id)
|
||||
&& trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
|
||||
if cx.access_levels.is_exported(visited_trait.def_id) && trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
|
||||
{
|
||||
let mut current_and_super_traits = DefIdSet::default();
|
||||
fill_trait_set(visited_trait.def_id.to_def_id(), &mut current_and_super_traits, cx);
|
||||
@@ -331,17 +330,15 @@ fn check_for_is_empty(
|
||||
None,
|
||||
None,
|
||||
),
|
||||
Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => {
|
||||
(
|
||||
format!(
|
||||
"{} `{}` has a public `len` method, but a private `is_empty` method",
|
||||
item_kind,
|
||||
item_name.as_str(),
|
||||
),
|
||||
Some(cx.tcx.def_span(is_empty.def_id)),
|
||||
None,
|
||||
)
|
||||
},
|
||||
Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => (
|
||||
format!(
|
||||
"{} `{}` has a public `len` method, but a private `is_empty` method",
|
||||
item_kind,
|
||||
item_name.as_str(),
|
||||
),
|
||||
Some(cx.tcx.def_span(is_empty.def_id)),
|
||||
None,
|
||||
),
|
||||
Some(is_empty)
|
||||
if !(is_empty.fn_has_self_parameter
|
||||
&& check_is_empty_sig(cx.tcx.fn_sig(is_empty.def_id).skip_binder(), self_kind, output)) =>
|
||||
|
||||
@@ -797,6 +797,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
methods::UNNECESSARY_FILTER_MAP,
|
||||
methods::UNNECESSARY_FOLD,
|
||||
methods::UNNECESSARY_LAZY_EVALUATIONS,
|
||||
methods::UNWRAP_OR_ELSE_DEFAULT,
|
||||
methods::UNWRAP_USED,
|
||||
methods::USELESS_ASREF,
|
||||
methods::WRONG_SELF_CONVENTION,
|
||||
@@ -1341,6 +1342,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(methods::UNNECESSARY_FILTER_MAP),
|
||||
LintId::of(methods::UNNECESSARY_FOLD),
|
||||
LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
|
||||
LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
|
||||
LintId::of(methods::USELESS_ASREF),
|
||||
LintId::of(methods::WRONG_SELF_CONVENTION),
|
||||
LintId::of(methods::ZST_OFFSET),
|
||||
@@ -1535,6 +1537,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(methods::STRING_EXTEND_CHARS),
|
||||
LintId::of(methods::UNNECESSARY_FOLD),
|
||||
LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
|
||||
LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
|
||||
LintId::of(methods::WRONG_SELF_CONVENTION),
|
||||
LintId::of(misc::TOPLEVEL_REF_ARG),
|
||||
LintId::of(misc::ZERO_PTR),
|
||||
|
||||
@@ -10,7 +10,7 @@ use clippy_utils::{
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use std::iter;
|
||||
@@ -222,7 +222,7 @@ impl_lint_pass!(LiteralDigitGrouping => [
|
||||
|
||||
impl EarlyLintPass for LiteralDigitGrouping {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
if in_external_macro(cx.sess, expr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -415,7 +415,7 @@ impl_lint_pass!(DecimalLiteralRepresentation => [DECIMAL_LITERAL_REPRESENTATION]
|
||||
|
||||
impl EarlyLintPass for DecimalLiteralRepresentation {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
if in_external_macro(cx.sess, expr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -204,11 +204,8 @@ struct MinifyingSugg<'a>(Sugg<'a>);
|
||||
|
||||
impl<'a> MinifyingSugg<'a> {
|
||||
fn as_str(&self) -> &str {
|
||||
// HACK: Don't sync to Clippy! Required because something with the `or_patterns` feature
|
||||
// changed and this would now require parentheses.
|
||||
match &self.0 {
|
||||
Sugg::NonParen(s) | Sugg::MaybeParen(s) | Sugg::BinOp(_, s) => s.as_ref(),
|
||||
}
|
||||
let (Sugg::NonParen(s) | Sugg::MaybeParen(s) | Sugg::BinOp(_, s)) = &self.0;
|
||||
s.as_ref()
|
||||
}
|
||||
|
||||
fn into_sugg(self) -> Sugg<'a> {
|
||||
|
||||
@@ -1,13 +1,36 @@
|
||||
use super::utils::make_iterator_snippet;
|
||||
use super::NEVER_LOOP;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, Stmt, StmtKind};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind, HirId, InlineAsmOperand, LoopSource, Node, Pat, Stmt, StmtKind};
|
||||
use rustc_lint::LateContext;
|
||||
use std::iter::{once, Iterator};
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Loop(block, _, _, _) = expr.kind {
|
||||
if let ExprKind::Loop(block, _, source, _) = expr.kind {
|
||||
match never_loop_block(block, expr.hir_id) {
|
||||
NeverLoopResult::AlwaysBreak => span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"),
|
||||
NeverLoopResult::AlwaysBreak => {
|
||||
span_lint_and_then(cx, NEVER_LOOP, expr.span, "this loop never actually loops", |diag| {
|
||||
if_chain! {
|
||||
if let LoopSource::ForLoop = source;
|
||||
if let Some((_, Node::Expr(parent_match))) = cx.tcx.hir().parent_iter(expr.hir_id).nth(1);
|
||||
if let Some((pat, iterator, _, for_span)) = higher::for_loop(parent_match);
|
||||
then {
|
||||
// Suggests using an `if let` instead. This is `Unspecified` because the
|
||||
// loop may (probably) contain `break` statements which would be invalid
|
||||
// in an `if let`.
|
||||
diag.span_suggestion_verbose(
|
||||
for_span.with_hi(iterator.span.hi()),
|
||||
"if you need the first element of the iterator, try writing",
|
||||
for_to_if_let_sugg(cx, iterator, pat),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
|
||||
}
|
||||
}
|
||||
@@ -170,3 +193,14 @@ fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(e: &mut T, main_
|
||||
e.map(|e| never_loop_expr(e, main_loop_id))
|
||||
.fold(NeverLoopResult::AlwaysBreak, combine_branches)
|
||||
}
|
||||
|
||||
fn for_to_if_let_sugg(cx: &LateContext<'_>, iterator: &Expr<'_>, pat: &Pat<'_>) -> String {
|
||||
let pat_snippet = snippet(cx, pat.span, "_");
|
||||
let iter_snippet = make_iterator_snippet(cx, iterator, &mut Applicability::Unspecified);
|
||||
|
||||
format!(
|
||||
"if let Some({pat}) = {iter}.next()",
|
||||
pat = pat_snippet,
|
||||
iter = iter_snippet
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use clippy_utils::{
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, MatchSource, Node, PatKind, QPath, UnOp};
|
||||
use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, MatchSource, Mutability, Node, PatKind, QPath, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::{symbol::sym, Span, Symbol};
|
||||
|
||||
@@ -48,7 +48,12 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
// borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used
|
||||
// afterwards a mutable borrow of a field isn't necessary.
|
||||
let ref_mut = if !iter_expr.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr, loop_expr) {
|
||||
"&mut "
|
||||
if cx.typeck_results().node_type(iter_expr.hir_id).ref_mutability() == Some(Mutability::Mut) {
|
||||
// Reborrow for mutable references. It may not be possible to get a mutable reference here.
|
||||
"&mut *"
|
||||
} else {
|
||||
"&mut "
|
||||
}
|
||||
} else {
|
||||
""
|
||||
};
|
||||
@@ -69,6 +74,8 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
struct IterExpr {
|
||||
/// The span of the whole expression, not just the path and fields stored here.
|
||||
span: Span,
|
||||
/// The HIR id of the whole expression, not just the path and fields stored here.
|
||||
hir_id: HirId,
|
||||
/// The fields used, in order of child to parent.
|
||||
fields: Vec<Symbol>,
|
||||
/// The path being used.
|
||||
@@ -78,12 +85,14 @@ struct IterExpr {
|
||||
/// the expression might have side effects.
|
||||
fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExpr> {
|
||||
let span = e.span;
|
||||
let hir_id = e.hir_id;
|
||||
let mut fields = Vec::new();
|
||||
loop {
|
||||
match e.kind {
|
||||
ExprKind::Path(ref path) => {
|
||||
break Some(IterExpr {
|
||||
span,
|
||||
hir_id,
|
||||
fields,
|
||||
path: cx.qpath_res(path, e.hir_id),
|
||||
});
|
||||
@@ -137,7 +146,7 @@ fn is_expr_same_child_or_parent_field(cx: &LateContext<'_>, expr: &Expr<'_>, fie
|
||||
match expr.kind {
|
||||
ExprKind::Field(base, name) => {
|
||||
if let Some((head_field, tail_fields)) = fields.split_first() {
|
||||
if name.name == *head_field && is_expr_same_field(cx, base, fields, path_res) {
|
||||
if name.name == *head_field && is_expr_same_field(cx, base, tail_fields, path_res) {
|
||||
return true;
|
||||
}
|
||||
// Check if the expression is a parent field
|
||||
|
||||
@@ -16,7 +16,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
|
||||
//check source object
|
||||
if let ExprKind::MethodCall(src_method, _, [drain_vec, drain_arg], _) = &arg.kind;
|
||||
if src_method.ident.as_str() == "drain";
|
||||
if let src_ty = cx.typeck_results().expr_ty(drain_vec).peel_refs();
|
||||
let src_ty = cx.typeck_results().expr_ty(drain_vec);
|
||||
//check if actual src type is mutable for code suggestion
|
||||
let immutable = src_ty.is_mutable_ptr();
|
||||
let src_ty = src_ty.peel_refs();
|
||||
if is_type_diagnostic_item(cx, src_ty, sym::vec_type);
|
||||
//check drain range
|
||||
if let src_ty_range = cx.typeck_results().expr_ty(drain_arg).peel_refs();
|
||||
@@ -30,8 +33,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
|
||||
"use of `extend` instead of `append` for adding the full range of a second vector",
|
||||
"try this",
|
||||
format!(
|
||||
"{}.append(&mut {})",
|
||||
"{}.append({}{})",
|
||||
snippet_with_applicability(cx, recv.span, "..", &mut applicability),
|
||||
if immutable { "" } else { "&mut " },
|
||||
snippet_with_applicability(cx, drain_vec.span, "..", &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{is_expr_path_def_path, paths, sugg};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::sym;
|
||||
|
||||
@@ -43,7 +44,7 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -
|
||||
|
||||
let call_site = expr.span.source_callsite();
|
||||
if_chain! {
|
||||
if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site);
|
||||
if let Some(snippet) = snippet_opt(cx, call_site);
|
||||
let snippet_split = snippet.split("::").collect::<Vec<_>>();
|
||||
if let Some((_, elements)) = snippet_split.split_last();
|
||||
|
||||
|
||||
@@ -52,18 +52,32 @@ pub(super) fn check<'tcx>(
|
||||
);
|
||||
}
|
||||
|
||||
// lint if caller of `.map().flatten()` is an Option
|
||||
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type) {
|
||||
let func_snippet = snippet(cx, map_arg.span, "..");
|
||||
let hint = format!(".and_then({})", func_snippet);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MAP_FLATTEN,
|
||||
expr.span.with_lo(recv.span.hi()),
|
||||
"called `map(..).flatten()` on an `Option`",
|
||||
"try using `and_then` instead",
|
||||
hint,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
// lint if caller of `.map().flatten()` is an Option or Result
|
||||
let caller_type = match cx.typeck_results().expr_ty(recv).kind() {
|
||||
ty::Adt(adt, _) => {
|
||||
if cx.tcx.is_diagnostic_item(sym::option_type, adt.did) {
|
||||
"Option"
|
||||
} else if cx.tcx.is_diagnostic_item(sym::result_type, adt.did) {
|
||||
"Result"
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
let func_snippet = snippet(cx, map_arg.span, "..");
|
||||
let hint = format!(".and_then({})", func_snippet);
|
||||
let lint_info = format!("called `map(..).flatten()` on an `{}`", caller_type);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MAP_FLATTEN,
|
||||
expr.span.with_lo(recv.span.hi()),
|
||||
&lint_info,
|
||||
"try using `and_then` instead",
|
||||
hint,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ mod uninit_assumed_init;
|
||||
mod unnecessary_filter_map;
|
||||
mod unnecessary_fold;
|
||||
mod unnecessary_lazy_eval;
|
||||
mod unwrap_or_else_default;
|
||||
mod unwrap_used;
|
||||
mod useless_asref;
|
||||
mod utils;
|
||||
@@ -310,6 +311,31 @@ declare_clippy_lint! {
|
||||
"using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and
|
||||
/// `Result` values.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Readability, these can be written as `_.unwrap_or_default`, which is
|
||||
/// simpler and more concise.
|
||||
///
|
||||
/// ### Examples
|
||||
/// ```rust
|
||||
/// # let x = Some(1);
|
||||
///
|
||||
/// // Bad
|
||||
/// x.unwrap_or_else(Default::default);
|
||||
/// x.unwrap_or_else(u32::default);
|
||||
///
|
||||
/// // Good
|
||||
/// x.unwrap_or_default();
|
||||
/// ```
|
||||
pub UNWRAP_OR_ELSE_DEFAULT,
|
||||
style,
|
||||
"using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or
|
||||
@@ -1766,6 +1792,7 @@ impl_lint_pass!(Methods => [
|
||||
SHOULD_IMPLEMENT_TRAIT,
|
||||
WRONG_SELF_CONVENTION,
|
||||
OK_EXPECT,
|
||||
UNWRAP_OR_ELSE_DEFAULT,
|
||||
MAP_UNWRAP_OR,
|
||||
RESULT_MAP_OR_INTO_OPTION,
|
||||
OPTION_MAP_OR_NONE,
|
||||
@@ -2172,7 +2199,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
|
||||
},
|
||||
("unwrap_or_else", [u_arg]) => match method_call!(recv) {
|
||||
Some(("map", [recv, map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, msrv) => {},
|
||||
_ => unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"),
|
||||
_ => {
|
||||
unwrap_or_else_default::check(cx, expr, recv, u_arg);
|
||||
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
|
||||
},
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::eager_or_lazy::is_lazyness_candidate;
|
||||
use clippy_utils::is_trait_item;
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_macro_callsite};
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type};
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, match_type};
|
||||
use clippy_utils::{contains_return, last_path_segment, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
@@ -34,15 +36,23 @@ pub(super) fn check<'tcx>(
|
||||
or_has_args: bool,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
let is_default_default = || is_trait_item(cx, fun, sym::Default);
|
||||
|
||||
let implements_default = |arg, default_trait_id| {
|
||||
let arg_ty = cx.typeck_results().expr_ty(arg);
|
||||
implements_trait(cx, arg_ty, default_trait_id, &[])
|
||||
};
|
||||
|
||||
if_chain! {
|
||||
if !or_has_args;
|
||||
if name == "unwrap_or";
|
||||
if let hir::ExprKind::Path(ref qpath) = fun.kind;
|
||||
let path = last_path_segment(qpath).ident.name;
|
||||
if matches!(path, kw::Default | sym::new);
|
||||
let arg_ty = cx.typeck_results().expr_ty(arg);
|
||||
if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
|
||||
if implements_trait(cx, arg_ty, default_trait_id, &[]);
|
||||
let path = last_path_segment(qpath).ident.name;
|
||||
// needs to target Default::default in particular or be *::new and have a Default impl
|
||||
// available
|
||||
if (matches!(path, kw::Default) && is_default_default())
|
||||
|| (matches!(path, sym::new) && implements_default(arg, default_trait_id));
|
||||
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
45
clippy_lints/src/methods/unwrap_or_else_default.rs
Normal file
45
clippy_lints/src/methods/unwrap_or_else_default.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
//! Lint for `some_result_or_option.unwrap_or_else(Default::default)`
|
||||
|
||||
use super::UNWRAP_OR_ELSE_DEFAULT;
|
||||
use clippy_utils::{
|
||||
diagnostics::span_lint_and_sugg, is_trait_item, source::snippet_with_applicability, ty::is_type_diagnostic_item,
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'_>,
|
||||
recv: &'tcx hir::Expr<'_>,
|
||||
u_arg: &'tcx hir::Expr<'_>,
|
||||
) {
|
||||
// something.unwrap_or_else(Default::default)
|
||||
// ^^^^^^^^^- recv ^^^^^^^^^^^^^^^^- u_arg
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr
|
||||
let recv_ty = cx.typeck_results().expr_ty(recv);
|
||||
let is_option = is_type_diagnostic_item(cx, recv_ty, sym::option_type);
|
||||
let is_result = is_type_diagnostic_item(cx, recv_ty, sym::result_type);
|
||||
|
||||
if_chain! {
|
||||
if is_option || is_result;
|
||||
if is_trait_item(cx, u_arg, sym::Default);
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNWRAP_OR_ELSE_DEFAULT,
|
||||
expr.span,
|
||||
"use of `.unwrap_or_else(..)` to construct default value",
|
||||
"try",
|
||||
format!(
|
||||
"{}.unwrap_or_default()",
|
||||
snippet_with_applicability(cx, recv.span, "..", &mut applicability)
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ use clippy_utils::source::snippet_opt;
|
||||
use rustc_ast::ast::{Expr, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
|
||||
use rustc_ast::visit::FnKind;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
@@ -307,7 +307,7 @@ impl EarlyLintPass for MiscEarlyLints {
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
if in_external_macro(cx.sess, expr.span) {
|
||||
return;
|
||||
}
|
||||
double_neg::check(cx, expr);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use rustc_ast::ast::{Pat, PatKind};
|
||||
use rustc_lint::{EarlyContext, LintContext};
|
||||
use rustc_lint::EarlyContext;
|
||||
|
||||
use super::UNNEEDED_FIELD_PATTERN;
|
||||
|
||||
@@ -48,7 +49,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
|
||||
match field.pat.kind {
|
||||
PatKind::Wild => {},
|
||||
_ => {
|
||||
if let Ok(n) = cx.sess().source_map().span_to_snippet(field.span) {
|
||||
if let Some(n) = snippet_opt(cx, field.span) {
|
||||
normal.push(n);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
|
||||
use clippy_utils::attrs::is_doc_hidden;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_ast::ast;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{self, MetaItem, MetaItemKind};
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::ty;
|
||||
@@ -55,6 +56,20 @@ impl MissingDoc {
|
||||
*self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
|
||||
}
|
||||
|
||||
fn has_include(meta: Option<MetaItem>) -> bool {
|
||||
if_chain! {
|
||||
if let Some(meta) = meta;
|
||||
if let MetaItemKind::List(list) = meta.kind;
|
||||
if let Some(meta) = list.get(0);
|
||||
if let Some(name) = meta.ident();
|
||||
then {
|
||||
name.name == sym::include
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_missing_docs_attrs(
|
||||
&self,
|
||||
cx: &LateContext<'_>,
|
||||
@@ -80,7 +95,7 @@ impl MissingDoc {
|
||||
|
||||
let has_doc = attrs
|
||||
.iter()
|
||||
.any(|a| a.doc_str().is_some());
|
||||
.any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
|
||||
if !has_doc {
|
||||
span_lint(
|
||||
cx,
|
||||
|
||||
@@ -87,10 +87,6 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
|
||||
self.found = true;
|
||||
return;
|
||||
},
|
||||
ExprKind::If(..) => {
|
||||
self.found = true;
|
||||
return;
|
||||
},
|
||||
ExprKind::Path(_) => {
|
||||
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
|
||||
if adj
|
||||
|
||||
@@ -27,11 +27,15 @@ declare_clippy_lint! {
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// fn fun(_a: &i32) {}
|
||||
///
|
||||
/// // Bad
|
||||
/// let x: &i32 = &&&&&&5;
|
||||
/// fun(&x);
|
||||
///
|
||||
/// // Good
|
||||
/// let x: &i32 = &5;
|
||||
/// fun(x);
|
||||
/// ```
|
||||
pub NEEDLESS_BORROW,
|
||||
style,
|
||||
|
||||
@@ -422,7 +422,7 @@ fn check_and_warn<'a>(cx: &EarlyContext<'_>, expr: &'a ast::Expr) {
|
||||
///
|
||||
/// is transformed to
|
||||
///
|
||||
/// ```ignore
|
||||
/// ```text
|
||||
/// {
|
||||
/// let x = 5;
|
||||
/// ```
|
||||
|
||||
@@ -122,7 +122,7 @@ impl LateLintPass<'_> for NeedlessForEach {
|
||||
/// 2. Detect use of `return` in `Loop` in the closure body.
|
||||
///
|
||||
/// NOTE: The functionality of this type is similar to
|
||||
/// [`crate::utilts::visitors::find_all_ret_expressions`], but we can't use
|
||||
/// [`clippy_utils::visitors::find_all_ret_expressions`], but we can't use
|
||||
/// `find_all_ret_expressions` instead of this type. The reasons are:
|
||||
/// 1. `find_all_ret_expressions` passes the argument of `ExprKind::Ret` to a callback, but what we
|
||||
/// need here is `ExprKind::Ret` itself.
|
||||
|
||||
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::has_drop;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource};
|
||||
use rustc_hir::{is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use std::ops::Deref;
|
||||
@@ -68,12 +68,14 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
ExprKind::Call(callee, args) => {
|
||||
if let ExprKind::Path(ref qpath) = callee.kind {
|
||||
let res = cx.qpath_res(qpath, callee.hir_id);
|
||||
match res {
|
||||
Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..) => {
|
||||
!has_drop(cx, cx.typeck_results().expr_ty(expr))
|
||||
&& args.iter().all(|arg| has_no_effect(cx, arg))
|
||||
},
|
||||
_ => false,
|
||||
let def_matched = matches!(
|
||||
res,
|
||||
Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..)
|
||||
);
|
||||
if def_matched || is_range_literal(expr) {
|
||||
!has_drop(cx, cx.typeck_results().expr_ty(expr)) && args.iter().all(|arg| has_no_effect(cx, arg))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
||||
use rustc_ast::ast::{
|
||||
Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, FnKind, Item, ItemKind, Local, Pat,
|
||||
PatKind,
|
||||
Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, FnKind, Item, ItemKind, Local, Pat, PatKind,
|
||||
};
|
||||
use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
@@ -127,6 +126,7 @@ const ALLOWED_TO_BE_SIMILAR: &[&[&str]] = &[
|
||||
&["qpath", "path"],
|
||||
&["lit", "lint"],
|
||||
&["wparam", "lparam"],
|
||||
&["iter", "item"],
|
||||
];
|
||||
|
||||
struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>);
|
||||
|
||||
@@ -7,6 +7,7 @@ use clippy_utils::{diagnostics::span_lint_and_help, in_macro, is_direct_expn_of,
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::Span;
|
||||
@@ -91,13 +92,23 @@ impl EarlyLintPass for MacroBraces {
|
||||
}
|
||||
|
||||
fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a MacroBraces) -> Option<MacroInfo<'a>> {
|
||||
let unnested_or_local = || {
|
||||
let nested = in_macro(span.ctxt().outer_expn_data().call_site);
|
||||
!nested
|
||||
|| span
|
||||
.macro_backtrace()
|
||||
.last()
|
||||
.map_or(false, |e| e.macro_def_id.map_or(false, DefId::is_local))
|
||||
};
|
||||
if_chain! {
|
||||
// Make sure we are only one level deep otherwise there are to many FP's
|
||||
if in_macro(span);
|
||||
if let Some((name, braces)) = find_matching_macro(span, &mac_braces.macro_braces);
|
||||
if let Some(snip) = snippet_opt(cx, span.ctxt().outer_expn_data().call_site);
|
||||
// we must check only invocation sites
|
||||
// https://github.com/rust-lang/rust-clippy/issues/7422
|
||||
if snip.starts_with(name);
|
||||
if snip.starts_with(&format!("{}!", name));
|
||||
if unnested_or_local();
|
||||
// make formatting consistent
|
||||
let c = snip.replace(" ", "");
|
||||
if !c.starts_with(&format!("{}!{}", name, braces.0));
|
||||
|
||||
@@ -2,9 +2,9 @@ use std::cmp;
|
||||
use std::iter;
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_self_ty;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_copy;
|
||||
use clippy_utils::{is_self, is_self_ty};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::attr;
|
||||
use rustc_errors::Applicability;
|
||||
@@ -170,7 +170,7 @@ impl<'tcx> PassByRefOrValue {
|
||||
if size <= self.ref_min_size;
|
||||
if let hir::TyKind::Rptr(_, MutTy { ty: decl_ty, .. }) = input.kind;
|
||||
then {
|
||||
let value_type = if is_self_ty(decl_ty) {
|
||||
let value_type = if fn_body.and_then(|body| body.params.get(index)).map_or(false, is_self) {
|
||||
"self".into()
|
||||
} else {
|
||||
snippet(cx, decl_ty.span, "_").into()
|
||||
|
||||
@@ -725,7 +725,7 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
|
||||
BinaryOp(_, box (lhs, rhs)) | CheckedBinaryOp(_, box (lhs, rhs)) => {
|
||||
visit_op(lhs);
|
||||
visit_op(rhs);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit as hir_visit;
|
||||
use rustc_hir::intravisit::Visitor as HirVisitor;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@@ -63,7 +63,7 @@ impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor {
|
||||
|
||||
impl EarlyLintPass for RedundantClosureCall {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
if in_external_macro(cx.sess, expr.span) {
|
||||
return;
|
||||
}
|
||||
if_chain! {
|
||||
|
||||
@@ -54,7 +54,8 @@ impl EarlyLintPass for DerefAddrOf {
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let sugg = if e.span.from_expansion() {
|
||||
if let Ok(macro_source) = cx.sess.source_map().span_to_snippet(e.span) {
|
||||
#[allow(clippy::option_if_let_else)]
|
||||
if let Some(macro_source) = snippet_opt(cx, e.span) {
|
||||
// Remove leading whitespace from the given span
|
||||
// e.g: ` $visitor` turns into `$visitor`
|
||||
let trim_leading_whitespaces = |span| {
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{differing_macro_contexts, eq_expr_value};
|
||||
use clippy_utils::{can_mut_borrow_both, differing_macro_contexts, eq_expr_value};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, StmtKind};
|
||||
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{sym, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@@ -70,9 +71,67 @@ impl<'tcx> LateLintPass<'tcx> for Swap {
|
||||
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
|
||||
check_manual_swap(cx, block);
|
||||
check_suspicious_swap(cx, block);
|
||||
check_xor_swap(cx, block);
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, span: Span, is_xor_based: bool) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
if !can_mut_borrow_both(cx, e1, e2) {
|
||||
if let ExprKind::Index(lhs1, idx1) = e1.kind {
|
||||
if let ExprKind::Index(lhs2, idx2) = e2.kind {
|
||||
if eq_expr_value(cx, lhs1, lhs2) {
|
||||
let ty = cx.typeck_results().expr_ty(lhs1).peel_refs();
|
||||
|
||||
if matches!(ty.kind(), ty::Slice(_))
|
||||
|| matches!(ty.kind(), ty::Array(_, _))
|
||||
|| is_type_diagnostic_item(cx, ty, sym::vec_type)
|
||||
|| is_type_diagnostic_item(cx, ty, sym::vecdeque_type)
|
||||
{
|
||||
let slice = Sugg::hir_with_applicability(cx, lhs1, "<slice>", &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_SWAP,
|
||||
span,
|
||||
&format!("this looks like you are swapping elements of `{}` manually", slice),
|
||||
"try",
|
||||
format!(
|
||||
"{}.swap({}, {})",
|
||||
slice.maybe_par(),
|
||||
snippet_with_applicability(cx, idx1.span, "..", &mut applicability),
|
||||
snippet_with_applicability(cx, idx2.span, "..", &mut applicability),
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let first = Sugg::hir_with_applicability(cx, e1, "..", &mut applicability);
|
||||
let second = Sugg::hir_with_applicability(cx, e2, "..", &mut applicability);
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MANUAL_SWAP,
|
||||
span,
|
||||
&format!("this looks like you are swapping `{}` and `{}` manually", first, second),
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"try",
|
||||
format!("std::mem::swap({}, {})", first.mut_addr(), second.mut_addr()),
|
||||
applicability,
|
||||
);
|
||||
if !is_xor_based {
|
||||
diag.note("or maybe you should use `std::mem::replace`?");
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Implementation of the `MANUAL_SWAP` lint.
|
||||
fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||
for w in block.stmts.windows(3) {
|
||||
@@ -96,123 +155,13 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||
if eq_expr_value(cx, tmp_init, lhs1);
|
||||
if eq_expr_value(cx, rhs1, lhs2);
|
||||
then {
|
||||
if let ExprKind::Field(lhs1, _) = lhs1.kind {
|
||||
if let ExprKind::Field(lhs2, _) = lhs2.kind {
|
||||
if lhs1.hir_id.owner == lhs2.hir_id.owner {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
let slice = check_for_slice(cx, lhs1, lhs2);
|
||||
let (replace, what, sugg) = if let Slice::NotSwappable = slice {
|
||||
return;
|
||||
} else if let Slice::Swappable(slice, idx1, idx2) = slice {
|
||||
if let Some(slice) = Sugg::hir_opt(cx, slice) {
|
||||
(
|
||||
false,
|
||||
format!(" elements of `{}`", slice),
|
||||
format!(
|
||||
"{}.swap({}, {})",
|
||||
slice.maybe_par(),
|
||||
snippet_with_applicability(cx, idx1.span, "..", &mut applicability),
|
||||
snippet_with_applicability(cx, idx2.span, "..", &mut applicability),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
(false, String::new(), String::new())
|
||||
}
|
||||
} else if let (Some(first), Some(second)) = (Sugg::hir_opt(cx, lhs1), Sugg::hir_opt(cx, rhs1)) {
|
||||
(
|
||||
true,
|
||||
format!(" `{}` and `{}`", first, second),
|
||||
format!("std::mem::swap({}, {})", first.mut_addr(), second.mut_addr()),
|
||||
)
|
||||
} else {
|
||||
(true, String::new(), String::new())
|
||||
};
|
||||
|
||||
let span = w[0].span.to(second.span);
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MANUAL_SWAP,
|
||||
span,
|
||||
&format!("this looks like you are swapping{} manually", what),
|
||||
|diag| {
|
||||
if !sugg.is_empty() {
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"try",
|
||||
sugg,
|
||||
applicability,
|
||||
);
|
||||
|
||||
if replace {
|
||||
diag.note("or maybe you should use `std::mem::replace`?");
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
generate_swap_warning(cx, lhs1, lhs2, span, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Slice<'a> {
|
||||
/// `slice.swap(idx1, idx2)` can be used
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # let mut a = vec![0, 1];
|
||||
/// let t = a[1];
|
||||
/// a[1] = a[0];
|
||||
/// a[0] = t;
|
||||
/// // can be written as
|
||||
/// a.swap(0, 1);
|
||||
/// ```
|
||||
Swappable(&'a Expr<'a>, &'a Expr<'a>, &'a Expr<'a>),
|
||||
/// The `swap` function cannot be used.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # let mut a = [vec![1, 2], vec![3, 4]];
|
||||
/// let t = a[0][1];
|
||||
/// a[0][1] = a[1][0];
|
||||
/// a[1][0] = t;
|
||||
/// ```
|
||||
NotSwappable,
|
||||
/// Not a slice
|
||||
None,
|
||||
}
|
||||
|
||||
/// Checks if both expressions are index operations into "slice-like" types.
|
||||
fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr<'_>) -> Slice<'a> {
|
||||
if let ExprKind::Index(lhs1, idx1) = lhs1.kind {
|
||||
if let ExprKind::Index(lhs2, idx2) = lhs2.kind {
|
||||
if eq_expr_value(cx, lhs1, lhs2) {
|
||||
let ty = cx.typeck_results().expr_ty(lhs1).peel_refs();
|
||||
|
||||
if matches!(ty.kind(), ty::Slice(_))
|
||||
|| matches!(ty.kind(), ty::Array(_, _))
|
||||
|| is_type_diagnostic_item(cx, ty, sym::vec_type)
|
||||
|| is_type_diagnostic_item(cx, ty, sym::vecdeque_type)
|
||||
{
|
||||
return Slice::Swappable(lhs1, idx1, idx2);
|
||||
}
|
||||
} else {
|
||||
return Slice::NotSwappable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Slice::None
|
||||
}
|
||||
|
||||
/// Implementation of the `ALMOST_SWAPPED` lint.
|
||||
fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||
for w in block.stmts.windows(2) {
|
||||
@@ -262,3 +211,40 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of the xor case for `MANUAL_SWAP` lint.
|
||||
fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||
for window in block.stmts.windows(3) {
|
||||
if_chain! {
|
||||
if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(&window[0]);
|
||||
if let Some((lhs1, rhs1)) = extract_sides_of_xor_assign(&window[1]);
|
||||
if let Some((lhs2, rhs2)) = extract_sides_of_xor_assign(&window[2]);
|
||||
if eq_expr_value(cx, lhs0, rhs1);
|
||||
if eq_expr_value(cx, lhs2, rhs1);
|
||||
if eq_expr_value(cx, lhs1, rhs0);
|
||||
if eq_expr_value(cx, lhs1, rhs2);
|
||||
then {
|
||||
let span = window[0].span.to(window[2].span);
|
||||
generate_swap_warning(cx, lhs0, rhs0, span, true);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the lhs and rhs of an xor assignment statement.
|
||||
fn extract_sides_of_xor_assign<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(&'a Expr<'hir>, &'a Expr<'hir>)> {
|
||||
if let StmtKind::Semi(expr) = stmt.kind {
|
||||
if let ExprKind::AssignOp(
|
||||
Spanned {
|
||||
node: BinOpKind::BitXor,
|
||||
..
|
||||
},
|
||||
lhs,
|
||||
rhs,
|
||||
) = expr.kind
|
||||
{
|
||||
return Some((lhs, rhs));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ declare_clippy_lint! {
|
||||
/// Checks for use of redundant allocations anywhere in the code.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Arc<T>>`, `Rc<Box<T>>`, Arc<&T>`, `Arc<Rc<T>>`,
|
||||
/// Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Arc<T>>`, `Rc<Box<T>>`, `Arc<&T>`, `Arc<Rc<T>>`,
|
||||
/// `Arc<Arc<T>>`, `Arc<Box<T>>`, `Box<&T>`, `Box<Rc<T>>`, `Box<Arc<T>>`, `Box<Box<T>>`, add an unnecessary level of indirection.
|
||||
///
|
||||
/// ### Example
|
||||
|
||||
@@ -35,8 +35,6 @@ declare_clippy_lint! {
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// #![feature(or_patterns)]
|
||||
///
|
||||
/// fn main() {
|
||||
/// if let Some(0 | 2) = Some(0) {}
|
||||
/// }
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::position_before_rarrow;
|
||||
use clippy_utils::source::{position_before_rarrow, snippet_opt};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_ast::visit::FnKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::BytePos;
|
||||
@@ -125,17 +125,16 @@ fn is_unit_expr(expr: &ast::Expr) -> bool {
|
||||
}
|
||||
|
||||
fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) {
|
||||
let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) {
|
||||
position_before_rarrow(&fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
|
||||
(
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
})
|
||||
} else {
|
||||
(ty.span, Applicability::MaybeIncorrect)
|
||||
};
|
||||
let (ret_span, appl) =
|
||||
snippet_opt(cx, span.with_hi(ty.span.hi())).map_or((ty.span, Applicability::MaybeIncorrect), |fn_source| {
|
||||
position_before_rarrow(&fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| {
|
||||
(
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
})
|
||||
});
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNUSED_UNIT,
|
||||
|
||||
@@ -36,13 +36,13 @@ impl TryConf {
|
||||
/// See (rust-clippy#7172)
|
||||
macro_rules! define_Conf {
|
||||
($(
|
||||
#[doc = $doc:literal]
|
||||
$(#[doc = $doc:literal])+
|
||||
$(#[conf_deprecated($dep:literal)])?
|
||||
($name:ident: $ty:ty = $default:expr),
|
||||
)*) => {
|
||||
/// Clippy lint configuration
|
||||
pub struct Conf {
|
||||
$(#[doc = $doc] pub $name: $ty,)*
|
||||
$($(#[doc = $doc])+ pub $name: $ty,)*
|
||||
}
|
||||
|
||||
mod defaults {
|
||||
@@ -119,7 +119,7 @@ macro_rules! define_Conf {
|
||||
stringify!($name),
|
||||
stringify!($ty),
|
||||
format!("{:?}", super::defaults::$name()),
|
||||
$doc,
|
||||
concat!($($doc, '\n',)*),
|
||||
deprecation_reason,
|
||||
)
|
||||
},
|
||||
@@ -132,18 +132,30 @@ macro_rules! define_Conf {
|
||||
|
||||
// N.B., this macro is parsed by util/lintlib.py
|
||||
define_Conf! {
|
||||
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION. Suppress lints whenever the suggested change would cause breakage for other crates.
|
||||
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION.
|
||||
///
|
||||
/// Suppress lints whenever the suggested change would cause breakage for other crates.
|
||||
(avoid_breaking_exported_api: bool = true),
|
||||
/// Lint: MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports
|
||||
/// Lint: MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE.
|
||||
///
|
||||
/// The minimum rust version that the project supports
|
||||
(msrv: Option<String> = None),
|
||||
/// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
|
||||
/// Lint: BLACKLISTED_NAME.
|
||||
///
|
||||
/// The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
|
||||
(blacklisted_names: Vec<String> = ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
|
||||
/// Lint: COGNITIVE_COMPLEXITY. The maximum cognitive complexity a function can have
|
||||
/// Lint: COGNITIVE_COMPLEXITY.
|
||||
///
|
||||
/// The maximum cognitive complexity a function can have
|
||||
(cognitive_complexity_threshold: u64 = 25),
|
||||
/// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. Use the Cognitive Complexity lint instead.
|
||||
/// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
|
||||
///
|
||||
/// Use the Cognitive Complexity lint instead.
|
||||
#[conf_deprecated("Please use `cognitive-complexity-threshold` instead")]
|
||||
(cyclomatic_complexity_threshold: Option<u64> = None),
|
||||
/// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
|
||||
/// Lint: DOC_MARKDOWN.
|
||||
///
|
||||
/// The list of words this lint should not consider as identifiers needing ticks
|
||||
(doc_valid_idents: Vec<String> = [
|
||||
"KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
|
||||
"DirectX",
|
||||
@@ -164,55 +176,109 @@ define_Conf! {
|
||||
"MinGW",
|
||||
"CamelCase",
|
||||
].iter().map(ToString::to_string).collect()),
|
||||
/// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
|
||||
/// Lint: TOO_MANY_ARGUMENTS.
|
||||
///
|
||||
/// The maximum number of argument a function or method can have
|
||||
(too_many_arguments_threshold: u64 = 7),
|
||||
/// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
|
||||
/// Lint: TYPE_COMPLEXITY.
|
||||
///
|
||||
/// The maximum complexity a type can have
|
||||
(type_complexity_threshold: u64 = 250),
|
||||
/// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
|
||||
/// Lint: MANY_SINGLE_CHAR_NAMES.
|
||||
///
|
||||
/// The maximum number of single char bindings a scope may have
|
||||
(single_char_binding_names_threshold: u64 = 4),
|
||||
/// Lint: BOXED_LOCAL, USELESS_VEC. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
|
||||
/// Lint: BOXED_LOCAL, USELESS_VEC.
|
||||
///
|
||||
/// The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
|
||||
(too_large_for_stack: u64 = 200),
|
||||
/// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
|
||||
/// Lint: ENUM_VARIANT_NAMES.
|
||||
///
|
||||
/// The minimum number of enum variants for the lints about variant names to trigger
|
||||
(enum_variant_name_threshold: u64 = 3),
|
||||
/// Lint: LARGE_ENUM_VARIANT. The maximum size of a enum's variant to avoid box suggestion
|
||||
/// Lint: LARGE_ENUM_VARIANT.
|
||||
///
|
||||
/// The maximum size of a enum's variant to avoid box suggestion
|
||||
(enum_variant_size_threshold: u64 = 200),
|
||||
/// Lint: VERBOSE_BIT_MASK. The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
|
||||
/// Lint: VERBOSE_BIT_MASK.
|
||||
///
|
||||
/// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
|
||||
(verbose_bit_mask_threshold: u64 = 1),
|
||||
/// Lint: DECIMAL_LITERAL_REPRESENTATION. The lower bound for linting decimal literals
|
||||
/// Lint: DECIMAL_LITERAL_REPRESENTATION.
|
||||
///
|
||||
/// The lower bound for linting decimal literals
|
||||
(literal_representation_threshold: u64 = 16384),
|
||||
/// Lint: TRIVIALLY_COPY_PASS_BY_REF. The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
|
||||
/// Lint: TRIVIALLY_COPY_PASS_BY_REF.
|
||||
///
|
||||
/// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
|
||||
(trivial_copy_size_limit: Option<u64> = None),
|
||||
/// Lint: LARGE_TYPE_PASS_BY_MOVE. The minimum size (in bytes) to consider a type for passing by reference instead of by value.
|
||||
/// Lint: LARGE_TYPE_PASS_BY_MOVE.
|
||||
///
|
||||
/// The minimum size (in bytes) to consider a type for passing by reference instead of by value.
|
||||
(pass_by_value_size_limit: u64 = 256),
|
||||
/// Lint: TOO_MANY_LINES. The maximum number of lines a function or method can have
|
||||
/// Lint: TOO_MANY_LINES.
|
||||
///
|
||||
/// The maximum number of lines a function or method can have
|
||||
(too_many_lines_threshold: u64 = 100),
|
||||
/// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS. The maximum allowed size for arrays on the stack
|
||||
/// Lint: LARGE_STACK_ARRAYS, LARGE_CONST_ARRAYS.
|
||||
///
|
||||
/// The maximum allowed size for arrays on the stack
|
||||
(array_size_threshold: u64 = 512_000),
|
||||
/// Lint: VEC_BOX. The size of the boxed type in bytes, where boxing in a `Vec` is allowed
|
||||
/// Lint: VEC_BOX.
|
||||
///
|
||||
/// The size of the boxed type in bytes, where boxing in a `Vec` is allowed
|
||||
(vec_box_size_threshold: u64 = 4096),
|
||||
/// Lint: TYPE_REPETITION_IN_BOUNDS. The maximum number of bounds a trait can have to be linted
|
||||
/// Lint: TYPE_REPETITION_IN_BOUNDS.
|
||||
///
|
||||
/// The maximum number of bounds a trait can have to be linted
|
||||
(max_trait_bounds: u64 = 3),
|
||||
/// Lint: STRUCT_EXCESSIVE_BOOLS. The maximum number of bool fields a struct can have
|
||||
/// Lint: STRUCT_EXCESSIVE_BOOLS.
|
||||
///
|
||||
/// The maximum number of bool fields a struct can have
|
||||
(max_struct_bools: u64 = 3),
|
||||
/// Lint: FN_PARAMS_EXCESSIVE_BOOLS. The maximum number of bool parameters a function can have
|
||||
/// Lint: FN_PARAMS_EXCESSIVE_BOOLS.
|
||||
///
|
||||
/// The maximum number of bool parameters a function can have
|
||||
(max_fn_params_bools: u64 = 3),
|
||||
/// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests).
|
||||
/// Lint: WILDCARD_IMPORTS.
|
||||
///
|
||||
/// Whether to allow certain wildcard imports (prelude, super in tests).
|
||||
(warn_on_all_wildcard_imports: bool = false),
|
||||
/// Lint: DISALLOWED_METHOD. The list of disallowed methods, written as fully qualified paths.
|
||||
/// Lint: DISALLOWED_METHOD.
|
||||
///
|
||||
/// The list of disallowed methods, written as fully qualified paths.
|
||||
(disallowed_methods: Vec<String> = Vec::new()),
|
||||
/// Lint: DISALLOWED_TYPE. The list of disallowed types, written as fully qualified paths.
|
||||
/// Lint: DISALLOWED_TYPE.
|
||||
///
|
||||
/// The list of disallowed types, written as fully qualified paths.
|
||||
(disallowed_types: Vec<String> = Vec::new()),
|
||||
/// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators.
|
||||
/// Lint: UNREADABLE_LITERAL.
|
||||
///
|
||||
/// Should the fraction of a decimal be linted to include separators.
|
||||
(unreadable_literal_lint_fractions: bool = true),
|
||||
/// Lint: UPPER_CASE_ACRONYMS. Enables verbose mode. Triggers if there is more than one uppercase char next to each other
|
||||
/// Lint: UPPER_CASE_ACRONYMS.
|
||||
///
|
||||
/// Enables verbose mode. Triggers if there is more than one uppercase char next to each other
|
||||
(upper_case_acronyms_aggressive: bool = false),
|
||||
/// Lint: _CARGO_COMMON_METADATA. For internal testing only, ignores the current `publish` settings in the Cargo manifest.
|
||||
/// Lint: _CARGO_COMMON_METADATA.
|
||||
///
|
||||
/// For internal testing only, ignores the current `publish` settings in the Cargo manifest.
|
||||
(cargo_ignore_publish: bool = false),
|
||||
/// Lint: NONSTANDARD_MACRO_BRACES. Enforce the named macros always use the braces specified. <br> A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro is could be used with a full path two `MacroMatcher`s have to be added one with the full path `crate_name::macro_name` and one with just the macro name.
|
||||
/// Lint: NONSTANDARD_MACRO_BRACES.
|
||||
///
|
||||
/// Enforce the named macros always use the braces specified.
|
||||
///
|
||||
/// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
|
||||
/// is could be used with a full path two `MacroMatcher`s have to be added one with the full path
|
||||
/// `crate_name::macro_name` and one with just the macro name.
|
||||
(standard_macro_braces: Vec<crate::nonstandard_macro_braces::MacroMatcher> = Vec::new()),
|
||||
/// Lint: MISSING_ENFORCED_IMPORT_RENAMES. The list of imports to always rename, a fully qualified path followed by the rename.
|
||||
/// Lint: MISSING_ENFORCED_IMPORT_RENAMES.
|
||||
///
|
||||
/// The list of imports to always rename, a fully qualified path followed by the rename.
|
||||
(enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()),
|
||||
/// Lint: RESTRICTED_SCRIPTS. The list of unicode scripts allowed to be used in the scope.
|
||||
/// Lint: RESTRICTED_SCRIPTS.
|
||||
///
|
||||
/// The list of unicode scripts allowed to be used in the scope.
|
||||
(allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ This lint has the following configuration variables:
|
||||
/// `default`
|
||||
macro_rules! CONFIGURATION_VALUE_TEMPLATE {
|
||||
() => {
|
||||
"* {name}: {ty}: {doc} (defaults to `{default}`)\n"
|
||||
"* {name}: `{ty}`: {doc} (defaults to `{default}`)\n"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -344,11 +344,16 @@ fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
|
||||
if let Some(split_pos) = doc_comment.find('.');
|
||||
then {
|
||||
let mut doc_comment = doc_comment.to_string();
|
||||
let documentation = doc_comment.split_off(split_pos);
|
||||
let mut documentation = doc_comment.split_off(split_pos);
|
||||
|
||||
// Extract lints
|
||||
doc_comment.make_ascii_lowercase();
|
||||
let lints: Vec<String> = doc_comment.split_off(DOC_START.len()).split(", ").map(str::to_string).collect();
|
||||
|
||||
// Format documentation correctly
|
||||
// split off leading `.` from lint name list and indent for correct formatting
|
||||
documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n ");
|
||||
|
||||
Some((lints, documentation))
|
||||
} else {
|
||||
None
|
||||
|
||||
Reference in New Issue
Block a user