benhamilton updated this revision to Diff 137015.
benhamilton marked 7 inline comments as done.
benhamilton added a comment.

Fixes from @jolesiak


Repository:
  rC Clang

https://reviews.llvm.org/D43902

Files:
  lib/Format/FormatToken.h
  lib/Format/TokenAnnotator.cpp
  unittests/Format/FormatTest.cpp

Index: unittests/Format/FormatTest.cpp
===================================================================
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -12080,6 +12080,36 @@
   EXPECT_EQ(FormatStyle::LK_ObjC, guessLanguage("foo", "@interface Foo\n@end\n"));
 }
 
+TEST_F(FormatTest, GuessLanguageWithCpp11AttributeSpecifiers) {
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[noreturn]];"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+            guessLanguage("foo.h", "array[[calculator getIndex]];"));
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+            guessLanguage("foo.h", "[[noreturn, deprecated(\"so sorry\")]];"));
+  EXPECT_EQ(
+      FormatStyle::LK_Cpp,
+      guessLanguage("foo.h", "[[noreturn, deprecated(\"gone, sorry\")]];"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+            guessLanguage("foo.h", "[[noreturn foo] bar];"));
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+            guessLanguage("foo.h", "[[clang::fallthrough]];"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+            guessLanguage("foo.h", "[[clang:fallthrough] foo];"));
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+            guessLanguage("foo.h", "[[gsl::suppress(\"type\")]];"));
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+            guessLanguage("foo.h", "[[using clang: fallthrough]];"));
+  EXPECT_EQ(FormatStyle::LK_ObjC,
+            guessLanguage("foo.h", "[[abusing clang:fallthrough] bar];"));
+  EXPECT_EQ(FormatStyle::LK_Cpp,
+            guessLanguage("foo.h", "[[using gsl: suppress(\"type\")]];"));
+  EXPECT_EQ(
+      FormatStyle::LK_Cpp,
+      guessLanguage("foo.h",
+                    "[[clang::callable_when(\"unconsumed\", \"unknown\")]]"));
+  EXPECT_EQ(FormatStyle::LK_Cpp, guessLanguage("foo.h", "[[foo::bar, ...]]"));
+}
+
 } // end namespace
 } // end namespace format
 } // end namespace clang
Index: lib/Format/TokenAnnotator.cpp
===================================================================
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -320,13 +320,68 @@
     return false;
   }
 
+  const FormatToken *parseCpp11Attribute(const FormatToken &Tok,
+                                         bool NamespaceAllowed) {
+    if (!Tok.isOneOf(tok::identifier, tok::ellipsis))
+      return nullptr;
+    const FormatToken *AttrTok = Tok.Next;
+    if (!AttrTok)
+      return nullptr;
+    if (NamespaceAllowed &&
+        AttrTok->startsSequence(tok::coloncolon, tok::identifier)) {
+      AttrTok = AttrTok->Next->Next;
+    }
+    if (!AttrTok)
+      return nullptr;
+    if (AttrTok->is(tok::l_paren)) {
+      const FormatToken *ParamToken = AttrTok->Next;
+      while (ParamToken && ParamToken->isNot(tok::r_paren))
+        ParamToken = ParamToken->Next;
+      if (!ParamToken)
+        return nullptr;
+      AttrTok = ParamToken->Next;
+    }
+    return AttrTok;
+  }
+
+  // Look for [[ ... ]] which is a valid C++11 attribute specifier but
+  // never a valid Objective-C or Objective-C++ method invocation.
+  bool parseCpp11AttributeSpecifier(const FormatToken &Tok) {
+    if (!Style.isCpp())
+      return false;
+    if (!Tok.startsSequence(tok::l_square, tok::l_square))
+      return false;
+    const FormatToken *AttrTok = Tok.Next->Next;
+    if (!AttrTok)
+      return false;
+    bool NamespaceAllowed;
+    // C++17 '[[using namespace: foo, bar(baz, blech)]]'
+    if (AttrTok->startsSequence(tok::kw_using, tok::identifier, tok::colon)) {
+      AttrTok = AttrTok->Next->Next->Next;
+      NamespaceAllowed = false;
+    } else {
+      // C++11 '[[namespace::foo, namespace::bar(baz, blech)]]'
+      NamespaceAllowed = true;
+    }
+    while (AttrTok) {
+      AttrTok = parseCpp11Attribute(*AttrTok, NamespaceAllowed);
+      if (!AttrTok || AttrTok->isNot(tok::comma))
+        break;
+      AttrTok = AttrTok->Next;
+    }
+    if (!AttrTok)
+      return false;
+    return AttrTok->startsSequence(tok::r_square, tok::r_square);
+  }
+
   bool parseSquare() {
     if (!CurrentToken)
       return false;
 
     // A '[' could be an index subscript (after an identifier or after
     // ')' or ']'), it could be the start of an Objective-C method
-    // expression, or it could the start of an Objective-C array literal.
+    // expression, it could the start of an Objective-C array literal,
+    // or it could be a C++ attribute specifier [[foo::bar]].
     FormatToken *Left = CurrentToken->Previous;
     Left->ParentBracket = Contexts.back().ContextKind;
     FormatToken *Parent = Left->getPreviousNonComment();
@@ -339,6 +394,12 @@
         (Contexts.back().CanBeExpression || Contexts.back().IsExpression ||
          Contexts.back().InTemplateArgument);
 
+    if (parseCpp11AttributeSpecifier(*Left)) {
+      CurrentToken->Type = TT_AttributeSpecifier;
+      next();
+      return true;
+    }
+
     bool StartsObjCMethodExpr =
         !CppArrayTemplates && Style.isCpp() &&
         Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
Index: lib/Format/FormatToken.h
===================================================================
--- lib/Format/FormatToken.h
+++ lib/Format/FormatToken.h
@@ -30,6 +30,7 @@
   TYPE(ArrayInitializerLSquare)                                                \
   TYPE(ArraySubscriptLSquare)                                                  \
   TYPE(AttributeParen)                                                         \
+  TYPE(AttributeSpecifier)                                                     \
   TYPE(BinaryOperator)                                                         \
   TYPE(BitFieldColon)                                                          \
   TYPE(BlockComment)                                                           \
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to