[PATCH] D77311: clang-format: [JS] detect C++ keywords.

2020-04-03 Thread Martin Probst via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
mprobst marked an inline comment as done.
Closed by commit rG146d685cd657: clang-format: [JS] detect C++ keywords. 
(authored by mprobst).

Changed prior to commit:
  https://reviews.llvm.org/D77311?vs=254741=254763#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77311/new/

https://reviews.llvm.org/D77311

Files:
  clang/lib/Format/FormatToken.h
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTestJS.cpp

Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -386,13 +386,6 @@
"return (x);\n");
 }
 
-TEST_F(FormatTestJS, CppKeywords) {
-  // Make sure we don't mess stuff up because of C++ keywords.
-  verifyFormat("return operator && (aa);");
-  // .. or QT ones.
-  verifyFormat("slots: Slot[];");
-}
-
 TEST_F(FormatTestJS, ES6DestructuringAssignment) {
   verifyFormat("var [a, b, c] = [1, 2, 3];");
   verifyFormat("const [a, b, c] = [1, 2, 3];");
@@ -2366,6 +2359,61 @@
   verifyFormat("return !!x;\n");
 }
 
+TEST_F(FormatTestJS, CppKeywords) {
+  // Make sure we don't mess stuff up because of C++ keywords.
+  verifyFormat("return operator && (aa);");
+  // .. or QT ones.
+  verifyFormat("const slots: Slot[];");
+  // use the "!" assertion operator to validate that clang-format understands
+  // these C++ keywords aren't keywords in JS/TS.
+  verifyFormat("auto!;");
+  verifyFormat("char!;");
+  verifyFormat("concept!;");
+  verifyFormat("double!;");
+  verifyFormat("extern!;");
+  verifyFormat("float!;");
+  verifyFormat("inline!;");
+  verifyFormat("int!;");
+  verifyFormat("long!;");
+  verifyFormat("register!;");
+  verifyFormat("restrict!;");
+  verifyFormat("sizeof!;");
+  verifyFormat("struct!;");
+  verifyFormat("typedef!;");
+  verifyFormat("union!;");
+  verifyFormat("unsigned!;");
+  verifyFormat("volatile!;");
+  verifyFormat("_Alignas!;");
+  verifyFormat("_Alignof!;");
+  verifyFormat("_Atomic!;");
+  verifyFormat("_Bool!;");
+  verifyFormat("_Complex!;");
+  verifyFormat("_Generic!;");
+  verifyFormat("_Imaginary!;");
+  verifyFormat("_Noreturn!;");
+  verifyFormat("_Static_assert!;");
+  verifyFormat("_Thread_local!;");
+  verifyFormat("__func__!;");
+  verifyFormat("__objc_yes!;");
+  verifyFormat("__objc_no!;");
+  verifyFormat("asm!;");
+  verifyFormat("bool!;");
+  verifyFormat("const_cast!;");
+  verifyFormat("dynamic_cast!;");
+  verifyFormat("explicit!;");
+  verifyFormat("friend!;");
+  verifyFormat("mutable!;");
+  verifyFormat("operator!;");
+  verifyFormat("reinterpret_cast!;");
+  verifyFormat("static_cast!;");
+  verifyFormat("template!;");
+  verifyFormat("typename!;");
+  verifyFormat("typeid!;");
+  verifyFormat("using!;");
+  verifyFormat("virtual!;");
+  verifyFormat("wchar_t!;");
+}
+
 TEST_F(FormatTestJS, NullPropagatingOperator) {
   verifyFormat("let x = foo?.bar?.baz();\n");
   verifyFormat("let x = foo?.(foo);\n");
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1522,9 +1522,9 @@
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (Current.is(tok::exclaim)) {
 if (Current.Previous &&
-(Current.Previous->isOneOf(tok::identifier, tok::kw_namespace,
-   tok::r_paren, tok::r_square,
-   tok::r_brace) ||
+(Keywords.IsJavaScriptIdentifier(*Current.Previous) ||
+ Current.Previous->isOneOf(tok::kw_namespace, tok::r_paren,
+   tok::r_square, tok::r_brace) ||
  Current.Previous->Tok.isLiteral())) {
   Current.Type = TT_JsNonNullAssertion;
   return;
@@ -3070,10 +3070,8 @@
 (Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
   return false;
 // In tagged template literals ("html`bar baz`"), there is no space between
-// the tag identifier and the template string. getIdentifierInfo makes sure
-// that the identifier is not a pseudo keyword like `yield`, either.
-if (Left.is(tok::identifier) && Keywords.IsJavaScriptIdentifier(Left) &&
-Right.is(TT_TemplateString))
+// the tag identifier and the template string.
+if (Keywords.IsJavaScriptIdentifier(Left) && Right.is(TT_TemplateString))
   return false;
 if (Right.is(tok::star) &&
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -910,9 +910,64 @@
   /// Returns \c true if \p Tok is a true JavaScript identifier, returns
   /// \c 

[PATCH] D77311: clang-format: [JS] detect C++ keywords.

2020-04-03 Thread Martin Probst via Phabricator via cfe-commits
mprobst marked 2 inline comments as done.
mprobst added inline comments.



Comment at: clang/lib/Format/FormatToken.h:913
   bool IsJavaScriptIdentifier(const FormatToken ) const {
-return Tok.is(tok::identifier) &&
-   JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) ==
-   JsExtraKeywords.end();
+switch (Tok.Tok.getKind()) {
+case tok::kw_break:

krasimir wrote:
> nit: may be worth adding a comment linking to:
> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords
Done, though I used the TS list of keywords (as it's a superset of the JS 
keywords).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77311/new/

https://reviews.llvm.org/D77311



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D77311: clang-format: [JS] detect C++ keywords.

2020-04-03 Thread Krasimir Georgiev via Phabricator via cfe-commits
krasimir added inline comments.



Comment at: clang/lib/Format/FormatToken.h:913
   bool IsJavaScriptIdentifier(const FormatToken ) const {
-return Tok.is(tok::identifier) &&
-   JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) ==
-   JsExtraKeywords.end();
+switch (Tok.Tok.getKind()) {
+case tok::kw_break:

nit: may be worth adding a comment linking to:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77311/new/

https://reviews.llvm.org/D77311



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D77311: clang-format: [JS] detect C++ keywords.

2020-04-03 Thread Krasimir Georgiev via Phabricator via cfe-commits
krasimir accepted this revision.
krasimir added a comment.
This revision is now accepted and ready to land.

Thank you!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77311/new/

https://reviews.llvm.org/D77311



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D77311: clang-format: [JS] detect C++ keywords.

2020-04-03 Thread MyDeveloperDay via Phabricator via cfe-commits
MyDeveloperDay accepted this revision.
MyDeveloperDay added a comment.

I think this LGTM and brings more clarity as its much easier to look for things 
in the positive than the negative


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77311/new/

https://reviews.llvm.org/D77311



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D77311: clang-format: [JS] detect C++ keywords.

2020-04-03 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 254740.
mprobst added a comment.

- - improve handling of keywors - rather than blacklisting all C++


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77311/new/

https://reviews.llvm.org/D77311

Files:
  clang/lib/Format/FormatToken.h
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTestJS.cpp

Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -386,13 +386,6 @@
"return (x);\n");
 }
 
-TEST_F(FormatTestJS, CppKeywords) {
-  // Make sure we don't mess stuff up because of C++ keywords.
-  verifyFormat("return operator && (aa);");
-  // .. or QT ones.
-  verifyFormat("slots: Slot[];");
-}
-
 TEST_F(FormatTestJS, ES6DestructuringAssignment) {
   verifyFormat("var [a, b, c] = [1, 2, 3];");
   verifyFormat("const [a, b, c] = [1, 2, 3];");
@@ -2366,6 +2359,61 @@
   verifyFormat("return !!x;\n");
 }
 
+TEST_F(FormatTestJS, CppKeywords) {
+  // Make sure we don't mess stuff up because of C++ keywords.
+  verifyFormat("return operator && (aa);");
+  // .. or QT ones.
+  verifyFormat("const slots: Slot[];");
+  // use the "!" assertion operator to validate that clang-format understands
+  // these C++ keywords aren't keywords in JS/TS.
+  verifyFormat("auto!;");
+  verifyFormat("char!;");
+  verifyFormat("concept!;");
+  verifyFormat("double!;");
+  verifyFormat("extern!;");
+  verifyFormat("float!;");
+  verifyFormat("inline!;");
+  verifyFormat("int!;");
+  verifyFormat("long!;");
+  verifyFormat("register!;");
+  verifyFormat("restrict!;");
+  verifyFormat("sizeof!;");
+  verifyFormat("struct!;");
+  verifyFormat("typedef!;");
+  verifyFormat("union!;");
+  verifyFormat("unsigned!;");
+  verifyFormat("volatile!;");
+  verifyFormat("_Alignas!;");
+  verifyFormat("_Alignof!;");
+  verifyFormat("_Atomic!;");
+  verifyFormat("_Bool!;");
+  verifyFormat("_Complex!;");
+  verifyFormat("_Generic!;");
+  verifyFormat("_Imaginary!;");
+  verifyFormat("_Noreturn!;");
+  verifyFormat("_Static_assert!;");
+  verifyFormat("_Thread_local!;");
+  verifyFormat("__func__!;");
+  verifyFormat("__objc_yes!;");
+  verifyFormat("__objc_no!;");
+  verifyFormat("asm!;");
+  verifyFormat("bool!;");
+  verifyFormat("const_cast!;");
+  verifyFormat("dynamic_cast!;");
+  verifyFormat("explicit!;");
+  verifyFormat("friend!;");
+  verifyFormat("mutable!;");
+  verifyFormat("operator!;");
+  verifyFormat("reinterpret_cast!;");
+  verifyFormat("static_cast!;");
+  verifyFormat("template!;");
+  verifyFormat("typename!;");
+  verifyFormat("typeid!;");
+  verifyFormat("using!;");
+  verifyFormat("virtual!;");
+  verifyFormat("wchar_t!;");
+}
+
 TEST_F(FormatTestJS, NullPropagatingOperator) {
   verifyFormat("let x = foo?.bar?.baz();\n");
   verifyFormat("let x = foo?.(foo);\n");
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1522,9 +1522,9 @@
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (Current.is(tok::exclaim)) {
 if (Current.Previous &&
-(Current.Previous->isOneOf(tok::identifier, tok::kw_namespace,
-   tok::r_paren, tok::r_square,
-   tok::r_brace) ||
+(Keywords.IsJavaScriptIdentifier(*Current.Previous) ||
+ Current.Previous->isOneOf(tok::kw_namespace, tok::r_paren,
+   tok::r_square, tok::r_brace) ||
  Current.Previous->Tok.isLiteral())) {
   Current.Type = TT_JsNonNullAssertion;
   return;
@@ -3070,10 +3070,8 @@
 (Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
   return false;
 // In tagged template literals ("html`bar baz`"), there is no space between
-// the tag identifier and the template string. getIdentifierInfo makes sure
-// that the identifier is not a pseudo keyword like `yield`, either.
-if (Left.is(tok::identifier) && Keywords.IsJavaScriptIdentifier(Left) &&
-Right.is(TT_TemplateString))
+// the tag identifier and the template string.
+if (Keywords.IsJavaScriptIdentifier(Left) && Right.is(TT_TemplateString))
   return false;
 if (Right.is(tok::star) &&
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -910,9 +910,62 @@
   /// Returns \c true if \p Tok is a true JavaScript identifier, returns
   /// \c false if it is a keyword or a pseudo keyword.
   bool IsJavaScriptIdentifier(const FormatToken ) const {
-return Tok.is(tok::identifier) &&
-   

[PATCH] D77311: clang-format: [JS] detect C++ keywords.

2020-04-03 Thread Martin Probst via Phabricator via cfe-commits
mprobst added a comment.

Thanks for the feedback. Indeed, whitelisting the JS keywords is better, but we 
still needed a way to blacklist all C++ keywords then - Krasimir's suggestion 
with the #include did the trick, thanks.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77311/new/

https://reviews.llvm.org/D77311



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D77311: clang-format: [JS] detect C++ keywords.

2020-04-03 Thread Martin Probst via Phabricator via cfe-commits
mprobst updated this revision to Diff 254741.
mprobst added a comment.

- fix formatting


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77311/new/

https://reviews.llvm.org/D77311

Files:
  clang/lib/Format/FormatToken.h
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTestJS.cpp

Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -386,13 +386,6 @@
"return (x);\n");
 }
 
-TEST_F(FormatTestJS, CppKeywords) {
-  // Make sure we don't mess stuff up because of C++ keywords.
-  verifyFormat("return operator && (aa);");
-  // .. or QT ones.
-  verifyFormat("slots: Slot[];");
-}
-
 TEST_F(FormatTestJS, ES6DestructuringAssignment) {
   verifyFormat("var [a, b, c] = [1, 2, 3];");
   verifyFormat("const [a, b, c] = [1, 2, 3];");
@@ -2366,6 +2359,61 @@
   verifyFormat("return !!x;\n");
 }
 
+TEST_F(FormatTestJS, CppKeywords) {
+  // Make sure we don't mess stuff up because of C++ keywords.
+  verifyFormat("return operator && (aa);");
+  // .. or QT ones.
+  verifyFormat("const slots: Slot[];");
+  // use the "!" assertion operator to validate that clang-format understands
+  // these C++ keywords aren't keywords in JS/TS.
+  verifyFormat("auto!;");
+  verifyFormat("char!;");
+  verifyFormat("concept!;");
+  verifyFormat("double!;");
+  verifyFormat("extern!;");
+  verifyFormat("float!;");
+  verifyFormat("inline!;");
+  verifyFormat("int!;");
+  verifyFormat("long!;");
+  verifyFormat("register!;");
+  verifyFormat("restrict!;");
+  verifyFormat("sizeof!;");
+  verifyFormat("struct!;");
+  verifyFormat("typedef!;");
+  verifyFormat("union!;");
+  verifyFormat("unsigned!;");
+  verifyFormat("volatile!;");
+  verifyFormat("_Alignas!;");
+  verifyFormat("_Alignof!;");
+  verifyFormat("_Atomic!;");
+  verifyFormat("_Bool!;");
+  verifyFormat("_Complex!;");
+  verifyFormat("_Generic!;");
+  verifyFormat("_Imaginary!;");
+  verifyFormat("_Noreturn!;");
+  verifyFormat("_Static_assert!;");
+  verifyFormat("_Thread_local!;");
+  verifyFormat("__func__!;");
+  verifyFormat("__objc_yes!;");
+  verifyFormat("__objc_no!;");
+  verifyFormat("asm!;");
+  verifyFormat("bool!;");
+  verifyFormat("const_cast!;");
+  verifyFormat("dynamic_cast!;");
+  verifyFormat("explicit!;");
+  verifyFormat("friend!;");
+  verifyFormat("mutable!;");
+  verifyFormat("operator!;");
+  verifyFormat("reinterpret_cast!;");
+  verifyFormat("static_cast!;");
+  verifyFormat("template!;");
+  verifyFormat("typename!;");
+  verifyFormat("typeid!;");
+  verifyFormat("using!;");
+  verifyFormat("virtual!;");
+  verifyFormat("wchar_t!;");
+}
+
 TEST_F(FormatTestJS, NullPropagatingOperator) {
   verifyFormat("let x = foo?.bar?.baz();\n");
   verifyFormat("let x = foo?.(foo);\n");
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1522,9 +1522,9 @@
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (Current.is(tok::exclaim)) {
 if (Current.Previous &&
-(Current.Previous->isOneOf(tok::identifier, tok::kw_namespace,
-   tok::r_paren, tok::r_square,
-   tok::r_brace) ||
+(Keywords.IsJavaScriptIdentifier(*Current.Previous) ||
+ Current.Previous->isOneOf(tok::kw_namespace, tok::r_paren,
+   tok::r_square, tok::r_brace) ||
  Current.Previous->Tok.isLiteral())) {
   Current.Type = TT_JsNonNullAssertion;
   return;
@@ -3070,10 +3070,8 @@
 (Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
   return false;
 // In tagged template literals ("html`bar baz`"), there is no space between
-// the tag identifier and the template string. getIdentifierInfo makes sure
-// that the identifier is not a pseudo keyword like `yield`, either.
-if (Left.is(tok::identifier) && Keywords.IsJavaScriptIdentifier(Left) &&
-Right.is(TT_TemplateString))
+// the tag identifier and the template string.
+if (Keywords.IsJavaScriptIdentifier(Left) && Right.is(TT_TemplateString))
   return false;
 if (Right.is(tok::star) &&
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -910,9 +910,62 @@
   /// Returns \c true if \p Tok is a true JavaScript identifier, returns
   /// \c false if it is a keyword or a pseudo keyword.
   bool IsJavaScriptIdentifier(const FormatToken ) const {
-return Tok.is(tok::identifier) &&
-   JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) ==

[PATCH] D77311: clang-format: [JS] detect C++ keywords.

2020-04-02 Thread Krasimir Georgiev via Phabricator via cfe-commits
krasimir added a comment.

In D77311#1957367 , @jfb wrote:

> Some of these are technically "future reserved keywords": 
> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords
>
> Wouldn't it be better to list all of JS's keywords at this point?


+1 to consider listing all of JS's keywords instead of listing all C++ keywords 
that are not JS keywords. With the current approach, any time a new C++ keyword 
token gets introduced, the switch in `IsJavaScriptIdentifier` would have to be 
updated.

But turning the implementation into something that lists JS keywords seems a 
bit tricky. Just a suggestion: maybe we can use the trick to #include 
TokenKinds.def 

 used in TokenKinds.h 
:

  bool IsJavaScriptIdentifier(const FormatToken ) const {
  switch (Tok.Tok.getKind()) {
// list all JS keywords defined as KEYWORD in TokenKinds.def
case tok::kw_break:
case tok::kw_case:
... 
case tok::kw_return:
return false;
  
// All of the remaining C keywords are JS identifiers.
#define KEYWORD(X,Y) case tok::kw_ ## X:
#include "clang/Basic/TokenKinds.def"
// #undef KEYWORD is not needed -- it's #undef-ed at the end of 
TokenKinds.def
return true;
  
// handle identifiers and everything else as in the patch.
case tok::identifier:
default: return false;
  }


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77311/new/

https://reviews.llvm.org/D77311



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D77311: clang-format: [JS] detect C++ keywords.

2020-04-02 Thread JF Bastien via Phabricator via cfe-commits
jfb added a comment.

Some of these are technically "future reserved keywords": 
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords

Wouldn't it be better to list all of JS's keywords at this point?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77311/new/

https://reviews.llvm.org/D77311



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D77311: clang-format: [JS] detect C++ keywords.

2020-04-02 Thread Martin Probst via Phabricator via cfe-commits
mprobst created this revision.
mprobst added a reviewer: krasimir.
Herald added subscribers: cfe-commits, jfb.
Herald added a project: clang.

C++ defines a number of keywords that are regular identifiers in
JavaScript, e.g. `concept`:

  const concept = 1; // legit JS

This change expands the existing `IsJavaScriptIdentifier(Tok)` function
to return false for C++ keywords that aren't keywords in JS.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D77311

Files:
  clang/lib/Format/FormatToken.h
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTestJS.cpp

Index: clang/unittests/Format/FormatTestJS.cpp
===
--- clang/unittests/Format/FormatTestJS.cpp
+++ clang/unittests/Format/FormatTestJS.cpp
@@ -2366,6 +2366,58 @@
   verifyFormat("return !!x;\n");
 }
 
+TEST_F(FormatTestJS, CppKeywordsInJavaScript) {
+  // use the "!" assertion operator to validate that clang-format understands
+  // these C++ keywords aren't keywords in JS/TS.
+  verifyFormat("auto!;");
+  verifyFormat("char!;");
+  verifyFormat("concept!;");
+  verifyFormat("double!;");
+  verifyFormat("extern!;");
+  verifyFormat("float!;");
+  verifyFormat("inline!;");
+  verifyFormat("int!;");
+  verifyFormat("long!;");
+  verifyFormat("register!;");
+  verifyFormat("restrict!;");
+  verifyFormat("sizeof!;");
+  verifyFormat("static!;");
+  verifyFormat("struct!;");
+  verifyFormat("typedef!;");
+  verifyFormat("union!;");
+  verifyFormat("unsigned!;");
+  verifyFormat("volatile!;");
+  verifyFormat("_Alignas!;");
+  verifyFormat("_Alignof!;");
+  verifyFormat("_Atomic!;");
+  verifyFormat("_Bool!;");
+  verifyFormat("_Complex!;");
+  verifyFormat("_Generic!;");
+  verifyFormat("_Imaginary!;");
+  verifyFormat("_Noreturn!;");
+  verifyFormat("_Static_assert!;");
+  verifyFormat("_Thread_local!;");
+  verifyFormat("__func__!;");
+  verifyFormat("__objc_yes!;");
+  verifyFormat("__objc_no!;");
+  verifyFormat("asm!;");
+  verifyFormat("bool!;");
+  verifyFormat("const_cast!;");
+  verifyFormat("dynamic_cast!;");
+  verifyFormat("explicit!;");
+  verifyFormat("friend!;");
+  verifyFormat("mutable!;");
+  verifyFormat("operator!;");
+  verifyFormat("reinterpret_cast!;");
+  verifyFormat("static_cast!;");
+  verifyFormat("template!;");
+  verifyFormat("typename!;");
+  verifyFormat("typeid!;");
+  verifyFormat("using!;");
+  verifyFormat("virtual!;");
+  verifyFormat("wchar_t!;");
+}
+
 TEST_F(FormatTestJS, NullPropagatingOperator) {
   verifyFormat("let x = foo?.bar?.baz();\n");
   verifyFormat("let x = foo?.(foo);\n");
Index: clang/lib/Format/TokenAnnotator.cpp
===
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1522,9 +1522,9 @@
 if (Style.Language == FormatStyle::LK_JavaScript) {
   if (Current.is(tok::exclaim)) {
 if (Current.Previous &&
-(Current.Previous->isOneOf(tok::identifier, tok::kw_namespace,
-   tok::r_paren, tok::r_square,
-   tok::r_brace) ||
+(Keywords.IsJavaScriptIdentifier(*Current.Previous) ||
+ Current.Previous->isOneOf(tok::kw_namespace, tok::r_paren,
+   tok::r_square, tok::r_brace) ||
  Current.Previous->Tok.isLiteral())) {
   Current.Type = TT_JsNonNullAssertion;
   return;
@@ -3070,10 +3070,8 @@
 (Right.is(TT_TemplateString) && Right.TokenText.startswith("}")))
   return false;
 // In tagged template literals ("html`bar baz`"), there is no space between
-// the tag identifier and the template string. getIdentifierInfo makes sure
-// that the identifier is not a pseudo keyword like `yield`, either.
-if (Left.is(tok::identifier) && Keywords.IsJavaScriptIdentifier(Left) &&
-Right.is(TT_TemplateString))
+// the tag identifier and the template string.
+if (Keywords.IsJavaScriptIdentifier(Left) && Right.is(TT_TemplateString))
   return false;
 if (Right.is(tok::star) &&
 Left.isOneOf(Keywords.kw_function, Keywords.kw_yield))
Index: clang/lib/Format/FormatToken.h
===
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -910,9 +910,65 @@
   /// Returns \c true if \p Tok is a true JavaScript identifier, returns
   /// \c false if it is a keyword or a pseudo keyword.
   bool IsJavaScriptIdentifier(const FormatToken ) const {
-return Tok.is(tok::identifier) &&
-   JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) ==
-   JsExtraKeywords.end();
+switch (Tok.Tok.getKind()) {
+case tok::kw_auto:
+case tok::kw_char:
+case tok::kw_concept:
+case tok::kw_double:
+case tok::kw_extern:
+case tok::kw_float:
+case tok::kw_inline:
+case tok::kw_int:
+case