aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ssr/src/matching.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ssr/src/matching.rs')
-rw-r--r--crates/ra_ssr/src/matching.rs51
1 files changed, 43 insertions, 8 deletions
diff --git a/crates/ra_ssr/src/matching.rs b/crates/ra_ssr/src/matching.rs
index bb87bda43..ce53d46d2 100644
--- a/crates/ra_ssr/src/matching.rs
+++ b/crates/ra_ssr/src/matching.rs
@@ -2,17 +2,16 @@
2//! process of matching, placeholder values are recorded. 2//! process of matching, placeholder values are recorded.
3 3
4use crate::{ 4use crate::{
5 parsing::{Placeholder, SsrTemplate}, 5 parsing::{Constraint, NodeKind, Placeholder, SsrTemplate},
6 SsrMatches, SsrPattern, SsrRule, 6 SsrMatches, SsrPattern, SsrRule,
7}; 7};
8use hir::Semantics; 8use hir::Semantics;
9use ra_db::FileRange; 9use ra_db::FileRange;
10use ra_syntax::ast::{AstNode, AstToken}; 10use ra_syntax::ast::{AstNode, AstToken};
11use ra_syntax::{ 11use ra_syntax::{ast, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken};
12 ast, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
13};
14use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
15use std::{cell::Cell, iter::Peekable}; 13use std::{cell::Cell, iter::Peekable};
14use test_utils::mark;
16 15
17// Creates a match error. If we're currently attempting to match some code that we thought we were 16// Creates a match error. If we're currently attempting to match some code that we thought we were
18// going to match, as indicated by the --debug-snippet flag, then populate the reason field. 17// going to match, as indicated by the --debug-snippet flag, then populate the reason field.
@@ -44,8 +43,8 @@ macro_rules! fail_match {
44 43
45/// Information about a match that was found. 44/// Information about a match that was found.
46#[derive(Debug)] 45#[derive(Debug)]
47pub(crate) struct Match { 46pub struct Match {
48 pub(crate) range: TextRange, 47 pub(crate) range: FileRange,
49 pub(crate) matched_node: SyntaxNode, 48 pub(crate) matched_node: SyntaxNode,
50 pub(crate) placeholder_values: FxHashMap<Var, PlaceholderMatch>, 49 pub(crate) placeholder_values: FxHashMap<Var, PlaceholderMatch>,
51 pub(crate) ignored_comments: Vec<ast::Comment>, 50 pub(crate) ignored_comments: Vec<ast::Comment>,
@@ -135,7 +134,7 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
135 match_state.attempt_match_node(&match_inputs, &pattern_tree, code)?; 134 match_state.attempt_match_node(&match_inputs, &pattern_tree, code)?;
136 match_state.validate_range(&sema.original_range(code))?; 135 match_state.validate_range(&sema.original_range(code))?;
137 match_state.match_out = Some(Match { 136 match_state.match_out = Some(Match {
138 range: sema.original_range(code).range, 137 range: sema.original_range(code),
139 matched_node: code.clone(), 138 matched_node: code.clone(),
140 placeholder_values: FxHashMap::default(), 139 placeholder_values: FxHashMap::default(),
141 ignored_comments: Vec::new(), 140 ignored_comments: Vec::new(),
@@ -171,6 +170,9 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
171 if let Some(placeholder) = 170 if let Some(placeholder) =
172 match_inputs.get_placeholder(&SyntaxElement::Node(pattern.clone())) 171 match_inputs.get_placeholder(&SyntaxElement::Node(pattern.clone()))
173 { 172 {
173 for constraint in &placeholder.constraints {
174 self.check_constraint(constraint, code)?;
175 }
174 if self.match_out.is_none() { 176 if self.match_out.is_none() {
175 return Ok(()); 177 return Ok(());
176 } 178 }
@@ -225,7 +227,7 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
225 match self.next_non_trivial(&mut code_it) { 227 match self.next_non_trivial(&mut code_it) {
226 None => { 228 None => {
227 if let Some(p) = pattern_it.next() { 229 if let Some(p) = pattern_it.next() {
228 fail_match!("Part of the pattern was unmached: {:?}", p); 230 fail_match!("Part of the pattern was unmatched: {:?}", p);
229 } 231 }
230 return Ok(()); 232 return Ok(());
231 } 233 }
@@ -294,6 +296,24 @@ impl<'db, 'sema> MatchState<'db, 'sema> {
294 Ok(()) 296 Ok(())
295 } 297 }
296 298
299 fn check_constraint(
300 &self,
301 constraint: &Constraint,
302 code: &SyntaxNode,
303 ) -> Result<(), MatchFailed> {
304 match constraint {
305 Constraint::Kind(kind) => {
306 kind.matches(code)?;
307 }
308 Constraint::Not(sub) => {
309 if self.check_constraint(&*sub, code).is_ok() {
310 fail_match!("Constraint {:?} failed for '{}'", constraint, code.text());
311 }
312 }
313 }
314 Ok(())
315 }
316
297 /// We want to allow the records to match in any order, so we have special matching logic for 317 /// We want to allow the records to match in any order, so we have special matching logic for
298 /// them. 318 /// them.
299 fn attempt_match_record_field_list( 319 fn attempt_match_record_field_list(
@@ -517,6 +537,21 @@ impl SsrPattern {
517 } 537 }
518} 538}
519 539
540impl NodeKind {
541 fn matches(&self, node: &SyntaxNode) -> Result<(), MatchFailed> {
542 let ok = match self {
543 Self::Literal => {
544 mark::hit!(literal_constraint);
545 ast::Literal::can_cast(node.kind())
546 }
547 };
548 if !ok {
549 fail_match!("Code '{}' isn't of kind {:?}", node.text(), self);
550 }
551 Ok(())
552 }
553}
554
520// If `node` contains nothing but an ident then return it, otherwise return None. 555// If `node` contains nothing but an ident then return it, otherwise return None.
521fn only_ident(element: SyntaxElement) -> Option<SyntaxToken> { 556fn only_ident(element: SyntaxElement) -> Option<SyntaxToken> {
522 match element { 557 match element {