benhamilton updated this revision to Diff 137089.
benhamilton marked 5 inline comments as done.
benhamilton added a comment.
- Fix comments from @krasimir and @djasper.
Repository:
rC Clang
https://reviews.llvm.org/D43902
Files:
lib/Format/ContinuationIndenter.cpp
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
@@ -6059,6 +6059,16 @@
AfterType);
}
+TEST_F(FormatTest, UnderstandsSquareAttributes) {
+ verifyFormat("SomeType s [[unused]] (InitValue);");
+ verifyFormat("SomeType s [[gnu::unused]] (InitValue);");
+ verifyFormat("SomeType s [[using gnu: unused]] (InitValue);");
+ verifyFormat("[[gsl::suppress(\"clang-tidy-check-name\")]] void f() {}");
+ verifyFormat("void f() [[deprecated(\"so sorry\")]];");
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " [[unused]] aaaaaaaaaaaaaaaaaaaaaaa(int i);");
+}
+
TEST_F(FormatTest, UnderstandsEllipsis) {
verifyFormat("int printf(const char *fmt, ...);");
verifyFormat("template <class... Ts> void Foo(Ts... ts) { Foo(ts...); }");
@@ -12080,6 +12090,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,62 @@
return false;
}
+ const FormatToken *parseCpp11AttributeSpecifier(const FormatToken &Tok) {
+ if (!Style.isCpp() || !Tok.startsSequence(tok::l_square, tok::l_square))
+ return nullptr;
+ const FormatToken *AttrTok = Tok.Next->Next;
+ if (!AttrTok)
+ return nullptr;
+ // C++17 '[[using namespace: foo, bar(baz, blech)]]'
+ bool IsUsingNamespace =
+ AttrTok->startsSequence(tok::kw_using, tok::identifier, tok::colon);
+ if (IsUsingNamespace) {
+ AttrTok = AttrTok->Next->Next->Next;
+ }
+ auto parseCpp11Attribute = [](const FormatToken &Tok,
+ bool AllowNamespace) -> const FormatToken * {
+ if (!Tok.isOneOf(tok::identifier, tok::ellipsis))
+ return nullptr;
+ const FormatToken *AttrTok = Tok.Next;
+ if (!AttrTok)
+ return nullptr;
+ if (AllowNamespace &&
+ 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;
+ };
+ while (AttrTok) {
+ AttrTok = parseCpp11Attribute(*AttrTok, !IsUsingNamespace);
+ if (!AttrTok || AttrTok->isNot(tok::comma))
+ break;
+ AttrTok = AttrTok->Next;
+ }
+ if (AttrTok && AttrTok->startsSequence(tok::r_square, tok::r_square)) {
+ return AttrTok->Next;
+ } else {
+ return nullptr;
+ }
+ }
+
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 +388,23 @@
(Contexts.back().CanBeExpression || Contexts.back().IsExpression ||
Contexts.back().InTemplateArgument);
+ const FormatToken *Cpp11AttributeSpecifierClosingRSquare =
+ parseCpp11AttributeSpecifier(*Left);
+ if (Cpp11AttributeSpecifierClosingRSquare) {
+ Left->Type = TT_AttributeSquare;
+ while (CurrentToken != Cpp11AttributeSpecifierClosingRSquare) {
+ if (CurrentToken->is(tok::colon)) {
+ CurrentToken->Type = TT_AttributeColon;
+ }
+ next();
+ }
+ CurrentToken->Type = TT_AttributeSquare;
+ CurrentToken->MatchingParen = Left;
+ Left->MatchingParen = CurrentToken;
+ next();
+ return true;
+ }
+
bool StartsObjCMethodExpr =
!CppArrayTemplates && Style.isCpp() &&
Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) &&
@@ -2118,7 +2184,7 @@
return 35;
if (!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare,
TT_ArrayInitializerLSquare,
- TT_DesignatedInitializerLSquare))
+ TT_DesignatedInitializerLSquare, TT_AttributeSquare))
return 500;
}
@@ -2369,11 +2435,12 @@
Style)) ||
(Style.SpacesInSquareBrackets &&
Right.MatchingParen->isOneOf(TT_ArraySubscriptLSquare,
- TT_StructuredBindingLSquare)));
+ TT_StructuredBindingLSquare)) ||
+ Right.MatchingParen->is(TT_AttributeParen));
if (Right.is(tok::l_square) &&
!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare,
TT_DesignatedInitializerLSquare,
- TT_StructuredBindingLSquare) &&
+ TT_StructuredBindingLSquare, TT_AttributeSquare) &&
!Left.isOneOf(tok::numeric_constant, TT_DictLiteral))
return false;
if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
@@ -2385,7 +2452,8 @@
if (Left.is(TT_BlockComment))
return !Left.TokenText.endswith("=*/");
if (Right.is(tok::l_paren)) {
- if (Left.is(tok::r_paren) && Left.is(TT_AttributeParen))
+ if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) ||
+ (Left.is(tok::r_square) && Left.is(TT_AttributeSquare)))
return true;
return Line.Type == LT_ObjCDecl || Left.is(tok::semi) ||
(Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
@@ -2596,6 +2664,8 @@
return false;
if (Right.is(TT_DictLiteral))
return Style.SpacesInContainerLiterals;
+ if (Right.is(TT_AttributeColon))
+ return false;
return true;
}
if (Left.is(TT_UnaryOperator))
@@ -2956,7 +3026,8 @@
return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal, tok::l_paren,
tok::less, tok::coloncolon);
- if (Right.is(tok::kw___attribute))
+ if (Right.is(tok::kw___attribute) ||
+ (Right.is(tok::l_square) && Right.is(TT_AttributeSquare)))
return true;
if (Left.is(tok::identifier) && Right.is(tok::string_literal))
@@ -2997,6 +3068,9 @@
(Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None ||
Left.getPrecedence() == prec::Assignment))
return true;
+ if ((Left.is(TT_AttributeSquare) && Right.is(tok::l_square)) ||
+ (Left.is(tok::r_square) && Right.is(TT_AttributeSquare)))
+ return false;
return Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace,
tok::kw_class, tok::kw_struct, tok::comment) ||
Right.isMemberAccess() ||
Index: lib/Format/FormatToken.h
===================================================================
--- lib/Format/FormatToken.h
+++ lib/Format/FormatToken.h
@@ -29,7 +29,9 @@
#define LIST_TOKEN_TYPES \
TYPE(ArrayInitializerLSquare) \
TYPE(ArraySubscriptLSquare) \
+ TYPE(AttributeColon) \
TYPE(AttributeParen) \
+ TYPE(AttributeSquare) \
TYPE(BinaryOperator) \
TYPE(BitFieldColon) \
TYPE(BlockComment) \
Index: lib/Format/ContinuationIndenter.cpp
===================================================================
--- lib/Format/ContinuationIndenter.cpp
+++ lib/Format/ContinuationIndenter.cpp
@@ -889,8 +889,8 @@
if ((PreviousNonComment &&
(PreviousNonComment->ClosesTemplateDeclaration ||
PreviousNonComment->isOneOf(
- TT_AttributeParen, TT_FunctionAnnotationRParen, TT_JavaAnnotation,
- TT_LeadingJavaAnnotation))) ||
+ TT_AttributeParen, TT_AttributeSquare, TT_FunctionAnnotationRParen,
+ TT_JavaAnnotation, TT_LeadingJavaAnnotation))) ||
(!Style.IndentWrappedFunctionNames &&
NextNonComment->isOneOf(tok::kw_operator, TT_FunctionDeclarationName)))
return std::max(State.Stack.back().LastSpace, State.Stack.back().Indent);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits