fix: Reject parse trees with missing nodes #587

Merged
wetneb merged 1 commit from 554-missing-nodes into main 2025-09-11 23:01:33 +02:00

View file

@ -1,4 +1,4 @@
class MyClass {
public:
int field_1;
}
};

View file

@ -8,4 +8,4 @@ class MyClass {
=======
char field_3;
>>>>>>> RIGHT
}
};

View file

@ -8,4 +8,4 @@ class MyClass {
=======
char field_3;
>>>>>>> RIGHT
}
};

View file

@ -3,4 +3,4 @@ class MyClass {
int field_1;
private:
size_t field_2;
}
};

View file

@ -2,4 +2,4 @@ class MyClass {
public:
int field_1;
char field_3;
}
};

View file

@ -1,3 +1,3 @@
struct my_struct {
int field_1;
}
};

View file

@ -3,4 +3,4 @@ struct my_struct {
char field_2;
size_t field_3;
void* pointer;
}
};

View file

@ -2,4 +2,4 @@ struct my_struct {
int field_1;
char field_2;
size_t field_3;
}
};

View file

@ -1,4 +1,4 @@
struct my_struct {
int field_1;
void* pointer;
}
};

View file

@ -5,4 +5,4 @@ class MyClass {
printf("too few arguments\n");
exit(1);
}
}
};

View file

@ -13,4 +13,4 @@ class MyClass {
void run(bool reallyFast) {
printf("world\n");
}
}
};

View file

@ -9,4 +9,4 @@ class MyClass {
void run() {
printf("hello\n");
}
}
};

View file

@ -9,4 +9,4 @@ class MyClass {
void run(bool reallyFast) {
printf("world\n");
}
}
};

View file

@ -5,4 +5,4 @@ class MyClass {
printf("too few arguments\n");
exit(1);
}
}
};

View file

@ -13,4 +13,4 @@ class MyClass {
void runFast() {
printf("world\n");
}
}
};

View file

@ -9,4 +9,4 @@ class MyClass {
void run() {
printf("hello\n");
}
}
};

View file

@ -9,4 +9,4 @@ class MyClass {
void runFast() {
printf("world\n");
}
}
};

View file

@ -319,13 +319,22 @@ impl<'a> AstNode<'a> {
let idx = local_source.ceil_char_boundary(32);
return Err(format!(
"parse error at {}:{}..{}:{}, starting with: {}",
"parse error at {}:{}..{}:{}, starting with: `{}`",
full_range.start_point.row,
full_range.start_point.column,
full_range.end_point.row,
full_range.end_point.column,
&local_source[..idx]
));
} else if node.is_missing() {
let full_range = node.range();
return Err(format!(
"parse error at {}:{}, expected `{}`",
full_range.start_point.row,
full_range.start_point.column,
node.kind(),
));
}
// if this is a leaf that spans multiple lines, create one child per line,
@ -1222,7 +1231,7 @@ mod tests {
assert_eq!(
parse,
Err("parse error at 1:1..1:3, starting with: {,".to_string())
Err("parse error at 1:1..1:3, starting with: `{,`".to_string())
);
let parse = AstNode::parse(
@ -1234,10 +1243,20 @@ mod tests {
assert_eq!(
parse,
Err("parse error at 0:0..0:39, starting with: 属于个人的非赢利性开源".to_string())
Err("parse error at 0:0..0:39, starting with: `属于个人的非赢利性开源`".to_string())
);
}
#[test]
fn missing_token() {
let ctx = ctx();
let lang_profile = LangProfile::detect_from_filename("test.java")
.expect("Could not load the Java lang profile");
let parse = AstNode::parse("class Test {", lang_profile, &ctx.arena, &ctx.ref_arena);
assert_eq!(parse, Err("parse error at 0:12, expected `}`".to_string()));
}
#[test]
fn heights() {
let ctx = ctx();
@ -1625,7 +1644,7 @@ mod tests {
{
"a": [
1,
2,
2
],
"b": {
"c": "foo"
@ -1643,7 +1662,7 @@ mod tests {
"\
\"a\": [
1,
2,
2
]"
);
assert_eq!(entry_a.indentation_shift(), Some(" "));
@ -1653,7 +1672,7 @@ mod tests {
"\
\"a\": [
1,
2,
2
]"
);
assert_eq!(
@ -1661,7 +1680,7 @@ mod tests {
"\
\"a\": [
1,
2,
2
]"
);
@ -1670,7 +1689,7 @@ mod tests {
"\
[
1,
2,
2
]"
);
assert_eq!(array.indentation_shift(), None);
@ -1680,7 +1699,7 @@ mod tests {
"\
[
1,
2,
2
]"
);
assert_eq!(
@ -1688,7 +1707,7 @@ mod tests {
"\
[
1,
2,
2
]"
);
}

View file

@ -569,10 +569,10 @@ fn foo() {
#[test]
fn dont_bundle_into_delims() {
let ctx = ctx();
let source = "(/* this is a comment */)";
let source = "fn test(/* this is a comment */) {}";
let rs = ctx.parse("a.rs", source);
let tup = rs[0][0];
let tup = rs[0][2];
assert_n_children(tup, 3);
let comment = tup[1];
assert_eq!(comment.kind, "block_comment");