Auto merge of #7897 - camsteffen:in-macro, r=flip1995

Replace `in_macro` usage with `from_expansion`

changelog: none

Generally replace `in_macro(span)` with `span.from_expansion()`. If we're just trying to avoid expanded code, this seems more appropriate because any kind of expanded code is prone to false positives. One place I did not touch is `macro_use.rs`. I think this lint could use a rewrite so I moved `in_macro` there, the only place it is still used.
This commit is contained in:
bors 2021-11-05 14:42:32 +00:00
commit 9a60a93cac
46 changed files with 194 additions and 208 deletions

View File

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::{eq_expr_value, get_trait_def_id, in_macro, paths};
use clippy_utils::{eq_expr_value, get_trait_def_id, paths};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
@ -453,22 +453,20 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
type Map = Map<'tcx>;
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
if in_macro(e.span) {
return;
}
match &e.kind {
ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
self.bool_expr(e);
},
ExprKind::Unary(UnOp::Not, inner) => {
if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() {
if !e.span.from_expansion() {
match &e.kind {
ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
self.bool_expr(e);
} else {
walk_expr(self, e);
}
},
_ => walk_expr(self, e),
},
ExprKind::Unary(UnOp::Not, inner) => {
if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() {
self.bool_expr(e);
}
},
_ => {},
}
}
walk_expr(self, e);
}
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
NestedVisitorMap::None

View File

@ -1,8 +1,8 @@
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then};
use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt};
use clippy_utils::{
both, count_eq, eq_expr_value, get_enclosing_block, get_parent_expr, if_sequence, in_macro, is_else_clause,
is_lint_allowed, search_same, ContainsName, SpanlessEq, SpanlessHash,
both, count_eq, eq_expr_value, get_enclosing_block, get_parent_expr, if_sequence, is_else_clause, is_lint_allowed,
search_same, ContainsName, SpanlessEq, SpanlessHash,
};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
@ -623,7 +623,7 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>]) {
let eq: &dyn Fn(&&Expr<'_>, &&Expr<'_>) -> bool = &|&lhs, &rhs| -> bool {
// Do not lint if any expr originates from a macro
if in_macro(lhs.span) || in_macro(rhs.span) {
if lhs.span.from_expansion() || rhs.span.from_expansion() {
return false;
}
// Do not spawn warning if `IFS_SAME_COND` already produced it.

View File

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
use clippy_utils::source::snippet_with_macro_callsite;
use clippy_utils::ty::{has_drop, is_copy};
use clippy_utils::{any_parent_is_automatically_derived, contains_name, in_macro, match_def_path, paths};
use clippy_utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@ -78,7 +78,7 @@ impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]);
impl LateLintPass<'_> for Default {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
if !in_macro(expr.span);
if !expr.span.from_expansion();
// Avoid cases already linted by `field_reassign_with_default`
if !self.reassigned_linted.contains(&expr.span);
if let ExprKind::Call(path, ..) = expr.kind;
@ -125,7 +125,7 @@ impl LateLintPass<'_> for Default {
if let StmtKind::Local(local) = stmt.kind;
if let Some(expr) = local.init;
if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
if !in_macro(expr.span);
if !expr.span.from_expansion();
// only take bindings to identifiers
if let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind;
// only when assigning `... = Default::default()`

View File

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::peel_mid_ty_refs;
use clippy_utils::{get_parent_node, in_macro, is_lint_allowed};
use clippy_utils::{get_parent_node, is_lint_allowed};
use rustc_ast::util::parser::PREC_PREFIX;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, MatchSource, Mutability, Node, UnOp};
@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
}
// Stop processing sub expressions when a macro call is seen
if in_macro(expr.span) {
if expr.span.from_expansion() {
if let Some((state, data)) = self.state.take() {
report(cx, expr, state, data);
}

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{in_macro, is_automatically_derived, is_default_equivalent, remove_blocks};
use clippy_utils::{is_automatically_derived, is_default_equivalent, remove_blocks};
use rustc_hir::{
def::{DefKind, Res},
Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
}) = item.kind;
if let attrs = cx.tcx.hir().attrs(item.hir_id());
if !is_automatically_derived(attrs);
if !in_macro(item.span);
if !item.span.from_expansion();
if let Some(def_id) = trait_ref.trait_def_id();
if cx.tcx.is_diagnostic_item(sym::Default, def_id);
if let impl_item_hir = child.id.hir_id();

View File

@ -1,9 +1,7 @@
use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::ty::{implements_trait, is_copy};
use clippy_utils::{
ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of, is_in_test_function,
};
use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, is_expn_of, is_in_test_function};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind};
@ -102,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
}
let macro_with_not_op = |expr_kind: &ExprKind<'_>| {
if let ExprKind::Unary(_, expr) = *expr_kind {
in_macro(expr.span)
expr.span.from_expansion()
} else {
false
}

