@@ -3,7 +3,7 @@ use clippy_utils::higher::VecArgs;
3
3
use clippy_utils:: last_path_segment;
4
4
use clippy_utils:: macros:: root_macro_call_first_node;
5
5
use clippy_utils:: source:: { indent_of, snippet} ;
6
- use rustc_errors:: { Applicability , Diagnostic } ;
6
+ use rustc_errors:: Applicability ;
7
7
use rustc_hir:: { Expr , ExprKind , QPath , TyKind } ;
8
8
use rustc_lint:: { LateContext , LateLintPass } ;
9
9
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
@@ -51,70 +51,53 @@ impl LateLintPass<'_> for RcCloneInVecInit {
51
51
let Some ( macro_call) = root_macro_call_first_node ( cx, expr) else { return ; } ;
52
52
let Some ( VecArgs :: Repeat ( elem, len) ) = VecArgs :: hir ( cx, expr) else { return ; } ;
53
53
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) ;
63
56
}
64
57
}
65
58
66
59
struct LintSuggestion {
67
- span : Span ,
68
60
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 ,
77
62
}
78
63
79
64
fn construct_lint_suggestions (
65
+ cx : & LateContext < ' _ > ,
80
66
span : Span ,
81
67
symbol_name : & str ,
82
- elem_snippet : & str ,
83
- len_snippet : & str ,
84
- indentation : usize ,
68
+ elem : & Expr < ' _ > ,
69
+ len : & Expr < ' _ > ,
85
70
) -> 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 ) ;
86
74
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) ;
89
77
90
78
vec ! [
91
79
LintSuggestion {
92
- span,
93
80
message: format!( "consider initializing each `{symbol_name}` element individually" ) ,
94
- suggestion: loop_init_suggestion,
95
- applicability: Applicability :: Unspecified ,
81
+ snippet: loop_init_suggestion,
96
82
} ,
97
83
LintSuggestion {
98
- span,
99
84
message: format!(
100
85
"or if this is intentional, consider extracting the `{symbol_name}` initialization to a variable"
101
86
) ,
102
- suggestion: extract_suggestion,
103
- applicability: Applicability :: Unspecified ,
87
+ snippet: extract_suggestion,
104
88
} ,
105
89
]
106
90
}
107
91
108
92
fn 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 ( ) ;
110
94
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}(..)" ) ;
117
99
}
100
+
118
101
elem_snippet
119
102
}
120
103
@@ -137,7 +120,7 @@ fn extract_suggestion(elem: &str, len: &str, indent: &str) -> String {
137
120
)
138
121
}
139
122
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 < ' _ > ) {
141
124
let symbol_name = symbol. as_str ( ) ;
142
125
143
126
span_lint_and_then (
@@ -146,10 +129,17 @@ fn emit_lint(cx: &LateContext<'_>, symbol: Symbol, lint_span: Span, lint_suggest
146
129
lint_span,
147
130
& format ! ( "calling `{symbol_name}::new` in `vec![elem; len]`" ) ,
148
131
|diag| {
132
+ let suggestions = construct_lint_suggestions ( cx, lint_span, symbol_name, elem, len) ;
133
+
149
134
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
+ } ) ;
153
143
} ,
154
144
) ;
155
145
}
0 commit comments