@@ -90,7 +90,7 @@ use itertools::Itertools;
9090use rustc_abi:: Integer ;
9191use rustc_ast:: ast:: { self , LitKind , RangeLimits } ;
9292use rustc_attr_data_structures:: { AttributeKind , find_attr} ;
93- use rustc_data_structures:: fx:: FxHashMap ;
93+ use rustc_data_structures:: fx:: { FxHashMap , FxIndexSet } ;
9494use rustc_data_structures:: packed:: Pu128 ;
9595use rustc_data_structures:: unhash:: UnindexMap ;
9696use rustc_hir:: LangItem :: { OptionNone , OptionSome , ResultErr , ResultOk } ;
@@ -104,7 +104,7 @@ use rustc_hir::{
104104 CoroutineKind , Destination , Expr , ExprField , ExprKind , FnDecl , FnRetTy , GenericArg , GenericArgs , HirId , Impl ,
105105 ImplItem , ImplItemKind , Item , ItemKind , LangItem , LetStmt , MatchSource , Mutability , Node , OwnerId , OwnerNode ,
106106 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,
108108} ;
109109use rustc_lexer:: { TokenKind , tokenize} ;
110110use rustc_lint:: { LateContext , Level , Lint , LintContext } ;
@@ -121,12 +121,13 @@ use rustc_middle::ty::{
121121use rustc_span:: hygiene:: { ExpnKind , MacroKind } ;
122122use rustc_span:: source_map:: SourceMap ;
123123use rustc_span:: symbol:: { Ident , Symbol , kw} ;
124- use rustc_span:: { InnerSpan , Span } ;
124+ use rustc_span:: { BytePos , InnerSpan , Span } ;
125125use source:: walk_span_to_context;
126126use visitors:: { Visitable , for_each_unconsumed_temporary} ;
127127
128128use crate :: consts:: { ConstEvalCtxt , Constant , mir_to_const} ;
129129use crate :: higher:: Range ;
130+ use crate :: source:: snippet;
130131use crate :: ty:: { adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type} ;
131132use crate :: visitors:: for_each_expr_without_closures;
132133
@@ -3473,3 +3474,53 @@ pub fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
34733474 None
34743475 }
34753476}
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