about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-07-04 02:37:34 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-07-09 22:17:44 +0300
commit4344a90308b810447adb011f3fd45fde41f7ce48 (patch)
tree350ece7d231f13a2626ffc4d50340f0abeef4704 /src
parent7aaf0de700d1bc242d270dcc7e2fee9e3533ea0a (diff)
downloadrust-4344a90308b810447adb011f3fd45fde41f7ce48.tar.gz
rust-4344a90308b810447adb011f3fd45fde41f7ce48.zip
Pretty-print `$crate` as `crate`/`::my_crate` in tokens
...but only if those tokens are printed from inside of AST pretty-printing.
Diffstat (limited to 'src')
-rw-r--r--src/libsyntax/print/pprust.rs109
-rw-r--r--src/test/ui/proc-macro/dollar-crate-issue-57089.stdout4
-rw-r--r--src/test/ui/proc-macro/dollar-crate.stdout12
3 files changed, 70 insertions, 55 deletions
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 67646cce69b..7e099bc4d50 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -18,7 +18,7 @@ use crate::tokenstream::{self, TokenStream, TokenTree};
 
 use rustc_target::spec::abi::{self, Abi};
 use syntax_pos::{self, BytePos};
-use syntax_pos::{DUMMY_SP, FileName};
+use syntax_pos::{DUMMY_SP, FileName, Span};
 
 use std::borrow::Cow;
 use std::io::Read;
@@ -181,7 +181,46 @@ pub fn literal_to_string(lit: token::Lit) -> String {
     out
 }
 
