diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -745,9 +745,8 @@ } State.Column += Spaces; - if (Current.isNot(tok::comment) && Previous.is(tok::l_paren) && - Previous.Previous && - (Previous.Previous->is(tok::kw_for) || Previous.Previous->isIf())) { + if (Current.isNot(tok::comment) && + Previous.isConditionLParen(/*IncludeSpecial=*/true)) { // Treat the condition inside an if as if it was a second function // parameter, i.e. let nested calls have a continuation indent. CurrentState.LastSpace = State.Column; 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 @@ -39,7 +39,8 @@ TYPE(CastRParen) \ TYPE(ClassLBrace) \ TYPE(CompoundRequirementLBrace) \ - TYPE(ConditionalExpr) \ + TYPE(ConditionLParen) /* the condition in an if statement */ \ + TYPE(ConditionalExpr) /* ternary ?: expression */ \ TYPE(ConflictAlternative) \ TYPE(ConflictEnd) \ TYPE(ConflictStart) \ @@ -515,9 +516,21 @@ } template bool isNot(T Kind) const { return !is(Kind); } - bool isIf(bool AllowConstexprMacro = true) const { - return is(tok::kw_if) || endsSequence(tok::kw_constexpr, tok::kw_if) || - (endsSequence(tok::identifier, tok::kw_if) && AllowConstexprMacro); + /// Returns \c true if the token is the open parenthesis of a + /// statement's condition like if or while. + bool isConditionLParen(bool IncludeSpecial) const { + if (!is(tok::l_paren)) + return false; + if (is(TT_ConditionLParen)) + return true; + const FormatToken *Prev = getPreviousNonComment(); + // `for` and `catch` special handling. Inside the parentheses is not + // an expression. + return Prev && + ((IncludeSpecial && Prev->isOneOf(TT_ForEachMacro, TT_ObjCForIn, + tok::kw_for, tok::kw_catch)) || + Prev->isOneOf(tok::kw_if, tok::kw_while, tok::kw_switch, + tok::kw_case, tok::kw_constexpr)); } bool closesScopeAfterBlock() const { 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 @@ -63,13 +63,6 @@ Left->Previous->MatchingParen->is(TT_LambdaLSquare); } -/// Returns \c true if the token is followed by a boolean condition, \c false -/// otherwise. -static bool isKeywordWithCondition(const FormatToken &Tok) { - return Tok.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch, - tok::kw_constexpr, tok::kw_catch); -} - /// A parser that gathers additional information about tokens. /// /// The \c TokenAnnotator tries to match parenthesis and square brakets and @@ -130,10 +123,9 @@ // parameter cases, but should not alter program semantics. if (CurrentToken->Next && CurrentToken->Next->is(tok::greater) && Left->ParentBracket != tok::less && - (isKeywordWithCondition(*Line.First) || - CurrentToken->getStartOfNonWhitespace() == - CurrentToken->Next->getStartOfNonWhitespace().getLocWithOffset( - -1))) + CurrentToken->getStartOfNonWhitespace() == + CurrentToken->Next->getStartOfNonWhitespace().getLocWithOffset( + -1)) return false; Left->MatchingParen = CurrentToken; CurrentToken->MatchingParen = Left; @@ -257,12 +249,11 @@ // type X = (...); // export type X = (...); Contexts.back().IsExpression = false; - } else if (OpeningParen.Previous && - (OpeningParen.Previous->isOneOf(tok::kw_static_assert, - tok::kw_while, tok::l_paren, - tok::comma) || - OpeningParen.Previous->isIf() || - OpeningParen.Previous->is(TT_BinaryOperator))) { + } else if (OpeningParen.isConditionLParen(/*IncludeSpecial=*/false) || + (OpeningParen.Previous && + OpeningParen.Previous->isOneOf(TT_BinaryOperator, tok::l_paren, + tok::comma, + tok::kw_static_assert))) { // static_assert, if and while usually contain expressions. Contexts.back().IsExpression = true; } else if (Style.isJavaScript() && OpeningParen.Previous && @@ -1437,17 +1428,18 @@ // recovered from an error (e.g. failure to find the matching >). if (!CurrentToken->isTypeFinalized() && !CurrentToken->isOneOf( - TT_LambdaLSquare, TT_LambdaLBrace, TT_AttributeMacro, TT_IfMacro, - TT_ForEachMacro, TT_TypenameMacro, TT_FunctionLBrace, - TT_ImplicitStringLiteral, TT_InlineASMBrace, TT_FatArrow, - TT_LambdaArrow, TT_NamespaceMacro, TT_OverloadedOperator, - TT_RegexLiteral, TT_TemplateString, TT_ObjCStringLiteral, - TT_UntouchableMacroFunc, TT_StatementAttributeLikeMacro, - TT_FunctionLikeOrFreestandingMacro, TT_ClassLBrace, TT_EnumLBrace, - TT_RecordLBrace, TT_StructLBrace, TT_UnionLBrace, TT_RequiresClause, + TT_AttributeMacro, TT_BracedListLBrace, TT_ClassLBrace, + TT_CompoundRequirementLBrace, TT_ConditionLParen, TT_EnumLBrace, + TT_FatArrow, TT_ForEachMacro, TT_FunctionLBrace, + TT_FunctionLikeOrFreestandingMacro, TT_IfMacro, + TT_ImplicitStringLiteral, TT_InlineASMBrace, TT_LambdaArrow, + TT_LambdaLBrace, TT_LambdaLSquare, TT_NamespaceMacro, + TT_ObjCStringLiteral, TT_OverloadedOperator, TT_RecordLBrace, + TT_RegexLiteral, TT_RequiresClause, TT_RequiresClauseInARequiresExpression, TT_RequiresExpression, - TT_RequiresExpressionLParen, TT_RequiresExpressionLBrace, - TT_CompoundRequirementLBrace, TT_BracedListLBrace)) + TT_RequiresExpressionLBrace, TT_RequiresExpressionLParen, + TT_StatementAttributeLikeMacro, TT_StructLBrace, TT_TemplateString, + TT_TypenameMacro, TT_UnionLBrace, TT_UntouchableMacroFunc)) CurrentToken->setType(TT_Unknown); CurrentToken->Role.reset(); CurrentToken->MatchingParen = nullptr; @@ -2992,8 +2984,7 @@ if (Left.is(tok::l_paren) && InFunctionDecl && Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign) return 100; - if (Left.is(tok::l_paren) && Left.Previous && - (Left.Previous->is(tok::kw_for) || Left.Previous->isIf())) + if (Left.isConditionLParen(/*IncludeSpecial=*/true)) return 1000; if (Left.is(tok::equal) && InFunctionDecl) return 110; @@ -3489,15 +3480,11 @@ (Left.is(tok::l_brace) && Left.isNot(BK_Block) && Right.is(tok::r_brace) && Right.isNot(BK_Block))) return Style.SpaceInEmptyParentheses; - if (Style.SpacesInConditionalStatement) { - if (Left.is(tok::l_paren) && Left.Previous && - isKeywordWithCondition(*Left.Previous)) - return true; - if (Right.is(tok::r_paren) && Right.MatchingParen && - Right.MatchingParen->Previous && - isKeywordWithCondition(*Right.MatchingParen->Previous)) - return true; - } + if (Style.SpacesInConditionalStatement && + (Left.isConditionLParen(/*IncludeSpecial=*/true) || + (Right.is(tok::r_paren) && Right.MatchingParen && + Right.MatchingParen->isConditionLParen(/*IncludeSpecial=*/true)))) + return true; // auto{x} auto(x) if (Left.is(tok::kw_auto) && Right.isOneOf(tok::l_paren, tok::l_brace)) @@ -3751,11 +3738,8 @@ return true; if (Left.is(tok::semi)) return true; - if (Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while, tok::kw_switch, - tok::kw_case, TT_ForEachMacro, TT_ObjCForIn)) - return Style.SpaceBeforeParensOptions.AfterControlStatements || - spaceRequiredBeforeParens(Right); - if (Left.isIf(Line.Type != LT_PreprocessorDirective)) + if (Right.isConditionLParen(/*IncludeSpecial=*/true) || + Left.is(tok::pp_elif)) return Style.SpaceBeforeParensOptions.AfterControlStatements || spaceRequiredBeforeParens(Right); @@ -4502,13 +4486,9 @@ // We only break before r_paren if we're in a block indented context. if (Right.is(tok::r_paren)) { - if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) { + if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) return Right.MatchingParen && - !(Right.MatchingParen->Previous && - (Right.MatchingParen->Previous->is(tok::kw_for) || - Right.MatchingParen->Previous->isIf())); - } - + !Right.MatchingParen->isConditionLParen(/*IncludeSpecial=*/true); return false; } diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -2422,8 +2422,10 @@ } else { if (FormatTok->isOneOf(tok::kw_constexpr, tok::identifier)) nextToken(); - if (FormatTok->is(tok::l_paren)) + if (FormatTok->Tok.is(tok::l_paren)) { + FormatTok->setType(TT_ConditionLParen); parseParens(); + } } handleAttributes(); @@ -2714,14 +2716,20 @@ void UnwrappedLineParser::parseForOrWhileLoop() { assert(FormatTok->isOneOf(tok::kw_for, tok::kw_while, TT_ForEachMacro) && "'for', 'while' or foreach macro expected"); + // Those that begin with a for require special treatment because inside the + // parentheses is not an expression. + bool IsFor = FormatTok->is(tok::kw_for) || FormatTok->is(TT_ForEachMacro); nextToken(); // JS' for await ( ... if (Style.isJavaScript() && FormatTok->is(Keywords.kw_await)) nextToken(); if (Style.isCpp() && FormatTok->is(tok::kw_co_await)) nextToken(); - if (FormatTok->is(tok::l_paren)) + if (FormatTok->is(tok::l_paren)) { + if (!IsFor) + FormatTok->setType(TT_ConditionLParen); parseParens(); + } keepAncestorBraces(); @@ -2827,8 +2835,10 @@ void UnwrappedLineParser::parseSwitch() { assert(FormatTok->is(tok::kw_switch) && "'switch' expected"); nextToken(); - if (FormatTok->is(tok::l_paren)) + if (FormatTok->is(tok::l_paren)) { + FormatTok->setType(TT_ConditionLParen); parseParens(); + } keepAncestorBraces();