@@ -90,7 +90,7 @@ use itertools::Itertools;
90
90
use rustc_abi:: Integer ;
91
91
use rustc_ast:: ast:: { self , LitKind , RangeLimits } ;
92
92
use rustc_attr_data_structures:: { AttributeKind , find_attr} ;
93
- use rustc_data_structures:: fx:: FxHashMap ;
93
+ use rustc_data_structures:: fx:: { FxHashMap , FxIndexSet } ;
94
94
use rustc_data_structures:: packed:: Pu128 ;
95
95
use rustc_data_structures:: unhash:: UnindexMap ;
96
96
use rustc_hir:: LangItem :: { OptionNone , OptionSome , ResultErr , ResultOk } ;
@@ -104,7 +104,7 @@ use rustc_hir::{
104
104
CoroutineKind , Destination , Expr , ExprField , ExprKind , FnDecl , FnRetTy , GenericArg , GenericArgs , HirId , Impl ,
105
105
ImplItem , ImplItemKind , Item , ItemKind , LangItem , LetStmt , MatchSource , Mutability , Node , OwnerId , OwnerNode ,
106
106
Param , Pat , PatExpr , PatExprKind , PatKind , Path , PathSegment , QPath , Stmt , StmtKind , TraitFn , TraitItem ,
107
- TraitItemKind , TraitRef , TyKind , UnOp , def,
107
+ TraitItemKind , TraitRef , TyKind , UnOp , UseKind , def,
108
108
} ;
109
109
use rustc_lexer:: { TokenKind , tokenize} ;
110
110
use rustc_lint:: { LateContext , Level , Lint , LintContext } ;
@@ -121,12 +121,13 @@ use rustc_middle::ty::{
121
121
use rustc_span:: hygiene:: { ExpnKind , MacroKind } ;
122
122
use rustc_span:: source_map:: SourceMap ;
123
123
use rustc_span:: symbol:: { Ident , Symbol , kw} ;
124
- use rustc_span:: { InnerSpan , Span } ;
124
+ use rustc_span:: { BytePos , InnerSpan , Span } ;
125
125
use source:: walk_span_to_context;
126
126
use visitors:: { Visitable , for_each_unconsumed_temporary} ;
127
127
128
128
use crate :: consts:: { ConstEvalCtxt , Constant , mir_to_const} ;
129
129
use crate :: higher:: Range ;
130
+ use crate :: source:: snippet;
130
131
use crate :: ty:: { adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type} ;
131
132
use crate :: visitors:: for_each_expr_without_closures;
132
133
@@ -3473,3 +3474,53 @@ pub fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
3473
3474
None
3474
3475
}
3475
3476
}
3477
+
3478
+ /// Returns true for `...prelude::...` imports.
3479
+ pub fn is_prelude_import ( segments : & [ PathSegment < ' _ > ] ) -> bool {
3480
+ segments
3481
+ . iter ( )
3482
+ . any ( |ps| ps. ident . as_str ( ) . contains ( sym:: prelude. as_str ( ) ) )
3483
+ }
3484
+
3485
+ /// Returns the entire span for a given glob import statement, including the `*` symbol.
3486
+ pub fn whole_glob_import_span ( cx : & LateContext < ' _ > , item : & Item < ' _ > , braced_glob : bool ) -> Option < Span > {
3487
+ let ItemKind :: Use ( use_path, UseKind :: Glob ) = item. kind else {
3488
+ return None ;
3489
+ } ;
3490
+
3491
+ if braced_glob {
3492
+ // This is a `_::{_, *}` import
3493
+ // In this case `use_path.span` is empty and ends directly in front of the `*`,
3494
+ // so we need to extend it by one byte.
3495
+ Some ( use_path. span . with_hi ( use_path. span . hi ( ) + BytePos ( 1 ) ) )
3496
+ } else {
3497
+ // In this case, the `use_path.span` ends right before the `::*`, so we need to
3498
+ // extend it up to the `*`. Since it is hard to find the `*` in weird
3499
+ // formatting like `use _ :: *;`, we extend it up to, but not including the
3500
+ // `;`. In nested imports, like `use _::{inner::*, _}` there is no `;` and we
3501
+ // can just use the end of the item span
3502
+ let mut span = use_path. span . with_hi ( item. span . hi ( ) ) ;
3503
+ if snippet ( cx, span, "" ) . ends_with ( ';' ) {
3504
+ span = use_path. span . with_hi ( item. span . hi ( ) - BytePos ( 1 ) ) ;
3505
+ }
3506
+ Some ( span)
3507
+ }
3508
+ }
3509
+
3510
+ /// Generates a suggestion for a glob import using only the actually used items.
3511
+ pub fn sugg_glob_import ( import_source_snippet : & str , used_imports : & FxIndexSet < Symbol > ) -> String {
3512
+ let mut imports: Vec < _ > = used_imports. iter ( ) . map ( ToString :: to_string) . collect ( ) ;
3513
+ let imports_string = if imports. len ( ) == 1 {
3514
+ imports. pop ( ) . unwrap ( )
3515
+ } else if import_source_snippet. is_empty ( ) {
3516
+ imports. join ( ", " )
3517
+ } else {
3518
+ format ! ( "{{{}}}" , imports. join( ", " ) )
3519
+ } ;
3520
+
3521
+ if import_source_snippet. is_empty ( ) {
3522
+ imports_string
3523
+ } else {
3524
+ format ! ( "{import_source_snippet}::{imports_string}" )
3525
+ }
3526
+ }
0 commit comments