r253873 - clang-format: Signficantly refactor the cast detection.

Daniel Jasper via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 23 07:55:56 PST 2015


Author: djasper
Date: Mon Nov 23 09:55:55 2015
New Revision: 253873

URL: http://llvm.org/viewvc/llvm-project?rev=253873&view=rev
Log:
clang-format: Signficantly refactor the cast detection.

No functional changes intended.

Modified:
    cfe/trunk/lib/Format/TokenAnnotator.cpp

Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=253873&r1=253872&r2=253873&view=diff
==============================================================================
--- cfe/trunk/lib/Format/TokenAnnotator.cpp (original)
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp Mon Nov 23 09:55:55 2015
@@ -1057,74 +1057,85 @@ private:
 
   /// \brief Determine whether ')' is ending a cast.
   bool rParenEndsCast(const FormatToken &Tok) {
-    FormatToken *LeftOfParens = nullptr;
-    if (Tok.MatchingParen)
-      LeftOfParens = Tok.MatchingParen->getPreviousNonComment();
+    // C-style casts are only used in C++ and Java.
+    if (Style.Language != FormatStyle::LK_Cpp &&
+        Style.Language != FormatStyle::LK_Java)
+      return false;
 
+    // Empty parens aren't casts and there are no casts at the end of the line.
+    if (Tok.Previous == Tok.MatchingParen || !Tok.Next || !Tok.MatchingParen)
+      return false;
+
+    FormatToken *LeftOfParens = Tok.MatchingParen->getPreviousNonComment();
     if (LeftOfParens) {
+      // If there is an identifier (or with a few exceptions a keyword) right
+      // before the parentheses, this is unlikely to be a cast.
       if (LeftOfParens->Tok.getIdentifierInfo() &&
           !LeftOfParens->isOneOf(Keywords.kw_in, tok::kw_return, tok::kw_case,
                                  tok::kw_delete))
         return false;
-      if (LeftOfParens->isOneOf(tok::kw_sizeof, tok::kw_alignof, tok::at,
-                                tok::r_square, TT_OverloadedOperator,
+
+      // Certain other tokens right before the parentheses are also signals that
+      // this cannot be a cast.
+      if (LeftOfParens->isOneOf(tok::at, tok::r_square, TT_OverloadedOperator,
                                 TT_TemplateCloser))
         return false;
-      if (LeftOfParens->is(tok::r_paren) && LeftOfParens->MatchingParen)
-        LeftOfParens = LeftOfParens->MatchingParen->Previous;
     }
-    if (Tok.Next) {
-      if (Tok.Next->is(tok::question))
-        return false;
-      if (Style.Language == FormatStyle::LK_JavaScript &&
-          Tok.Next->is(Keywords.kw_in))
-        return false;
-      if (Style.Language == FormatStyle::LK_Java && Tok.Next->is(tok::l_paren))
-        return true;
-    }
-    bool IsCast = false;
-    bool ParensAreEmpty = Tok.Previous == Tok.MatchingParen;
+
+    if (Tok.Next->is(tok::question))
+      return false;
+
+    // As Java has no function types, a "(" after the ")" likely means that this
+    // is a cast.
+    if (Style.Language == FormatStyle::LK_Java && Tok.Next->is(tok::l_paren))
+      return true;
+
+    // If a (non-string) literal follows, this is likely a cast.
+    if (Tok.Next->isNot(tok::string_literal) &&
+        (Tok.Next->Tok.isLiteral() ||
+         Tok.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof)))
+      return true;
+
+    // Heuristically try to determine whether the parentheses contain a type.
     bool ParensAreType =
         !Tok.Previous ||
         Tok.Previous->isOneOf(TT_PointerOrReference, TT_TemplateCloser) ||
         Tok.Previous->isSimpleTypeSpecifier();
     bool ParensCouldEndDecl =
-        Tok.Next &&
         Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater);
     if (ParensAreType && !ParensCouldEndDecl &&
         (Contexts.size() > 1 && Contexts[Contexts.size() - 2].IsExpression))
-      IsCast = true;
-    else if (Tok.Next && Tok.Next->isNot(tok::string_literal) &&
-             (Tok.Next->Tok.isLiteral() ||
-              Tok.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof)))
-      IsCast = true;
-    else if (LeftOfParens && Tok.Next) {
-      if (Tok.Next->isOneOf(tok::identifier, tok::numeric_constant)) {
-        IsCast = true;
-      } else {
-        // Use heuristics to recognize c style casting.
-        FormatToken *Prev = Tok.Previous;
-        if (Prev && Prev->isOneOf(tok::amp, tok::star))
-          Prev = Prev->Previous;
-
-        if (Prev && Tok.Next && Tok.Next->Next) {
-          bool NextIsUnary = Tok.Next->isUnaryOperator() ||
-                             Tok.Next->isOneOf(tok::amp, tok::star);
-          IsCast =
-              NextIsUnary && !Tok.Next->is(tok::plus) &&
-              Tok.Next->Next->isOneOf(tok::identifier, tok::numeric_constant);
-        }
-
-        for (; Prev != Tok.MatchingParen; Prev = Prev->Previous) {
-          if (!Prev ||
-              !Prev->isOneOf(tok::kw_const, tok::identifier, tok::coloncolon)) {
-            IsCast = false;
-            break;
-          }
-        }
-      }
+      return true;
+
+    // At this point, we heuristically assume that there are no casts at the
+    // start of the line. We assume that we have found most cases where there
+    // are by the logic above, e.g. "(void)x;".
+    if (!LeftOfParens)
+      return false;
+
+    // If the following token is an identifier, this is a cast. All cases where
+    // this can be something else are handled above.
+    if (Tok.Next->is(tok::identifier))
+      return true;
+
+    if (!Tok.Next->Next)
+      return false;
+
+    // If the next token after the parenthesis is a unary operator, assume
+    // that this is cast, unless there are unexpected tokens inside the
+    // parenthesis.
+    bool NextIsUnary =
+        Tok.Next->isUnaryOperator() || Tok.Next->isOneOf(tok::amp, tok::star);
+    if (!NextIsUnary || Tok.Next->is(tok::plus) ||
+        !Tok.Next->Next->isOneOf(tok::identifier, tok::numeric_constant))
+      return false;
+    // Search for unexpected tokens.
+    for (FormatToken *Prev = Tok.Previous; Prev != Tok.MatchingParen;
+         Prev = Prev->Previous) {
+      if (!Prev->isOneOf(tok::kw_const, tok::identifier, tok::coloncolon))
+        return false;
     }
-    return IsCast && !ParensAreEmpty;
+    return true;
   }
 
   /// \brief Return the type of the given token assuming it is * or &.




More information about the cfe-commits mailing list