@@ -164,45 +164,6 @@ fn is_capture(place: PlaceRef<'_>) -> bool {
164164 }
165165}
166166
167- /// Give a diagnostic when any of the string constants look like a naked format string that would
168- /// interpolate our dead local.
169- fn maybe_suggest_literal_matching_name (
170- body : & Body < ' _ > ,
171- name : Symbol ,
172- ) -> Vec < errors:: UnusedVariableStringInterp > {
173- struct LiteralFinder < ' body , ' tcx > {
174- body : & ' body Body < ' tcx > ,
175- name : String ,
176- name_colon : String ,
177- found : Vec < errors:: UnusedVariableStringInterp > ,
178- }
179-
180- impl < ' tcx > Visitor < ' tcx > for LiteralFinder < ' _ , ' tcx > {
181- fn visit_const_operand ( & mut self , constant : & ConstOperand < ' tcx > , loc : Location ) {
182- if let ty:: Ref ( _, ref_ty, _) = constant. ty ( ) . kind ( )
183- && ref_ty. kind ( ) == & ty:: Str
184- {
185- let rendered_constant = constant. const_ . to_string ( ) ;
186- if rendered_constant. contains ( & self . name )
187- || rendered_constant. contains ( & self . name_colon )
188- {
189- let lit = self . body . source_info ( loc) . span ;
190- self . found . push ( errors:: UnusedVariableStringInterp { lit } ) ;
191- }
192- }
193- }
194- }
195-
196- let mut finder = LiteralFinder {
197- body,
198- name : format ! ( "{{{name}}}" ) ,
199- name_colon : format ! ( "{{{name}:" ) ,
200- found : vec ! [ ] ,
201- } ;
202- finder. visit_body ( body) ;
203- finder. found
204- }
205-
206167/// Give a diagnostic when an unused variable may be a typo of a unit variant or a struct.
207168fn maybe_suggest_unit_pattern_typo < ' tcx > (
208169 tcx : TyCtxt < ' tcx > ,
@@ -879,6 +840,44 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
879840 fn report_fully_unused ( & mut self ) {
880841 let tcx = self . tcx ;
881842
843+ // Give a diagnostic when any of the string constants look like a naked format string that
844+ // would interpolate our dead local.
845+ let mut string_constants_in_body = None ;
846+ let mut maybe_suggest_literal_matching_name = |name : Symbol | {
847+ // Visiting MIR to enumerate string constants can be expensive, so cache the result.
848+ let string_constants_in_body = string_constants_in_body. get_or_insert_with ( || {
849+ struct LiteralFinder {
850+ found : Vec < ( Span , String ) > ,
851+ }
852+
853+ impl < ' tcx > Visitor < ' tcx > for LiteralFinder {
854+ fn visit_const_operand ( & mut self , constant : & ConstOperand < ' tcx > , _: Location ) {
855+ if let ty:: Ref ( _, ref_ty, _) = constant. ty ( ) . kind ( )
856+ && ref_ty. kind ( ) == & ty:: Str
857+ {
858+ let rendered_constant = constant. const_ . to_string ( ) ;
859+ self . found . push ( ( constant. span , rendered_constant) ) ;
860+ }
861+ }
862+ }
863+
864+ let mut finder = LiteralFinder { found : vec ! [ ] } ;
865+ finder. visit_body ( self . body ) ;
866+ finder. found
867+ } ) ;
868+
869+ let brace_name = format ! ( "{{{name}" ) ;
870+ string_constants_in_body
871+ . iter ( )
872+ . filter ( |( _, rendered_constant) | {
873+ rendered_constant
874+ . split ( & brace_name)
875+ . any ( |c| matches ! ( c. chars( ) . next( ) , Some ( '}' | ':' ) ) )
876+ } )
877+ . map ( |& ( lit, _) | errors:: UnusedVariableStringInterp { lit } )
878+ . collect :: < Vec < _ > > ( )
879+ } ;
880+
882881 // First, report fully unused locals.
883882 for ( index, place) in self . checked_places . iter ( ) {
884883 if self . ever_live . contains ( index) {
@@ -940,7 +939,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
940939 def_span,
941940 errors:: UnusedVariable {
942941 name,
943- string_interp : maybe_suggest_literal_matching_name ( self . body , name) ,
942+ string_interp : maybe_suggest_literal_matching_name ( name) ,
944943 sugg,
945944 } ,
946945 ) ;
@@ -1030,7 +1029,7 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
10301029 spans,
10311030 errors:: UnusedVariable {
10321031 name,
1033- string_interp : maybe_suggest_literal_matching_name ( self . body , name) ,
1032+ string_interp : maybe_suggest_literal_matching_name ( name) ,
10341033 sugg,
10351034 } ,
10361035 ) ;
0 commit comments