@@ -78,7 +78,7 @@ use std::sync::OnceLock;
78
78
use std:: sync:: { Mutex , MutexGuard } ;
79
79
80
80
use if_chain:: if_chain;
81
- use rustc_ast:: ast:: { self , LitKind } ;
81
+ use rustc_ast:: ast:: { self , LitKind , RangeLimits } ;
82
82
use rustc_ast:: Attribute ;
83
83
use rustc_data_structures:: fx:: FxHashMap ;
84
84
use rustc_data_structures:: unhash:: UnhashMap ;
@@ -96,6 +96,7 @@ use rustc_hir::{
96
96
use rustc_lexer:: { tokenize, TokenKind } ;
97
97
use rustc_lint:: { LateContext , Level , Lint , LintContext } ;
98
98
use rustc_middle:: hir:: place:: PlaceBase ;
99
+ use rustc_middle:: mir:: ConstantKind ;
99
100
use rustc_middle:: ty as rustc_ty;
100
101
use rustc_middle:: ty:: adjustment:: { Adjust , Adjustment , AutoBorrow } ;
101
102
use rustc_middle:: ty:: binding:: BindingMode ;
@@ -114,7 +115,8 @@ use rustc_span::symbol::{kw, Ident, Symbol};
114
115
use rustc_span:: Span ;
115
116
use rustc_target:: abi:: Integer ;
116
117
117
- use crate :: consts:: { constant, Constant } ;
118
+ use crate :: consts:: { constant, miri_to_const, Constant } ;
119
+ use crate :: higher:: Range ;
118
120
use crate :: ty:: { can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param} ;
119
121
use crate :: visitors:: for_each_expr;
120
122
@@ -1491,6 +1493,68 @@ pub fn is_else_clause(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
1491
1493
}
1492
1494
}
1493
1495
1496
+ /// Checks whether the given `Expr` is a range equivalent to a `RangeFull`.
1497
+ /// For the lower bound, this means that:
1498
+ /// - either there is none
1499
+ /// - or it is the smallest value that can be represented by the range's integer type
1500
+ /// For the upper bound, this means that:
1501
+ /// - either there is none
1502
+ /// - or it is the largest value that can be represented by the range's integer type and is
1503
+ /// inclusive
1504
+ /// - or it is a call to some container's `len` method and is exclusive, and the range is passed to
1505
+ /// a method call on that same container (e.g. `v.drain(..v.len())`)
1506
+ /// If the given `Expr` is not some kind of range, the function returns `false`.
1507
+ pub fn is_range_full ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , container_path : Option < & Path < ' _ > > ) -> bool {
1508
+ let ty = cx. typeck_results ( ) . expr_ty ( expr) ;
1509
+ if let Some ( Range { start, end, limits } ) = Range :: hir ( expr) {
1510
+ let start_is_none_or_min = start. map_or ( true , |start| {
1511
+ if let rustc_ty:: Adt ( _, subst) = ty. kind ( )
1512
+ && let bnd_ty = subst. type_at ( 0 )
1513
+ && let Some ( min_val) = bnd_ty. numeric_min_val ( cx. tcx )
1514
+ && let const_val = cx. tcx . valtree_to_const_val ( ( bnd_ty, min_val. to_valtree ( ) ) )
1515
+ && let min_const_kind = ConstantKind :: from_value ( const_val, bnd_ty)
1516
+ && let Some ( min_const) = miri_to_const ( cx. tcx , min_const_kind)
1517
+ && let Some ( ( start_const, _) ) = constant ( cx, cx. typeck_results ( ) , start)
1518
+ {
1519
+ start_const == min_const
1520
+ } else {
1521
+ false
1522
+ }
1523
+ } ) ;
1524
+ let end_is_none_or_max = end. map_or ( true , |end| {
1525
+ match limits {
1526
+ RangeLimits :: Closed => {
1527
+ if let rustc_ty:: Adt ( _, subst) = ty. kind ( )
1528
+ && let bnd_ty = subst. type_at ( 0 )
1529
+ && let Some ( max_val) = bnd_ty. numeric_max_val ( cx. tcx )
1530
+ && let const_val = cx. tcx . valtree_to_const_val ( ( bnd_ty, max_val. to_valtree ( ) ) )
1531
+ && let max_const_kind = ConstantKind :: from_value ( const_val, bnd_ty)
1532
+ && let Some ( max_const) = miri_to_const ( cx. tcx , max_const_kind)
1533
+ && let Some ( ( end_const, _) ) = constant ( cx, cx. typeck_results ( ) , end)
1534
+ {
1535
+ end_const == max_const
1536
+ } else {
1537
+ false
1538
+ }
1539
+ } ,
1540
+ RangeLimits :: HalfOpen => {
1541
+ if let Some ( container_path) = container_path
1542
+ && let ExprKind :: MethodCall ( name, self_arg, [ ] , _) = end. kind
1543
+ && name. ident . name == sym:: len
1544
+ && let ExprKind :: Path ( QPath :: Resolved ( None , path) ) = self_arg. kind
1545
+ {
1546
+ container_path. res == path. res
1547
+ } else {
1548
+ false
1549
+ }
1550
+ } ,
1551
+ }
1552
+ } ) ;
1553
+ return start_is_none_or_min && end_is_none_or_max;
1554
+ }
1555
+ false
1556
+ }
1557
+
1494
1558
/// Checks whether the given expression is a constant integer of the given value.
1495
1559
/// unlike `is_integer_literal`, this version does const folding
1496
1560
pub fn is_integer_const ( cx : & LateContext < ' _ > , e : & Expr < ' _ > , value : u128 ) -> bool {
0 commit comments