+fn ident_to_string(ident: ast::Ident, is_raw: bool) -> String {
+    ident_to_string_ext(ident.name, is_raw, Some(ident.span))
+}
+
+// AST pretty-printer is used as a fallback for turning AST structures into token streams for
+// proc macros. Additionally, proc macros may stringify their input and expect it survive the
+// stringification (especially true for proc macro derives written between Rust 1.15 and 1.30).
+// So we need to somehow pretty-print `$crate` in a way preserving at least some of its
+// hygiene data, most importantly name of the crate it refers to.
+// As a result we print `$crate` as `crate` if it refers to the local crate
+// and as `::other_crate_name` if it refers to some other crate.
+// Note, that this is only done if the ident token is printed from inside of AST pretty-pringing,
+// but not otherwise. Pretty-printing is the only way for proc macros to discover token contents,
+// so we should not perform this lossy conversion if the top level call to the pretty-printer was
+// done for a token stream or a single token.
+fn ident_to_string_ext(
+    name: ast::Name, is_raw: bool, convert_dollar_crate: Option<Span>
+) -> String {
+    if is_raw {
+        format!("r#{}", name)
+    } else {
+        if name == kw::DollarCrate {
+            if let Some(span) = convert_dollar_crate {
+                let converted = span.ctxt().dollar_crate_name();
+                return if converted.is_path_segment_keyword() {
+                    converted.to_string()
+                } else {
+                    format!("::{}", converted)
+                }
+            }
+        }
+        name.to_string()
+    }
+}
+
 pub fn token_kind_to_string(tok: &TokenKind) -> String {
+    token_kind_to_string_ext(tok, None)
+}
+
+fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option<Span>) -> String {
     match *tok {
         token::Eq                   => "=".to_string(),
         token::Lt                   => "<".to_string(),
@@ -227,8 +266,7 @@ pub fn token_kind_to_string(tok: &TokenKind) -> String {
         token::Literal(lit) => literal_to_string(lit),
 
         /* Name components */
-        token::Ident(s, false)      => s.to_string(),
-        token::Ident(s, true)       => format!("r#{}", s),
+        token::Ident(s, is_raw)     => ident_to_string_ext(s, is_raw, convert_dollar_crate),
         token::Lifetime(s)          => s.to_string(),
 
         /* Other */
@@ -243,7 +281,12 @@ pub fn token_kind_to_string(tok: &TokenKind) -> String {
 }
 
 pub fn token_to_string(token: &Token) -> String {
-    token_kind_to_string(&token.kind)
+    token_to_string_ext(token, false)
+}
+
+fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String {
+    let convert_dollar_crate = if convert_dollar_crate { Some(token.span) } else { None };
+    token_kind_to_string_ext(&token.kind, convert_dollar_crate)
 }
 
 crate fn nonterminal_to_string(nt: &Nonterminal) -> String {
@@ -256,9 +299,8 @@ crate fn nonterminal_to_string(nt: &Nonterminal) -> String {
         token::NtBlock(ref e)       => block_to_string(e),
         token::NtStmt(ref e)        => stmt_to_string(e),
         token::NtPat(ref e)         => pat_to_string(e),
-        token::NtIdent(e, false)    => ident_to_string(e),
-        token::NtIdent(e, true)     => format!("r#{}", ident_to_string(e)),
-        token::NtLifetime(e)        => ident_to_string(e),
+        token::NtIdent(e, is_raw)   => ident_to_string(e, is_raw),
+        token::NtLifetime(e)        => e.to_string(),
         token::NtLiteral(ref e)     => expr_to_string(e),
         token::NtTT(ref tree)       => tt_to_string(tree.clone()),
         token::NtImplItem(ref e)    => impl_item_to_string(e),
@@ -293,15 +335,15 @@ pub fn lifetime_to_string(lt: &ast::Lifetime) -> String {
 }
 
 pub fn tt_to_string(tt: tokenstream::TokenTree) -> String {
-    to_string(|s| s.print_tt(tt))
+    to_string(|s| s.print_tt(tt, false))
 }
 
 pub fn tts_to_string(tts: &[tokenstream::TokenTree]) -> String {
-    to_string(|s| s.print_tts(tts.iter().cloned().collect()))
+    tokens_to_string(tts.iter().cloned().collect())
 }
 
 pub fn tokens_to_string(tokens: TokenStream) -> String {
-    to_string(|s| s.print_tts(tokens))
+    to_string(|s| s.print_tts_ext(tokens, false))
 }
 
 pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
@@ -344,10 +386,6 @@ pub fn path_segment_to_string(p: &ast::PathSegment) -> String {
     to_string(|s| s.print_path_segment(p, false))
 }
 
-pub fn ident_to_string(id: ast::Ident) -> String {
-    to_string(|s| s.print_ident(id))
-}
-
 pub fn vis_to_string(v: &ast::Visibility) -> String {
     to_string(|s| s.print_visibility(v))
 }
@@ -629,11 +667,7 @@ pub trait PrintState<'a> {
                 self.writer().word("::");
             }
             if segment.ident.name != kw::PathRoot {
-                if segment.ident.name == kw::DollarCrate {
-                    self.print_dollar_crate(segment.ident);
-                } else {
-                    self.writer().word(segment.ident.as_str().to_string());
-                }
+                self.writer().word(ident_to_string(segment.ident, segment.ident.is_raw_guess()));
             }
         }
     }
@@ -707,10 +741,10 @@ pub trait PrintState<'a> {
     /// appropriate macro, transcribe back into the grammar we just parsed from,
     /// and then pretty-print the resulting AST nodes (so, e.g., we print
     /// expression arguments as expressions). It can be done! I think.
-    fn print_tt(&mut self, tt: tokenstream::TokenTree) {
+    fn print_tt(&mut self, tt: tokenstream::TokenTree, convert_dollar_crate: bool) {
         match tt {
             TokenTree::Token(ref token) => {
-                self.writer().word(token_to_string(&token));
+                self.writer().word(token_to_string_ext(&token, convert_dollar_crate));
                 match token.kind {
                     token::DocComment(..) => {
                         self.writer().hardbreak()
@@ -729,12 +763,16 @@ pub trait PrintState<'a> {
     }
 
     fn print_tts(&mut self, tts: tokenstream::TokenStream) {
+        self.print_tts_ext(tts, true)
+    }
+
+    fn print_tts_ext(&mut self, tts: tokenstream::TokenStream, convert_dollar_crate: bool) {
         self.ibox(0);
         for (i, tt) in tts.into_trees().enumerate() {
             if i != 0 {
                 self.writer().space();
             }
-            self.print_tt(tt);
+            self.print_tt(tt, convert_dollar_crate);
         }
         self.end();
     }
@@ -744,21 +782,6 @@ pub trait PrintState<'a> {
     }
 
     fn nbsp(&mut self) { self.writer().word(" ") }
-
-    // AST pretty-printer is used as a fallback for turning AST structures into token streams for
-    // proc macros. Additionally, proc macros may stringify their input and expect it survive the
-    // stringification (especially true for proc macro derives written between Rust 1.15 and 1.30).
-    // So we need to somehow pretty-print `$crate` in paths in a way preserving at least some of
-    // its hygiene data, most importantly name of the crate it refers to.
-    // As a result we print `$crate` as `crate` if it refers to the local crate
-    // and as `::other_crate_name` if it refers to some other crate.
-    fn print_dollar_crate(&mut self, ident: ast::Ident) {
-        let name = ident.span.ctxt().dollar_crate_name();
-        if !ast::Ident::with_empty_ctxt(name).is_path_segment_keyword() {
-            self.writer().word("::");
-        }
-        self.writer().word(name.as_str().to_string())
-    }
 }
 
 impl<'a> PrintState<'a> for State<'a> {
@@ -2287,11 +2310,7 @@ impl<'a> State<'a> {
     }
 
     crate fn print_ident(&mut self, ident: ast::Ident) {
-        if ident.is_raw_guess() {
-            self.s.word(format!("r#{}", ident));
-        } else {
-            self.s.word(ident.as_str().to_string());
-        }
+        self.s.word(ident_to_string(ident, ident.is_raw_guess()));
         self.ann.post(self, AnnNode::Ident(&ident))
     }
 
@@ -2322,11 +2341,7 @@ impl<'a> State<'a> {
                           segment: &ast::PathSegment,
                           colons_before_params: bool) {
         if segment.ident.name != kw::PathRoot {
-            if segment.ident.name == kw::DollarCrate {
-                self.print_dollar_crate(segment.ident);
-            } else {
-                self.print_ident(segment.ident);
-            }
+            self.print_ident(segment.ident);
             if let Some(ref args) = segment.args {
                 self.print_generic_args(args, colons_before_params);
             }
diff --git a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout
index 0611fcb13f2..84821259d7b 100644
--- a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout
+++ b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout
@@ -1,4 +1,4 @@
-PRINT-BANG INPUT (DISPLAY): struct M ( $crate :: S ) ;
+PRINT-BANG INPUT (DISPLAY): struct M ( crate :: S ) ;
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
@@ -39,7 +39,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): struct A(crate::S);
-PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( $crate :: S ) ;
+PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( crate :: S ) ;
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
diff --git a/src/test/ui/proc-macro/dollar-crate.stdout b/src/test/ui/proc-macro/dollar-crate.stdout
index 3c88ee99842..9d9677d49e3 100644
--- a/src/test/ui/proc-macro/dollar-crate.stdout
+++ b/src/test/ui/proc-macro/dollar-crate.stdout
@@ -1,4 +1,4 @@
-PRINT-BANG INPUT (DISPLAY): struct M ( $crate :: S ) ;
+PRINT-BANG INPUT (DISPLAY): struct M ( crate :: S ) ;
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
@@ -39,7 +39,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): struct A(crate::S);
-PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( $crate :: S ) ;
+PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( crate :: S ) ;
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
@@ -80,7 +80,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): struct D(crate::S);
-PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ( $crate :: S ) ;
+PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ( crate :: S ) ;
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
@@ -120,7 +120,7 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
         span: #2 bytes(LO..HI),
     },
 ]
-PRINT-BANG INPUT (DISPLAY): struct M ( $crate :: S ) ;
+PRINT-BANG INPUT (DISPLAY): struct M ( ::dollar_crate_external :: S ) ;
 PRINT-BANG INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
@@ -161,7 +161,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-ATTR INPUT (DISPLAY): struct A(::dollar_crate_external::S);
-PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( $crate :: S ) ;
+PRINT-ATTR RE-COLLECTED (DISPLAY): struct A ( ::dollar_crate_external :: S ) ;
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
@@ -202,7 +202,7 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): struct D(::dollar_crate_external::S);
-PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ( $crate :: S ) ;
+PRINT-DERIVE RE-COLLECTED (DISPLAY): struct D ( ::dollar_crate_external :: S ) ;
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",