@@ -5,6 +5,7 @@ mod expect_used;
55mod filetype_is_file;
66mod filter_map_identity;
77mod filter_next;
8+ mod from_iter_instead_of_collect;
89mod get_unwrap;
910mod implicit_clone;
1011mod inefficient_to_string;
@@ -1761,7 +1762,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
17611762 hir:: ExprKind :: Call ( ref func, ref args) => {
17621763 if let hir:: ExprKind :: Path ( path) = & func. kind {
17631764 if match_qpath ( path, & [ "from_iter" ] ) {
1764- lint_from_iter ( cx, expr, args) ;
1765+ from_iter_instead_of_collect :: check ( cx, expr, args) ;
17651766 }
17661767 }
17671768 } ,
@@ -3440,65 +3441,6 @@ fn is_bool(ty: &hir::Ty<'_>) -> bool {
34403441 }
34413442}
34423443
3443- fn lint_from_iter ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > , args : & [ hir:: Expr < ' _ > ] ) {
3444- let ty = cx. typeck_results ( ) . expr_ty ( expr) ;
3445- let arg_ty = cx. typeck_results ( ) . expr_ty ( & args[ 0 ] ) ;
3446-
3447- if_chain ! {
3448- if let Some ( from_iter_id) = get_trait_def_id( cx, & paths:: FROM_ITERATOR ) ;
3449- if let Some ( iter_id) = get_trait_def_id( cx, & paths:: ITERATOR ) ;
3450-
3451- if implements_trait( cx, ty, from_iter_id, & [ ] ) && implements_trait( cx, arg_ty, iter_id, & [ ] ) ;
3452- then {
3453- // `expr` implements `FromIterator` trait
3454- let iter_expr = sugg:: Sugg :: hir( cx, & args[ 0 ] , ".." ) . maybe_par( ) ;
3455- let turbofish = extract_turbofish( cx, expr, ty) ;
3456- let sugg = format!( "{}.collect::<{}>()" , iter_expr, turbofish) ;
3457- span_lint_and_sugg(
3458- cx,
3459- FROM_ITER_INSTEAD_OF_COLLECT ,
3460- expr. span,
3461- "usage of `FromIterator::from_iter`" ,
3462- "use `.collect()` instead of `::from_iter()`" ,
3463- sugg,
3464- Applicability :: MaybeIncorrect ,
3465- ) ;
3466- }
3467- }
3468- }
3469-
3470- fn extract_turbofish ( cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > , ty : Ty < ' tcx > ) -> String {
3471- if_chain ! {
3472- let call_site = expr. span. source_callsite( ) ;
3473- if let Ok ( snippet) = cx. sess( ) . source_map( ) . span_to_snippet( call_site) ;
3474- let snippet_split = snippet. split( "::" ) . collect:: <Vec <_>>( ) ;
3475- if let Some ( ( _, elements) ) = snippet_split. split_last( ) ;
3476-
3477- then {
3478- // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
3479- if let Some ( type_specifier) = snippet_split. iter( ) . find( |e| e. starts_with( '<' ) && e. ends_with( '>' ) ) {
3480- // remove the type specifier from the path elements
3481- let without_ts = elements. iter( ) . filter_map( |e| {
3482- if e == type_specifier { None } else { Some ( ( * e) . to_string( ) ) }
3483- } ) . collect:: <Vec <_>>( ) ;
3484- // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
3485- format!( "{}{}" , without_ts. join( "::" ) , type_specifier)
3486- } else {
3487- // type is not explicitly specified so wildcards are needed
3488- // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
3489- let ty_str = ty. to_string( ) ;
3490- let start = ty_str. find( '<' ) . unwrap_or( 0 ) ;
3491- let end = ty_str. find( '>' ) . unwrap_or_else( || ty_str. len( ) ) ;
3492- let nb_wildcard = ty_str[ start..end] . split( ',' ) . count( ) ;
3493- let wildcards = format!( "_{}" , ", _" . repeat( nb_wildcard - 1 ) ) ;
3494- format!( "{}<{}>" , elements. join( "::" ) , wildcards)
3495- }
3496- } else {
3497- ty. to_string( )
3498- }
3499- }
3500- }
3501-
35023444fn fn_header_equals ( expected : hir:: FnHeader , actual : hir:: FnHeader ) -> bool {
35033445 expected. constness == actual. constness
35043446 && expected. unsafety == actual. unsafety
0 commit comments