]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_expand/src/proc_macro_server.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / compiler / rustc_expand / src / proc_macro_server.rs
CommitLineData
3c0e092e 1use crate::base::ExtCtxt;
e74abb32 2
3dfed10e 3use rustc_ast as ast;
5e7ed085 4use rustc_ast::token;
5869c6ff
XL
5use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
6use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
74b04a01 7use rustc_ast_pretty::pprust;
17df50a5 8use rustc_data_structures::fx::FxHashMap;
dfeec247 9use rustc_data_structures::sync::Lrc;
3c0e092e 10use rustc_errors::{Diagnostic, PResult};
dfeec247
XL
11use rustc_parse::lexer::nfc_normalize;
12use rustc_parse::{nt_to_tokenstream, parse_stream_from_source_str};
74b04a01 13use rustc_session::parse::ParseSess;
17df50a5 14use rustc_span::def_id::CrateNum;
f9f354fc 15use rustc_span::symbol::{self, kw, sym, Symbol};
5e7ed085 16use rustc_span::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
416331ca 17
e74abb32 18use pm::bridge::{server, TokenTree};
dfeec247 19use pm::{Delimiter, Level, LineColumn, Spacing};
416331ca 20use std::ops::Bound;
dfeec247 21use std::{ascii, panic};
a1dfa0c6
XL
22
23trait FromInternal<T> {
24 fn from_internal(x: T) -> Self;
25}
26
27trait ToInternal<T> {
28 fn to_internal(self) -> T;
29}
30
31impl FromInternal<token::DelimToken> for Delimiter {
32 fn from_internal(delim: token::DelimToken) -> Delimiter {
33 match delim {
34 token::Paren => Delimiter::Parenthesis,
35 token::Brace => Delimiter::Brace,
36 token::Bracket => Delimiter::Bracket,
37 token::NoDelim => Delimiter::None,
38 }
39 }
40}
41
42impl ToInternal<token::DelimToken> for Delimiter {
43 fn to_internal(self) -> token::DelimToken {
44 match self {
45 Delimiter::Parenthesis => token::Paren,
46 Delimiter::Brace => token::Brace,
47 Delimiter::Bracket => token::Bracket,
48 Delimiter::None => token::NoDelim,
49 }
50 }
51}
52
3c0e092e 53impl FromInternal<(TreeAndSpacing, &'_ mut Vec<Self>, &mut Rustc<'_, '_>)>
a1dfa0c6
XL
54 for TokenTree<Group, Punct, Ident, Literal>
55{
dfeec247 56 fn from_internal(
3c0e092e 57 ((tree, spacing), stack, rustc): (TreeAndSpacing, &mut Vec<Self>, &mut Rustc<'_, '_>),
dfeec247 58 ) -> Self {
74b04a01 59 use rustc_ast::token::*;
a1dfa0c6 60
1b1a35ee 61 let joint = spacing == Joint;
dc9dc135 62 let Token { kind, span } = match tree {
0731742a
XL
63 tokenstream::TokenTree::Delimited(span, delim, tts) => {
64 let delimiter = Delimiter::from_internal(delim);
f035d41b 65 return TokenTree::Group(Group { delimiter, stream: tts, span, flatten: false });
a1dfa0c6 66 }
dc9dc135 67 tokenstream::TokenTree::Token(token) => token,
a1dfa0c6
XL
68 };
69
70 macro_rules! tt {
9fa01778 71 ($ty:ident { $($field:ident $(: $value:expr)*),+ $(,)? }) => (
a1dfa0c6 72 TokenTree::$ty(self::$ty {
dc9dc135 73 $($field $(: $value)*,)+
a1dfa0c6
XL
74 span,
75 })
0731742a
XL
76 );
77 ($ty:ident::$method:ident($($value:expr),*)) => (
78 TokenTree::$ty(self::$ty::$method($($value,)* span))
79 );
a1dfa0c6
XL
80 }
81 macro_rules! op {
82 ($a:expr) => {
0731742a 83 tt!(Punct::new($a, joint))
a1dfa0c6
XL
84 };
85 ($a:expr, $b:expr) => {{
0731742a
XL
86 stack.push(tt!(Punct::new($b, joint)));
87 tt!(Punct::new($a, true))
a1dfa0c6
XL
88 }};
89 ($a:expr, $b:expr, $c:expr) => {{
0731742a
XL
90 stack.push(tt!(Punct::new($c, joint)));
91 stack.push(tt!(Punct::new($b, true)));
92 tt!(Punct::new($a, true))
a1dfa0c6
XL
93 }};
94 }
95
dc9dc135 96 match kind {
a1dfa0c6
XL
97 Eq => op!('='),
98 Lt => op!('<'),
99 Le => op!('<', '='),
100 EqEq => op!('=', '='),
101 Ne => op!('!', '='),
102 Ge => op!('>', '='),
103 Gt => op!('>'),
104 AndAnd => op!('&', '&'),
105 OrOr => op!('|', '|'),
106 Not => op!('!'),
107 Tilde => op!('~'),
108 BinOp(Plus) => op!('+'),
109 BinOp(Minus) => op!('-'),
110 BinOp(Star) => op!('*'),
111 BinOp(Slash) => op!('/'),
112 BinOp(Percent) => op!('%'),
113 BinOp(Caret) => op!('^'),
114 BinOp(And) => op!('&'),
115 BinOp(Or) => op!('|'),
116 BinOp(Shl) => op!('<', '<'),
117 BinOp(Shr) => op!('>', '>'),
118 BinOpEq(Plus) => op!('+', '='),
119 BinOpEq(Minus) => op!('-', '='),
120 BinOpEq(Star) => op!('*', '='),
121 BinOpEq(Slash) => op!('/', '='),
122 BinOpEq(Percent) => op!('%', '='),
123 BinOpEq(Caret) => op!('^', '='),
124 BinOpEq(And) => op!('&', '='),
125 BinOpEq(Or) => op!('|', '='),
126 BinOpEq(Shl) => op!('<', '<', '='),
127 BinOpEq(Shr) => op!('>', '>', '='),
128 At => op!('@'),
129 Dot => op!('.'),
130 DotDot => op!('.', '.'),
131 DotDotDot => op!('.', '.', '.'),
132 DotDotEq => op!('.', '.', '='),
133 Comma => op!(','),
134 Semi => op!(';'),
135 Colon => op!(':'),
136 ModSep => op!(':', ':'),
137 RArrow => op!('-', '>'),
138 LArrow => op!('<', '-'),
139 FatArrow => op!('=', '>'),
140 Pound => op!('#'),
141 Dollar => op!('$'),
142 Question => op!('?'),
143 SingleQuote => op!('\''),
144
dc9dc135 145 Ident(name, false) if name == kw::DollarCrate => tt!(Ident::dollar_crate()),
3c0e092e 146 Ident(name, is_raw) => tt!(Ident::new(rustc.sess(), name, is_raw)),
dc9dc135 147 Lifetime(name) => {
f9f354fc 148 let ident = symbol::Ident::new(name, span).without_first_quote();
3c0e092e 149 stack.push(tt!(Ident::new(rustc.sess(), ident.name, false)));
0731742a 150 tt!(Punct::new('\'', true))
a1dfa0c6 151 }
dc9dc135 152 Literal(lit) => tt!(Literal { lit }),
3dfed10e 153 DocComment(_, attr_style, data) => {
a1dfa0c6 154 let mut escaped = String::new();
3dfed10e 155 for ch in data.as_str().chars() {
a1dfa0c6
XL
156 escaped.extend(ch.escape_debug());
157 }
5099ac24 158 let stream = [
dc9dc135 159 Ident(sym::doc, false),
a1dfa0c6 160 Eq,
dc9dc135 161 TokenKind::lit(token::Str, Symbol::intern(&escaped), None),
a1dfa0c6
XL
162 ]
163 .into_iter()
dc9dc135 164 .map(|kind| tokenstream::TokenTree::token(kind, span))
a1dfa0c6
XL
165 .collect();
166 stack.push(TokenTree::Group(Group {
167 delimiter: Delimiter::Bracket,
168 stream,
169 span: DelimSpan::from_single(span),
f035d41b 170 flatten: false,
a1dfa0c6 171 }));
3dfed10e 172 if attr_style == ast::AttrStyle::Inner {
0731742a 173 stack.push(tt!(Punct::new('!', false)));
a1dfa0c6 174 }
0731742a 175 tt!(Punct::new('#', false))
a1dfa0c6
XL
176 }
177
5e7ed085
FG
178 Interpolated(nt) if let NtIdent(ident, is_raw) = *nt => {
179 TokenTree::Ident(Ident::new(rustc.sess(), ident.name, is_raw, ident.span))
94222f64 180 }
9fa01778 181 Interpolated(nt) => {
3c0e092e 182 let stream = nt_to_tokenstream(&nt, rustc.sess(), CanSynthesizeMissingTokens::No);
94222f64
XL
183 TokenTree::Group(Group {
184 delimiter: Delimiter::None,
185 stream,
186 span: DelimSpan::from_single(span),
3c0e092e 187 flatten: crate::base::pretty_printing_compatibility_hack(&nt, rustc.sess()),
94222f64 188 })
a1dfa0c6
XL
189 }
190
191 OpenDelim(..) | CloseDelim(..) => unreachable!(),
1b1a35ee 192 Eof => unreachable!(),
a1dfa0c6
XL
193 }
194 }
195}
196
197impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> {
198 fn to_internal(self) -> TokenStream {
74b04a01 199 use rustc_ast::token::*;
a1dfa0c6
XL
200
201 let (ch, joint, span) = match self {
202 TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
f035d41b 203 TokenTree::Group(Group { delimiter, stream, span, .. }) => {
74b04a01
XL
204 return tokenstream::TokenTree::Delimited(span, delimiter.to_internal(), stream)
205 .into();
a1dfa0c6 206 }
0731742a 207 TokenTree::Ident(self::Ident { sym, is_raw, span }) => {
dc9dc135 208 return tokenstream::TokenTree::token(Ident(sym, is_raw), span).into();
a1dfa0c6
XL
209 }
210 TokenTree::Literal(self::Literal {
dc9dc135 211 lit: token::Lit { kind: token::Integer, symbol, suffix },
a1dfa0c6 212 span,
74b04a01 213 }) if symbol.as_str().starts_with('-') => {
a1dfa0c6 214 let minus = BinOp(BinOpToken::Minus);
dc9dc135
XL
215 let symbol = Symbol::intern(&symbol.as_str()[1..]);
216 let integer = TokenKind::lit(token::Integer, symbol, suffix);
217 let a = tokenstream::TokenTree::token(minus, span);
218 let b = tokenstream::TokenTree::token(integer, span);
5099ac24 219 return [a, b].into_iter().collect();
a1dfa0c6
XL
220 }
221 TokenTree::Literal(self::Literal {
dc9dc135 222 lit: token::Lit { kind: token::Float, symbol, suffix },
a1dfa0c6 223 span,
74b04a01 224 }) if symbol.as_str().starts_with('-') => {
a1dfa0c6 225 let minus = BinOp(BinOpToken::Minus);
dc9dc135
XL
226 let symbol = Symbol::intern(&symbol.as_str()[1..]);
227 let float = TokenKind::lit(token::Float, symbol, suffix);
228 let a = tokenstream::TokenTree::token(minus, span);
229 let b = tokenstream::TokenTree::token(float, span);
5099ac24 230 return [a, b].into_iter().collect();
a1dfa0c6 231 }
dc9dc135 232 TokenTree::Literal(self::Literal { lit, span }) => {
dfeec247 233 return tokenstream::TokenTree::token(Literal(lit), span).into();
a1dfa0c6
XL
234 }
235 };
236
dc9dc135 237 let kind = match ch {
a1dfa0c6
XL
238 '=' => Eq,
239 '<' => Lt,
240 '>' => Gt,
241 '!' => Not,
242 '~' => Tilde,
243 '+' => BinOp(Plus),
244 '-' => BinOp(Minus),
245 '*' => BinOp(Star),
246 '/' => BinOp(Slash),
247 '%' => BinOp(Percent),
248 '^' => BinOp(Caret),
249 '&' => BinOp(And),
250 '|' => BinOp(Or),
251 '@' => At,
252 '.' => Dot,
253 ',' => Comma,
254 ';' => Semi,
255 ':' => Colon,
256 '#' => Pound,
257 '$' => Dollar,
258 '?' => Question,
259 '\'' => SingleQuote,
260 _ => unreachable!(),
261 };
262
dc9dc135 263 let tree = tokenstream::TokenTree::token(kind, span);
1b1a35ee 264 TokenStream::new(vec![(tree, if joint { Joint } else { Alone })])
a1dfa0c6
XL
265 }
266}
267
dfeec247
XL
268impl ToInternal<rustc_errors::Level> for Level {
269 fn to_internal(self) -> rustc_errors::Level {
a1dfa0c6 270 match self {
3c0e092e 271 Level::Error => rustc_errors::Level::Error { lint: false },
dfeec247
XL
272 Level::Warning => rustc_errors::Level::Warning,
273 Level::Note => rustc_errors::Level::Note,
274 Level::Help => rustc_errors::Level::Help,
a1dfa0c6
XL
275 _ => unreachable!("unknown proc_macro::Level variant: {:?}", self),
276 }
277 }
278}
279
3dfed10e
XL
280pub struct FreeFunctions;
281
a1dfa0c6
XL
282#[derive(Clone)]
283pub struct TokenStreamIter {
284 cursor: tokenstream::Cursor,
285 stack: Vec<TokenTree<Group, Punct, Ident, Literal>>,
286}
287
288#[derive(Clone)]
289pub struct Group {
290 delimiter: Delimiter,
291 stream: TokenStream,
292 span: DelimSpan,
f035d41b
XL
293 /// A hack used to pass AST fragments to attribute and derive macros
294 /// as a single nonterminal token instead of a token stream.
295 /// FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
296 flatten: bool,
a1dfa0c6
XL
297}
298
299#[derive(Copy, Clone, PartialEq, Eq, Hash)]
300pub struct Punct {
301 ch: char,
302 // NB. not using `Spacing` here because it doesn't implement `Hash`.
303 joint: bool,
304 span: Span,
305}
306
0731742a
XL
307impl Punct {
308 fn new(ch: char, joint: bool, span: Span) -> Punct {
dfeec247
XL
309 const LEGAL_CHARS: &[char] = &[
310 '=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^', '&', '|', '@', '.', ',', ';',
311 ':', '#', '$', '?', '\'',
312 ];
0731742a
XL
313 if !LEGAL_CHARS.contains(&ch) {
314 panic!("unsupported character `{:?}`", ch)
315 }
316 Punct { ch, joint, span }
317 }
318}
319
a1dfa0c6
XL
320#[derive(Copy, Clone, PartialEq, Eq, Hash)]
321pub struct Ident {
322 sym: Symbol,
a1dfa0c6 323 is_raw: bool,
0731742a
XL
324 span: Span,
325}
326
327impl Ident {
f9f354fc 328 fn new(sess: &ParseSess, sym: Symbol, is_raw: bool, span: Span) -> Ident {
a2a8927a 329 let sym = nfc_normalize(sym.as_str());
48663c56 330 let string = sym.as_str();
a2a8927a 331 if !rustc_lexer::is_ident(string) {
0731742a
XL
332 panic!("`{:?}` is not a valid identifier", string)
333 }
e74abb32 334 if is_raw && !sym.can_be_raw() {
532ac7d7 335 panic!("`{}` cannot be a raw identifier", string);
0731742a 336 }
f9f354fc 337 sess.symbol_gallery.insert(sym, span);
0731742a
XL
338 Ident { sym, is_raw, span }
339 }
340 fn dollar_crate(span: Span) -> Ident {
341 // `$crate` is accepted as an ident only if it comes from the compiler.
dc9dc135 342 Ident { sym: kw::DollarCrate, is_raw: false, span }
0731742a 343 }
a1dfa0c6
XL
344}
345
346// FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
347#[derive(Clone, Debug)]
348pub struct Literal {
349 lit: token::Lit,
a1dfa0c6
XL
350 span: Span,
351}
352
3c0e092e
XL
353pub(crate) struct Rustc<'a, 'b> {
354 ecx: &'a mut ExtCtxt<'b>,
a1dfa0c6
XL
355 def_site: Span,
356 call_site: Span,
e74abb32 357 mixed_site: Span,
17df50a5 358 krate: CrateNum,
17df50a5 359 rebased_spans: FxHashMap<usize, Span>,
a1dfa0c6
XL
360}
361
3c0e092e
XL
362impl<'a, 'b> Rustc<'a, 'b> {
363 pub fn new(ecx: &'a mut ExtCtxt<'b>) -> Self {
364 let expn_data = ecx.current_expansion.id.expn_data();
a1dfa0c6 365 Rustc {
3c0e092e
XL
366 def_site: ecx.with_def_site_ctxt(expn_data.def_site),
367 call_site: ecx.with_call_site_ctxt(expn_data.call_site),
368 mixed_site: ecx.with_mixed_site_ctxt(expn_data.call_site),
136023e0 369 krate: expn_data.macro_def_id.unwrap().krate,
17df50a5 370 rebased_spans: FxHashMap::default(),
3c0e092e 371 ecx,
a1dfa0c6
XL
372 }
373 }
dc9dc135 374
3c0e092e
XL
375 fn sess(&self) -> &ParseSess {
376 self.ecx.parse_sess()
377 }
378
dc9dc135 379 fn lit(&mut self, kind: token::LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Literal {
dfeec247 380 Literal { lit: token::Lit::new(kind, symbol, suffix), span: server::Span::call_site(self) }
dc9dc135 381 }
a1dfa0c6
XL
382}
383
3c0e092e 384impl server::Types for Rustc<'_, '_> {
3dfed10e 385 type FreeFunctions = FreeFunctions;
a1dfa0c6
XL
386 type TokenStream = TokenStream;
387 type TokenStreamBuilder = tokenstream::TokenStreamBuilder;
388 type TokenStreamIter = TokenStreamIter;
389 type Group = Group;
390 type Punct = Punct;
391 type Ident = Ident;
392 type Literal = Literal;
393 type SourceFile = Lrc<SourceFile>;
394 type MultiSpan = Vec<Span>;
395 type Diagnostic = Diagnostic;
396 type Span = Span;
397}
398
3c0e092e 399impl server::FreeFunctions for Rustc<'_, '_> {
3dfed10e 400 fn track_env_var(&mut self, var: &str, value: Option<&str>) {
3c0e092e
XL
401 self.sess()
402 .env_depinfo
403 .borrow_mut()
404 .insert((Symbol::intern(var), value.map(Symbol::intern)));
3dfed10e 405 }
136023e0
XL
406
407 fn track_path(&mut self, path: &str) {
3c0e092e 408 self.sess().file_depinfo.borrow_mut().insert(Symbol::intern(path));
136023e0 409 }
3dfed10e
XL
410}
411
3c0e092e 412impl server::TokenStream for Rustc<'_, '_> {
a1dfa0c6 413 fn new(&mut self) -> Self::TokenStream {
e74abb32 414 TokenStream::default()
a1dfa0c6
XL
415 }
416 fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
417 stream.is_empty()
418 }
419 fn from_str(&mut self, src: &str) -> Self::TokenStream {
60c5eb7d 420 parse_stream_from_source_str(
dc9dc135 421 FileName::proc_macro_source_code(src),
a1dfa0c6 422 src.to_string(),
3c0e092e 423 self.sess(),
a1dfa0c6
XL
424 Some(self.call_site),
425 )
426 }
427 fn to_string(&mut self, stream: &Self::TokenStream) -> String {
f035d41b 428 pprust::tts_to_string(stream)
a1dfa0c6 429 }
3c0e092e
XL
430 fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
431 // Parse the expression from our tokenstream.
432 let expr: PResult<'_, _> = try {
433 let mut p = rustc_parse::stream_to_parser(
434 self.sess(),
435 stream.clone(),
436 Some("proc_macro expand expr"),
437 );
438 let expr = p.parse_expr()?;
439 if p.token != token::Eof {
440 p.unexpected()?;
441 }
442 expr
443 };
5e7ed085
FG
444 let expr = expr.map_err(|mut err| {
445 err.emit();
446 })?;
3c0e092e
XL
447
448 // Perform eager expansion on the expression.
449 let expr = self
450 .ecx
451 .expander()
452 .fully_expand_fragment(crate::expand::AstFragment::Expr(expr))
453 .make_expr();
454
455 // NOTE: For now, limit `expand_expr` to exclusively expand to literals.
456 // This may be relaxed in the future.
457 // We don't use `nt_to_tokenstream` as the tokenstream currently cannot
458 // be recovered in the general case.
459 match &expr.kind {
460 ast::ExprKind::Lit(l) => {
461 Ok(tokenstream::TokenTree::token(token::Literal(l.token), l.span).into())
462 }
463 ast::ExprKind::Unary(ast::UnOp::Neg, e) => match &e.kind {
464 ast::ExprKind::Lit(l) => match l.token {
465 token::Lit { kind: token::Integer | token::Float, .. } => {
a2a8927a 466 Ok(Self::TokenStream::from_iter([
3c0e092e
XL
467 // FIXME: The span of the `-` token is lost when
468 // parsing, so we cannot faithfully recover it here.
469 tokenstream::TokenTree::token(token::BinOp(token::Minus), e.span),
470 tokenstream::TokenTree::token(token::Literal(l.token), l.span),
a2a8927a 471 ]))
3c0e092e
XL
472 }
473 _ => Err(()),
474 },
475 _ => Err(()),
476 },
477 _ => Err(()),
478 }
479 }
a1dfa0c6
XL
480 fn from_token_tree(
481 &mut self,
482 tree: TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>,
483 ) -> Self::TokenStream {
484 tree.to_internal()
485 }
486 fn into_iter(&mut self, stream: Self::TokenStream) -> Self::TokenStreamIter {
dfeec247 487 TokenStreamIter { cursor: stream.trees(), stack: vec![] }
a1dfa0c6
XL
488 }
489}
490
3c0e092e 491impl server::TokenStreamBuilder for Rustc<'_, '_> {
a1dfa0c6
XL
492 fn new(&mut self) -> Self::TokenStreamBuilder {
493 tokenstream::TokenStreamBuilder::new()
494 }
495 fn push(&mut self, builder: &mut Self::TokenStreamBuilder, stream: Self::TokenStream) {
496 builder.push(stream);
497 }
498 fn build(&mut self, builder: Self::TokenStreamBuilder) -> Self::TokenStream {
499 builder.build()
500 }
501}
502
3c0e092e 503impl server::TokenStreamIter for Rustc<'_, '_> {
a1dfa0c6
XL
504 fn next(
505 &mut self,
506 iter: &mut Self::TokenStreamIter,
507 ) -> Option<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> {
508 loop {
509 let tree = iter.stack.pop().or_else(|| {
1b1a35ee 510 let next = iter.cursor.next_with_spacing()?;
6a06907d 511 Some(TokenTree::from_internal((next, &mut iter.stack, self)))
a1dfa0c6 512 })?;
f035d41b
XL
513 // A hack used to pass AST fragments to attribute and derive macros
514 // as a single nonterminal token instead of a token stream.
515 // Such token needs to be "unwrapped" and not represented as a delimited group.
516 // FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
a1dfa0c6 517 if let TokenTree::Group(ref group) = tree {
f035d41b 518 if group.flatten {
0731742a 519 iter.cursor.append(group.stream.clone());
a1dfa0c6
XL
520 continue;
521 }
522 }
523 return Some(tree);
524 }
525 }
526}
527
3c0e092e 528impl server::Group for Rustc<'_, '_> {
a1dfa0c6 529 fn new(&mut self, delimiter: Delimiter, stream: Self::TokenStream) -> Self::Group {
f035d41b
XL
530 Group {
531 delimiter,
532 stream,
533 span: DelimSpan::from_single(server::Span::call_site(self)),
534 flatten: false,
535 }
a1dfa0c6
XL
536 }
537 fn delimiter(&mut self, group: &Self::Group) -> Delimiter {
538 group.delimiter
539 }
540 fn stream(&mut self, group: &Self::Group) -> Self::TokenStream {
541 group.stream.clone()
542 }
543 fn span(&mut self, group: &Self::Group) -> Self::Span {
544 group.span.entire()
545 }
546 fn span_open(&mut self, group: &Self::Group) -> Self::Span {
547 group.span.open
548 }
549 fn span_close(&mut self, group: &Self::Group) -> Self::Span {
550 group.span.close
551 }
552 fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) {
553 group.span = DelimSpan::from_single(span);
554 }
555}
556
3c0e092e 557impl server::Punct for Rustc<'_, '_> {
a1dfa0c6 558 fn new(&mut self, ch: char, spacing: Spacing) -> Self::Punct {
0731742a 559 Punct::new(ch, spacing == Spacing::Joint, server::Span::call_site(self))
a1dfa0c6
XL
560 }
561 fn as_char(&mut self, punct: Self::Punct) -> char {
562 punct.ch
563 }
564 fn spacing(&mut self, punct: Self::Punct) -> Spacing {
dfeec247 565 if punct.joint { Spacing::Joint } else { Spacing::Alone }
a1dfa0c6
XL
566 }
567 fn span(&mut self, punct: Self::Punct) -> Self::Span {
568 punct.span
569 }
570 fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct {
571 Punct { span, ..punct }
572 }
573}
574
3c0e092e 575impl server::Ident for Rustc<'_, '_> {
a1dfa0c6 576 fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
3c0e092e 577 Ident::new(self.sess(), Symbol::intern(string), is_raw, span)
a1dfa0c6
XL
578 }
579 fn span(&mut self, ident: Self::Ident) -> Self::Span {
580 ident.span
581 }
582 fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident {
583 Ident { span, ..ident }
584 }
585}
586
3c0e092e 587impl server::Literal for Rustc<'_, '_> {
17df50a5 588 fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
94222f64 589 let name = FileName::proc_macro_source_code(s);
3c0e092e 590 let mut parser = rustc_parse::new_parser_from_source_str(self.sess(), name, s.to_owned());
94222f64
XL
591
592 let first_span = parser.token.span.data();
593 let minus_present = parser.eat(&token::BinOp(token::Minus));
594
595 let lit_span = parser.token.span.data();
5e7ed085
FG
596 let token::Literal(mut lit) = parser.token.kind else {
597 return Err(());
17df50a5 598 };
94222f64
XL
599
600 // Check no comment or whitespace surrounding the (possibly negative)
601 // literal, or more tokens after it.
602 if (lit_span.hi.0 - first_span.lo.0) as usize != s.len() {
17df50a5
XL
603 return Err(());
604 }
94222f64
XL
605
606 if minus_present {
607 // If minus is present, check no comment or whitespace in between it
608 // and the literal token.
609 if first_span.hi.0 != lit_span.lo.0 {
610 return Err(());
611 }
612
613 // Check literal is a kind we allow to be negated in a proc macro token.
614 match lit.kind {
615 token::LitKind::Bool
616 | token::LitKind::Byte
617 | token::LitKind::Char
618 | token::LitKind::Str
619 | token::LitKind::StrRaw(_)
620 | token::LitKind::ByteStr
621 | token::LitKind::ByteStrRaw(_)
622 | token::LitKind::Err => return Err(()),
623 token::LitKind::Integer | token::LitKind::Float => {}
624 }
625
626 // Synthesize a new symbol that includes the minus sign.
c295e0f8 627 let symbol = Symbol::intern(&s[..1 + lit.symbol.as_str().len()]);
94222f64
XL
628 lit = token::Lit::new(lit.kind, symbol, lit.suffix);
629 }
630
17df50a5
XL
631 Ok(Literal { lit, span: self.call_site })
632 }
94222f64
XL
633 fn to_string(&mut self, literal: &Self::Literal) -> String {
634 literal.lit.to_string()
635 }
f9f354fc
XL
636 fn debug_kind(&mut self, literal: &Self::Literal) -> String {
637 format!("{:?}", literal.lit.kind)
638 }
639 fn symbol(&mut self, literal: &Self::Literal) -> String {
640 literal.lit.symbol.to_string()
641 }
642 fn suffix(&mut self, literal: &Self::Literal) -> Option<String> {
643 literal.lit.suffix.as_ref().map(Symbol::to_string)
a1dfa0c6
XL
644 }
645 fn integer(&mut self, n: &str) -> Self::Literal {
dc9dc135 646 self.lit(token::Integer, Symbol::intern(n), None)
a1dfa0c6
XL
647 }
648 fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal {
dc9dc135 649 self.lit(token::Integer, Symbol::intern(n), Some(Symbol::intern(kind)))
a1dfa0c6
XL
650 }
651 fn float(&mut self, n: &str) -> Self::Literal {
dc9dc135 652 self.lit(token::Float, Symbol::intern(n), None)
a1dfa0c6
XL
653 }
654 fn f32(&mut self, n: &str) -> Self::Literal {
416331ca 655 self.lit(token::Float, Symbol::intern(n), Some(sym::f32))
a1dfa0c6
XL
656 }
657 fn f64(&mut self, n: &str) -> Self::Literal {
416331ca 658 self.lit(token::Float, Symbol::intern(n), Some(sym::f64))
a1dfa0c6
XL
659 }
660 fn string(&mut self, string: &str) -> Self::Literal {
661 let mut escaped = String::new();
662 for ch in string.chars() {
663 escaped.extend(ch.escape_debug());
664 }
dc9dc135 665 self.lit(token::Str, Symbol::intern(&escaped), None)
a1dfa0c6
XL
666 }
667 fn character(&mut self, ch: char) -> Self::Literal {
668 let mut escaped = String::new();
669 escaped.extend(ch.escape_unicode());
dc9dc135 670 self.lit(token::Char, Symbol::intern(&escaped), None)
a1dfa0c6
XL
671 }
672 fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal {
673 let string = bytes
674 .iter()
675 .cloned()
676 .flat_map(ascii::escape_default)
677 .map(Into::<char>::into)
678 .collect::<String>();
dc9dc135 679 self.lit(token::ByteStr, Symbol::intern(&string), None)
a1dfa0c6
XL
680 }
681 fn span(&mut self, literal: &Self::Literal) -> Self::Span {
682 literal.span
683 }
684 fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) {
685 literal.span = span;
686 }
687 fn subspan(
688 &mut self,
689 literal: &Self::Literal,
690 start: Bound<usize>,
691 end: Bound<usize>,
692 ) -> Option<Self::Span> {
693 let span = literal.span;
694 let length = span.hi().to_usize() - span.lo().to_usize();
695
696 let start = match start {
697 Bound::Included(lo) => lo,
1b1a35ee 698 Bound::Excluded(lo) => lo.checked_add(1)?,
a1dfa0c6
XL
699 Bound::Unbounded => 0,
700 };
701
702 let end = match end {
1b1a35ee 703 Bound::Included(hi) => hi.checked_add(1)?,
a1dfa0c6
XL
704 Bound::Excluded(hi) => hi,
705 Bound::Unbounded => length,
706 };
707
708 // Bounds check the values, preventing addition overflow and OOB spans.
f035d41b
XL
709 if start > u32::MAX as usize
710 || end > u32::MAX as usize
711 || (u32::MAX - start as u32) < span.lo().to_u32()
712 || (u32::MAX - end as u32) < span.lo().to_u32()
a1dfa0c6
XL
713 || start >= end
714 || end > length
715 {
716 return None;
717 }
718
719 let new_lo = span.lo() + BytePos::from_usize(start);
720 let new_hi = span.lo() + BytePos::from_usize(end);
721 Some(span.with_lo(new_lo).with_hi(new_hi))
722 }
723}
724
3c0e092e 725impl server::SourceFile for Rustc<'_, '_> {
a1dfa0c6
XL
726 fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
727 Lrc::ptr_eq(file1, file2)
728 }
729 fn path(&mut self, file: &Self::SourceFile) -> String {
730 match file.name {
ba9703b0
XL
731 FileName::Real(ref name) => name
732 .local_path()
17df50a5 733 .expect("attempting to get a file path in an imported file in `proc_macro::SourceFile::path`")
a1dfa0c6
XL
734 .to_str()
735 .expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
736 .to_string(),
17df50a5 737 _ => file.name.prefer_local().to_string(),
a1dfa0c6
XL
738 }
739 }
740 fn is_real(&mut self, file: &Self::SourceFile) -> bool {
741 file.is_real_file()
742 }
743}
744
3c0e092e 745impl server::MultiSpan for Rustc<'_, '_> {
a1dfa0c6
XL
746 fn new(&mut self) -> Self::MultiSpan {
747 vec![]
748 }
749 fn push(&mut self, spans: &mut Self::MultiSpan, span: Self::Span) {
750 spans.push(span)
751 }
752}
753
3c0e092e 754impl server::Diagnostic for Rustc<'_, '_> {
a1dfa0c6
XL
755 fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic {
756 let mut diag = Diagnostic::new(level.to_internal(), msg);
757 diag.set_span(MultiSpan::from_spans(spans));
758 diag
759 }
760 fn sub(
761 &mut self,
762 diag: &mut Self::Diagnostic,
763 level: Level,
764 msg: &str,
765 spans: Self::MultiSpan,
766 ) {
767 diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None);
768 }
5e7ed085
FG
769 fn emit(&mut self, mut diag: Self::Diagnostic) {
770 self.sess().span_diagnostic.emit_diagnostic(&mut diag);
a1dfa0c6
XL
771 }
772}
773
3c0e092e 774impl server::Span for Rustc<'_, '_> {
a1dfa0c6 775 fn debug(&mut self, span: Self::Span) -> String {
3c0e092e 776 if self.ecx.ecfg.span_debug {
f035d41b
XL
777 format!("{:?}", span)
778 } else {
779 format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0)
780 }
a1dfa0c6
XL
781 }
782 fn def_site(&mut self) -> Self::Span {
783 self.def_site
784 }
785 fn call_site(&mut self) -> Self::Span {
786 self.call_site
787 }
e74abb32
XL
788 fn mixed_site(&mut self) -> Self::Span {
789 self.mixed_site
790 }
a1dfa0c6 791 fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
3c0e092e 792 self.sess().source_map().lookup_char_pos(span.lo()).file
a1dfa0c6
XL
793 }
794 fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
c295e0f8 795 span.parent_callsite()
a1dfa0c6
XL
796 }
797 fn source(&mut self, span: Self::Span) -> Self::Span {
798 span.source_callsite()
799 }
800 fn start(&mut self, span: Self::Span) -> LineColumn {
3c0e092e 801 let loc = self.sess().source_map().lookup_char_pos(span.lo());
dfeec247 802 LineColumn { line: loc.line, column: loc.col.to_usize() }
a1dfa0c6
XL
803 }
804 fn end(&mut self, span: Self::Span) -> LineColumn {
3c0e092e 805 let loc = self.sess().source_map().lookup_char_pos(span.hi());
dfeec247 806 LineColumn { line: loc.line, column: loc.col.to_usize() }
a1dfa0c6 807 }
c295e0f8
XL
808 fn before(&mut self, span: Self::Span) -> Self::Span {
809 span.shrink_to_lo()
810 }
811 fn after(&mut self, span: Self::Span) -> Self::Span {
812 span.shrink_to_hi()
813 }
a1dfa0c6 814 fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
3c0e092e
XL
815 let self_loc = self.sess().source_map().lookup_char_pos(first.lo());
816 let other_loc = self.sess().source_map().lookup_char_pos(second.lo());
a1dfa0c6
XL
817
818 if self_loc.file.name != other_loc.file.name {
819 return None;
820 }
821
822 Some(first.to(second))
823 }
824 fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
825 span.with_ctxt(at.ctxt())
826 }
dfeec247 827 fn source_text(&mut self, span: Self::Span) -> Option<String> {
3c0e092e 828 self.sess().source_map().span_to_snippet(span).ok()
532ac7d7 829 }
17df50a5
XL
830 /// Saves the provided span into the metadata of
831 /// *the crate we are currently compiling*, which must
832 /// be a proc-macro crate. This id can be passed to
833 /// `recover_proc_macro_span` when our current crate
834 /// is *run* as a proc-macro.
835 ///
836 /// Let's suppose that we have two crates - `my_client`
837 /// and `my_proc_macro`. The `my_proc_macro` crate
838 /// contains a procedural macro `my_macro`, which
839 /// is implemented as: `quote! { "hello" }`
840 ///
841 /// When we *compile* `my_proc_macro`, we will execute
842 /// the `quote` proc-macro. This will save the span of
843 /// "hello" into the metadata of `my_proc_macro`. As a result,
844 /// the body of `my_proc_macro` (after expansion) will end
5e7ed085 845 /// up containing a call that looks like this:
17df50a5
XL
846 /// `proc_macro::Ident::new("hello", proc_macro::Span::recover_proc_macro_span(0))`
847 ///
848 /// where `0` is the id returned by this function.
849 /// When `my_proc_macro` *executes* (during the compilation of `my_client`),
850 /// the call to `recover_proc_macro_span` will load the corresponding
851 /// span from the metadata of `my_proc_macro` (which we have access to,
852 /// since we've loaded `my_proc_macro` from disk in order to execute it).
853 /// In this way, we have obtained a span pointing into `my_proc_macro`
136023e0 854 fn save_span(&mut self, span: Self::Span) -> usize {
3c0e092e 855 self.sess().save_proc_macro_span(span)
17df50a5
XL
856 }
857 fn recover_proc_macro_span(&mut self, id: usize) -> Self::Span {
3c0e092e 858 let (resolver, krate, def_site) = (&*self.ecx.resolver, self.krate, self.def_site);
17df50a5 859 *self.rebased_spans.entry(id).or_insert_with(|| {
136023e0
XL
860 // FIXME: `SyntaxContext` for spans from proc macro crates is lost during encoding,
861 // replace it with a def-site context until we are encoding it properly.
862 resolver.get_proc_macro_quoted_span(krate, id).with_ctxt(def_site.ctxt())
17df50a5
XL
863 })
864 }
a1dfa0c6 865}