@@ -92,58 +92,52 @@ pub(crate) fn get_match(
9292 sema : & Semantics < ra_ide_db:: RootDatabase > ,
9393) -> Result < Match , MatchFailed > {
9494 record_match_fails_reasons_scope ( debug_active, || {
95- MatchState :: try_match ( rule, code, restrict_range, sema)
95+ Matcher :: try_match ( rule, code, restrict_range, sema)
9696 } )
9797}
9898
99- /// Inputs to matching. This cannot be part of `MatchState`, since we mutate `MatchState` and in at
100- /// least one case need to hold a borrow of a placeholder from the input pattern while calling a
101- /// mutable `MatchState` method.
102- struct MatchInputs < ' pattern > {
103- ssr_pattern : & ' pattern SsrPattern ,
104- }
105-
106- /// State used while attempting to match our search pattern against a particular node of the AST.
107- struct MatchState < ' db , ' sema > {
99+ /// Checks if our search pattern matches a particular node of the AST.
100+ struct Matcher < ' db , ' sema > {
108101 sema : & ' sema Semantics < ' db , ra_ide_db:: RootDatabase > ,
109102 /// If any placeholders come from anywhere outside of this range, then the match will be
110103 /// rejected.
111104 restrict_range : Option < FileRange > ,
112- /// The match that we're building. We do two passes for a successful match. On the first pass,
113- /// this is None so that we can avoid doing things like storing copies of what placeholders
114- /// matched to. If that pass succeeds, then we do a second pass where we collect those details.
115- /// This means that if we have a pattern like `$a.foo()` we won't do an insert into the
116- /// placeholders map for every single method call in the codebase. Instead we'll discard all the
117- /// method calls that aren't calls to `foo` on the first pass and only insert into the
118- /// placeholders map on the second pass. Likewise for ignored comments.
119- match_out : Option < Match > ,
105+ rule : & ' sema SsrRule ,
106+ }
107+
108+ /// Which phase of matching we're currently performing. We do two phases because most attempted
109+ /// matches will fail and it means we can defer more expensive checks to the second phase.
110+ enum Phase < ' a > {
111+ /// On the first phase, we perform cheap checks. No state is mutated and nothing is recorded.
112+ First ,
113+ /// On the second phase, we construct the `Match`. Things like what placeholders bind to is
114+ /// recorded.
115+ Second ( & ' a mut Match ) ,
120116}
121117
122- impl < ' db , ' sema > MatchState < ' db , ' sema > {
118+ impl < ' db , ' sema > Matcher < ' db , ' sema > {
123119 fn try_match (
124- rule : & SsrRule ,
120+ rule : & ' sema SsrRule ,
125121 code : & SyntaxNode ,
126122 restrict_range : & Option < FileRange > ,
127123 sema : & ' sema Semantics < ' db , ra_ide_db:: RootDatabase > ,
128124 ) -> Result < Match , MatchFailed > {
129- let mut match_state =
130- MatchState { sema, restrict_range : restrict_range. clone ( ) , match_out : None } ;
131- let match_inputs = MatchInputs { ssr_pattern : & rule. pattern } ;
125+ let match_state = Matcher { sema, restrict_range : restrict_range. clone ( ) , rule } ;
132126 let pattern_tree = rule. pattern . tree_for_kind ( code. kind ( ) ) ?;
133127 // First pass at matching, where we check that node types and idents match.
134- match_state. attempt_match_node ( & match_inputs , & pattern_tree, code) ?;
128+ match_state. attempt_match_node ( & mut Phase :: First , & pattern_tree, code) ?;
135129 match_state. validate_range ( & sema. original_range ( code) ) ?;
136- match_state . match_out = Some ( Match {
130+ let mut the_match = Match {
137131 range : sema. original_range ( code) ,
138132 matched_node : code. clone ( ) ,
139133 placeholder_values : FxHashMap :: default ( ) ,
140134 ignored_comments : Vec :: new ( ) ,
141135 template : rule. template . clone ( ) ,
142- } ) ;
136+ } ;
143137 // Second matching pass, where we record placeholder matches, ignored comments and maybe do
144138 // any other more expensive checks that we didn't want to do on the first pass.
145- match_state. attempt_match_node ( & match_inputs , & pattern_tree, code) ?;
146- Ok ( match_state . match_out . unwrap ( ) )
139+ match_state. attempt_match_node ( & mut Phase :: Second ( & mut the_match ) , & pattern_tree, code) ?;
140+ Ok ( the_match )
147141 }
148142
149143 /// Checks that `range` is within the permitted range if any. This is applicable when we're
@@ -161,27 +155,22 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
161155 }
162156
163157 fn attempt_match_node (
164- & mut self ,
165- match_inputs : & MatchInputs ,
158+ & self ,
159+ phase : & mut Phase ,
166160 pattern : & SyntaxNode ,
167161 code : & SyntaxNode ,
168162 ) -> Result < ( ) , MatchFailed > {
169163 // Handle placeholders.
170- if let Some ( placeholder) =
171- match_inputs. get_placeholder ( & SyntaxElement :: Node ( pattern. clone ( ) ) )
172- {
164+ if let Some ( placeholder) = self . get_placeholder ( & SyntaxElement :: Node ( pattern. clone ( ) ) ) {
173165 for constraint in & placeholder. constraints {
174166 self . check_constraint ( constraint, code) ?;
175167 }
176- if self . match_out . is_none ( ) {
177- return Ok ( ( ) ) ;
178- }
179- let original_range = self . sema . original_range ( code) ;
180- // We validated the range for the node when we started the match, so the placeholder
181- // probably can't fail range validation, but just to be safe...
182- self . validate_range ( & original_range) ?;
183- if let Some ( match_out) = & mut self . match_out {
184- match_out. placeholder_values . insert (
168+ if let Phase :: Second ( matches_out) = phase {
169+ let original_range = self . sema . original_range ( code) ;
170+ // We validated the range for the node when we started the match, so the placeholder
171+ // probably can't fail range validation, but just to be safe...
172+ self . validate_range ( & original_range) ?;
173+ matches_out. placeholder_values . insert (
185174 Var ( placeholder. ident . to_string ( ) ) ,
186175 PlaceholderMatch :: new ( code, original_range) ,
187176 ) ;
@@ -190,53 +179,59 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
190179 }
191180 // Non-placeholders.
192181 if pattern. kind ( ) != code. kind ( ) {
193- fail_match ! ( "Pattern had a {:?}, code had {:?}" , pattern. kind( ) , code. kind( ) ) ;
182+ fail_match ! (
183+ "Pattern had a `{}` ({:?}), code had `{}` ({:?})" ,
184+ pattern. text( ) ,
185+ pattern. kind( ) ,
186+ code. text( ) ,
187+ code. kind( )
188+ ) ;
194189 }
195190 // Some kinds of nodes have special handling. For everything else, we fall back to default
196191 // matching.
197192 match code. kind ( ) {
198193 SyntaxKind :: RECORD_FIELD_LIST => {
199- self . attempt_match_record_field_list ( match_inputs , pattern, code)
194+ self . attempt_match_record_field_list ( phase , pattern, code)
200195 }
201- SyntaxKind :: TOKEN_TREE => self . attempt_match_token_tree ( match_inputs , pattern, code) ,
202- _ => self . attempt_match_node_children ( match_inputs , pattern, code) ,
196+ SyntaxKind :: TOKEN_TREE => self . attempt_match_token_tree ( phase , pattern, code) ,
197+ _ => self . attempt_match_node_children ( phase , pattern, code) ,
203198 }
204199 }
205200
206201 fn attempt_match_node_children (
207- & mut self ,
208- match_inputs : & MatchInputs ,
202+ & self ,
203+ phase : & mut Phase ,
209204 pattern : & SyntaxNode ,
210205 code : & SyntaxNode ,
211206 ) -> Result < ( ) , MatchFailed > {
212207 self . attempt_match_sequences (
213- match_inputs ,
208+ phase ,
214209 PatternIterator :: new ( pattern) ,
215210 code. children_with_tokens ( ) ,
216211 )
217212 }
218213
219214 fn attempt_match_sequences (
220- & mut self ,
221- match_inputs : & MatchInputs ,
215+ & self ,
216+ phase : & mut Phase ,
222217 pattern_it : PatternIterator ,
223218 mut code_it : SyntaxElementChildren ,
224219 ) -> Result < ( ) , MatchFailed > {
225220 let mut pattern_it = pattern_it. peekable ( ) ;
226221 loop {
227- match self . next_non_trivial ( & mut code_it) {
222+ match phase . next_non_trivial ( & mut code_it) {
228223 None => {
229224 if let Some ( p) = pattern_it. next ( ) {
230225 fail_match ! ( "Part of the pattern was unmatched: {:?}" , p) ;
231226 }
232227 return Ok ( ( ) ) ;
233228 }
234229 Some ( SyntaxElement :: Token ( c) ) => {
235- self . attempt_match_token ( & mut pattern_it, & c) ?;
230+ self . attempt_match_token ( phase , & mut pattern_it, & c) ?;
236231 }
237232 Some ( SyntaxElement :: Node ( c) ) => match pattern_it. next ( ) {
238233 Some ( SyntaxElement :: Node ( p) ) => {
239- self . attempt_match_node ( match_inputs , & p, & c) ?;
234+ self . attempt_match_node ( phase , & p, & c) ?;
240235 }
241236 Some ( p) => fail_match ! ( "Pattern wanted '{}', code has {}" , p, c. text( ) ) ,
242237 None => fail_match ! ( "Pattern reached end, code has {}" , c. text( ) ) ,
@@ -246,11 +241,12 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
246241 }
247242
248243 fn attempt_match_token (
249- & mut self ,
244+ & self ,
245+ phase : & mut Phase ,
250246 pattern : & mut Peekable < PatternIterator > ,
251247 code : & ra_syntax:: SyntaxToken ,
252248 ) -> Result < ( ) , MatchFailed > {
253- self . record_ignored_comments ( code) ;
249+ phase . record_ignored_comments ( code) ;
254250 // Ignore whitespace and comments.
255251 if code. kind ( ) . is_trivia ( ) {
256252 return Ok ( ( ) ) ;
@@ -317,8 +313,8 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
317313 /// We want to allow the records to match in any order, so we have special matching logic for
318314 /// them.
319315 fn attempt_match_record_field_list (
320- & mut self ,
321- match_inputs : & MatchInputs ,
316+ & self ,
317+ phase : & mut Phase ,
322318 pattern : & SyntaxNode ,
323319 code : & SyntaxNode ,
324320 ) -> Result < ( ) , MatchFailed > {
@@ -334,11 +330,11 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
334330 for p in pattern. children_with_tokens ( ) {
335331 if let SyntaxElement :: Node ( p) = p {
336332 if let Some ( name_element) = p. first_child_or_token ( ) {
337- if match_inputs . get_placeholder ( & name_element) . is_some ( ) {
333+ if self . get_placeholder ( & name_element) . is_some ( ) {
338334 // If the pattern is using placeholders for field names then order
339335 // independence doesn't make sense. Fall back to regular ordered
340336 // matching.
341- return self . attempt_match_node_children ( match_inputs , pattern, code) ;
337+ return self . attempt_match_node_children ( phase , pattern, code) ;
342338 }
343339 if let Some ( ident) = only_ident ( name_element) {
344340 let code_record = fields_by_name. remove ( ident. text ( ) ) . ok_or_else ( || {
@@ -347,7 +343,7 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
347343 ident
348344 )
349345 } ) ?;
350- self . attempt_match_node ( match_inputs , & p, & code_record) ?;
346+ self . attempt_match_node ( phase , & p, & code_record) ?;
351347 }
352348 }
353349 }
@@ -367,16 +363,15 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
367363 /// pattern matches the macro invocation. For matches within the macro call, we'll already have
368364 /// expanded the macro.
369365 fn attempt_match_token_tree (
370- & mut self ,
371- match_inputs : & MatchInputs ,
366+ & self ,
367+ phase : & mut Phase ,
372368 pattern : & SyntaxNode ,
373369 code : & ra_syntax:: SyntaxNode ,
374370 ) -> Result < ( ) , MatchFailed > {
375371 let mut pattern = PatternIterator :: new ( pattern) . peekable ( ) ;
376372 let mut children = code. children_with_tokens ( ) ;
377373 while let Some ( child) = children. next ( ) {
378- if let Some ( placeholder) = pattern. peek ( ) . and_then ( |p| match_inputs. get_placeholder ( p) )
379- {
374+ if let Some ( placeholder) = pattern. peek ( ) . and_then ( |p| self . get_placeholder ( p) ) {
380375 pattern. next ( ) ;
381376 let next_pattern_token = pattern
382377 . peek ( )
@@ -402,7 +397,7 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
402397 if Some ( first_token. to_string ( ) ) == next_pattern_token {
403398 if let Some ( SyntaxElement :: Node ( p) ) = pattern. next ( ) {
404399 // We have a subtree that starts with the next token in our pattern.
405- self . attempt_match_token_tree ( match_inputs , & p, & n) ?;
400+ self . attempt_match_token_tree ( phase , & p, & n) ?;
406401 break ;
407402 }
408403 }
@@ -411,7 +406,7 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
411406 } ;
412407 last_matched_token = next;
413408 }
414- if let Some ( match_out) = & mut self . match_out {
409+ if let Phase :: Second ( match_out) = phase {
415410 match_out. placeholder_values . insert (
416411 Var ( placeholder. ident . to_string ( ) ) ,
417412 PlaceholderMatch :: from_range ( FileRange {
@@ -427,11 +422,11 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
427422 // Match literal (non-placeholder) tokens.
428423 match child {
429424 SyntaxElement :: Token ( token) => {
430- self . attempt_match_token ( & mut pattern, & token) ?;
425+ self . attempt_match_token ( phase , & mut pattern, & token) ?;
431426 }
432427 SyntaxElement :: Node ( node) => match pattern. next ( ) {
433428 Some ( SyntaxElement :: Node ( p) ) => {
434- self . attempt_match_token_tree ( match_inputs , & p, & node) ?;
429+ self . attempt_match_token_tree ( phase , & p, & node) ?;
435430 }
436431 Some ( SyntaxElement :: Token ( p) ) => fail_match ! (
437432 "Pattern has token '{}', code has subtree '{}'" ,
@@ -448,6 +443,13 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
448443 Ok ( ( ) )
449444 }
450445
446+ fn get_placeholder ( & self , element : & SyntaxElement ) -> Option < & Placeholder > {
447+ only_ident ( element. clone ( ) )
448+ . and_then ( |ident| self . rule . pattern . placeholders_by_stand_in . get ( ident. text ( ) ) )
449+ }
450+ }
451+
452+ impl Phase < ' _ > {
451453 fn next_non_trivial ( & mut self , code_it : & mut SyntaxElementChildren ) -> Option < SyntaxElement > {
452454 loop {
453455 let c = code_it. next ( ) ;
@@ -463,7 +465,7 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
463465
464466 fn record_ignored_comments ( & mut self , token : & SyntaxToken ) {
465467 if token. kind ( ) == SyntaxKind :: COMMENT {
466- if let Some ( match_out) = & mut self . match_out {
468+ if let Phase :: Second ( match_out) = self {
467469 if let Some ( comment) = ast:: Comment :: cast ( token. clone ( ) ) {
468470 match_out. ignored_comments . push ( comment) ;
469471 }
@@ -472,13 +474,6 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
472474 }
473475}
474476
475- impl MatchInputs < ' _ > {
476- fn get_placeholder ( & self , element : & SyntaxElement ) -> Option < & Placeholder > {
477- only_ident ( element. clone ( ) )
478- . and_then ( |ident| self . ssr_pattern . placeholders_by_stand_in . get ( ident. text ( ) ) )
479- }
480- }
481-
482477fn is_closing_token ( kind : SyntaxKind ) -> bool {
483478 kind == SyntaxKind :: R_PAREN || kind == SyntaxKind :: R_CURLY || kind == SyntaxKind :: R_BRACK
484479}
@@ -596,12 +591,12 @@ impl PatternIterator {
596591#[ cfg( test) ]
597592mod tests {
598593 use super :: * ;
599- use crate :: MatchFinder ;
594+ use crate :: { MatchFinder , SsrRule } ;
600595
601596 #[ test]
602597 fn parse_match_replace ( ) {
603598 let rule: SsrRule = "foo($x) ==>> bar($x)" . parse ( ) . unwrap ( ) ;
604- let input = "fn main() { foo(1+2); }" ;
599+ let input = "fn foo() {} fn main() { foo(1+2); }" ;
605600
606601 use ra_db:: fixture:: WithFixture ;
607602 let ( db, file_id) = ra_ide_db:: RootDatabase :: with_single_file ( input) ;
@@ -623,6 +618,6 @@ mod tests {
623618 let edit = crate :: replacing:: matches_to_edit ( & matches, input) ;
624619 let mut after = input. to_string ( ) ;
625620 edit. apply ( & mut after) ;
626- assert_eq ! ( after, "fn main() { bar(1+2); }" ) ;
621+ assert_eq ! ( after, "fn foo() {} fn main() { bar(1+2); }" ) ;
627622 }
628623}
0 commit comments