pub struct ExprUseVisitor<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> {
cx: Cx,
delegate: RefCell<D>,
upvars: Option<&'tcx FxIndexMap<HirId, Upvar>>,
}Expand description
A visitor that reports how each expression is being used.
See module-level docs and Delegate for details.
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, )
pub fn consume_clone_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>
pub fn consume_or_clone_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 fake_read_scrutinee( &self, discr_place: &PlaceWithHirId<'tcx>, refutable: bool, ) -> 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: &StructTailExpr<'hir>, ) -> 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,
)
fn walk_autoref( &self, expr: &Expr<'_>, base_place: &PlaceWithHirId<'tcx>, autoref: &AutoBorrow, )
Walks the autoref autoref applied to the autoderef’d
expr. base_place is expr represented as a place,
after all relevant autoderefs have occurred.
fn walk_arm( &self, discr_place: &PlaceWithHirId<'tcx>, arm: &Arm<'_>, ) -> Result<(), Cx::Error>
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
This should mirror how pattern-matching gets lowered to MIR, as otherwise lowering will ICE when trying to resolve the upvars.
However, it is okay to approximate it here by doing more accesses than
the actual MIR builder will, which is useful when some checks are too
cumbersome to perform here. For example, if after typeck it becomes
clear that only one variant of an enum is inhabited, and therefore a
read of the discriminant is not necessary, walk_pat will have
over-approximated the necessary upvar capture granularity.
Do note that discrepancies like these do still create obscure corners in the semantics of the language, and should be avoided if possible.
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>
The job of the methods whose name starts with cat_ is to analyze
expressions and construct the corresponding Places. The cat
stands for “categorize”, this is a leftover from long ago when
places were called “categorizations”.
impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D>
The job of the methods whose name starts with cat_ is to analyze
expressions and construct the corresponding Places. The cat
stands for “categorize”, this is a leftover from long ago when
places were called “categorizations”.
Note that a Place differs somewhat from the expression itself. 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.
fn expect_and_resolve_type( &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 xbinding matches against a value of typeTand givesxthe 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 Self::pat_ty_adjusted, 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.
Sourcefn pat_deref_place(
&self,
hir_id: HirId,
base_place: PlaceWithHirId<'tcx>,
inner: &Pat<'_>,
target_ty: Ty<'tcx>,
) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
fn pat_deref_place( &self, hir_id: HirId, base_place: PlaceWithHirId<'tcx>, inner: &Pat<'_>, target_ty: Ty<'tcx>, ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
Represents the place matched on by a deref pattern’s interior.
Sourcefn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool
fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool
Checks whether a type has multiple variants, and therefore, whether a read of the discriminant might be necessary. Note that the actual MIR builder code does a more specific check, filtering out variants that happen to be uninhabited.
Here, it is not practical to perform such a check, because inhabitedness queries require typeck results, and typeck requires closure capture analysis.
Moreover, the language is moving towards uninhabited variants still semantically causing a discriminant read, so we shouldn’t perform any such check.
FIXME(never_patterns): update this comment once the aforementioned MIR builder code is changed to be insensitive to inhhabitedness.
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> 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<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.