@@ -21,22 +21,61 @@ use crate::ast_manip::MutVisit;
21
21
/// causes problems for us later on. This folder detects nodes like `&foo` and gives them a
22
22
/// macro-generated span to fix the problem.
23
23
struct FixFormat {
24
+ ctxt : FormatCtxt ,
25
+ }
26
+
27
+ #[ derive( Clone ) ]
28
+ struct FormatCtxt {
24
29
/// The span of the most recent ancestor `Expr`.
25
30
parent_span : Span ,
26
31
/// Are we currently inside (the macro-generated part of) a `format!` invocation?
27
32
in_format : bool ,
33
+ /// Are we currently inside the match in (the macro-generated part of) a
34
+ /// `format!` invocation?
35
+ in_match : bool ,
36
+ }
37
+
38
+ impl FormatCtxt {
39
+ fn new ( span : Span ) -> Self {
40
+ FormatCtxt {
41
+ parent_span : span,
42
+ in_format : false ,
43
+ in_match : false ,
44
+ }
45
+ }
46
+
47
+ fn enter_span ( & self , span : Span ) -> Self {
48
+ FormatCtxt {
49
+ parent_span : span,
50
+ ..* self
51
+ }
52
+ }
53
+
54
+ fn enter_format ( & self , span : Span ) -> Self {
55
+ FormatCtxt {
56
+ parent_span : span,
57
+ in_format : true ,
58
+ ..* self
59
+ }
60
+ }
61
+
62
+ fn enter_match ( & self , span : Span ) -> Self {
63
+ FormatCtxt {
64
+ parent_span : span,
65
+ in_match : true ,
66
+ ..* self
67
+ }
68
+ }
28
69
}
29
70
30
71
impl FixFormat {
31
- fn descend < F , R > ( & mut self , in_format : bool , cur_span : Span , f : F ) -> R
72
+ fn descend < F , R > ( & mut self , new_ctxt : FormatCtxt , f : F ) -> R
32
73
where
33
74
F : FnOnce ( & mut Self ) -> R ,
34
75
{
35
- let old_in_format = mem:: replace ( & mut self . in_format , in_format) ;
36
- let old_parent_span = mem:: replace ( & mut self . parent_span , cur_span) ;
76
+ let old_ctxt = mem:: replace ( & mut self . ctxt , new_ctxt) ;
37
77
let r = f ( self ) ;
38
- self . in_format = old_in_format;
39
- self . parent_span = old_parent_span;
78
+ self . ctxt = old_ctxt;
40
79
r
41
80
}
42
81
@@ -48,40 +87,62 @@ impl FixFormat {
48
87
// recognize it by its span: it's macro-generated, but the "macro definition" actually
49
88
// points to the format string, which lies inside the macro invocation itself.
50
89
51
- if !matches ! ( [ e . node ] ExprKind :: Match ( .. ) ) {
90
+ if !e . span . from_expansion ( ) {
52
91
return false ;
53
92
}
54
93
55
- if !e. span . from_expansion ( ) {
56
- return false ;
94
+ if let ExprKind :: Call ( callee, _) = & e. node {
95
+ if let ExprKind :: Path ( None , path) = & callee. node {
96
+ let matches_fmt_args = path. segments . len ( ) == 4 &&
97
+ path. segments [ 1 ] . ident . as_str ( ) == "fmt" &&
98
+ path. segments [ 2 ] . ident . as_str ( ) == "Arguments" &&
99
+ ( path. segments [ 3 ] . ident . as_str ( ) == "new_v1" ||
100
+ path. segments [ 3 ] . ident . as_str ( ) == "new_v1_formatted" ) ;
101
+ return matches_fmt_args;
102
+ }
57
103
}
58
104
59
- e . span . source_callsite ( ) . contains ( e . span )
105
+ false
60
106
}
61
107
}
62
108
63
109
impl MutVisitor for FixFormat {
64
110
fn visit_expr ( & mut self , e : & mut P < Expr > ) {
65
- if self . in_format
66
- && !e . span . from_expansion ( )
111
+ if !e . span . from_expansion ( )
112
+ && self . ctxt . in_match
67
113
&& matches ! ( [ e. node] ExprKind :: AddrOf ( ..) )
68
114
{
69
115
trace ! ( "EXITING format! at {:?}" , e) ;
70
- // Current node is the `&foo`. We need to change its span. On recursing into `foo`,
71
- // we are no longer inside a `format!` invocation.
72
- let new_span = self . parent_span ;
73
- self . descend ( false , e. span , |this| {
116
+ // Current node is the `&foo`. We need to change its span. On
117
+ // recursing into `foo`, we are no longer inside a `format!`
118
+ // invocation.
119
+ let mac_span = self . ctxt . parent_span ;
120
+ let leave_ctxt = FormatCtxt :: new ( e. span ) ;
121
+ self . descend ( leave_ctxt, |this| {
74
122
mut_visit:: noop_visit_expr ( e, this) ;
75
- e. span = new_span ;
123
+ e. span = mac_span ;
76
124
} )
77
- } else if !self . in_format && self . is_format_entry ( & e) {
125
+ } else if !e. span . from_expansion ( )
126
+ && self . ctxt . in_format
127
+ && !self . ctxt . in_match
128
+ {
129
+ trace ! ( "Fixing format! string at {:?}" , e) ;
130
+ let mac_span = self . ctxt . parent_span ;
131
+ let new_ctxt = self . ctxt . enter_span ( mac_span) ;
132
+ self . descend ( new_ctxt, |this| {
133
+ mut_visit:: noop_visit_expr ( e, this) ;
134
+ e. span = mac_span;
135
+ } )
136
+ } else if self . ctxt . in_format && matches ! ( [ e. node] ExprKind :: Match ( ..) ) {
137
+ let new_ctxt = self . ctxt . enter_match ( e. span ) ;
138
+ self . descend ( new_ctxt, |this| mut_visit:: noop_visit_expr ( e, this) )
139
+ } else if !self . ctxt . in_format && self . is_format_entry ( & e) {
78
140
trace ! ( "ENTERING format! at {:?}" , e) ;
79
- self . descend ( true , e. span , |this| mut_visit:: noop_visit_expr ( e, this) )
141
+ let new_ctxt = self . ctxt . enter_format ( e. span ) ;
142
+ self . descend ( new_ctxt, |this| mut_visit:: noop_visit_expr ( e, this) )
80
143
} else {
81
- let in_format = self . in_format ;
82
- self . descend ( in_format, e. span , |this| {
83
- mut_visit:: noop_visit_expr ( e, this)
84
- } )
144
+ let new_ctxt = self . ctxt . enter_span ( e. span ) ;
145
+ self . descend ( new_ctxt, |this| mut_visit:: noop_visit_expr ( e, this) )
85
146
}
86
147
}
87
148
@@ -129,8 +190,7 @@ impl MutVisitor for FixAttrs {
129
190
#[ cfg_attr( feature = "profile" , flame) ]
130
191
pub fn fix_format < T : MutVisit > ( node : & mut T ) {
131
192
let mut fix_format = FixFormat {
132
- parent_span : DUMMY_SP ,
133
- in_format : false ,
193
+ ctxt : FormatCtxt :: new ( DUMMY_SP ) ,
134
194
} ;
135
195
node. visit ( & mut fix_format)
136
196
}
0 commit comments