mprobst created this revision.
mprobst added a reviewer: djasper.
mprobst added a subscriber: cfe-commits.
Herald added a subscriber: klimek.

Refactors AnnotatedLine.startsWith/endsWith by extracting the core functionality
into FormatToken.startsSequence/endsSequence. This allows checking tokens within
the pointered linked list structure with a lookahead, automatically ignoring
comments, which is useful in many places (e.g. see subsequent commit).

clang-format: [JS] fix async parsing.

Only treat the sequence `async function` as the start of a function expression,
as opposed to every occurrence of the token `async` (whoops).

http://reviews.llvm.org/D20737

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

Index: unittests/Format/FormatTestJS.cpp
===================================================================
--- unittests/Format/FormatTestJS.cpp
+++ unittests/Format/FormatTestJS.cpp
@@ -354,6 +354,10 @@
   verifyFormat("class X {\n"
                "  async asyncMethod() { return fetch(1); }\n"
                "}");
+  verifyFormat("function initialize() {\n"
+               "  // Comment.\n"
+               "  return async.then();\n"
+               "}\n");
 }
 
 TEST_F(FormatTestJS, ArrayLiterals) {
Index: lib/Format/UnwrappedLineParser.cpp
===================================================================
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -1013,7 +1013,9 @@
       // Parse function literal unless 'function' is the first token in a line
       // in which case this should be treated as a free-standing function.
       if (Style.Language == FormatStyle::LK_JavaScript &&
-          FormatTok->isOneOf(Keywords.kw_async, Keywords.kw_function) &&
+          (FormatTok->is(Keywords.kw_function) ||
+           FormatTok->startsSequence(Keywords.kw_async,
+                                     Keywords.kw_function)) &&
           Line->Tokens.size() > 0) {
         tryToParseJSFunction();
         break;
@@ -1200,7 +1202,8 @@
 }
 
 void UnwrappedLineParser::tryToParseJSFunction() {
-  assert(FormatTok->isOneOf(Keywords.kw_async, Keywords.kw_function));
+  assert(FormatTok->is(Keywords.kw_function) ||
+         FormatTok->startsSequence(Keywords.kw_async, Keywords.kw_function));
   if (FormatTok->is(Keywords.kw_async))
     nextToken();
   // Consume "function".
@@ -1254,7 +1257,8 @@
   // replace this by using parseAssigmentExpression() inside.
   do {
     if (Style.Language == FormatStyle::LK_JavaScript) {
-      if (FormatTok->isOneOf(Keywords.kw_async, Keywords.kw_function)) {
+      if (FormatTok->is(Keywords.kw_function) ||
+          FormatTok->startsSequence(Keywords.kw_async, Keywords.kw_function)) {
         tryToParseJSFunction();
         continue;
       }
@@ -1352,7 +1356,8 @@
       break;
     case tok::identifier:
       if (Style.Language == FormatStyle::LK_JavaScript &&
-          FormatTok->isOneOf(Keywords.kw_async, Keywords.kw_function))
+          (FormatTok->is(Keywords.kw_function) ||
+           FormatTok->startsSequence(Keywords.kw_async, Keywords.kw_function)))
         tryToParseJSFunction();
       else
         nextToken();
Index: lib/Format/TokenAnnotator.h
===================================================================
--- lib/Format/TokenAnnotator.h
+++ lib/Format/TokenAnnotator.h
@@ -83,15 +83,15 @@
   /// \c true if this line starts with the given tokens in order, ignoring
   /// comments.
   template <typename... Ts> bool startsWith(Ts... Tokens) const {
-    return startsWithInternal(First, Tokens...);
+    return First && First->startsSequence(Tokens...);
   }
 
   /// \c true if this line ends with the given tokens in reversed order,
   /// ignoring comments.
   /// For example, given tokens [T1, T2, T3, ...], the function returns true if
   /// this line is like "... T3 T2 T1".
   template <typename... Ts> bool endsWith(Ts... Tokens) const {
-    return endsWithInternal(Last, Tokens...);
+    return Last && Last->endsSequence(Tokens...);
   }
 
   /// \c true if this line looks like a function definition instead of a
@@ -130,44 +130,6 @@
   // Disallow copying.
   AnnotatedLine(const AnnotatedLine &) = delete;
   void operator=(const AnnotatedLine &) = delete;
-
-  template <typename A, typename... Ts>
-  bool startsWithInternal(const FormatToken *Tok, A K1) const {
-    // Even though we skip comments in the outer `startWithInternal` function,
-    // this loop is still necessary if it is invoked by the public interface
-    // `startsWith`.
-    while (Tok && Tok->is(tok::comment))
-      Tok = Tok->Next;
-    return Tok && Tok->is(K1);
-  }
-
-  template <typename A, typename... Ts>
-  bool startsWithInternal(const FormatToken *Tok, A K1, Ts... Tokens) const {
-    // Skip comments before calling `startsWithInternal(Tok, K1)` so that  the
-    // second call to `startsWithInternal` takes the correct `Tok->Next`, which
-    // should be the next token of the token checked in the first call.
-    while (Tok && Tok->is(tok::comment))
-      Tok = Tok->Next;
-    return Tok && startsWithInternal(Tok, K1) &&
-           startsWithInternal(Tok->Next, Tokens...);
-  }
-
-  template <typename A, typename... Ts>
-  bool endsWithInternal(const FormatToken *Tok, A K1) const {
-    // See the comments above in `startsWithInternal(Tok, K1)`.
-    while (Tok && Tok->is(tok::comment))
-      Tok = Tok->Previous;
-    return Tok && Tok->is(K1);
-  }
-
-  template <typename A, typename... Ts>
-  bool endsWithInternal(const FormatToken *Tok, A K1, Ts... Tokens) const {
-    // See the comments above in `startsWithInternal(Tok, K1, Tokens)`.
-    while (Tok && Tok->is(tok::comment))
-      Tok = Tok->Previous;
-    return Tok && endsWithInternal(Tok, K1) &&
-           endsWithInternal(Tok->Previous, Tokens...);
-  }
 };
 
 /// \brief Determines extra information about the tokens comprising an
Index: lib/Format/FormatToken.h
===================================================================
--- lib/Format/FormatToken.h
+++ lib/Format/FormatToken.h
@@ -297,6 +297,20 @@
   }
   template <typename T> bool isNot(T Kind) const { return !is(Kind); }
 
+  /// \c true if this token starts a sequence with the given tokens in order,
+  /// following the ``Next`` pointers, ignoring comments.
+  template <typename A, typename... Ts>
+  bool startsSequence(A K1, Ts... Tokens) const {
+    return startsSequenceInternal(K1, Tokens...);
+  }
+
+  /// \c true if this token ends a sequence with the given tokens in order,
+  /// following the ``Previous`` pointers, ignoring comments.
+  template <typename A, typename... Ts>
+  bool endsSequence(A K1, Ts... Tokens) const {
+    return endsSequenceInternal(K1, Tokens...);
+  }
+
   bool isStringLiteral() const { return tok::isStringLiteral(Tok.getKind()); }
 
   bool isObjCAtKeyword(tok::ObjCKeywordKind Kind) const {
@@ -429,6 +443,34 @@
   // Disallow copying.
   FormatToken(const FormatToken &) = delete;
   void operator=(const FormatToken &) = delete;
+
+  template <typename A, typename... Ts>
+  bool startsSequenceInternal(A K1, Ts... Tokens) const {
+    if (is(tok::comment) && Next)
+      return Next->startsSequenceInternal(K1, Tokens...);
+    return is(K1) && Next && Next->startsSequenceInternal(Tokens...);
+  }
+
+  template <typename A>
+  bool startsSequenceInternal(A K1) const {
+    if (is(tok::comment) && Next)
+      return Next->startsSequenceInternal(K1);
+    return is(K1);
+  }
+
+  template <typename A, typename... Ts>
+  bool endsSequenceInternal(A K1) const {
+    if (is(tok::comment) && Previous)
+      return Previous->endsSequenceInternal(K1);
+    return is(K1);
+  }
+
+  template <typename A, typename... Ts>
+  bool endsSequenceInternal(A K1, Ts... Tokens) const {
+    if (is(tok::comment) && Previous)
+      return Previous->endsSequenceInternal(K1, Tokens...);
+    return is(K1) && Previous && Previous->endsSequenceInternal(Tokens...);
+  }
 };
 
 class ContinuationIndenter;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to