Struct rustc_hir_typeck::expr_use_visitor::ExprUseVisitor
source · pub struct ExprUseVisitor<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> {
cx: Cx,
delegate: RefCell<D>,
upvars: Option<&'tcx FxIndexMap<HirId, Upvar>>,
}
Expand description
The ExprUseVisitor type
This is the code that actually walks the tree.
Fields§
§cx: Cx
§delegate: RefCell<D>
We use a RefCell
here so that delegates can mutate themselves, but we can
still have calls to our own helper functions.
upvars: Option<&'tcx FxIndexMap<HirId, Upvar>>
Implementations§
source§impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'tcx, (&'a LateContext<'tcx>, LocalDefId), D>
impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'tcx, (&'a LateContext<'tcx>, LocalDefId), D>
pub fn for_clippy( cx: &'a LateContext<'tcx>, body_def_id: LocalDefId, delegate: D, ) -> Self
source§impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D>
impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D>
sourcepub(crate) fn new(cx: Cx, delegate: D) -> Self
pub(crate) fn new(cx: Cx, delegate: D) -> Self
Creates the ExprUseVisitor, configuring it with the various options provided:
delegate
– who receives the callbacksparam_env
— parameter environment for trait lookups (esp. pertaining toCopy
)typeck_results
— typeck results for the code being analyzed
pub fn consume_body(&self, body: &Body<'_>) -> Result<(), Cx::Error>
fn consume_or_copy( &self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, )
fn consume_exprs(&self, exprs: &[Expr<'_>]) -> Result<(), Cx::Error>
pub fn consume_expr(&self, expr: &Expr<'_>) -> Result<(), Cx::Error>
fn mutate_expr(&self, expr: &Expr<'_>) -> Result<(), Cx::Error>
fn borrow_expr(&self, expr: &Expr<'_>, bk: BorrowKind) -> Result<(), Cx::Error>
pub fn walk_expr(&self, expr: &Expr<'_>) -> Result<(), Cx::Error>
fn walk_stmt(&self, stmt: &Stmt<'_>) -> Result<(), Cx::Error>
fn maybe_read_scrutinee<'t>( &self, discr: &Expr<'_>, discr_place: PlaceWithHirId<'tcx>, pats: impl Iterator<Item = &'t Pat<'t>>, ) -> Result<(), Cx::Error>
fn walk_local<F>( &self, expr: &Expr<'_>, pat: &Pat<'_>, els: Option<&Block<'_>>, f: F, ) -> Result<(), Cx::Error>
sourcefn walk_block(&self, blk: &Block<'_>) -> Result<(), Cx::Error>
fn walk_block(&self, blk: &Block<'_>) -> Result<(), Cx::Error>
Indicates that the value of blk
will be consumed, meaning either copied or moved
depending on its type.
fn walk_struct_expr<'hir>( &self, fields: &[ExprField<'_>], opt_with: &Option<&'hir Expr<'_>>, ) -> Result<(), Cx::Error>
sourcefn walk_adjustment(&self, expr: &Expr<'_>) -> Result<(), Cx::Error>
fn walk_adjustment(&self, expr: &Expr<'_>) -> Result<(), Cx::Error>
Invoke the appropriate delegate calls for anything that gets consumed or borrowed as part of the automatic adjustment process.
sourcefn walk_autoref(
&self,
expr: &Expr<'_>,
base_place: &PlaceWithHirId<'tcx>,
autoref: &AutoBorrow<'tcx>,
)
fn walk_autoref( &self, expr: &Expr<'_>, base_place: &PlaceWithHirId<'tcx>, autoref: &AutoBorrow<'tcx>, )
Walks the autoref autoref
applied to the autoderef’d
expr
. base_place
is the mem-categorized form of expr
after all relevant autoderefs have occurred.
fn walk_arm( &self, discr_place: &PlaceWithHirId<'tcx>, arm: &Arm<'_>, ) -> Result<(), Cx::Error>
sourcefn walk_irrefutable_pat(
&self,
discr_place: &PlaceWithHirId<'tcx>,
pat: &Pat<'_>,
) -> Result<(), Cx::Error>
fn walk_irrefutable_pat( &self, discr_place: &PlaceWithHirId<'tcx>, pat: &Pat<'_>, ) -> Result<(), Cx::Error>
Walks a pat that occurs in isolation (i.e., top-level of fn argument or let binding, and not a match arm or nested pat.)
sourcefn walk_pat(
&self,
discr_place: &PlaceWithHirId<'tcx>,
pat: &Pat<'_>,
has_guard: bool,
) -> Result<(), Cx::Error>
fn walk_pat( &self, discr_place: &PlaceWithHirId<'tcx>, pat: &Pat<'_>, has_guard: bool, ) -> Result<(), Cx::Error>
The core driver for walking a pattern
sourcefn walk_captures(&self, closure_expr: &Closure<'_>) -> Result<(), Cx::Error>
fn walk_captures(&self, closure_expr: &Closure<'_>) -> Result<(), Cx::Error>
Handle the case where the current body contains a closure.
When the current body being handled is a closure, then we must make sure that
- The parent closure only captures Places from the nested closure that are not local to it.
In the following example the closures c
only captures p.x
even though incr
is a capture of the nested closure
struct P { x: i32 }
let mut p = P { x: 4 };
let c = || {
let incr = 10;
let nested = || p.x += incr;
};
- When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing closure as the DefId.
source§impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D>
impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D>
The job of the categorization methods is to analyze an expression to determine what kind of memory is used in evaluating it (for example, where dereferences occur and what kind of pointer is dereferenced; whether the memory is mutable, etc.).
Categorization effectively transforms all of our expressions into expressions of the following forms (the actual enum has many more possibilities, naturally, but they are all variants of these base forms):
E = rvalue // some computed rvalue
| x // address of a local variable or argument
| *E // deref of a ptr
| E.comp // access to an interior component
Imagine a routine ToAddr(Expr) that evaluates an expression and returns an
address where the result is to be found. If Expr is a place, then this
is the address of the place. If Expr
is an rvalue, this is the address of
some temporary spot in memory where the result is stored.
Now, cat_expr()
classifies the expression Expr
and the address A = ToAddr(Expr)
as follows:
cat
: what kind of expression was this? This is a subset of the full expression forms which only includes those that we care about for the purpose of the analysis.mutbl
: mutability of the addressA
.ty
: the type of data found at the addressA
.
The resulting categorization tree differs somewhat from the expressions
themselves. For example, auto-derefs are explicit. Also, an index a[b]
is
decomposed into two operations: a dereference to reach the array data and
then an index to jump forward to the relevant item.
§By-reference upvars
One part of the codegen which may be non-obvious is that we translate closure upvars into the dereference of a borrowed pointer; this more closely resembles the runtime codegen. So, for example, if we had:
let mut x = 3;
let y = 5;
let inc = || x += y;
Then when we categorize x
(within the closure) we would yield a
result of *x'
, effectively, where x'
is a Categorization::Upvar
reference
tied to x
. The type of x'
will be a borrowed pointer.
fn resolve_type_vars_or_error( &self, id: HirId, ty: Option<Ty<'tcx>>, ) -> Result<Ty<'tcx>, Cx::Error>
fn node_ty(&self, hir_id: HirId) -> Result<Ty<'tcx>, Cx::Error>
fn expr_ty(&self, expr: &Expr<'_>) -> Result<Ty<'tcx>, Cx::Error>
fn expr_ty_adjusted(&self, expr: &Expr<'_>) -> Result<Ty<'tcx>, Cx::Error>
sourcefn pat_ty_adjusted(&self, pat: &Pat<'_>) -> Result<Ty<'tcx>, Cx::Error>
fn pat_ty_adjusted(&self, pat: &Pat<'_>) -> Result<Ty<'tcx>, Cx::Error>
Returns the type of value that this pattern matches against. Some non-obvious cases:
- a
ref x
binding matches against a value of typeT
and givesx
the type&T
; we returnT
. - a pattern with implicit derefs (thanks to default binding
modes #42640) may look like
Some(x)
but in fact have implicit deref patterns attached (e.g., it is really&Some(x)
). In that case, we return the “outermost” type (e.g.,&Option<T>
).
sourcefn pat_ty_unadjusted(&self, pat: &Pat<'_>) -> Result<Ty<'tcx>, Cx::Error>
fn pat_ty_unadjusted(&self, pat: &Pat<'_>) -> Result<Ty<'tcx>, Cx::Error>
Like TypeckResults::pat_ty
, but ignores implicit &
patterns.
fn cat_expr(&self, expr: &Expr<'_>) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
sourcefn cat_expr_(
&self,
expr: &Expr<'_>,
adjustments: &[Adjustment<'tcx>],
) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
fn cat_expr_( &self, expr: &Expr<'_>, adjustments: &[Adjustment<'tcx>], ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
This recursion helper avoids going through too many adjustments, since only non-overloaded deref recurses.
fn cat_expr_adjusted( &self, expr: &Expr<'_>, previous: PlaceWithHirId<'tcx>, adjustment: &Adjustment<'tcx>, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
fn cat_expr_adjusted_with<F>( &self, expr: &Expr<'_>, previous: F, adjustment: &Adjustment<'tcx>, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
fn cat_expr_unadjusted( &self, expr: &Expr<'_>, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
fn cat_res( &self, hir_id: HirId, span: Span, expr_ty: Ty<'tcx>, res: Res, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
sourcefn cat_upvar(
&self,
hir_id: HirId,
var_id: HirId,
) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
fn cat_upvar( &self, hir_id: HirId, var_id: HirId, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
Categorize an upvar.
Note: the actual upvar access contains invisible derefs of closure environment and upvar reference as appropriate. Only regionck cares about these dereferences, so we let it compute them as needed.
fn cat_rvalue(&self, hir_id: HirId, expr_ty: Ty<'tcx>) -> PlaceWithHirId<'tcx>
fn cat_projection( &self, node: HirId, base_place: PlaceWithHirId<'tcx>, ty: Ty<'tcx>, kind: ProjectionKind, ) -> PlaceWithHirId<'tcx>
fn cat_overloaded_place( &self, expr: &Expr<'_>, base: &Expr<'_>, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
fn cat_deref( &self, node: HirId, base_place: PlaceWithHirId<'tcx>, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
sourcefn variant_index_for_adt(
&self,
qpath: &QPath<'_>,
pat_hir_id: HirId,
span: Span,
) -> Result<VariantIdx, Cx::Error>
fn variant_index_for_adt( &self, qpath: &QPath<'_>, pat_hir_id: HirId, span: Span, ) -> Result<VariantIdx, Cx::Error>
Returns the variant index for an ADT used within a Struct or TupleStruct pattern
Here pat_hir_id
is the HirId of the pattern itself.
sourcefn total_fields_in_adt_variant(
&self,
pat_hir_id: HirId,
variant_index: VariantIdx,
span: Span,
) -> Result<usize, Cx::Error>
fn total_fields_in_adt_variant( &self, pat_hir_id: HirId, variant_index: VariantIdx, span: Span, ) -> Result<usize, Cx::Error>
Returns the total number of fields in an ADT variant used within a pattern.
Here pat_hir_id
is the HirId of the pattern itself.
sourcefn total_fields_in_tuple(
&self,
pat_hir_id: HirId,
span: Span,
) -> Result<usize, Cx::Error>
fn total_fields_in_tuple( &self, pat_hir_id: HirId, span: Span, ) -> Result<usize, Cx::Error>
Returns the total number of fields in a tuple used within a Tuple pattern.
Here pat_hir_id
is the HirId of the pattern itself.
sourcefn cat_pattern<F>(
&self,
place_with_id: PlaceWithHirId<'tcx>,
pat: &Pat<'_>,
op: &mut F,
) -> Result<(), Cx::Error>
fn cat_pattern<F>( &self, place_with_id: PlaceWithHirId<'tcx>, pat: &Pat<'_>, op: &mut F, ) -> Result<(), Cx::Error>
Here, place
is the PlaceWithHirId
being matched and pat is the pattern it
is being matched against.
In general, the way that this works is that we walk down the pattern,
constructing a PlaceWithHirId
that represents the path that will be taken
to reach the value being matched.
fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool
Auto Trait Implementations§
impl<'tcx, Cx, D> DynSend for ExprUseVisitor<'tcx, Cx, D>
impl<'tcx, Cx, D> !DynSync for ExprUseVisitor<'tcx, Cx, D>
impl<'tcx, Cx, D> !Freeze for ExprUseVisitor<'tcx, Cx, D>
impl<'tcx, Cx, D> !RefUnwindSafe for ExprUseVisitor<'tcx, Cx, D>
impl<'tcx, Cx, D> Send for ExprUseVisitor<'tcx, Cx, D>
impl<'tcx, Cx, D> !Sync for ExprUseVisitor<'tcx, Cx, D>
impl<'tcx, Cx, D> Unpin for ExprUseVisitor<'tcx, Cx, D>
impl<'tcx, Cx, D> UnwindSafe for ExprUseVisitor<'tcx, Cx, D>where
Cx: UnwindSafe,
D: UnwindSafe,
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T, R> CollectAndApply<T, R> for T
impl<T, R> CollectAndApply<T, R> for T
source§impl<T> Filterable for T
impl<T> Filterable for T
source§fn filterable(
self,
filter_name: &'static str,
) -> RequestFilterDataProvider<T, fn(_: DataRequest<'_>) -> bool>
fn filterable( self, filter_name: &'static str, ) -> RequestFilterDataProvider<T, fn(_: DataRequest<'_>) -> bool>
source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§impl<P> IntoQueryParam<P> for P
impl<P> IntoQueryParam<P> for P
fn into_query_param(self) -> P
source§impl<T> MaybeResult<T> for T
impl<T> MaybeResult<T> for T
source§impl<T> Pointable for T
impl<T> Pointable for T
source§impl<I, T, U> Upcast<I, U> for Twhere
U: UpcastFrom<I, T>,
impl<I, T, U> Upcast<I, U> for Twhere
U: UpcastFrom<I, T>,
source§impl<I, T> UpcastFrom<I, T> for T
impl<I, T> UpcastFrom<I, T> for T
fn upcast_from(from: T, _tcx: I) -> T
source§impl<Tcx, T> Value<Tcx> for Twhere
Tcx: DepContext,
impl<Tcx, T> Value<Tcx> for Twhere
Tcx: DepContext,
default fn from_cycle_error( tcx: Tcx, cycle_error: &CycleError, _guar: ErrorGuaranteed, ) -> T
source§impl<T> WithSubscriber for T
impl<T> WithSubscriber for T
source§fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
source§fn with_current_subscriber(self) -> WithDispatch<Self>
fn with_current_subscriber(self) -> WithDispatch<Self>
impl<'a, T> Captures<'a> for Twhere
T: ?Sized,
impl<T> ErasedDestructor for Twhere
T: 'static,
Layout§
Note: Unable to compute type layout, possibly due to this type having generic parameters. Layout can only be computed for concrete, fully-instantiated types.