Skip to content

Commit a895797

Browse files
committed
Fix error spans for include! and compile_error!
1 parent 79defab commit a895797

File tree

4 files changed

+56
-29
lines changed

4 files changed

+56
-29
lines changed

src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -460,10 +460,10 @@ fn compile_error_expand(
460460
let err = match &*tt.token_trees {
461461
[tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
462462
symbol: text,
463-
span,
463+
span: _,
464464
kind: tt::LitKind::Str | tt::LitKind::StrRaw(_),
465465
suffix: _,
466-
}))] => ExpandError::other(*span, Box::from(unescape_str(text).as_str())),
466+
}))] => ExpandError::other(span, Box::from(unescape_str(text).as_str())),
467467
_ => ExpandError::other(span, "`compile_error!` argument must be a string"),
468468
};
469469

@@ -706,18 +706,19 @@ fn relative_file(
706706
fn parse_string(tt: &tt::Subtree) -> Result<(Symbol, Span), ExpandError> {
707707
tt.token_trees
708708
.first()
709+
.ok_or(tt.delimiter.open.cover(tt.delimiter.close))
709710
.and_then(|tt| match tt {
710711
tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
711712
symbol: text,
712713
span,
713714
kind: tt::LitKind::Str,
714715
suffix: _,
715-
})) => Some((unescape_str(text), *span)),
716+
})) => Ok((unescape_str(text), *span)),
716717
// FIXME: We wrap expression fragments in parentheses which can break this expectation
717718
// here
718719
// Remove this once we handle none delims correctly
719-
tt::TokenTree::Subtree(t) if t.delimiter.kind == DelimiterKind::Parenthesis => {
720-
t.token_trees.first().and_then(|tt| match tt {
720+
tt::TokenTree::Subtree(tt) if tt.delimiter.kind == DelimiterKind::Parenthesis => {
721+
tt.token_trees.first().and_then(|tt| match tt {
721722
tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
722723
symbol: text,
723724
span,
@@ -727,9 +728,11 @@ fn parse_string(tt: &tt::Subtree) -> Result<(Symbol, Span), ExpandError> {
727728
_ => None,
728729
})
729730
}
730-
_ => None,
731+
.ok_or(tt.delimiter.open.cover(tt.delimiter.close)),
732+
::tt::TokenTree::Leaf(l) => Err(*l.span()),
733+
::tt::TokenTree::Subtree(tt) => Err(tt.delimiter.open.cover(tt.delimiter.close)),
731734
})
732-
.ok_or(ExpandError::other(tt.delimiter.open, "expected string literal"))
735+
.map_err(|span| ExpandError::other(span, "expected string literal"))
733736
}
734737

735738
fn include_expand(
@@ -763,7 +766,8 @@ pub fn include_input_to_file_id(
763766
arg_id: MacroCallId,
764767
arg: &tt::Subtree,
765768
) -> Result<EditionedFileId, ExpandError> {
766-
relative_file(db, arg_id, parse_string(arg)?.0.as_str(), false, arg.delimiter.open)
769+
let (s, span) = parse_string(arg)?;
770+
relative_file(db, arg_id, s.as_str(), false, span)
767771
}
768772

769773
fn include_bytes_expand(

src/tools/rust-analyzer/crates/hir/src/lib.rs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -837,13 +837,17 @@ fn macro_call_diagnostics(
837837
let node =
838838
InFile::new(file_id, db.ast_id_map(file_id).get_erased(loc.kind.erased_ast_id()));
839839
let (message, error) = err.render_to_string(db.upcast());
840-
let precise_location = Some(
841-
err.span().range
842-
+ db.ast_id_map(err.span().anchor.file_id.into())
843-
.get_erased(err.span().anchor.ast_id)
844-
.text_range()
845-
.start(),
846-
);
840+
let precise_location = if err.span().anchor.file_id == file_id {
841+
Some(
842+
err.span().range
843+
+ db.ast_id_map(err.span().anchor.file_id.into())
844+
.get_erased(err.span().anchor.ast_id)
845+
.text_range()
846+
.start(),
847+
)
848+
} else {
849+
None
850+
};
847851
acc.push(MacroError { node, precise_location, message, error }.into());
848852
}
849853

@@ -1798,13 +1802,17 @@ impl DefWithBody {
17981802
BodyDiagnostic::MacroError { node, err } => {
17991803
let (message, error) = err.render_to_string(db.upcast());
18001804

1801-
let precise_location = Some(
1802-
err.span().range
1803-
+ db.ast_id_map(err.span().anchor.file_id.into())
1804-
.get_erased(err.span().anchor.ast_id)
1805-
.text_range()
1806-
.start(),
1807-
);
1805+
let precise_location = if err.span().anchor.file_id == node.file_id {
1806+
Some(
1807+
err.span().range
1808+
+ db.ast_id_map(err.span().anchor.file_id.into())
1809+
.get_erased(err.span().anchor.ast_id)
1810+
.text_range()
1811+
.start(),
1812+
)
1813+
} else {
1814+
None
1815+
};
18081816
MacroError {
18091817
node: (*node).map(|it| it.into()),
18101818
precise_location,

src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ macro_rules! include { () => {} }
4848
macro_rules! compile_error { () => {} }
4949
5050
include!("doesntexist");
51-
//^^^^^^^ error: failed to load file `doesntexist`
51+
//^^^^^^^^^^^^^ error: failed to load file `doesntexist`
5252
5353
compile_error!("compile_error macro works");
5454
//^^^^^^^^^^^^^ error: compile_error macro works
@@ -128,7 +128,7 @@ macro_rules! env { () => {} }
128128
macro_rules! concat { () => {} }
129129
130130
include!(concat!(env!("OUT_DIR"), "/out.rs"));
131-
//^^^^^^^ error: `OUT_DIR` not set, enable "build scripts" to fix
131+
//^^^^^^^^^ error: `OUT_DIR` not set, enable "build scripts" to fix
132132
"#,
133133
);
134134
}
@@ -163,20 +163,25 @@ macro_rules! include {}
163163
164164
#[rustc_builtin_macro]
165165
macro_rules! compile_error {}
166+
#[rustc_builtin_macro]
167+
macro_rules! concat {}
166168
167169
fn main() {
168170
// Test a handful of built-in (eager) macros:
169171
170172
include!(invalid);
171-
//^^^^^^^ error: expected string literal
173+
//^^^^^^^ error: expected string literal
172174
include!("does not exist");
173-
//^^^^^^^ error: failed to load file `does not exist`
175+
//^^^^^^^^^^^^^^^^ error: failed to load file `does not exist`
176+
177+
include!(concat!("does ", "not ", "exist"));
178+
//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `does not exist`
174179
175180
env!(invalid);
176-
//^^^ error: expected string literal
181+
//^^^^^^^ error: expected string literal
177182
178183
env!("OUT_DIR");
179-
//^^^ error: `OUT_DIR` not set, enable "build scripts" to fix
184+
//^^^^^^^^^ error: `OUT_DIR` not set, enable "build scripts" to fix
180185
181186
compile_error!("compile_error works");
182187
//^^^^^^^^^^^^^ error: compile_error works
@@ -201,7 +206,7 @@ fn f() {
201206
m!();
202207
203208
m!(hi);
204-
//^ error: leftover tokens
209+
//^ error: leftover tokens
205210
}
206211
"#,
207212
);

src/tools/rust-analyzer/crates/span/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId =
3333

3434
pub type Span = SpanData<SyntaxContextId>;
3535

36+
impl Span {
37+
pub fn cover(self, other: Span) -> Span {
38+
if self.anchor != other.anchor {
39+
return self;
40+
}
41+
let range = self.range.cover(other.range);
42+
Span { range, ..self }
43+
}
44+
}
45+
3646
/// Spans represent a region of code, used by the IDE to be able link macro inputs and outputs
3747
/// together. Positions in spans are relative to some [`SpanAnchor`] to make them more incremental
3848
/// friendly.

0 commit comments

Comments
 (0)