View File

@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::in_macro;
use rustc_ast::ast::{AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
@ -135,7 +134,7 @@ fn is_bool_ty(ty: &Ty) -> bool {
impl EarlyLintPass for ExcessiveBools {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
if in_macro(item.span) {
if item.span.from_expansion() {
return;
}
match &item.kind {

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
use clippy_utils::{in_macro, SpanlessEq};
use clippy_utils::SpanlessEq;
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
@ -39,7 +39,7 @@ declare_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB]);
impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if in_macro(expr.span) {
if expr.span.from_expansion() {
return;
}
if_chain! {

View File

@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::in_macro;
use clippy_utils::source::snippet;
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashMap;
@ -66,7 +65,7 @@ declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRU
impl LateLintPass<'_> for InconsistentStructConstructor {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if_chain! {
if !in_macro(expr.span);
if !expr.span.from_expansion();
if let ExprKind::Struct(qpath, fields, base) = expr.kind;
let ty = cx.typeck_results().expr_ty(expr);
if let Some(adt_def) = ty.ty_adt_def();

View File

@ -1,7 +1,7 @@
//! lint on inherent implementations
use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::{in_macro, is_lint_allowed};
use clippy_utils::is_lint_allowed;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{def_id::LocalDefId, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
@ -123,8 +123,10 @@ fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option<Span> {
..
}) = cx.tcx.hir().get(id)
{
(!in_macro(span) && impl_item.generics.params.is_empty() && !is_lint_allowed(cx, MULTIPLE_INHERENT_IMPL, id))
.then(|| span)
(!span.from_expansion()
&& impl_item.generics.params.is_empty()
&& !is_lint_allowed(cx, MULTIPLE_INHERENT_IMPL, id))
.then(|| span)
} else {
None
}

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{in_macro, trait_ref_of_method};
use clippy_utils::trait_ref_of_method;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::intravisit::{
walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty,
@ -128,7 +128,7 @@ fn check_fn_inner<'tcx>(
span: Span,
report_extra_lifetimes: bool,
) {
if in_macro(span) || has_where_lifetimes(cx, &generics.where_clause) {
if span.from_expansion() || has_where_lifetimes(cx, &generics.where_clause) {
return;
}

View File

@ -2,11 +2,8 @@
//! floating-point literal expressions.
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::numeric_literal::{NumericLiteral, Radix};
use clippy_utils::source::snippet_opt;
use clippy_utils::{
in_macro,
numeric_literal::{NumericLiteral, Radix},
};
use if_chain::if_chain;
use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind};
use rustc_errors::Applicability;
@ -283,7 +280,7 @@ impl LiteralDigitGrouping {
| WarningType::InconsistentDigitGrouping
| WarningType::UnusualByteGroupings
| WarningType::LargeDigitGroups => {
!in_macro(lit.span)
!lit.span.from_expansion()
}
WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => {
true

View File

@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::in_macro;
use clippy_utils::source::snippet;
use hir::def::{DefKind, Res};
use if_chain::if_chain;
@ -9,6 +8,7 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::hygiene::ExpnKind;
use rustc_span::{edition::Edition, sym, Span};
declare_clippy_lint! {
@ -213,3 +213,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
}
}
}
fn in_macro(span: Span) -> bool {
span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
}

View File

@ -8,9 +8,9 @@ use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs};
use clippy_utils::visitors::is_local_used;
use clippy_utils::{
get_parent_expr, in_macro, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild,
meets_msrv, msrvs, path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns,
remove_blocks, strip_pat_refs,
get_parent_expr, is_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild, meets_msrv, msrvs,
path_to_local, path_to_local_id, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns, remove_blocks,
strip_pat_refs,
};
use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
use core::array;
@ -26,7 +26,6 @@ use rustc_hir::{
};
use rustc_hir::{HirIdMap, HirIdSet};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty, TyS, VariantDef};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
@ -601,7 +600,7 @@ impl_lint_pass!(Matches => [
impl<'tcx> LateLintPass<'tcx> for Matches {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) {
if expr.span.from_expansion() {
return;
}
@ -640,8 +639,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
if_chain! {
if !in_external_macro(cx.sess(), local.span);
if !in_macro(local.span);
if !local.span.from_expansion();
if let Some(expr) = local.init;
if let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind;
if arms.len() == 1 && arms[0].guard.is_none();
@ -676,8 +674,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
if_chain! {
if !in_external_macro(cx.sess(), pat.span);
if !in_macro(pat.span);
if !pat.span.from_expansion();
if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind;
if let Some(def_id) = path.res.opt_def_id();
let ty = cx.tcx.type_of(def_id);
@ -704,7 +701,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
#[rustfmt::skip]
fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
if in_macro(expr.span) {
if expr.span.from_expansion() {
// Don't lint match expressions present in
// macro_rules! block
return;
@ -1447,7 +1444,7 @@ fn find_bool_lit(ex: &ExprKind<'_>, is_if_let: bool) -> Option<bool> {
#[allow(clippy::too_many_lines)]
fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
if in_macro(expr.span) || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
if expr.span.from_expansion() || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
return;
}

View File

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::ty::is_non_aggregate_primitive_type;
use clippy_utils::{in_macro, is_default_equivalent, is_lang_ctor, match_def_path, meets_msrv, msrvs, paths};
use clippy_utils::{is_default_equivalent, is_lang_ctor, match_def_path, meets_msrv, msrvs, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone;
@ -213,7 +213,7 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<
expr_span,
"replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`",
|diag| {
if !in_macro(expr_span) {
if !expr_span.from_expansion() {
let suggestion = format!("std::mem::take({})", snippet(cx, dest.span, ""));
diag.span_suggestion(

View File

@ -1,7 +1,7 @@
use super::{contains_return, BIND_INSTEAD_OF_MAP};
use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_with_macro_callsite};
use clippy_utils::{in_macro, remove_blocks, visitors::find_all_ret_expressions};
use clippy_utils::{remove_blocks, visitors::find_all_ret_expressions};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
@ -106,7 +106,7 @@ pub(crate) trait BindInsteadOfMap {
let mut suggs = Vec::new();
let can_sugg: bool = find_all_ret_expressions(cx, closure_expr, |ret_expr| {
if_chain! {
if !in_macro(ret_expr.span);
if !ret_expr.span.from_expansion();
if let hir::ExprKind::Call(func_path, [arg]) = ret_expr.kind;
if let hir::ExprKind::Path(QPath::Resolved(_, path)) = func_path.kind;
if Self::is_variant(cx, path.res);

View File

@ -68,7 +68,7 @@ use bind_instead_of_map::BindInsteadOfMap;
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
use clippy_utils::{contains_return, get_trait_def_id, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_hir::def::Res;
@ -1900,7 +1900,7 @@ macro_rules! method_call {
impl<'tcx> LateLintPass<'tcx> for Methods {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if in_macro(expr.span) {
if expr.span.from_expansion() {
return;
}

View File

@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::in_macro;
use if_chain::if_chain;
use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind};
use rustc_errors::Applicability;
@ -78,7 +77,7 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
let self_param = match (binding_mode, mutbl) {
(Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(),
(Mode::Ref(Some(lifetime)), Mutability::Mut) => {
if in_macro(lifetime.ident.span) {
if lifetime.ident.span.from_expansion() {
applicability = Applicability::HasPlaceholders;
"&'_ mut self".to_string()
} else {
@ -87,7 +86,7 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
},
(Mode::Ref(None), Mutability::Not) => "&self".to_string(),
(Mode::Ref(Some(lifetime)), Mutability::Not) => {
if in_macro(lifetime.ident.span) {
if lifetime.ident.span.from_expansion() {
applicability = Applicability::HasPlaceholders;
"&'_ self".to_string()
} else {
@ -114,7 +113,7 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
impl EarlyLintPass for NeedlessArbitrarySelfType {
fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
// Bail out if the parameter it's not a receiver or was not written by the user
if !p.is_self() || in_macro(p.span) {
if !p.is_self() || p.span.from_expansion() {
return;
}

View File

@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::in_macro;
use clippy_utils::source::snippet_opt;
use if_chain::if_chain;
use rustc_errors::Applicability;
@ -41,7 +40,7 @@ declare_lint_pass!(NeedlessBitwiseBool => [NEEDLESS_BITWISE_BOOL]);
fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let ty = cx.typeck_results().expr_ty(expr);
if_chain! {
if !in_macro(expr.span);
if !expr.span.from_expansion();
if let (&ExprKind::Binary(ref op, _, right), &ty::Bool) = (&expr.kind, &ty.kind());
if op.node == BinOpKind::BitAnd || op.node == BinOpKind::BitOr;
if let ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) | ExprKind::Unary(..) = right.kind;

View File

@ -4,7 +4,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{snippet_opt, snippet_with_applicability, snippet_with_context};
use clippy_utils::{get_parent_expr, in_macro, path_to_local};
use clippy_utils::{get_parent_expr, path_to_local};
use if_chain::if_chain;
use rustc_ast::util::parser::PREC_POSTFIX;
use rustc_data_structures::fx::FxIndexMap;
@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) {
// This binding id has been seen before. Add this pattern to the list of changes.
if let Some(prev_pat) = opt_prev_pat {
if in_macro(pat.span) {
if pat.span.from_expansion() {
// Doesn't match the context of the previous pattern. Can't lint here.
*opt_prev_pat = None;
} else {
@ -174,7 +174,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
}
if_chain! {
if !in_macro(pat.span);
if !pat.span.from_expansion();
if let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind();
// only lint immutable refs, because borrowed `&mut T` cannot be moved out
if let ty::Ref(_, _, Mutability::Not) = *tam.kind();
@ -248,12 +248,12 @@ impl NeedlessBorrow {
span,
kind: ExprKind::Unary(UnOp::Deref, _),
..
}) if !in_macro(span) => {
}) if !span.from_expansion() => {
// Remove explicit deref.
let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0;
pat.replacements.push((span, snip.into()));
},
Some(parent) if !in_macro(parent.span) => {
Some(parent) if !parent.span.from_expansion() => {
// Double reference might be needed at this point.
if parent.precedence().order() == PREC_POSTFIX {
// Parentheses would be needed here, don't lint.
@ -264,7 +264,7 @@ impl NeedlessBorrow {
pat.replacements.push((e.span, format!("&{}", snip)));
}
},
_ if !in_macro(e.span) => {
_ if !e.span.from_expansion() => {
// Double reference might be needed at this point.
pat.always_deref = false;
let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app);

View File

@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::in_macro;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_type_diagnostic_item;
use rustc_errors::Applicability;
@ -38,7 +37,7 @@ declare_lint_pass!(OptionNeedlessDeref=> [
impl<'tcx> LateLintPass<'tcx> for OptionNeedlessDeref {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if expr.span.from_expansion() || in_macro(expr.span) {
if expr.span.from_expansion() {
return;
}
let typeck = cx.typeck_results();

View File

@ -3,14 +3,16 @@ use std::{
hash::{Hash, Hasher},
};
use clippy_utils::{diagnostics::span_lint_and_help, in_macro, is_direct_expn_of, source::snippet_opt};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::snippet_opt;
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;
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::{Span, Symbol};
use serde::{de, Deserialize};
declare_clippy_lint! {
@ -37,7 +39,7 @@ declare_clippy_lint! {
const BRACES: &[(&str, &str)] = &[("(", ")"), ("{", "}"), ("[", "]")];
/// The (name, (open brace, close brace), source snippet)
type MacroInfo<'a> = (&'a str, &'a (String, String), String);
type MacroInfo<'a> = (Symbol, &'a (String, String), String);
#[derive(Clone, Debug, Default)]
pub struct MacroBraces {
@ -93,17 +95,16 @@ 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.ctxt().outer_expn_data().call_site.from_expansion()
|| 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 ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind;
let name = &*mac_name.as_str();
if let Some(braces) = mac_braces.macro_braces.get(name);
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
@ -114,14 +115,14 @@ fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a Mac
if !c.starts_with(&format!("{}!{}", name, braces.0));
if !mac_braces.done.contains(&span.ctxt().outer_expn_data().call_site);
then {
Some((name, braces, snip))
Some((mac_name, braces, snip))
} else {
None
}
}
}
fn emit_help(cx: &EarlyContext<'_>, snip: String, braces: &(String, String), name: &str, span: Span) {
fn emit_help(cx: &EarlyContext<'_>, snip: String, braces: &(String, String), name: Symbol, span: Span) {
let with_space = &format!("! {}", braces.0);
let without_space = &format!("!{}", braces.0);
let mut help = snip;
@ -144,15 +145,6 @@ fn emit_help(cx: &EarlyContext<'_>, snip: String, braces: &(String, String), nam
);
}
fn find_matching_macro(
span: Span,
braces: &FxHashMap<String, (String, String)>,
) -> Option<(&String, &(String, String))> {
braces
.iter()
.find(|(macro_name, _)| is_direct_expn_of(span, macro_name).is_some())
}
fn macro_braces(conf: FxHashSet<MacroMatcher>) -> FxHashMap<String, (String, String)> {
let mut braces = vec![
macro_matcher!(

View File

@ -3,7 +3,7 @@ use clippy_utils::higher;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{
can_move_expr_to_closure, eager_or_lazy, in_constant, in_macro, is_else_clause, is_lang_ctor, peel_hir_expr_while,
can_move_expr_to_closure, eager_or_lazy, in_constant, is_else_clause, is_lang_ctor, peel_hir_expr_while,
CaptureKind,
};
use if_chain::if_chain;
@ -126,7 +126,7 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo
/// this construct is found, or None if this construct is not found.
fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionIfLetElseOccurence> {
if_chain! {
if !in_macro(expr.span); // Don't lint macros, because it behaves weirdly
if !expr.span.from_expansion(); // Don't lint macros, because it behaves weirdly
if !in_constant(cx, expr.hir_id);
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) })
= higher::IfLet::hir(cx, expr);

View File

@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::in_macro;
use clippy_utils::source::snippet_opt;
use if_chain::if_chain;
use rustc_errors::Applicability;
@ -41,7 +40,7 @@ static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers";
impl LateLintPass<'_> for PtrEq {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if in_macro(expr.span) {
if expr.span.from_expansion() {
return;
}

View File

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::get_parent_expr;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::is_type_lang_item;
use clippy_utils::{get_parent_expr, in_macro};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
@ -43,7 +43,7 @@ declare_lint_pass!(RedundantSlicing => [REDUNDANT_SLICING]);
impl LateLintPass<'_> for RedundantSlicing {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if in_macro(expr.span) {
if expr.span.from_expansion() {
return;
}

View File

@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::in_macro;
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use if_chain::if_chain;
@ -50,7 +49,7 @@ impl EarlyLintPass for DerefAddrOf {
if_chain! {
if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind;
if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind;
if !in_macro(addrof_target.span);
if !addrof_target.span.from_expansion();
then {
let mut applicability = Applicability::MachineApplicable;
let sugg = if e.span.from_expansion() {

View File

@ -1,6 +1,5 @@
use clippy_utils::consts::{constant_context, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::in_macro;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
@ -49,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
if let ExprKind::MethodCall(path, _, [receiver, count], _) = &expr.kind;
if path.ident.name == sym!(repeat);
if constant_context(cx, cx.typeck_results()).expr(count) == Some(Constant::Int(1));
if !in_macro(receiver.span);
if !receiver.span.from_expansion();
then {
let ty = cx.typeck_results().expr_ty(receiver).peel_refs();
if ty.is_str() {

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet_opt;
use clippy_utils::{fn_def_id, in_macro, path_to_local_id};
use clippy_utils::{fn_def_id, path_to_local_id};
use if_chain::if_chain;
use rustc_ast::ast::Attribute;
use rustc_errors::Applicability;
@ -90,8 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
if !last_statement_borrows(cx, initexpr);
if !in_external_macro(cx.sess(), initexpr.span);
if !in_external_macro(cx.sess(), retexpr.span);
if !in_external_macro(cx.sess(), local.span);
if !in_macro(local.span);
if !local.span.from_expansion();
then {
span_lint_and_then(
cx,

View File

@ -1,5 +1,4 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
use clippy_utils::in_macro;
use rustc_ast::{ptr::P, Crate, Item, ItemKind, MacroDef, ModKind, UseTreeKind, VisibilityKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
@ -110,7 +109,7 @@ fn track_uses(
single_use_usages: &mut Vec<(Symbol, Span, bool)>,
macros: &mut Vec<Symbol>,
) {
if in_macro(item.span) || item.vis.kind.is_pub() {
if item.span.from_expansion() || item.vis.kind.is_pub() {
return;
}

View File

@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::in_macro;
use clippy_utils::paths;
use clippy_utils::source::snippet_with_macro_callsite;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_ref_to_diagnostic_item};
@ -40,7 +39,7 @@ declare_lint_pass!(StrlenOnCStrings => [STRLEN_ON_C_STRINGS]);
impl LateLintPass<'tcx> for StrlenOnCStrings {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if in_macro(expr.span) {
if expr.span.from_expansion() {
return;
}

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::{in_macro, SpanlessHash};
use clippy_utils::SpanlessHash;
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unhash::UnhashMap;
@ -93,7 +93,7 @@ fn get_trait_res_span_from_bound(bound: &GenericBound<'_>) -> Option<(Res, Span)
impl TraitBounds {
fn check_type_repetition(self, cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
if in_macro(gen.span) {
if gen.span.from_expansion() {
return;
}
let hash = |ty| -> u64 {
@ -107,7 +107,7 @@ impl TraitBounds {
if_chain! {
if let WherePredicate::BoundPredicate(ref p) = bound;
if p.bounds.len() as u64 <= self.max_trait_bounds;
if !in_macro(p.span);
if !p.span.from_expansion();
let h = hash(p.bounded_ty);
if let Some(ref v) = map.insert(h, p.bounds.iter().collect::<Vec<_>>());
@ -151,7 +151,7 @@ impl TraitBounds {
}
fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
if in_macro(gen.span) || gen.params.is_empty() || gen.where_clause.predicates.is_empty() {
if gen.span.from_expansion() || gen.params.is_empty() || gen.where_clause.predicates.is_empty() {
return;
}
@ -170,7 +170,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
for predicate in gen.where_clause.predicates {
if_chain! {
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
if !in_macro(bound_predicate.span);
if !bound_predicate.span.from_expansion();
if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
if let Some(segment) = segments.first();
if let Some(trait_resolutions_direct) = map.get(&segment.ident);

View File

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{snippet, snippet_with_macro_callsite};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{differing_macro_contexts, get_parent_expr, in_macro, is_lang_ctor, match_def_path, paths};
use clippy_utils::{get_parent_expr, is_lang_ctor, match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::LangItem::ResultErr;
@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
use rustc_span::{hygiene, sym};
declare_clippy_lint! {
/// ### What it does
@ -93,15 +93,9 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
};
let expr_err_ty = cx.typeck_results().expr_ty(err_arg);
let differing_contexts = differing_macro_contexts(expr.span, err_arg.span);
let origin_snippet = if in_macro(expr.span) && in_macro(err_arg.span) && differing_contexts {
snippet(cx, err_arg.span.ctxt().outer_expn_data().call_site, "_")
} else if err_arg.span.from_expansion() && !in_macro(expr.span) {
snippet_with_macro_callsite(cx, err_arg.span, "_")
} else {
snippet(cx, err_arg.span, "_")
};
let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt());
let mut applicability = Applicability::MachineApplicable;
let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability);
let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) {
"" // already returns
} else {
@ -120,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
"returning an `Err(_)` with the `?` operator",
"try this",
suggestion,
Applicability::MachineApplicable
applicability,
);
}
}

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
use clippy_utils::is_lint_allowed;
use clippy_utils::source::{indent_of, reindent_multiline, snippet};
use clippy_utils::{in_macro, is_lint_allowed};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, HirId, Local, UnsafeSource};
@ -134,7 +134,7 @@ impl UndocumentedUnsafeBlocks {
let enclosing_scope_span = map.opt_span(enclosing_hir_id)?;
let between_span = if in_macro(block_span) {
let between_span = if block_span.from_expansion() {
self.macro_expansion = true;
enclosing_scope_span.with_hi(block_span.hi())
} else {

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use clippy_utils::{contains_return, in_macro, is_lang_ctor, return_ty, visitors::find_all_ret_expressions};
use clippy_utils::{contains_return, is_lang_ctor, return_ty, visitors::find_all_ret_expressions};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
let mut suggs = Vec::new();
let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| {
if_chain! {
if !in_macro(ret_expr.span);
if !ret_expr.span.from_expansion();
// Check if a function call.
if let ExprKind::Call(func, [arg]) = ret_expr.kind;
// Check if OPTION_SOME or RESULT_OK, depending on return type.

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::same_type_and_consts;
use clippy_utils::{in_macro, meets_msrv, msrvs};
use clippy_utils::{meets_msrv, msrvs};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@ -197,7 +197,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
if_chain! {
if !in_macro(hir_ty.span);
if !hir_ty.span.from_expansion();
if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
if let Some(&StackItem::Check {
impl_id,
@ -214,8 +214,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
};
if same_type_and_consts(ty, cx.tcx.type_of(impl_id));
let hir = cx.tcx.hir();
let id = hir.get_parent_node(hir_ty.hir_id);
if !hir.opt_span(id).map_or(false, in_macro);
// prevents false positive on `#[derive(serde::Deserialize)]`
if !hir.span(hir.get_parent_node(hir_ty.hir_id)).in_derive_expansion();
then {
span_lint(cx, hir_ty.span);
}
@ -224,7 +224,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
if !in_macro(expr.span);
if !expr.span.from_expansion();
if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id);

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_test_module_or_function;
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::{in_macro, is_test_module_or_function};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{
@ -196,7 +196,7 @@ impl LateLintPass<'_> for WildcardImports {
impl WildcardImports {
fn check_exceptions(&self, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool {
in_macro(item.span)
item.span.from_expansion()
|| is_prelude_import(segments)
|| (is_super_only_import(segments) && self.test_modules_deep > 0)
}

View File

@ -250,12 +250,6 @@ pub fn is_lang_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, lang_item: LangItem
false
}
/// Returns `true` if this `span` was expanded by any macro.
#[must_use]
pub fn in_macro(span: Span) -> bool {
span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
}
pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
matches!(
expr.kind,

View File

@ -179,7 +179,7 @@ impl<'tcx> Visitor<'tcx> for ReturnBreakContinueMacroVisitor {
// desugaring, as this will detect a break if there's a while loop
// or a for loop inside the expression.
_ => {
if utils::in_macro(ex.span) {
if ex.span.from_expansion() {
self.seen_return_break_continue = true;
} else {
rustc_hir::intravisit::walk_expr(self, ex);

View File

@ -8,7 +8,7 @@ You may need following tooltips to catch up with common operations.
- [Checking for a specific type](#checking-for-a-specific-type)
- [Checking if a type implements a specific trait](#checking-if-a-type-implements-a-specific-trait)
- [Checking if a type defines a specific method](#checking-if-a-type-defines-a-specific-method)
- [Dealing with macros](#dealing-with-macros)
- [Dealing with macros](#dealing-with-macros-and-expansions)
Useful Rustc dev guide links:
- [Stages of compilation](https://rustc-dev-guide.rust-lang.org/compiler-src.html#the-main-stages-of-compilation)
@ -182,64 +182,78 @@ impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
}
```
## Dealing with macros
## Dealing with macros and expansions
There are several helpers in [`clippy_utils`][utils] to deal with macros:
Keep in mind that macros are already expanded and desugaring is already applied
to the code representation that you are working with in Clippy. This unfortunately causes a lot of
false positives because macro expansions are "invisible" unless you actively check for them.
Generally speaking, code with macro expansions should just be ignored by Clippy because that code can be
dynamic in ways that are difficult or impossible to see.
Use the following functions to deal with macros:
- `in_macro()`: detect if the given span is expanded by a macro
- `span.from_expansion()`: detects if a span is from macro expansion or desugaring.
Checking this is a common first step in a lint.
You may want to use this for example to not start linting in any macro.
```rust
if expr.span.from_expansion() {
// just forget it
return;
}
```
```rust
macro_rules! foo {
($param:expr) => {
match $param {
"bar" => println!("whatever"),
_ => ()
}
};
}
- `span.ctxt()`: the span's context represents whether it is from expansion, and if so, which macro call expanded it.
It is sometimes useful to check if the context of two spans are equal.
foo!("bar");
```rust
// expands to `1 + 0`, but don't lint
1 + mac!()
```
```rust
if left.span.ctxt() != right.span.ctxt() {
// the coder most likely cannot modify this expression
return;
}
```
Note: Code that is not from expansion is in the "root" context. So any spans where `from_expansion` returns `true` can
be assumed to have the same context. And so just using `span.from_expansion()` is often good enough.
// if we lint the `match` of `foo` call and test its span
assert_eq!(in_macro(match_span), true);
```
- `in_external_macro()`: detect if the given span is from an external macro, defined in a foreign crate
- `in_external_macro(span)`: detect if the given span is from a macro defined in a foreign crate.
If you want the lint to work with macro-generated code, this is the next line of defense to avoid macros
not defined in the current crate. It doesn't make sense to lint code that the coder can't change.
You may want to use it for example to not start linting in macros from other crates
You may want to use it for example to not start linting in macros from other crates
```rust
#[macro_use]
extern crate a_crate_with_macros;
```rust
#[macro_use]
extern crate a_crate_with_macros;
// `foo` is defined in `a_crate_with_macros`
foo!("bar");
// `foo` is defined in `a_crate_with_macros`
foo!("bar");
// if we lint the `match` of `foo` call and test its span
assert_eq!(in_external_macro(cx.sess(), match_span), true);
```
// if we lint the `match` of `foo` call and test its span
assert_eq!(in_external_macro(cx.sess(), match_span), true);
```
- `differing_macro_contexts()`: returns true if the two given spans are not from the same context
```rust
macro_rules! m {
($a:expr, $b:expr) => {
if $a.is_some() {
$b;
}
}
}
```rust
macro_rules! m {
($a:expr, $b:expr) => {
if $a.is_some() {
$b;
}
}
}
let x: Option<u32> = Some(42);
m!(x, x.unwrap());
let x: Option<u32> = Some(42);
m!(x, x.unwrap());
// These spans are not from the same context
// x.is_some() is from inside the macro
// x.unwrap() is from outside the macro
assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true);
```
// These spans are not from the same context
// x.is_some() is from inside the macro
// x.unwrap() is from outside the macro
assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true);
```
[TyS]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html
[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html
@ -249,4 +263,3 @@ assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true);
[TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html
[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty
[paths]: ../clippy_utils/src/paths.rs
[utils]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_utils/src/lib.rs

View File

@ -1,5 +1,5 @@
#![warn(clippy::if_chain_style)]
#![allow(clippy::no_effect)]
#![allow(clippy::no_effect, clippy::nonminimal_bool)]
extern crate if_chain;

View File

@ -2,7 +2,9 @@
// [edition2018] edition:2018
// [edition2021] edition:2021
// run-rustfix
#![warn(clippy::manual_assert)]
#![allow(clippy::nonminimal_bool)]
fn main() {
let a = vec![1, 2, 3];

View File

@ -1,5 +1,5 @@
error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:22:5
--> $DIR/manual_assert.rs:24:5
|
LL | / if !a.is_empty() {
LL | | panic!("qaqaq{:?}", a);
@ -9,7 +9,7 @@ LL | | }
= note: `-D clippy::manual-assert` implied by `-D warnings`
error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:25:5
--> $DIR/manual_assert.rs:27:5
|
LL | / if !a.is_empty() {
LL | | panic!("qwqwq");
@ -17,7 +17,7 @@ LL | | }
| |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:42:5
--> $DIR/manual_assert.rs:44:5
|
LL | / if b.is_empty() {
LL | | panic!("panic1");
@ -25,7 +25,7 @@ LL | | }
| |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:45:5
--> $DIR/manual_assert.rs:47:5
|
LL | / if b.is_empty() && a.is_empty() {
LL | | panic!("panic2");
@ -33,7 +33,7 @@ LL | | }
| |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:48:5
--> $DIR/manual_assert.rs:50:5
|
LL | / if a.is_empty() && !b.is_empty() {
LL | | panic!("panic3");
@ -41,7 +41,7 @@ LL | | }
| |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:51:5
--> $DIR/manual_assert.rs:53:5
|
LL | / if b.is_empty() || a.is_empty() {
LL | | panic!("panic4");
@ -49,7 +49,7 @@ LL | | }
| |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:54:5
--> $DIR/manual_assert.rs:56:5
|
LL | / if a.is_empty() || !b.is_empty() {
LL | | panic!("panic5");

View File

@ -2,7 +2,9 @@
// [edition2018] edition:2018
// [edition2021] edition:2021
// run-rustfix
#![warn(clippy::manual_assert)]
#![allow(clippy::nonminimal_bool)]
fn main() {
let a = vec![1, 2, 3];

View File

@ -1,5 +1,5 @@
error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:22:5
--> $DIR/manual_assert.rs:24:5
|
LL | / if !a.is_empty() {
LL | | panic!("qaqaq{:?}", a);
@ -9,7 +9,7 @@ LL | | }
= note: `-D clippy::manual-assert` implied by `-D warnings`
error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:25:5
--> $DIR/manual_assert.rs:27:5
|
LL | / if !a.is_empty() {
LL | | panic!("qwqwq");
@ -17,7 +17,7 @@ LL | | }
| |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:42:5
--> $DIR/manual_assert.rs:44:5
|
LL | / if b.is_empty() {
LL | | panic!("panic1");
@ -25,7 +25,7 @@ LL | | }
| |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:45:5
--> $DIR/manual_assert.rs:47:5
|
LL | / if b.is_empty() && a.is_empty() {
LL | | panic!("panic2");
@ -33,7 +33,7 @@ LL | | }
| |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:48:5
--> $DIR/manual_assert.rs:50:5
|
LL | / if a.is_empty() && !b.is_empty() {
LL | | panic!("panic3");
@ -41,7 +41,7 @@ LL | | }
| |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:51:5
--> $DIR/manual_assert.rs:53:5
|
LL | / if b.is_empty() || a.is_empty() {
LL | | panic!("panic4");
@ -49,7 +49,7 @@ LL | | }
| |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
error: only a `panic!` in `if`-then statement
--> $DIR/manual_assert.rs:54:5
--> $DIR/manual_assert.rs:56:5
|
LL | / if a.is_empty() || !b.is_empty() {
LL | | panic!("panic5");

View File

@ -2,7 +2,9 @@
// [edition2018] edition:2018
// [edition2021] edition:2021
// run-rustfix
#![warn(clippy::manual_assert)]
#![allow(clippy::nonminimal_bool)]
fn main() {
let a = vec![1, 2, 3];

View File

@ -2,7 +2,9 @@
// [edition2018] edition:2018
// [edition2021] edition:2021
// run-rustfix
#![warn(clippy::manual_assert)]
#![allow(clippy::nonminimal_bool)]
fn main() {
let a = vec![1, 2, 3];