about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Tolnay <dtolnay@gmail.com>2022-01-14 14:52:04 -0800
committerDavid Tolnay <dtolnay@gmail.com>2022-01-18 11:14:42 -0800
commita6c9d8f524c035b71c15058f3682dc684c268d82 (patch)
treea01644decab845224b84a12dee91c20565f514e0
parentc70c646a0f7d7e9a1a481d5ae5b26b140cfd4cf2 (diff)
downloadrust-a6c9d8f524c035b71c15058f3682dc684c268d82.tar.gz
rust-a6c9d8f524c035b71c15058f3682dc684c268d82.zip
Invert the keyword list to list only *no* space before delim
-rw-r--r--src/librustdoc/clean/render_macro_matchers.rs98
1 files changed, 60 insertions, 38 deletions
diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs
index a6faa0d6857..dff370ab750 100644
--- a/src/librustdoc/clean/render_macro_matchers.rs
+++ b/src/librustdoc/clean/render_macro_matchers.rs
@@ -5,7 +5,8 @@ use rustc_ast_pretty::pprust::PrintState;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::FilePathMapping;
-use rustc_span::symbol::{kw, Symbol};
+use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::Span;
 
 /// Render a macro matcher in a format suitable for displaying to the user
 /// as part of an item declaration.
@@ -153,7 +154,7 @@ fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) {
                 }
                 (Pound, token::Not) => (false, PoundBang),
                 (_, token::Ident(symbol, /* is_raw */ false))
-                    if !usually_needs_space_between_keyword_and_open_delim(*symbol) =>
+                    if !usually_needs_space_between_keyword_and_open_delim(*symbol, tt.span) =>
                 {
                     (true, Ident)
                 }
@@ -177,42 +178,63 @@ fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) {
     }
 }
 
-// This rough subset of keywords is listed here to distinguish tokens resembling
-// `f(0)` (no space between ident and paren) from tokens resembling `if let (0,
-// 0) = x` (space between ident and paren).
-fn usually_needs_space_between_keyword_and_open_delim(symbol: Symbol) -> bool {
+fn usually_needs_space_between_keyword_and_open_delim(symbol: Symbol, span: Span) -> bool {
+    let ident = Ident { name: symbol, span };
+    let is_keyword = ident.is_used_keyword() || ident.is_unused_keyword();
+    if !is_keyword {
+        // An identifier that is not a keyword usually does not need a space
+        // before an open delim. For example: `f(0)` or `f[0]`.
+        return false;
+    }
+
     match symbol {
-        kw::As
-        | kw::Box
-        | kw::Break
-        | kw::Const
-        | kw::Continue
-        | kw::Crate
-        | kw::Else
-        | kw::Enum
-        | kw::Extern
-        | kw::For
-        | kw::If
-        | kw::Impl
-        | kw::In
-        | kw::Let
-        | kw::Loop
-        | kw::Macro
-        | kw::Match
-        | kw::Mod
-        | kw::Move
-        | kw::Mut
-        | kw::Ref
-        | kw::Return
-        | kw::Static
-        | kw::Struct
-        | kw::Trait
-        | kw::Type
-        | kw::Unsafe
-        | kw::Use
-        | kw::Where
-        | kw::While
-        | kw::Yield => true,
-        _ => false,
+        // No space after keywords that are syntactically an expression. For
+        // example: a tuple struct created with `let _ = Self(0, 0)`, or if
+        // someone has `impl Index<MyStruct> for bool` then `true[MyStruct]`.
+        kw::False | kw::SelfLower | kw::SelfUpper | kw::True => false,
+
+        // No space, as in `let _: fn();`
+        kw::Fn => false,
+
+        // No space, as in `pub(crate) type T;`
+        kw::Pub => false,
+
+        // No space for keywords that can end an expression, as in `fut.await()`
+        // where fut's Output type is `fn()`.
+        kw::Await => false,
+
+        // Otherwise space after keyword. Some examples:
+        //
+        // `expr as [T; 2]`
+        //         ^
+        // `box (tuple,)`
+        //     ^
+        // `break (tuple,)`
+        //       ^
+        // `type T = dyn (Fn() -> dyn Trait) + Send;`
+        //              ^
+        // `for (tuple,) in iter {}`
+        //     ^
+        // `if (tuple,) == v {}`
+        //    ^
+        // `impl [T] {}`
+        //      ^
+        // `for x in [..] {}`
+        //          ^
+        // `let () = unit;`
+        //     ^
+        // `match [x, y] {...}`
+        //       ^
+        // `&mut (x as T)`
+        //      ^
+        // `return [];`
+        //        ^
+        // `fn f<T>() where (): Into<T>`
+        //                 ^
+        // `while (a + b).what() {}`
+        //       ^
+        // `yield [];`
+        //       ^
+        _ => true,
     }
 }