Skip to content

Commit 8372a2e

Browse files
committed
Rust: ensure error and token locations are valid
The locations are "clipped" to the ranges of the parent node of a token, and the root node of the parse tree for errors.
1 parent 58d2c71 commit 8372a2e

File tree

4 files changed

+193
-168
lines changed

4 files changed

+193
-168
lines changed

rust/ast-generator/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ impl Translator<'_> {{
522522
writeln!(buf, " self.emit_location(label, &node);")?;
523523
writeln!(
524524
buf,
525-
" self.emit_tokens(label.into(), node.syntax().children_with_tokens());"
525+
" self.emit_tokens(&node, label.into(), node.syntax().children_with_tokens());"
526526
)?;
527527
writeln!(buf, " label")?;
528528

rust/extractor/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ fn extract(
2727
);
2828

2929
for err in parse_errors {
30-
translator.emit_parse_error(&err);
30+
translator.emit_parse_error(&ast, &err);
3131
}
3232
let no_location = (LineCol { line: 0, col: 0 }, LineCol { line: 0, col: 0 });
3333
if translator.semi.is_none() {

rust/extractor/src/translate/base.rs

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,21 @@ impl<'a> Translator<'a> {
139139
);
140140
}
141141
}
142-
pub fn emit_location_token(&mut self, label: Label<generated::Token>, token: &SyntaxToken) {
143-
let (start, end) = self.location(token.text_range());
144-
self.trap.emit_location(self.label, label, start, end)
142+
pub fn emit_location_token(
143+
&mut self,
144+
label: Label<generated::Token>,
145+
parent: &impl ast::AstNode,
146+
token: &SyntaxToken,
147+
) {
148+
let parent_range = parent.syntax().text_range();
149+
let token_range = token.text_range();
150+
if let Some(clipped_range) = token_range.intersect(parent_range) {
151+
if let Some(parent_range2) = self.text_range_for_node(parent) {
152+
let token_range = clipped_range + parent_range2.start() - parent_range.start();
153+
let (start, end) = self.location(token_range);
154+
self.trap.emit_location(self.label, label, start, end)
155+
}
156+
}
145157
}
146158
pub fn emit_diagnostic(
147159
&mut self,
@@ -175,31 +187,41 @@ impl<'a> Translator<'a> {
175187
location,
176188
);
177189
}
178-
pub fn emit_parse_error(&mut self, err: &SyntaxError) {
179-
let location = self.location(err.range());
180-
let message = err.to_string();
181-
self.emit_diagnostic(
182-
DiagnosticSeverity::Warning,
183-
"parse_error".to_owned(),
184-
message.clone(),
185-
message,
186-
location,
187-
);
190+
pub fn emit_parse_error(&mut self, owner: &impl ast::AstNode, err: &SyntaxError) {
191+
let owner_range: TextRange = owner.syntax().text_range();
192+
let err_range = err.range();
193+
if let Some(owner_range2) = self.text_range_for_node(owner) {
194+
let location = if let Some(clipped_range) = err_range.intersect(owner_range) {
195+
let err_range = clipped_range + owner_range2.start() - owner_range.start();
196+
self.location(err_range)
197+
} else {
198+
self.location(owner_range2)
199+
};
200+
let message = err.to_string();
201+
self.emit_diagnostic(
202+
DiagnosticSeverity::Warning,
203+
"parse_error".to_owned(),
204+
message.clone(),
205+
message,
206+
location,
207+
);
208+
}
188209
}
189210
pub fn emit_tokens(
190211
&mut self,
191-
parent: Label<generated::AstNode>,
212+
parent_node: &impl ast::AstNode,
213+
parent_label: Label<generated::AstNode>,
192214
children: SyntaxElementChildren,
193215
) {
194216
for child in children {
195217
if let NodeOrToken::Token(token) = child {
196218
if token.kind() == SyntaxKind::COMMENT {
197219
let label = self.trap.emit(generated::Comment {
198220
id: TrapId::Star,
199-
parent,
221+
parent: parent_label,
200222
text: token.text().to_owned(),
201223
});
202-
self.emit_location_token(label.into(), &token);
224+
self.emit_location_token(label.into(), parent_node, &token);
203225
}
204226
}
205227
}
@@ -230,11 +252,11 @@ impl<'a> Translator<'a> {
230252
.get_erased(err.span().anchor.ast_id)
231253
.text_range()
232254
.start();
233-
self.emit_parse_error(&SyntaxError::new(message, location));
255+
self.emit_parse_error(mcall, &SyntaxError::new(message, location));
234256
};
235257
}
236258
for err in value.value.iter() {
237-
self.emit_parse_error(err);
259+
self.emit_parse_error(mcall, err);
238260
}
239261
}
240262
let expand_to = ra_ap_hir_expand::ExpandTo::from_call_site(mcall);
@@ -261,7 +283,7 @@ impl<'a> Translator<'a> {
261283
MacroCall::emit_expanded(label, value, &mut self.trap.writer);
262284
} else {
263285
let range = self.text_range_for_node(mcall);
264-
self.emit_parse_error(&SyntaxError::new(
286+
self.emit_parse_error(mcall, &SyntaxError::new(
265287
format!(
266288
"macro expansion failed: the macro '{}' expands to {:?} but a {:?} was expected",
267289
mcall.path().map(|p| p.to_string()).unwrap_or_default(),
@@ -273,13 +295,16 @@ impl<'a> Translator<'a> {
273295
} else {
274296
let range = self.text_range_for_node(mcall);
275297

276-
self.emit_parse_error(&SyntaxError::new(
277-
format!(
278-
"macro expansion failed: could not resolve macro '{}'",
279-
mcall.path().map(|p| p.to_string()).unwrap_or_default()
298+
self.emit_parse_error(
299+
mcall,
300+
&SyntaxError::new(
301+
format!(
302+
"macro expansion failed: could not resolve macro '{}'",
303+
mcall.path().map(|p| p.to_string()).unwrap_or_default()
304+
),
305+
range.unwrap_or_else(|| TextRange::empty(TextSize::from(0))),
280306
),
281-
range.unwrap_or_else(|| TextRange::empty(TextSize::from(0))),
282-
));
307+
);
283308
}
284309
}
285310
}

0 commit comments

Comments
 (0)