diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -43,6 +43,7 @@ TYPE(ConflictAlternative) \ TYPE(ConflictEnd) \ TYPE(ConflictStart) \ + TYPE(CppCastLParen) \ TYPE(CtorInitializerColon) \ TYPE(CtorInitializerComma) \ TYPE(DesignatedInitializerLSquare) \ diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -358,7 +358,8 @@ if (CurrentToken->Previous->is(TT_BinaryOperator)) Contexts.back().IsExpression = true; if (CurrentToken->is(tok::r_paren)) { - if (MightBeFunctionType && ProbablyFunctionType && CurrentToken->Next && + if (Left->isNot(TT_CppCastLParen) && MightBeFunctionType && + ProbablyFunctionType && CurrentToken->Next && (CurrentToken->Next->is(tok::l_paren) || (CurrentToken->Next->is(tok::l_square) && Line.MustBeDeclaration))) Left->setType(Left->Next->is(tok::caret) ? TT_ObjCBlockLParen @@ -1733,6 +1734,9 @@ Current.Tok.setKind(tok::unknown); else Current.setType(TT_LineComment); + } else if (Current.is(tok::l_paren)) { + if (lParenStartsCppCast(Current)) + Current.setType(TT_CppCastLParen); } else if (Current.is(tok::r_paren)) { if (rParenEndsCast(Current)) Current.setType(TT_CastRParen); @@ -1880,6 +1884,25 @@ return Style.isJavaScript() && PreviousNotConst->is(tok::kw_const); } + /// Determine whether '(' is starting a C++ cast. + bool lParenStartsCppCast(const FormatToken &Tok) { + // C-style casts are only used in C++. + if (!Style.isCpp()) + return false; + + FormatToken *LeftOfParens = Tok.getPreviousNonComment(); + if (LeftOfParens && LeftOfParens->is(TT_TemplateCloser) && + LeftOfParens->MatchingParen) { + auto *Prev = LeftOfParens->MatchingParen->getPreviousNonComment(); + if (Prev && Prev->isOneOf(tok::kw_const_cast, tok::kw_dynamic_cast, + tok::kw_reinterpret_cast, tok::kw_static_cast)) + // FIXME: Maybe we should handle identifiers ending with "_cast", + // e.g. any_cast? + return true; + } + return false; + } + /// Determine whether ')' is ending a cast. bool rParenEndsCast(const FormatToken &Tok) { // C-style casts are only used in C++, C# and Java. diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -10565,6 +10565,19 @@ TEST_F(FormatTest, FormatsCasts) { verifyFormat("Type *A = static_cast(P);"); + verifyFormat("static_cast(P);"); + verifyFormat("static_cast(Fun)(Args);"); + verifyFormat("static_cast(*Fun)(Args);"); + verifyFormat("if (static_cast(A) + B >= 0)\n ;"); + // Check that static_cast<...>(...) does not require the next token to be on + // the same line. + verifyFormat("some_loooong_output << something_something__ << " + "static_cast(R)\n" + " << something;"); + verifyFormat("a = static_cast(*Fun)(Args);"); + verifyFormat("const_cast(*Fun)(Args);"); + verifyFormat("dynamic_cast(*Fun)(Args);"); + verifyFormat("reinterpret_cast(*Fun)(Args);"); verifyFormat("Type *A = (Type *)P;"); verifyFormat("Type *A = (vector)P;"); verifyFormat("int a = (int)(2.0f);");