@@ -3,7 +3,7 @@ use clippy_utils::higher::VecArgs;
33use clippy_utils:: last_path_segment;
44use clippy_utils:: macros:: root_macro_call_first_node;
55use clippy_utils:: source:: { indent_of, snippet} ;
6- use rustc_errors:: { Applicability , Diagnostic } ;
6+ use rustc_errors:: Applicability ;
77use rustc_hir:: { Expr , ExprKind , QPath , TyKind } ;
88use rustc_lint:: { LateContext , LateLintPass } ;
99use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
@@ -51,70 +51,53 @@ impl LateLintPass<'_> for RcCloneInVecInit {
5151 let Some ( macro_call) = root_macro_call_first_node ( cx, expr) else { return ; } ;
5252 let Some ( VecArgs :: Repeat ( elem, len) ) = VecArgs :: hir ( cx, expr) else { return ; } ;
5353 let Some ( symbol) = new_reference_call ( cx, elem) else { return ; } ;
54- let lint_span = macro_call. span ;
55- let symbol_name = symbol. as_str ( ) ;
56- let len_snippet = snippet ( cx, len. span , ".." ) ;
57- let elem_snippet = elem_snippet ( cx, elem, symbol_name) ;
58- let indentation = indent_of ( cx, lint_span) . unwrap_or ( 0 ) ;
59- let lint_suggestions =
60- construct_lint_suggestions ( lint_span, symbol_name, & elem_snippet, len_snippet. as_ref ( ) , indentation) ;
61-
62- emit_lint ( cx, symbol, lint_span, & lint_suggestions) ;
54+
55+ emit_lint ( cx, symbol, macro_call. span , elem, len) ;
6356 }
6457}
6558
6659struct LintSuggestion {
67- span : Span ,
6860 message : String ,
69- suggestion : String ,
70- applicability : Applicability ,
71- }
72-
73- impl LintSuggestion {
74- fn span_suggestion ( & self , diag : & mut Diagnostic ) {
75- diag. span_suggestion ( self . span , & self . message , & self . suggestion , self . applicability ) ;
76- }
61+ snippet : String ,
7762}
7863
7964fn construct_lint_suggestions (
65+ cx : & LateContext < ' _ > ,
8066 span : Span ,
8167 symbol_name : & str ,
82- elem_snippet : & str ,
83- len_snippet : & str ,
84- indentation : usize ,
68+ elem : & Expr < ' _ > ,
69+ len : & Expr < ' _ > ,
8570) -> Vec < LintSuggestion > {
71+ let len_snippet = snippet ( cx, len. span , ".." ) ;
72+ let elem_snippet = elem_snippet ( cx, elem, symbol_name) ;
73+ let indentation = indent_of ( cx, span) . unwrap_or ( 0 ) ;
8674 let indentation = " " . repeat ( indentation) ;
87- let loop_init_suggestion = loop_init_suggestion ( elem_snippet, len_snippet, & indentation) ;
88- let extract_suggestion = extract_suggestion ( elem_snippet, len_snippet, & indentation) ;
75+ let loop_init_suggestion = loop_init_suggestion ( & elem_snippet, len_snippet. as_ref ( ) , & indentation) ;
76+ let extract_suggestion = extract_suggestion ( & elem_snippet, len_snippet. as_ref ( ) , & indentation) ;
8977
9078 vec ! [
9179 LintSuggestion {
92- span,
9380 message: format!( "consider initializing each `{symbol_name}` element individually" ) ,
94- suggestion: loop_init_suggestion,
95- applicability: Applicability :: Unspecified ,
81+ snippet: loop_init_suggestion,
9682 } ,
9783 LintSuggestion {
98- span,
9984 message: format!(
10085 "or if this is intentional, consider extracting the `{symbol_name}` initialization to a variable"
10186 ) ,
102- suggestion: extract_suggestion,
103- applicability: Applicability :: Unspecified ,
87+ snippet: extract_suggestion,
10488 } ,
10589 ]
10690}
10791
10892fn elem_snippet ( cx : & LateContext < ' _ > , elem : & Expr < ' _ > , symbol_name : & str ) -> String {
109- let mut elem_snippet = snippet ( cx, elem. span , ".." ) . to_string ( ) ;
93+ let elem_snippet = snippet ( cx, elem. span , ".." ) . to_string ( ) ;
11094 if elem_snippet. contains ( '\n' ) {
111- let reference_initialization = format ! ( "{symbol_name}::new" ) ;
112- // This string must be found in `elem_snippet`, otherwise we won't be constructing the snippet in
113- // the first place.
114- let reference_initialization_end =
115- elem_snippet. find ( & reference_initialization) . unwrap ( ) + reference_initialization. len ( ) ;
116- elem_snippet. replace_range ( reference_initialization_end.., ".." ) ;
95+ let reference_creation = format ! ( "{symbol_name}::new" ) ;
96+ let ( code_until_reference_creation, _right) = elem_snippet. split_once ( & reference_creation) . unwrap ( ) ;
97+
98+ return format ! ( "{code_until_reference_creation}{reference_creation}(..)" ) ;
11799 }
100+
118101 elem_snippet
119102}
120103
@@ -137,7 +120,7 @@ fn extract_suggestion(elem: &str, len: &str, indent: &str) -> String {
137120 )
138121}
139122
140- fn emit_lint ( cx : & LateContext < ' _ > , symbol : Symbol , lint_span : Span , lint_suggestions : & [ LintSuggestion ] ) {
123+ fn emit_lint ( cx : & LateContext < ' _ > , symbol : Symbol , lint_span : Span , elem : & Expr < ' _ > , len : & Expr < ' _ > ) {
141124 let symbol_name = symbol. as_str ( ) ;
142125
143126 span_lint_and_then (
@@ -146,10 +129,17 @@ fn emit_lint(cx: &LateContext<'_>, symbol: Symbol, lint_span: Span, lint_suggest
146129 lint_span,
147130 & format ! ( "calling `{symbol_name}::new` in `vec![elem; len]`" ) ,
148131 |diag| {
132+ let suggestions = construct_lint_suggestions ( cx, lint_span, symbol_name, elem, len) ;
133+
149134 diag. note ( format ! ( "each element will point to the same `{symbol_name}` instance" ) ) ;
150- lint_suggestions
151- . iter ( )
152- . for_each ( |suggestion| suggestion. span_suggestion ( diag) ) ;
135+ suggestions. iter ( ) . for_each ( |suggestion| {
136+ diag. span_suggestion (
137+ lint_span,
138+ & suggestion. message ,
139+ & suggestion. snippet ,
140+ Applicability :: Unspecified ,
141+ ) ;
142+ } ) ;
153143 } ,
154144 ) ;
155145}
0 commit comments