mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 04:44:57 +00:00
Fix error spans for include! and compile_error!
This commit is contained in:
parent
ae9c553902
commit
d46060b168
4 changed files with 56 additions and 29 deletions
|
@ -460,10 +460,10 @@ fn compile_error_expand(
|
||||||
let err = match &*tt.token_trees {
|
let err = match &*tt.token_trees {
|
||||||
[tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
[tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
||||||
symbol: text,
|
symbol: text,
|
||||||
span,
|
span: _,
|
||||||
kind: tt::LitKind::Str | tt::LitKind::StrRaw(_),
|
kind: tt::LitKind::Str | tt::LitKind::StrRaw(_),
|
||||||
suffix: _,
|
suffix: _,
|
||||||
}))] => ExpandError::other(*span, Box::from(unescape_str(text).as_str())),
|
}))] => ExpandError::other(span, Box::from(unescape_str(text).as_str())),
|
||||||
_ => ExpandError::other(span, "`compile_error!` argument must be a string"),
|
_ => ExpandError::other(span, "`compile_error!` argument must be a string"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -706,18 +706,19 @@ fn relative_file(
|
||||||
fn parse_string(tt: &tt::Subtree) -> Result<(Symbol, Span), ExpandError> {
|
fn parse_string(tt: &tt::Subtree) -> Result<(Symbol, Span), ExpandError> {
|
||||||
tt.token_trees
|
tt.token_trees
|
||||||
.first()
|
.first()
|
||||||
|
.ok_or(tt.delimiter.open.cover(tt.delimiter.close))
|
||||||
.and_then(|tt| match tt {
|
.and_then(|tt| match tt {
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
||||||
symbol: text,
|
symbol: text,
|
||||||
span,
|
span,
|
||||||
kind: tt::LitKind::Str,
|
kind: tt::LitKind::Str,
|
||||||
suffix: _,
|
suffix: _,
|
||||||
})) => Some((unescape_str(text), *span)),
|
})) => Ok((unescape_str(text), *span)),
|
||||||
// FIXME: We wrap expression fragments in parentheses which can break this expectation
|
// FIXME: We wrap expression fragments in parentheses which can break this expectation
|
||||||
// here
|
// here
|
||||||
// Remove this once we handle none delims correctly
|
// Remove this once we handle none delims correctly
|
||||||
tt::TokenTree::Subtree(t) if t.delimiter.kind == DelimiterKind::Parenthesis => {
|
tt::TokenTree::Subtree(tt) if tt.delimiter.kind == DelimiterKind::Parenthesis => {
|
||||||
t.token_trees.first().and_then(|tt| match tt {
|
tt.token_trees.first().and_then(|tt| match tt {
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
||||||
symbol: text,
|
symbol: text,
|
||||||
span,
|
span,
|
||||||
|
@ -727,9 +728,11 @@ fn parse_string(tt: &tt::Subtree) -> Result<(Symbol, Span), ExpandError> {
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => None,
|
.ok_or(tt.delimiter.open.cover(tt.delimiter.close)),
|
||||||
|
::tt::TokenTree::Leaf(l) => Err(*l.span()),
|
||||||
|
::tt::TokenTree::Subtree(tt) => Err(tt.delimiter.open.cover(tt.delimiter.close)),
|
||||||
})
|
})
|
||||||
.ok_or(ExpandError::other(tt.delimiter.open, "expected string literal"))
|
.map_err(|span| ExpandError::other(span, "expected string literal"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn include_expand(
|
fn include_expand(
|
||||||
|
@ -763,7 +766,8 @@ pub fn include_input_to_file_id(
|
||||||
arg_id: MacroCallId,
|
arg_id: MacroCallId,
|
||||||
arg: &tt::Subtree,
|
arg: &tt::Subtree,
|
||||||
) -> Result<EditionedFileId, ExpandError> {
|
) -> Result<EditionedFileId, ExpandError> {
|
||||||
relative_file(db, arg_id, parse_string(arg)?.0.as_str(), false, arg.delimiter.open)
|
let (s, span) = parse_string(arg)?;
|
||||||
|
relative_file(db, arg_id, s.as_str(), false, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn include_bytes_expand(
|
fn include_bytes_expand(
|
||||||
|
|
|
@ -837,13 +837,17 @@ fn macro_call_diagnostics(
|
||||||
let node =
|
let node =
|
||||||
InFile::new(file_id, db.ast_id_map(file_id).get_erased(loc.kind.erased_ast_id()));
|
InFile::new(file_id, db.ast_id_map(file_id).get_erased(loc.kind.erased_ast_id()));
|
||||||
let (message, error) = err.render_to_string(db.upcast());
|
let (message, error) = err.render_to_string(db.upcast());
|
||||||
let precise_location = Some(
|
let precise_location = if err.span().anchor.file_id == file_id {
|
||||||
|
Some(
|
||||||
err.span().range
|
err.span().range
|
||||||
+ db.ast_id_map(err.span().anchor.file_id.into())
|
+ db.ast_id_map(err.span().anchor.file_id.into())
|
||||||
.get_erased(err.span().anchor.ast_id)
|
.get_erased(err.span().anchor.ast_id)
|
||||||
.text_range()
|
.text_range()
|
||||||
.start(),
|
.start(),
|
||||||
);
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
acc.push(MacroError { node, precise_location, message, error }.into());
|
acc.push(MacroError { node, precise_location, message, error }.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1798,13 +1802,17 @@ impl DefWithBody {
|
||||||
BodyDiagnostic::MacroError { node, err } => {
|
BodyDiagnostic::MacroError { node, err } => {
|
||||||
let (message, error) = err.render_to_string(db.upcast());
|
let (message, error) = err.render_to_string(db.upcast());
|
||||||
|
|
||||||
let precise_location = Some(
|
let precise_location = if err.span().anchor.file_id == node.file_id {
|
||||||
|
Some(
|
||||||
err.span().range
|
err.span().range
|
||||||
+ db.ast_id_map(err.span().anchor.file_id.into())
|
+ db.ast_id_map(err.span().anchor.file_id.into())
|
||||||
.get_erased(err.span().anchor.ast_id)
|
.get_erased(err.span().anchor.ast_id)
|
||||||
.text_range()
|
.text_range()
|
||||||
.start(),
|
.start(),
|
||||||
);
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
MacroError {
|
MacroError {
|
||||||
node: (*node).map(|it| it.into()),
|
node: (*node).map(|it| it.into()),
|
||||||
precise_location,
|
precise_location,
|
||||||
|
|
|
@ -48,7 +48,7 @@ macro_rules! include { () => {} }
|
||||||
macro_rules! compile_error { () => {} }
|
macro_rules! compile_error { () => {} }
|
||||||
|
|
||||||
include!("doesntexist");
|
include!("doesntexist");
|
||||||
//^^^^^^^ error: failed to load file `doesntexist`
|
//^^^^^^^^^^^^^ error: failed to load file `doesntexist`
|
||||||
|
|
||||||
compile_error!("compile_error macro works");
|
compile_error!("compile_error macro works");
|
||||||
//^^^^^^^^^^^^^ error: compile_error macro works
|
//^^^^^^^^^^^^^ error: compile_error macro works
|
||||||
|
@ -128,7 +128,7 @@ macro_rules! env { () => {} }
|
||||||
macro_rules! concat { () => {} }
|
macro_rules! concat { () => {} }
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/out.rs"));
|
include!(concat!(env!("OUT_DIR"), "/out.rs"));
|
||||||
//^^^^^^^ error: `OUT_DIR` not set, enable "build scripts" to fix
|
//^^^^^^^^^ error: `OUT_DIR` not set, enable "build scripts" to fix
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -163,6 +163,8 @@ macro_rules! include {}
|
||||||
|
|
||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
macro_rules! compile_error {}
|
macro_rules! compile_error {}
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
macro_rules! concat {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Test a handful of built-in (eager) macros:
|
// Test a handful of built-in (eager) macros:
|
||||||
|
@ -170,13 +172,16 @@ fn main() {
|
||||||
include!(invalid);
|
include!(invalid);
|
||||||
//^^^^^^^ error: expected string literal
|
//^^^^^^^ error: expected string literal
|
||||||
include!("does not exist");
|
include!("does not exist");
|
||||||
//^^^^^^^ error: failed to load file `does not exist`
|
//^^^^^^^^^^^^^^^^ error: failed to load file `does not exist`
|
||||||
|
|
||||||
|
include!(concat!("does ", "not ", "exist"));
|
||||||
|
//^^^^^^^^^^^^^^^^^^^^^^^^^^ error: failed to load file `does not exist`
|
||||||
|
|
||||||
env!(invalid);
|
env!(invalid);
|
||||||
//^^^ error: expected string literal
|
//^^^^^^^ error: expected string literal
|
||||||
|
|
||||||
env!("OUT_DIR");
|
env!("OUT_DIR");
|
||||||
//^^^ error: `OUT_DIR` not set, enable "build scripts" to fix
|
//^^^^^^^^^ error: `OUT_DIR` not set, enable "build scripts" to fix
|
||||||
|
|
||||||
compile_error!("compile_error works");
|
compile_error!("compile_error works");
|
||||||
//^^^^^^^^^^^^^ error: compile_error works
|
//^^^^^^^^^^^^^ error: compile_error works
|
||||||
|
|
|
@ -33,6 +33,16 @@ pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId =
|
||||||
|
|
||||||
pub type Span = SpanData<SyntaxContextId>;
|
pub type Span = SpanData<SyntaxContextId>;
|
||||||
|
|
||||||
|
impl Span {
|
||||||
|
pub fn cover(self, other: Span) -> Span {
|
||||||
|
if self.anchor != other.anchor {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
let range = self.range.cover(other.range);
|
||||||
|
Span { range, ..self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Spans represent a region of code, used by the IDE to be able link macro inputs and outputs
|
/// Spans represent a region of code, used by the IDE to be able link macro inputs and outputs
|
||||||
/// together. Positions in spans are relative to some [`SpanAnchor`] to make them more incremental
|
/// together. Positions in spans are relative to some [`SpanAnchor`] to make them more incremental
|
||||||
/// friendly.
|
/// friendly.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue