aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ssr/src/matching.rs
diff options
context:
space:
mode:
authorDavid Lattimore <[email protected]>2020-07-24 11:53:48 +0100
committerDavid Lattimore <[email protected]>2020-07-24 12:34:00 +0100
commit3dac31fe80b9d7279e87b94615b0d55805e83412 (patch)
treed172c092d9ca93c182b2d88c30c3086a9ea797b0 /crates/ra_ssr/src/matching.rs
parent8d09ab86edfc01405fd0045bef82e0642efd5f01 (diff)
SSR: Allow function calls to match method calls
This differs from how this used to work before I removed it in that: a) It's only one direction. Function calls in the pattern can match method calls in the code, but not the other way around. b) We now check that the function call in the pattern resolves to the same function as the method call in the code. The lack of (b) was the reason I felt the need to remove the feature before.
Diffstat (limited to 'crates/ra_ssr/src/matching.rs')
-rw-r--r--crates/ra_ssr/src/matching.rs42
1 files changed, 40 insertions, 2 deletions
diff --git a/crates/ra_ssr/src/matching.rs b/crates/ra_ssr/src/matching.rs
index f3cc60c29..4862622bd 100644
--- a/crates/ra_ssr/src/matching.rs
+++ b/crates/ra_ssr/src/matching.rs
@@ -189,10 +189,17 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
189 } 189 }
190 return Ok(()); 190 return Ok(());
191 } 191 }
192 // Non-placeholders. 192 // We allow a UFCS call to match a method call, provided they resolve to the same function.
193 if let Some(pattern_function) = self.rule.pattern.ufcs_function_calls.get(pattern) {
194 if let (Some(pattern), Some(code)) =
195 (ast::CallExpr::cast(pattern.clone()), ast::MethodCallExpr::cast(code.clone()))
196 {
197 return self.attempt_match_ufcs(phase, &pattern, &code, *pattern_function);
198 }
199 }
193 if pattern.kind() != code.kind() { 200 if pattern.kind() != code.kind() {
194 fail_match!( 201 fail_match!(
195 "Pattern had a `{}` ({:?}), code had `{}` ({:?})", 202 "Pattern had `{}` ({:?}), code had `{}` ({:?})",
196 pattern.text(), 203 pattern.text(),
197 pattern.kind(), 204 pattern.kind(),
198 code.text(), 205 code.text(),
@@ -514,6 +521,37 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
514 Ok(()) 521 Ok(())
515 } 522 }
516 523
524 fn attempt_match_ufcs(
525 &self,
526 phase: &mut Phase,
527 pattern: &ast::CallExpr,
528 code: &ast::MethodCallExpr,
529 pattern_function: hir::Function,
530 ) -> Result<(), MatchFailed> {
531 use ast::ArgListOwner;
532 let code_resolved_function = self
533 .sema
534 .resolve_method_call(code)
535 .ok_or_else(|| match_error!("Failed to resolve method call"))?;
536 if pattern_function != code_resolved_function {
537 fail_match!("Method call resolved to a different function");
538 }
539 // Check arguments.
540 let mut pattern_args = pattern
541 .arg_list()
542 .ok_or_else(|| match_error!("Pattern function call has no args"))?
543 .args();
544 self.attempt_match_opt(phase, pattern_args.next(), code.expr())?;
545 let mut code_args =
546 code.arg_list().ok_or_else(|| match_error!("Code method call has no args"))?.args();
547 loop {
548 match (pattern_args.next(), code_args.next()) {
549 (None, None) => return Ok(()),
550 (p, c) => self.attempt_match_opt(phase, p, c)?,
551 }
552 }
553 }
554
517 fn get_placeholder(&self, element: &SyntaxElement) -> Option<&Placeholder> { 555 fn get_placeholder(&self, element: &SyntaxElement) -> Option<&Placeholder> {
518 only_ident(element.clone()).and_then(|ident| self.rule.get_placeholder(&ident)) 556 only_ident(element.clone()).and_then(|ident| self.rule.get_placeholder(&ident))
519 } 557 }