Fix bug where patterns with top-level alternatives were not considered 'rooted'
This commit is contained in:
parent
1401767689
commit
548c12fb88
5 changed files with 169 additions and 22 deletions
|
|
@ -1695,31 +1695,54 @@ fn test_query_sibling_patterns_dont_match_children_of_an_error() {
|
|||
language,
|
||||
r#"
|
||||
("{" @open "}" @close)
|
||||
|
||||
[
|
||||
(line_comment)
|
||||
(block_comment)
|
||||
] @comment
|
||||
|
||||
("<" @first "<" @second)
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Most of the document will fail to parse, resulting in a
|
||||
// large number of tokens that are *direct* children of an
|
||||
// ERROR node.
|
||||
//
|
||||
// These children should still match, unless they are part
|
||||
// of a "non-rooted" pattern, in which there are multiple
|
||||
// top-level sibling nodes. Those patterns should not match
|
||||
// directly inside of an error node, because the contents of
|
||||
// an error node are not syntactically well-structured, so we
|
||||
// would get many spurious matches.
|
||||
let source = "
|
||||
fn a() {}
|
||||
|
||||
<<<<<<<<<< add pub b fn () {}
|
||||
// comment 1
|
||||
pub fn b() {
|
||||
/* comment 2 */
|
||||
==========
|
||||
pub fn c() {
|
||||
// comment 3
|
||||
>>>>>>>>>> add pub c fn () {}
|
||||
}
|
||||
";
|
||||
|
||||
let mut parser = Parser::new();
|
||||
parser.set_language(language).unwrap();
|
||||
|
||||
let tree = parser.parse(&source, None).unwrap();
|
||||
|
||||
let mut cursor = QueryCursor::new();
|
||||
let matches = cursor.matches(&query, tree.root_node(), source.as_bytes());
|
||||
assert_eq!(
|
||||
collect_matches(matches, &query, source),
|
||||
&[(0, vec![("open", "{"), ("close", "}")])],
|
||||
&[
|
||||
(0, vec![("open", "{"), ("close", "}")]),
|
||||
(1, vec![("comment", "// comment 1")]),
|
||||
(1, vec![("comment", "/* comment 2 */")]),
|
||||
(1, vec![("comment", "// comment 3")]),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
@ -3956,6 +3979,97 @@ fn test_query_is_pattern_guaranteed_at_step() {
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_is_pattern_rooted() {
|
||||
struct Row {
|
||||
description: &'static str,
|
||||
pattern: &'static str,
|
||||
is_rooted: bool,
|
||||
}
|
||||
|
||||
let rows = [
|
||||
Row {
|
||||
description: "simple token",
|
||||
pattern: r#"(identifier)"#,
|
||||
is_rooted: true,
|
||||
},
|
||||
Row {
|
||||
description: "simple non-terminal",
|
||||
pattern: r#"(function_definition name: (identifier))"#,
|
||||
is_rooted: true,
|
||||
},
|
||||
Row {
|
||||
description: "alternative of many tokens",
|
||||
pattern: r#"["if" "def" (identifier) (comment)]"#,
|
||||
is_rooted: true,
|
||||
},
|
||||
Row {
|
||||
description: "alternative of many non-terminals",
|
||||
pattern: r#"[
|
||||
(function_definition name: (identifier))
|
||||
(class_definition name: (identifier))
|
||||
(block)
|
||||
]"#,
|
||||
is_rooted: true,
|
||||
},
|
||||
Row {
|
||||
description: "two siblings",
|
||||
pattern: r#"("{" "}")"#,
|
||||
is_rooted: false,
|
||||
},
|
||||
Row {
|
||||
description: "top-level repetition",
|
||||
pattern: r#"(comment)*"#,
|
||||
is_rooted: false,
|
||||
},
|
||||
Row {
|
||||
description: "alternative where one option has two siblings",
|
||||
pattern: r#"[
|
||||
(block)
|
||||
(class_definition)
|
||||
("(" ")")
|
||||
(function_definition)
|
||||
]"#,
|
||||
is_rooted: false,
|
||||
},
|
||||
Row {
|
||||
description: "alternative where one option has a top-level repetition",
|
||||
pattern: r#"[
|
||||
(block)
|
||||
(class_definition)
|
||||
(comment)*
|
||||
(function_definition)
|
||||
]"#,
|
||||
is_rooted: false,
|
||||
},
|
||||
];
|
||||
|
||||
allocations::record(|| {
|
||||
eprintln!("");
|
||||
|
||||
let language = get_language("python");
|
||||
for row in &rows {
|
||||
if let Some(filter) = EXAMPLE_FILTER.as_ref() {
|
||||
if !row.description.contains(filter.as_str()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
eprintln!(" query example: {:?}", row.description);
|
||||
let query = Query::new(language, row.pattern).unwrap();
|
||||
assert_eq!(
|
||||
query.is_pattern_rooted(0),
|
||||
row.is_rooted,
|
||||
"Description: {}, Pattern: {:?}",
|
||||
row.description,
|
||||
row.pattern
|
||||
.split_ascii_whitespace()
|
||||
.collect::<Vec<_>>()
|
||||
.join(" "),
|
||||
)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_capture_quantifiers() {
|
||||
struct Row {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue