diff options
Diffstat (limited to 'crates/ra_ssr/src/matching.rs')
-rw-r--r-- | crates/ra_ssr/src/matching.rs | 51 |
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 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | parsing::{Placeholder, SsrTemplate}, | 5 | parsing::{Constraint, NodeKind, Placeholder, SsrTemplate}, |
6 | SsrMatches, SsrPattern, SsrRule, | 6 | SsrMatches, SsrPattern, SsrRule, |
7 | }; | 7 | }; |
8 | use hir::Semantics; | 8 | use hir::Semantics; |
9 | use ra_db::FileRange; | 9 | use ra_db::FileRange; |
10 | use ra_syntax::ast::{AstNode, AstToken}; | 10 | use ra_syntax::ast::{AstNode, AstToken}; |
11 | use ra_syntax::{ | 11 | use ra_syntax::{ast, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken}; |
12 | ast, SyntaxElement, SyntaxElementChildren, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, | ||
13 | }; | ||
14 | use rustc_hash::FxHashMap; | 12 | use rustc_hash::FxHashMap; |
15 | use std::{cell::Cell, iter::Peekable}; | 13 | use std::{cell::Cell, iter::Peekable}; |
14 | use 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)] |
47 | pub(crate) struct Match { | 46 | pub 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 | ||
540 | impl 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. |
521 | fn only_ident(element: SyntaxElement) -> Option<SyntaxToken> { | 556 | fn only_ident(element: SyntaxElement) -> Option<SyntaxToken> { |
522 | match element { | 557 | match element { |