diff options
| author | flip1995 <philipp.krones@embecosm.com> | 2021-07-01 18:17:38 +0200 |
|---|---|---|
| committer | flip1995 <philipp.krones@embecosm.com> | 2021-07-01 18:17:38 +0200 |
| commit | 1a385b80dca128bfc5c9fc4cfb0bc8e9f5a3ef07 (patch) | |
| tree | 79a5fb72746db0fe2833c57dc197c2dd85a77c47 /src/tools/clippy/clippy_utils | |
| parent | 3cb1c1134050c059a15d9ca7a00d4dd89111a373 (diff) | |
| parent | 61eb38aeda6cb54b93b872bf503d70084c4d621c (diff) | |
| download | rust-1a385b80dca128bfc5c9fc4cfb0bc8e9f5a3ef07.tar.gz rust-1a385b80dca128bfc5c9fc4cfb0bc8e9f5a3ef07.zip | |
Merge commit '61eb38aeda6cb54b93b872bf503d70084c4d621c' into clippyup
Diffstat (limited to 'src/tools/clippy/clippy_utils')
| -rw-r--r-- | src/tools/clippy/clippy_utils/Cargo.toml | 2 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/ast_utils.rs | 11 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/attrs.rs | 5 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/consts.rs | 10 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/lib.rs | 106 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/ptr.rs | 32 |
6 files changed, 117 insertions, 49 deletions
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index 93ed3b18400..6ede9011208 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.54" +version = "0.1.55" authors = ["The Rust Clippy Developers"] edition = "2018" publish = false diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 90c034bd02a..30c2260d15c 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -47,9 +47,14 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool { | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r), (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)), (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp), - (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)), + (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => { + eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)) + }, (Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => { - lr == rr && eq_maybe_qself(lqself, rqself) &&eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf)) + lr == rr + && eq_maybe_qself(lqself, rqself) + && eq_path(lp, rp) + && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf)) }, (Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), @@ -82,7 +87,7 @@ pub fn eq_maybe_qself(l: &Option<QSelf>, r: &Option<QSelf>) -> bool { match (l, r) { (Some(l), Some(r)) => eq_qself(l, r), (None, None) => true, - _ => false + _ => false, } } diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index 0318c483959..c19b558cd8c 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -157,3 +157,8 @@ pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool { .filter_map(ast::Attribute::meta_item_list) .any(|l| attr::list_contains_name(&l, sym::hidden)) } + +/// Return true if the attributes contain `#[unstable]` +pub fn is_unstable(attrs: &[ast::Attribute]) -> bool { + attrs.iter().any(|attr| attr.has_name(sym::unstable)) +} diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 0d7fdeeb920..15c27d1a996 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1,6 +1,6 @@ #![allow(clippy::float_cmp)] -use crate::{clip, sext, unsext}; +use crate::{clip, is_direct_expn_of, sext, unsext}; use if_chain::if_chain; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; @@ -230,7 +230,13 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { match e.kind { ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)), ExprKind::Block(block, _) => self.block(block), - ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))), + ExprKind::Lit(ref lit) => { + if is_direct_expn_of(e.span, "cfg").is_some() { + None + } else { + Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))) + } + }, ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec), ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple), ExprKind::Repeat(value, _) => { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 769836aaf18..ef4854afc83 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -72,7 +72,7 @@ use rustc_hir::LangItem::{ResultErr, ResultOk}; use rustc_hir::{ def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Node, Param, Pat, PatKind, Path, - PathSegment, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, + PathSegment, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp, }; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::exports::Export; @@ -326,16 +326,6 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) .map_or(false, |did| is_diag_trait_item(cx, did, diag_item)) } -/// Checks if an expression references a variable of the given name. -pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool { - if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind { - if let [p] = path.segments { - return p.ident.name == var; - } - } - false -} - pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> { match *path { QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"), @@ -707,16 +697,6 @@ pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> { } } -/// Gets the name of a `Pat`, if any. -pub fn get_pat_name(pat: &Pat<'_>) -> Option<Symbol> { - match pat.kind { - PatKind::Binding(.., ref spname, _) => Some(spname.name), - PatKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name), - PatKind::Box(p) | PatKind::Ref(p, _) => get_pat_name(&*p), - _ => None, - } -} - pub struct ContainsName { pub name: Symbol, pub result: bool, @@ -861,14 +841,16 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio }) } -/// Gets the loop enclosing the given expression, if any. -pub fn get_enclosing_loop(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> { +/// Gets the loop or closure enclosing the given expression, if any. +pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> { let map = tcx.hir(); for (_, node) in map.parent_iter(expr.hir_id) { match node { Node::Expr( - e @ Expr { - kind: ExprKind::Loop(..), + e + @ + Expr { + kind: ExprKind::Loop(..) | ExprKind::Closure(..), .. }, ) => return Some(e), @@ -1399,6 +1381,55 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some()) } +/// Checks if an expression represents the identity function +/// Only examines closures and `std::convert::identity` +pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + /// Checks if a function's body represents the identity function. Looks for bodies of the form: + /// * `|x| x` + /// * `|x| return x` + /// * `|x| { return x }` + /// * `|x| { return x; }` + fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool { + let id = if_chain! { + if let [param] = func.params; + if let PatKind::Binding(_, id, _, _) = param.pat.kind; + then { + id + } else { + return false; + } + }; + + let mut expr = &func.value; + loop { + match expr.kind { + #[rustfmt::skip] + ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _, ) + | ExprKind::Ret(Some(e)) => expr = e, + #[rustfmt::skip] + ExprKind::Block(&Block { stmts: [stmt], expr: None, .. }, _) => { + if_chain! { + if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind; + if let ExprKind::Ret(Some(ret_val)) = e.kind; + then { + expr = ret_val; + } else { + return false; + } + } + }, + _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(), + } + } + } + + match expr.kind { + ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)), + ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY), + _ => false, + } +} + /// Gets the node where an expression is either used, or it's type is unified with another branch. pub fn get_expr_use_or_unification_node(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<Node<'tcx>> { let map = tcx.hir(); @@ -1654,6 +1685,19 @@ pub fn peel_hir_expr_refs(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) { (e, count) } +/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is +/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed. +pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> { + loop { + match expr.kind { + ExprKind::AddrOf(_, _, e) => expr = e, + ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e, + _ => break, + } + } + expr +} + #[macro_export] macro_rules! unwrap_cargo_metadata { ($cx: ident, $lint: ident, $deps: expr) => {{ @@ -1683,3 +1727,15 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { } } } + +/// Checks whether item either has `test` attribute applied, or +/// is a module with `test` in its name. +pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool { + if let Some(def_id) = tcx.hir().opt_local_def_id(item.hir_id()) { + if tcx.has_attr(def_id.to_def_id(), sym::test) { + return true; + } + } + + matches!(item.kind, ItemKind::Mod(..)) && item.ident.name.as_str().contains("test") +} diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs index 791688cd194..8adb6915952 100644 --- a/src/tools/clippy/clippy_utils/src/ptr.rs +++ b/src/tools/clippy/clippy_utils/src/ptr.rs @@ -1,10 +1,10 @@ use crate::source::snippet; -use crate::{get_pat_name, match_var}; +use crate::{path_to_local_id, strip_pat_refs}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::{Body, BodyId, Expr, ExprKind, Param}; +use rustc_hir::{Body, BodyId, Expr, ExprKind, HirId, PatKind}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; use std::borrow::Cow; pub fn get_spans( @@ -14,10 +14,11 @@ pub fn get_spans( replacements: &[(&'static str, &'static str)], ) -> Option<Vec<(Span, Cow<'static, str>)>> { if let Some(body) = opt_body_id.map(|id| cx.tcx.hir().body(id)) { - get_binding_name(&body.params[idx]).map_or_else( - || Some(vec![]), - |name| extract_clone_suggestions(cx, name, replacements, body), - ) + if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(body.params[idx].pat).kind { + extract_clone_suggestions(cx, binding_id, replacements, body) + } else { + Some(vec![]) + } } else { Some(vec![]) } @@ -25,13 +26,13 @@ pub fn get_spans( fn extract_clone_suggestions<'tcx>( cx: &LateContext<'tcx>, - name: Symbol, + id: HirId, replace: &[(&'static str, &'static str)], body: &'tcx Body<'_>, ) -> Option<Vec<(Span, Cow<'static, str>)>> { let mut visitor = PtrCloneVisitor { cx, - name, + id, replace, spans: vec![], abort: false, @@ -42,7 +43,7 @@ fn extract_clone_suggestions<'tcx>( struct PtrCloneVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, - name: Symbol, + id: HirId, replace: &'a [(&'static str, &'static str)], spans: Vec<(Span, Cow<'static, str>)>, abort: bool, @@ -55,16 +56,15 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> { if self.abort { return; } - if let ExprKind::MethodCall(seg, _, args, _) = expr.kind { - if args.len() == 1 && match_var(&args[0], self.name) { + if let ExprKind::MethodCall(seg, _, [recv], _) = expr.kind { + if path_to_local_id(recv, self.id) { if seg.ident.name.as_str() == "capacity" { self.abort = true; return; } for &(fn_name, suffix) in self.replace { if seg.ident.name.as_str() == fn_name { - self.spans - .push((expr.span, snippet(self.cx, args[0].span, "_") + suffix)); + self.spans.push((expr.span, snippet(self.cx, recv.span, "_") + suffix)); return; } } @@ -77,7 +77,3 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> { NestedVisitorMap::None } } - -fn get_binding_name(arg: &Param<'_>) -> Option<Symbol> { - get_pat_name(arg.pat) -} |
