diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index f02c33cc674..aecb0c6dbfa 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -268,8 +268,8 @@ fn symbol(&self, symbol: &Binding) { fn qpath(&self, qpath: &Binding<&QPath<'_>>) { if let QPath::LangItem(lang_item, ..) = *qpath.value { chain!(self, "matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _))"); - } else { - chain!(self, "match_qpath({qpath}, &[{}])", path_to_string(qpath.value)); + } else if let Ok(path) = path_to_string(qpath.value) { + chain!(self, "match_qpath({qpath}, &[{}])", path); } } @@ -738,8 +738,8 @@ fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool { get_attr(cx.sess(), attrs, "author").count() > 0 } -fn path_to_string(path: &QPath<'_>) -> String { - fn inner(s: &mut String, path: &QPath<'_>) { +fn path_to_string(path: &QPath<'_>) -> Result { + fn inner(s: &mut String, path: &QPath<'_>) -> Result<(), ()> { match *path { QPath::Resolved(_, path) => { for (i, segment) in path.segments.iter().enumerate() { @@ -751,16 +751,18 @@ fn inner(s: &mut String, path: &QPath<'_>) { }, QPath::TypeRelative(ty, segment) => match &ty.kind { hir::TyKind::Path(inner_path) => { - inner(s, inner_path); + inner(s, inner_path)?; *s += ", "; write!(s, "{:?}", segment.ident.as_str()).unwrap(); }, other => write!(s, "/* unimplemented: {other:?}*/").unwrap(), }, - QPath::LangItem(..) => panic!("path_to_string: called for lang item qpath"), + QPath::LangItem(..) => return Err(()), } + + Ok(()) } let mut s = String::new(); - inner(&mut s, path); - s + inner(&mut s, path)?; + Ok(s) } diff --git a/tests/ui/author/macro_in_closure.rs b/tests/ui/author/macro_in_closure.rs new file mode 100644 index 00000000000..444e6a12165 --- /dev/null +++ b/tests/ui/author/macro_in_closure.rs @@ -0,0 +1,5 @@ +fn main() { + #[clippy::author] + let print_text = |x| println!("{}", x); + print_text("hello"); +} diff --git a/tests/ui/author/macro_in_closure.stdout b/tests/ui/author/macro_in_closure.stdout new file mode 100644 index 00000000000..9ab71986f40 --- /dev/null +++ b/tests/ui/author/macro_in_closure.stdout @@ -0,0 +1,39 @@ +if let StmtKind::Local(local) = stmt.kind + && let Some(init) = local.init + && let ExprKind::Closure(CaptureBy::Ref, fn_decl, body_id, _, None) = init.kind + && let FnRetTy::DefaultReturn(_) = fn_decl.output + && expr = &cx.tcx.hir().body(body_id).value + && let ExprKind::Block(block, None) = expr.kind + && block.stmts.len() == 1 + && let StmtKind::Semi(e) = block.stmts[0].kind + && let ExprKind::Call(func, args) = e.kind + && let ExprKind::Path(ref qpath) = func.kind + && match_qpath(qpath, &["$crate", "io", "_print"]) + && args.len() == 1 + && let ExprKind::Call(func1, args1) = args[0].kind + && let ExprKind::Path(ref qpath1) = func1.kind + && args1.len() == 2 + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind + && let ExprKind::Array(elements) = inner.kind + && elements.len() == 2 + && let ExprKind::Lit(ref lit) = elements[0].kind + && let LitKind::Str(s, _) = lit.node + && s.as_str() == "" + && let ExprKind::Lit(ref lit1) = elements[1].kind + && let LitKind::Str(s1, _) = lit1.node + && s1.as_str() == "\n" + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind + && let ExprKind::Array(elements1) = inner1.kind + && elements1.len() == 1 + && let ExprKind::Call(func2, args2) = elements1[0].kind + && let ExprKind::Path(ref qpath2) = func2.kind + && args2.len() == 1 + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind + && let ExprKind::Path(ref qpath3) = inner2.kind + && match_qpath(qpath3, &["x"]) + && block.expr.is_none() + && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind + && name.as_str() == "print_text" +{ + // report your lint here +} diff --git a/tests/ui/author/macro_in_loop.rs b/tests/ui/author/macro_in_loop.rs new file mode 100644 index 00000000000..8a520501f8d --- /dev/null +++ b/tests/ui/author/macro_in_loop.rs @@ -0,0 +1,8 @@ +#![feature(stmt_expr_attributes)] + +fn main() { + #[clippy::author] + for i in 0..1 { + println!("{}", i); + } +} diff --git a/tests/ui/author/macro_in_loop.stdout b/tests/ui/author/macro_in_loop.stdout new file mode 100644 index 00000000000..bd054b6abc4 --- /dev/null +++ b/tests/ui/author/macro_in_loop.stdout @@ -0,0 +1,48 @@ +if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr) + && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = pat.kind + && name.as_str() == "i" + && let ExprKind::Struct(qpath, fields, None) = arg.kind + && matches!(qpath, QPath::LangItem(LangItem::Range, _)) + && fields.len() == 2 + && fields[0].ident.as_str() == "start" + && let ExprKind::Lit(ref lit) = fields[0].expr.kind + && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node + && fields[1].ident.as_str() == "end" + && let ExprKind::Lit(ref lit1) = fields[1].expr.kind + && let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node + && let ExprKind::Block(block, None) = body.kind + && block.stmts.len() == 1 + && let StmtKind::Semi(e) = block.stmts[0].kind + && let ExprKind::Block(block1, None) = e.kind + && block1.stmts.len() == 1 + && let StmtKind::Semi(e1) = block1.stmts[0].kind + && let ExprKind::Call(func, args) = e1.kind + && let ExprKind::Path(ref qpath1) = func.kind + && match_qpath(qpath1, &["$crate", "io", "_print"]) + && args.len() == 1 + && let ExprKind::Call(func1, args1) = args[0].kind + && let ExprKind::Path(ref qpath2) = func1.kind + && args1.len() == 2 + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind + && let ExprKind::Array(elements) = inner.kind + && elements.len() == 2 + && let ExprKind::Lit(ref lit2) = elements[0].kind + && let LitKind::Str(s, _) = lit2.node + && s.as_str() == "" + && let ExprKind::Lit(ref lit3) = elements[1].kind + && let LitKind::Str(s1, _) = lit3.node + && s1.as_str() == "\n" + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind + && let ExprKind::Array(elements1) = inner1.kind + && elements1.len() == 1 + && let ExprKind::Call(func2, args2) = elements1[0].kind + && let ExprKind::Path(ref qpath3) = func2.kind + && args2.len() == 1 + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind + && let ExprKind::Path(ref qpath4) = inner2.kind + && match_qpath(qpath4, &["i"]) + && block1.expr.is_none() + && block.expr.is_none() +{ + // report your lint here +}