Skip to content

Commit

Permalink
Auto merge of rust-lang#7938 - camsteffen:visitors, r=xFrednet
Browse files Browse the repository at this point in the history
Introduce `expr_visitor` and `expr_visitor_no_bodies`

changelog: none

A couple utils that satisfy a *lot* of visitor use cases. Factoring in every possible usage would be really big so I just focused on cleaning clippy_utils.
  • Loading branch information
bors committed Nov 8, 2021
2 parents 6fcdf81 + 2c7b7e8 commit 94517d3
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 308 deletions.
6 changes: 3 additions & 3 deletions clippy_lints/src/eta_reduction.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::higher::VecArgs;
use clippy_utils::source::snippet_opt;
use clippy_utils::usage::UsedAfterExprVisitor;
use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local_id};
use clippy_utils::usage::local_used_after_expr;
use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local, path_to_local_id};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
Expand Down Expand Up @@ -118,7 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
if let ty::Closure(_, substs) = callee_ty.peel_refs().kind();
if substs.as_closure().kind() == ClosureKind::FnMut;
if get_enclosing_loop_or_closure(cx.tcx, expr).is_some()
|| UsedAfterExprVisitor::is_found(cx, callee);
|| path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, callee));

then {
// Mutable closure is used after current expr; we cannot consume it.
Expand Down
11 changes: 2 additions & 9 deletions clippy_lints/src/format_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_middle::ty::Ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, BytePos, ExpnData, ExpnKind, Span, Symbol};
use rustc_span::{sym, ExpnData, ExpnKind, Span, Symbol};

declare_clippy_lint! {
/// ### What it does
Expand Down Expand Up @@ -128,7 +128,7 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb
span_lint_and_then(
cx,
FORMAT_IN_FORMAT_ARGS,
trim_semicolon(cx, call_site),
call_site,
&format!("`format!` in `{}!` args", name),
|diag| {
diag.help(&format!(
Expand Down Expand Up @@ -192,13 +192,6 @@ fn is_aliased(args: &[FormatArgsArg<'_>], i: usize) -> bool {
.any(|(j, arg)| i != j && std::ptr::eq(value, arg.value))
}

fn trim_semicolon(cx: &LateContext<'_>, span: Span) -> Span {
snippet_opt(cx, span).map_or(span, |snippet| {
let snippet = snippet.trim_end_matches(';');
span.with_hi(span.lo() + BytePos(u32::try_from(snippet.len()).unwrap()))
})
}

fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
where
I: Iterator<Item = &'tcx Adjustment<'tcx>>,
Expand Down
30 changes: 17 additions & 13 deletions clippy_lints/src/implicit_return.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ use clippy_utils::{
diagnostics::span_lint_and_sugg,
get_async_fn_body, is_async_fn,
source::{snippet_with_applicability, snippet_with_context, walk_span_to_context},
visitors::visit_break_exprs,
visitors::expr_visitor_no_bodies,
};
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::intravisit::{FnKind, Visitor};
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
Expand Down Expand Up @@ -144,20 +144,24 @@ fn lint_implicit_returns(

ExprKind::Loop(block, ..) => {
let mut add_return = false;
visit_break_exprs(block, |break_expr, dest, sub_expr| {
if dest.target_id.ok() == Some(expr.hir_id) {
if call_site_span.is_none() && break_expr.span.ctxt() == ctxt {
// At this point sub_expr can be `None` in async functions which either diverge, or return the
// unit type.
if let Some(sub_expr) = sub_expr {
lint_break(cx, break_expr.span, sub_expr.span);
expr_visitor_no_bodies(|e| {
if let ExprKind::Break(dest, sub_expr) = e.kind {
if dest.target_id.ok() == Some(expr.hir_id) {
if call_site_span.is_none() && e.span.ctxt() == ctxt {
// At this point sub_expr can be `None` in async functions which either diverge, or return
// the unit type.
if let Some(sub_expr) = sub_expr {
lint_break(cx, e.span, sub_expr.span);
}
} else {
// the break expression is from a macro call, add a return to the loop
add_return = true;
}
} else {
// the break expression is from a macro call, add a return to the loop
add_return = true;
}
}
});
true
})
.visit_block(block);
if add_return {
#[allow(clippy::option_if_let_else)]
if let Some(span) = call_site_span {
Expand Down
3 changes: 0 additions & 3 deletions clippy_lints/src/matches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,9 +632,6 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
if let ExprKind::Match(ex, arms, _) = expr.kind {
check_match_ref_pats(cx, ex, arms.iter().map(|el| el.pat), expr);
}
if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) {
check_match_ref_pats(cx, let_expr, once(let_pat), expr);
}
}

fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
Expand Down
71 changes: 20 additions & 51 deletions clippy_utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![feature(box_patterns)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
#![feature(let_else)]
#![feature(rustc_private)]
#![feature(control_flow_enum)]
#![recursion_limit = "512"]
Expand Down Expand Up @@ -68,7 +69,7 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::{HirIdMap, HirIdSet};
use rustc_hir::intravisit::{self, walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::intravisit::{walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
use rustc_hir::{
Expand Down Expand Up @@ -96,6 +97,7 @@ use rustc_target::abi::Integer;

use crate::consts::{constant, Constant};
use crate::ty::{can_partially_move_ty, is_copy, is_recursively_primitive_type};
use crate::visitors::expr_visitor_no_bodies;

pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
if let Ok(version) = RustcVersion::parse(msrv) {
Expand Down Expand Up @@ -1107,63 +1109,30 @@ pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool {

/// Returns `true` if `expr` contains a return expression
pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
struct RetCallFinder {
found: bool,
}

impl<'tcx> hir::intravisit::Visitor<'tcx> for RetCallFinder {
type Map = Map<'tcx>;

fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
if self.found {
return;
}
let mut found = false;
expr_visitor_no_bodies(|expr| {
if !found {
if let hir::ExprKind::Ret(..) = &expr.kind {
self.found = true;
} else {
hir::intravisit::walk_expr(self, expr);
found = true;
}
}

fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
hir::intravisit::NestedVisitorMap::None
}
}

let mut visitor = RetCallFinder { found: false };
visitor.visit_expr(expr);
visitor.found
}

struct FindMacroCalls<'a, 'b> {
names: &'a [&'b str],
result: Vec<Span>,
}

impl<'a, 'b, 'tcx> Visitor<'tcx> for FindMacroCalls<'a, 'b> {
type Map = Map<'tcx>;

fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
if self.names.iter().any(|fun| is_expn_of(expr.span, fun).is_some()) {
self.result.push(expr.span);
}
// and check sub-expressions
intravisit::walk_expr(self, expr);
}

fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
NestedVisitorMap::None
}
!found
})
.visit_expr(expr);
found
}

/// Finds calls of the specified macros in a function body.
pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec<Span> {
let mut fmc = FindMacroCalls {
names,
result: Vec::new(),
};
fmc.visit_expr(&body.value);
fmc.result
let mut result = Vec::new();
expr_visitor_no_bodies(|expr| {
if names.iter().any(|fun| is_expn_of(expr.span, fun).is_some()) {
result.push(expr.span);
}
true
})
.visit_expr(&body.value);
result
}

/// Extends the span to the beginning of the spans line, incl. whitespaces.
Expand Down
58 changes: 18 additions & 40 deletions clippy_utils/src/ptr.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::source::snippet;
use crate::visitors::expr_visitor_no_bodies;
use crate::{path_to_local_id, strip_pat_refs};
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{Body, BodyId, Expr, ExprKind, HirId, PatKind};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind};
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;
use rustc_span::Span;
use std::borrow::Cow;

Expand All @@ -30,50 +30,28 @@ fn extract_clone_suggestions<'tcx>(
replace: &[(&'static str, &'static str)],
body: &'tcx Body<'_>,
) -> Option<Vec<(Span, Cow<'static, str>)>> {
let mut visitor = PtrCloneVisitor {
cx,
id,
replace,
spans: vec![],
abort: false,
};
visitor.visit_body(body);
if visitor.abort { None } else { Some(visitor.spans) }
}

struct PtrCloneVisitor<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
id: HirId,
replace: &'a [(&'static str, &'static str)],
spans: Vec<(Span, Cow<'static, str>)>,
abort: bool,
}

impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
type Map = Map<'tcx>;

fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
if self.abort {
return;
let mut abort = false;
let mut spans = Vec::new();
expr_visitor_no_bodies(|expr| {
if abort {
return false;
}
if let ExprKind::MethodCall(seg, _, [recv], _) = expr.kind {
if path_to_local_id(recv, self.id) {
if path_to_local_id(recv, id) {
if seg.ident.name.as_str() == "capacity" {
self.abort = true;
return;
abort = true;
return false;
}
for &(fn_name, suffix) in self.replace {
for &(fn_name, suffix) in replace {
if seg.ident.name.as_str() == fn_name {
self.spans.push((expr.span, snippet(self.cx, recv.span, "_") + suffix));
return;
spans.push((expr.span, snippet(cx, recv.span, "_") + suffix));
return false;
}
}
}
}
walk_expr(self, expr);
}

fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
NestedVisitorMap::None
}
!abort
})
.visit_body(body);
if abort { None } else { Some(spans) }
}
Loading

0 comments on commit 94517d3

Please sign in to comment.