Index: clang/include/clang/Format/Format.h =================================================================== --- clang/include/clang/Format/Format.h +++ clang/include/clang/Format/Format.h @@ -1628,8 +1628,15 @@ /// (https://developers.google.com/protocol-buffers/). LK_TextProto }; - bool isCpp() const { return Language == LK_Cpp || Language == LK_ObjC; } + bool isCppOnly() const { return Language == LK_Cpp; } + bool isObjectiveC() const { return Language == LK_ObjC; } + bool isCpp() const { return isCppOnly() || isObjectiveC(); } bool isCSharp() const { return Language == LK_CSharp; } + bool isProtoBuf() const { return Language == LK_Proto; } + bool isTableGen() const { return Language == LK_TableGen; } + bool isTextProtoBuf() const { return Language == LK_TextProto; } + bool isJava() const { return Language == LK_Java; } + bool isJavaScript() const { return Language == LK_JavaScript; } /// Language, this format style is targeted at. LanguageKind Language; @@ -2011,8 +2018,8 @@ /// \endcode SBPO_ControlStatements, /// Same as ``SBPO_ControlStatements`` except this option doesn't apply to - /// ForEach macros. This is useful in projects where ForEach macros are - /// treated as function calls instead of control statements. + /// ForEach macros. This is useful in projects where ForEach macros are + /// treated as function calls instead of control statements. /// \code /// void f() { /// Q_FOREACH(...) { Index: clang/lib/Format/ContinuationIndenter.cpp =================================================================== --- clang/lib/Format/ContinuationIndenter.cpp +++ clang/lib/Format/ContinuationIndenter.cpp @@ -418,8 +418,7 @@ // ... // }.bind(...)); // FIXME: We should find a more generic solution to this problem. - !(State.Column <= NewLineColumn && - Style.Language == FormatStyle::LK_JavaScript) && + !(State.Column <= NewLineColumn && Style.isJavaScript()) && !(Previous.closesScopeAfterBlock() && State.Column <= NewLineColumn)) return true; @@ -658,7 +657,7 @@ State.Column > getNewLineColumn(State)) State.Stack.back().ContainsUnwrappedBuilder = true; - if (Current.is(TT_LambdaArrow) && Style.Language == FormatStyle::LK_Java) + if (Current.is(TT_LambdaArrow) && Style.isJava()) State.Stack.back().NoLineBreak = true; if (Current.isMemberAccess() && Previous.is(tok::r_paren) && (Previous.MatchingParen && @@ -794,9 +793,8 @@ // is common and should be formatted like a free-standing function. The same // goes for wrapping before the lambda return type arrow. if (!Current.is(TT_LambdaArrow) && - (Style.Language != FormatStyle::LK_JavaScript || - Current.NestingLevel != 0 || !PreviousNonComment || - !PreviousNonComment->is(tok::equal) || + (!Style.isJavaScript() || Current.NestingLevel != 0 || + !PreviousNonComment || !PreviousNonComment->is(tok::equal) || !Current.isOneOf(Keywords.kw_async, Keywords.kw_function))) State.Stack.back().NestedBlockIndent = State.Column; @@ -962,7 +960,7 @@ NextNonComment = &Current; // Java specific bits. - if (Style.Language == FormatStyle::LK_Java && + if (Style.isJava() && Current.isOneOf(Keywords.kw_implements, Keywords.kw_extends)) return std::max(State.Stack.back().LastSpace, State.Stack.back().Indent + Style.ContinuationIndentWidth); @@ -1339,7 +1337,7 @@ (Style.AlignOperands != FormatStyle::OAS_DontAlign || *I < prec::Assignment) && (!Previous || Previous->isNot(tok::kw_return) || - (Style.Language != FormatStyle::LK_Java && *I > 0)) && + (!Style.isJava() && *I > 0)) && (Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign || *I != prec::Comma || Current.NestingLevel == 0)) { NewParenState.Indent = @@ -1887,9 +1885,8 @@ // FIXME: String literal breaking is currently disabled for C#, Java and // JavaScript, as it requires strings to be merged using "+" which we // don't support. - if (Style.Language == FormatStyle::LK_Java || - Style.Language == FormatStyle::LK_JavaScript || Style.isCSharp() || - !Style.BreakStringLiterals || !AllowBreak) + if (Style.isJava() || Style.Language == FormatStyle::LK_JavaScript || + Style.isCSharp() || !Style.BreakStringLiterals || !AllowBreak) return nullptr; // Don't break string literals inside preprocessor directives (except for Index: clang/lib/Format/Format.cpp =================================================================== --- clang/lib/Format/Format.cpp +++ clang/lib/Format/Format.cpp @@ -2351,12 +2351,11 @@ return Replaces; if (isLikelyXml(Code)) return Replaces; - if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript && - isMpegTS(Code)) + if (Style.isJavaScript() && isMpegTS(Code)) return Replaces; - if (Style.Language == FormatStyle::LanguageKind::LK_JavaScript) + if (Style.isJavaScript()) return sortJavaScriptImports(Style, Code, Ranges, FileName); - if (Style.Language == FormatStyle::LanguageKind::LK_Java) + if (Style.isJava()) return sortJavaImports(Style, Code, Ranges, FileName, Replaces); sortCppIncludes(Style, Code, Ranges, FileName, Replaces, Cursor); return Replaces; @@ -2519,7 +2518,7 @@ return {tooling::Replacements(), 0}; if (isLikelyXml(Code)) return {tooling::Replacements(), 0}; - if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code)) + if (Expanded.isJavaScript() && isMpegTS(Code)) return {tooling::Replacements(), 0}; typedef std::function( @@ -2539,8 +2538,7 @@ }); } - if (Style.Language == FormatStyle::LK_JavaScript && - Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) + if (Style.isJavaScript() && Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) Passes.emplace_back([&](const Environment &Env) { return JavaScriptRequoter(Env, Expanded).process(); }); @@ -2549,7 +2547,7 @@ return Formatter(Env, Expanded, Status).process(); }); - if (Style.Language == FormatStyle::LK_JavaScript && + if (Style.isJavaScript() && Style.InsertTrailingCommas == FormatStyle::TCS_Wrapped) Passes.emplace_back([&](const Environment &Env) { return TrailingCommaInserter(Env, Expanded).process(); Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -102,8 +102,7 @@ Contexts.back().InTemplateArgument = Left->Previous && Left->Previous->Tok.isNot(tok::kw_template); - if (Style.Language == FormatStyle::LK_Java && - CurrentToken->is(tok::question)) + if (Style.isJava() && CurrentToken->is(tok::question)) next(); while (CurrentToken) { @@ -115,8 +114,8 @@ // msg < item: data > // msg: < item: data > // In TT_TextProto, map does not occur. - if (Style.Language == FormatStyle::LK_TextProto || - (Style.Language == FormatStyle::LK_Proto && Left->Previous && + if (Style.isTextProtoBuf() || + (Style.isProtoBuf() && Left->Previous && Left->Previous->isOneOf(TT_SelectorName, TT_DictLiteral))) CurrentToken->setType(TT_DictLiteral); else @@ -124,15 +123,13 @@ next(); return true; } - if (CurrentToken->is(tok::question) && - Style.Language == FormatStyle::LK_Java) { + if (CurrentToken->is(tok::question) && Style.isJava()) { next(); continue; } if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) || (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext && - !Style.isCSharp() && Style.Language != FormatStyle::LK_Proto && - Style.Language != FormatStyle::LK_TextProto)) + !Style.isCSharp() && !Style.isProtoBuf() && !Style.isTextProtoBuf())) return false; // If a && or || is found and interpreted as a binary operator, this set // of angles is likely part of something like "a < b && c > d". If the @@ -146,7 +143,7 @@ !Line.startsWith(tok::kw_template)) return false; updateParameterCount(Left, CurrentToken); - if (Style.Language == FormatStyle::LK_Proto) { + if (Style.isProtoBuf()) { if (FormatToken *Previous = CurrentToken->getPreviousNonComment()) { if (CurrentToken->is(tok::colon) || (CurrentToken->isOneOf(tok::l_brace, tok::less) && @@ -182,7 +179,7 @@ if (Left->is(TT_OverloadedOperatorLParen)) { Contexts.back().IsExpression = false; - } else if (Style.Language == FormatStyle::LK_JavaScript && + } else if (Style.isJavaScript() && (Line.startsWith(Keywords.kw_type, tok::identifier) || Line.startsWith(tok::kw_export, Keywords.kw_type, tok::identifier))) { @@ -197,13 +194,13 @@ Left->Previous->is(TT_BinaryOperator))) { // static_assert, if and while usually contain expressions. Contexts.back().IsExpression = true; - } else if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous && + } else if (Style.isJavaScript() && Left->Previous && (Left->Previous->is(Keywords.kw_function) || (Left->Previous->endsSequence(tok::identifier, Keywords.kw_function)))) { // function(...) or function f(...) Contexts.back().IsExpression = false; - } else if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous && + } else if (Style.isJavaScript() && Left->Previous && Left->Previous->is(TT_JsTypeColon)) { // let x: (SomeType); Contexts.back().IsExpression = false; @@ -503,7 +500,7 @@ Left->setType(TT_InlineASMSymbolicNameLSquare); } else if (IsCpp11AttributeSpecifier) { Left->setType(TT_AttributeSquare); - } else if (Style.Language == FormatStyle::LK_JavaScript && Parent && + } else if (Style.isJavaScript() && Parent && Contexts.back().ContextKind == tok::l_brace && Parent->isOneOf(tok::l_brace, tok::comma)) { Left->setType(TT_JsComputedPropertyName); @@ -515,8 +512,7 @@ } else if (CurrentToken->is(tok::r_square) && Parent && Parent->is(TT_TemplateCloser)) { Left->setType(TT_ArraySubscriptLSquare); - } else if (Style.Language == FormatStyle::LK_Proto || - Style.Language == FormatStyle::LK_TextProto) { + } else if (Style.isProtoBuf() || Style.isTextProtoBuf()) { // Square braces in LK_Proto can either be message field attributes: // // optional Aaa aaa = 1 [ @@ -567,8 +563,7 @@ ScopedContextCreator ContextCreator(*this, tok::l_square, BindingIncrease); Contexts.back().IsExpression = true; - if (Style.Language == FormatStyle::LK_JavaScript && Parent && - Parent->is(TT_JsTypeColon)) + if (Style.isJavaScript() && Parent && Parent->is(TT_JsTypeColon)) Contexts.back().IsExpression = false; Contexts.back().ColonIsObjCMethodExpr = StartsObjCMethodExpr; @@ -680,7 +675,7 @@ Contexts.back().ColonIsDictLiteral = true; if (Left->BlockKind == BK_BracedInit) Contexts.back().IsExpression = true; - if (Style.Language == FormatStyle::LK_JavaScript && Left->Previous && + if (Style.isJavaScript() && Left->Previous && Left->Previous->is(TT_JsTypeColon)) Contexts.back().IsExpression = false; @@ -700,19 +695,16 @@ Previous = Previous->getPreviousNonComment(); if ((CurrentToken->is(tok::colon) && (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) || - Style.Language == FormatStyle::LK_Proto || - Style.Language == FormatStyle::LK_TextProto) { + Style.isProtoBuf() || Style.isTextProtoBuf()) { Left->setType(TT_DictLiteral); if (Previous->Tok.getIdentifierInfo() || Previous->is(tok::string_literal)) Previous->setType(TT_SelectorName); } - if (CurrentToken->is(tok::colon) || - Style.Language == FormatStyle::LK_JavaScript) + if (CurrentToken->is(tok::colon) || Style.isJavaScript()) Left->setType(TT_DictLiteral); } - if (CurrentToken->is(tok::comma) && - Style.Language == FormatStyle::LK_JavaScript) + if (CurrentToken->is(tok::comma) && Style.isJavaScript()) Left->setType(TT_DictLiteral); if (!consumeToken()) return false; @@ -776,7 +768,7 @@ if (!Tok->Previous) return false; // Colons from ?: are handled in parseConditional(). - if (Style.Language == FormatStyle::LK_JavaScript) { + if (Style.isJavaScript()) { if (Contexts.back().ColonIsForRangeExpr || // colon in for loop (Contexts.size() == 1 && // switch/case labels !Line.First->isOneOf(tok::kw_enum, tok::kw_case)) || @@ -800,11 +792,10 @@ break; } } - if (Contexts.back().ColonIsDictLiteral || - Style.Language == FormatStyle::LK_Proto || - Style.Language == FormatStyle::LK_TextProto) { + if (Contexts.back().ColonIsDictLiteral || Style.isProtoBuf() || + Style.isTextProtoBuf()) { Tok->setType(TT_DictLiteral); - if (Style.Language == FormatStyle::LK_TextProto) { + if (Style.isTextProtoBuf()) { if (FormatToken *Previous = Tok->getPreviousNonComment()) Previous->setType(TT_SelectorName); } @@ -867,8 +858,7 @@ case tok::amp: // | and & in declarations/type expressions represent union and // intersection types, respectively. - if (Style.Language == FormatStyle::LK_JavaScript && - !Contexts.back().IsExpression) + if (Style.isJavaScript() && !Contexts.back().IsExpression) Tok->setType(TT_JsTypeOperator); break; case tok::kw_if: @@ -883,7 +873,7 @@ } break; case tok::kw_for: - if (Style.Language == FormatStyle::LK_JavaScript) { + if (Style.isJavaScript()) { // x.for and {for: ...} if ((Tok->Previous && Tok->Previous->is(tok::period)) || (Tok->Next && Tok->Next->is(tok::colon))) @@ -924,7 +914,7 @@ return false; break; case tok::l_brace: - if (Style.Language == FormatStyle::LK_TextProto) { + if (Style.isTextProtoBuf()) { FormatToken *Previous = Tok->getPreviousNonComment(); if (Previous && Previous->getType() != TT_DictLiteral) Previous->setType(TT_SelectorName); @@ -940,8 +930,8 @@ // msg < item: data > // msg: < item: data > // In TT_TextProto, map does not occur. - if (Style.Language == FormatStyle::LK_TextProto || - (Style.Language == FormatStyle::LK_Proto && Tok->Previous && + if (Style.isTextProtoBuf() || + (Style.isProtoBuf() && Tok->Previous && Tok->Previous->isOneOf(TT_SelectorName, TT_DictLiteral))) { Tok->setType(TT_DictLiteral); FormatToken *Previous = Tok->getPreviousNonComment(); @@ -964,14 +954,13 @@ return false; break; case tok::greater: - if (Style.Language != FormatStyle::LK_TextProto) + if (!Style.isTextProtoBuf()) Tok->setType(TT_BinaryOperator); if (Tok->Previous && Tok->Previous->is(TT_TemplateCloser)) Tok->SpacesRequiredBefore = 1; break; case tok::kw_operator: - if (Style.Language == FormatStyle::LK_TextProto || - Style.Language == FormatStyle::LK_Proto) + if (Style.isTextProtoBuf() || Style.isProtoBuf()) break; while (CurrentToken && !CurrentToken->isOneOf(tok::l_paren, tok::semi, tok::r_paren)) { @@ -997,7 +986,7 @@ } if (Tok->isOneOf(TT_CSharpNullConditional, TT_CSharpNullCoalescing)) break; - if (Style.Language == FormatStyle::LK_JavaScript && Tok->Next && + if (Style.isJavaScript() && Tok->Next && Tok->Next->isOneOf(tok::semi, tok::comma, tok::colon, tok::r_paren, tok::r_brace)) { // Question marks before semicolons, colons, etc. indicate optional @@ -1010,7 +999,7 @@ // Declarations cannot be conditional expressions, this can only be part // of a type declaration. if (Line.MustBeDeclaration && !Contexts.back().IsExpression && - Style.Language == FormatStyle::LK_JavaScript) + Style.isJavaScript()) break; if (Style.isCSharp()) { // `Type?)`, `Type?>`, `Type? name;` and `Type? name =` can only be @@ -1143,7 +1132,7 @@ if (!CurrentToken) return Type; - if (Style.Language == FormatStyle::LK_JavaScript && IsFirstToken) { + if (Style.isJavaScript() && IsFirstToken) { // JavaScript files can contain shebang lines of the form: // #!/usr/bin/env node // Treat these like C++ #include directives. @@ -1211,8 +1200,7 @@ // definitions (github.com/google/protobuf) or missing "#" (either way we // should not break the line). IdentifierInfo *Info = CurrentToken->Tok.getIdentifierInfo(); - if ((Style.Language == FormatStyle::LK_Java && - CurrentToken->is(Keywords.kw_package)) || + if ((Style.isJava() && CurrentToken->is(Keywords.kw_package)) || (Info && Info->getPPKeywordID() == tok::pp_import && CurrentToken->Next && CurrentToken->Next->isOneOf(tok::string_literal, tok::identifier, @@ -1231,7 +1219,7 @@ // In .proto files, top-level options and package statements are very // similar to import statements and should not be line-wrapped. - if (Style.Language == FormatStyle::LK_Proto && Line.Level == 0 && + if (Style.isProtoBuf() && Line.Level == 0 && CurrentToken->isOneOf(Keywords.kw_option, Keywords.kw_package)) { next(); if (CurrentToken && CurrentToken->is(tok::identifier)) { @@ -1245,14 +1233,13 @@ bool ImportStatement = false; // import {...} from '...'; - if (Style.Language == FormatStyle::LK_JavaScript && - CurrentToken->is(Keywords.kw_import)) + if (Style.isJavaScript() && CurrentToken->is(Keywords.kw_import)) ImportStatement = true; while (CurrentToken) { if (CurrentToken->is(tok::kw_virtual)) KeywordVirtualFound = true; - if (Style.Language == FormatStyle::LK_JavaScript) { + if (Style.isJavaScript()) { // export {...} from '...'; // An export followed by "from 'some string';" is a re-export from // another module identified by a URI and is treated as a @@ -1377,7 +1364,7 @@ !Line.First->isOneOf(tok::kw_template, tok::kw_using, tok::kw_return) && // Type aliases use `type X = ...;` in TypeScript and can be exported // using `export type ...`. - !(Style.Language == FormatStyle::LK_JavaScript && + !(Style.isJavaScript() && (Line.startsWith(Keywords.kw_type, tok::identifier) || Line.startsWith(tok::kw_export, Keywords.kw_type, tok::identifier))) && @@ -1409,7 +1396,7 @@ } else if (Current.is(TT_TrailingReturnArrow)) { Contexts.back().IsExpression = false; } else if (Current.is(TT_LambdaArrow) || Current.is(Keywords.kw_assert)) { - Contexts.back().IsExpression = Style.Language == FormatStyle::LK_Java; + Contexts.back().IsExpression = Style.isJava(); } else if (Current.Previous && Current.Previous->is(TT_CtorInitializerColon)) { Contexts.back().IsExpression = true; @@ -1519,7 +1506,7 @@ } } - if (Style.Language == FormatStyle::LK_JavaScript) { + if (Style.isJavaScript()) { if (Current.is(tok::exclaim)) { if (Current.Previous && (Keywords.IsJavaScriptIdentifier( @@ -1555,8 +1542,7 @@ Contexts.back().FirstStartOfName = nullptr; } else if (Current.isOneOf(tok::kw_auto, tok::kw___auto_type)) { AutoFound = true; - } else if (Current.is(tok::arrow) && - Style.Language == FormatStyle::LK_Java) { + } else if (Current.is(tok::arrow) && Style.isJava()) { Current.setType(TT_LambdaArrow); } else if (Current.is(tok::arrow) && AutoFound && Line.MustBeDeclaration && Current.NestingLevel == 0 && @@ -1581,8 +1567,8 @@ } else if (Current.isOneOf(tok::exclaim, tok::tilde)) { Current.setType(TT_UnaryOperator); } else if (Current.is(tok::question)) { - if (Style.Language == FormatStyle::LK_JavaScript && - Line.MustBeDeclaration && !Contexts.back().IsExpression) { + if (Style.isJavaScript() && Line.MustBeDeclaration && + !Contexts.back().IsExpression) { // In JavaScript, `interface X { foo?(): bar; }` is an optional method // on the interface, not a ternary expression. Current.setType(TT_JsTypeOptionalQuestion); @@ -1591,8 +1577,7 @@ } } else if (Current.isBinaryOperator() && (!Current.Previous || Current.Previous->isNot(tok::l_square)) && - (!Current.is(tok::greater) && - Style.Language != FormatStyle::LK_TextProto)) { + (!Current.is(tok::greater) && !Style.isTextProtoBuf())) { Current.setType(TT_BinaryOperator); } else if (Current.is(tok::comment)) { if (Current.TokenText.startswith("/*")) { @@ -1625,9 +1610,8 @@ Current.setType(TT_FunctionAnnotationRParen); } } - } else if (Current.is(tok::at) && Current.Next && - Style.Language != FormatStyle::LK_JavaScript && - Style.Language != FormatStyle::LK_Java) { + } else if (Current.is(tok::at) && Current.Next && !Style.isJavaScript() && + !Style.isJava()) { // In Java & JavaScript, "@..." is a decorator or annotation. In ObjC, it // marks declarations and properties that need special formatting. switch (Current.Next->Tok.getObjCKeywordID()) { @@ -1647,7 +1631,7 @@ if (PreviousNoComment && PreviousNoComment->isOneOf(tok::comma, tok::l_brace)) Current.setType(TT_DesignatedInitializerPeriod); - else if (Style.Language == FormatStyle::LK_Java && Current.Previous && + else if (Style.isJava() && Current.Previous && Current.Previous->isOneOf(TT_JavaAnnotation, TT_LeadingJavaAnnotation)) { Current.setType(Current.Previous->getType()); @@ -1672,9 +1656,7 @@ // Line.MightBeFunctionDecl can only be true after the parentheses of a // function declaration have been found. Current.setType(TT_TrailingAnnotation); - } else if ((Style.Language == FormatStyle::LK_Java || - Style.Language == FormatStyle::LK_JavaScript) && - Current.Previous) { + } else if ((Style.isJava() || Style.isJavaScript()) && Current.Previous) { if (Current.Previous->is(tok::at) && Current.isNot(Keywords.kw_interface)) { const FormatToken &AtToken = *Current.Previous; @@ -1703,13 +1685,13 @@ if (Tok.Previous->isOneOf(TT_LeadingJavaAnnotation, Keywords.kw_instanceof, Keywords.kw_as)) return false; - if (Style.Language == FormatStyle::LK_JavaScript && - Tok.Previous->is(Keywords.kw_in)) + if (Style.isJavaScript() && Tok.Previous->is(Keywords.kw_in)) return false; // Skip "const" as it does not have an influence on whether this is a name. FormatToken *PreviousNotConst = Tok.getPreviousNonComment(); - while (PreviousNotConst && PreviousNotConst->is(tok::kw_const)) + while (PreviousNotConst && + PreviousNotConst->isOneOf(tok::kw_const, tok::kw_constexpr)) PreviousNotConst = PreviousNotConst->getPreviousNonComment(); if (!PreviousNotConst) @@ -1739,8 +1721,7 @@ /// Determine whether ')' is ending a cast. bool rParenEndsCast(const FormatToken &Tok) { // C-style casts are only used in C++, C# and Java. - if (!Style.isCSharp() && !Style.isCpp() && - Style.Language != FormatStyle::LK_Java) + if (!Style.isCSharp() && !Style.isCpp() && !Style.isJava()) return false; // Empty parens aren't casts and there are no casts at the end of the line. @@ -1789,7 +1770,7 @@ // 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)) + if (Style.isJava() && Tok.Next->is(tok::l_paren)) return true; // If a (non-string) literal follows, this is likely a cast. @@ -1849,7 +1830,7 @@ /// Return the type of the given token assuming it is * or &. TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression, bool InTemplateArgument) { - if (Style.Language == FormatStyle::LK_JavaScript) + if (Style.isJavaScript()) return TT_BinaryOperator; // && in C# must be a binary operator. @@ -1918,8 +1899,32 @@ return TT_BinaryOperator; } - // It is very unlikely that we are going to find a pointer or reference type - // definition on the RHS of an assignment. + // Try to distinguish (A && B) from (A &&b), which is ambiguous without + // other semantic information + // However in a noexcept context where it is going to be a boolean + // operation noexcept(A && b) resulting in a binary operation + if (Tok.is(tok::ampamp) && PrevToken && + PrevToken->isOneOf(tok::identifier, TT_TemplateCloser) && NextToken) { + const FormatToken *NextNextToken = NextToken->getNextNonComment(); + const FormatToken *PrevPrevToken = PrevToken->getPreviousNonComment(); + if (NextToken->is(tok::identifier)) { + if (NextNextToken && NextNextToken->isOneOf(tok::less, tok::coloncolon)) + return TT_BinaryOperator; + if (PrevPrevToken) { + const FormatToken *PrevPrevPrevToken = + PrevPrevToken->getPreviousNonComment(); + // We already know its `x y identifier && identifer z` + // just need to confirm x,y,z + if (PrevPrevPrevToken && PrevPrevPrevToken->is(tok::kw_noexcept) && + PrevPrevToken->is(tok::l_paren) && + NextNextToken->is(tok::r_paren)) + return TT_BinaryOperator; + } + } + } + + // It is very unlikely that we are going to find a pointer or reference + // type definition on the RHS of an assignment. if (IsExpression && !Contexts.back().CaretFound) return TT_BinaryOperator; @@ -1969,12 +1974,13 @@ bool AutoFound; const AdditionalKeywords &Keywords; - // Set of "<" tokens that do not open a template parameter list. If parseAngle - // determines that a specific token can't be a template opener, it will make - // same decision irrespective of the decisions for tokens leading up to it. - // Store this information to prevent this from causing exponential runtime. + // Set of "<" tokens that do not open a template parameter list. If + // parseAngle determines that a specific token can't be a template opener, + // it will make same decision irrespective of the decisions for tokens + // leading up to it. Store this information to prevent this from causing + // exponential runtime. llvm::SmallPtrSet NonTemplateLess; -}; +}; // namespace static const int PrecedenceUnaryOperator = prec::PointerToMember + 1; static const int PrecedenceArrowAndPeriod = prec::PointerToMember + 2; @@ -1999,7 +2005,8 @@ if (!Current || Precedence > PrecedenceArrowAndPeriod) return; - // Conditional expressions need to be parsed separately for proper nesting. + // Conditional expressions need to be parsed separately for proper + // nesting. if (Precedence == prec::Conditional) { parseConditionalExpr(); return; @@ -2042,8 +2049,8 @@ // Consume scopes: (), [], <> and {} if (Current->opensScope()) { - // In fragment of a JavaScript template string can look like '}..${' and - // thus close a scope and open a new one at the same time. + // In fragment of a JavaScript template string can look like '}..${' + // and thus close a scope and open a new one at the same time. while (Current && (!Current->closesScope() || Current->opensScope())) { next(); parse(); @@ -2083,8 +2090,7 @@ return prec::Conditional; if (NextNonComment && Current->is(TT_SelectorName) && (NextNonComment->isOneOf(TT_DictLiteral, TT_JsTypeColon) || - ((Style.Language == FormatStyle::LK_Proto || - Style.Language == FormatStyle::LK_TextProto) && + ((Style.isProtoBuf() || Style.isTextProtoBuf()) && NextNonComment->is(tok::less)))) return prec::Assignment; if (Current->is(TT_JsComputedPropertyName)) @@ -2099,19 +2105,17 @@ return 0; if (Current->is(TT_RangeBasedForLoopColon)) return prec::Comma; - if ((Style.Language == FormatStyle::LK_Java || - Style.Language == FormatStyle::LK_JavaScript) && + if ((Style.isJava() || Style.isJavaScript()) && Current->is(Keywords.kw_instanceof)) return prec::Relational; - if (Style.Language == FormatStyle::LK_JavaScript && + if (Style.isJavaScript() && Current->isOneOf(Keywords.kw_in, Keywords.kw_as)) return prec::Relational; if (Current->is(TT_BinaryOperator) || Current->is(tok::comma)) return Current->getPrecedence(); if (Current->isOneOf(tok::period, tok::arrow)) return PrecedenceArrowAndPeriod; - if ((Style.Language == FormatStyle::LK_Java || - Style.Language == FormatStyle::LK_JavaScript) && + if ((Style.isJava() || Style.isJavaScript()) && Current->isOneOf(Keywords.kw_extends, Keywords.kw_implements, Keywords.kw_throws)) return 0; @@ -2178,7 +2182,7 @@ FormatToken *Current; }; -} // end anonymous namespace +} // namespace void TokenAnnotator::setCommentLineLevels( SmallVectorImpl &Lines) { @@ -2462,8 +2466,8 @@ // line should not force other line breaks (e.g. when ObjC method // expression is a part of other expression). Current->SplitPenalty = splitPenalty(Line, *Current, InFunctionDecl); - if (Style.Language == FormatStyle::LK_ObjC && - Current->is(TT_SelectorName) && Current->ParameterIndex > 0) { + if (Style.isObjectiveC() && Current->is(TT_SelectorName) && + Current->ParameterIndex > 0) { if (Current->ParameterIndex == 1) Current->SplitPenalty += 5 * Current->BindingStrength; } else { @@ -2516,14 +2520,14 @@ if (Left.is(tok::semi)) return 0; - if (Style.Language == FormatStyle::LK_Java) { + if (Style.isJava()) { if (Right.isOneOf(Keywords.kw_extends, Keywords.kw_throws)) return 1; if (Right.is(Keywords.kw_implements)) return 2; if (Left.is(tok::comma) && Left.NestingLevel == 0) return 3; - } else if (Style.Language == FormatStyle::LK_JavaScript) { + } else if (Style.isJavaScript()) { if (Right.is(Keywords.kw_function) && Left.isNot(tok::comma)) return 100; if (Left.is(TT_JsTypeColon)) @@ -2539,7 +2543,7 @@ if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral)) return 1; if (Right.is(tok::l_square)) { - if (Style.Language == FormatStyle::LK_Proto) + if (Style.isProtoBuf()) return 1; if (Left.is(tok::r_square)) return 200; @@ -2552,8 +2556,7 @@ return 500; } - if (Left.is(tok::coloncolon) || - (Right.is(tok::period) && Style.Language == FormatStyle::LK_Proto)) + if (Left.is(tok::coloncolon) || (Right.is(tok::period) && Style.isProtoBuf())) return 500; if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) || Right.is(tok::kw_operator)) { @@ -2717,7 +2720,7 @@ const FormatToken &Right) { if (Left.is(tok::kw_return) && Right.isNot(tok::semi)) return true; - if (Left.is(Keywords.kw_assert) && Style.Language == FormatStyle::LK_Java) + if (Left.is(Keywords.kw_assert) && Style.isJava()) return true; if (Style.ObjCSpaceAfterProperty && Line.Type == LT_ObjCProperty && Left.Tok.getObjCKeywordID() == tok::objc_property) @@ -2766,8 +2769,8 @@ if (Left.is(tok::coloncolon)) return false; if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less)) { - if (Style.Language == FormatStyle::LK_TextProto || - (Style.Language == FormatStyle::LK_Proto && + if (Style.isTextProtoBuf() || + (Style.isProtoBuf() && (Left.is(TT_DictLiteral) || Right.is(TT_DictLiteral)))) { // Format empty list as `<>`. if (Left.is(tok::less) && Right.is(tok::greater)) @@ -2856,8 +2859,7 @@ const auto SpaceRequiredForArrayInitializerLSquare = [](const FormatToken &LSquareTok, const FormatStyle &Style) { return Style.SpacesInContainerLiterals || - ((Style.Language == FormatStyle::LK_Proto || - Style.Language == FormatStyle::LK_TextProto) && + ((Style.isProtoBuf() || Style.isTextProtoBuf()) && !Style.Cpp11BracedListStyle && LSquareTok.endsSequence(tok::l_square, tok::colon, TT_SelectorName)); @@ -2894,8 +2896,12 @@ return Style.Cpp11BracedListStyle ? Style.SpacesInParentheses : true; if (Left.is(TT_BlockComment)) // No whitespace in x(/*foo=*/1), except for JavaScript. - return Style.Language == FormatStyle::LK_JavaScript || - !Left.TokenText.endswith("=*/"); + return Style.isJavaScript() || !Left.TokenText.endswith("=*/"); + + // Space between template and attribute. + // e.g. template [[nodiscard]] ... + if (Left.is(TT_TemplateCloser) && Right.is(TT_AttributeSquare)) + return true; if (Right.is(tok::l_paren)) { if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) || (Left.is(tok::r_square) && Left.is(TT_AttributeSquare))) @@ -2974,8 +2980,7 @@ if (Right.is(tok::l_brace) && Right.BlockKind == BK_BracedInit && !Left.opensScope() && Style.SpaceBeforeCpp11BracedList) return true; - } else if (Style.Language == FormatStyle::LK_Proto || - Style.Language == FormatStyle::LK_TextProto) { + } else if (Style.isProtoBuf() || Style.isTextProtoBuf()) { if (Right.is(tok::period) && Left.isOneOf(Keywords.kw_optional, Keywords.kw_required, Keywords.kw_repeated, Keywords.kw_extend)) @@ -3076,7 +3081,7 @@ if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when)) return Style.SpaceBeforeParens == FormatStyle::SBPO_ControlStatements || spaceRequiredBeforeParens(Right); - } else if (Style.Language == FormatStyle::LK_JavaScript) { + } else if (Style.isJavaScript()) { if (Left.is(TT_JsFatArrow)) return true; // for await ( ... @@ -3167,7 +3172,7 @@ if (Left.is(TT_JsNonNullAssertion) && Right.isOneOf(Keywords.kw_as, Keywords.kw_in)) return true; // "x! as string", "x! in y" - } else if (Style.Language == FormatStyle::LK_Java) { + } else if (Style.isJava()) { if (Left.is(tok::r_square) && Right.is(tok::l_brace)) return true; if (Left.is(Keywords.kw_synchronized) && Right.is(tok::l_paren)) @@ -3255,8 +3260,8 @@ Right.isOneOf(TT_BinaryOperator, TT_SelectorName); if (Left.is(tok::greater) && Right.is(tok::greater)) { - if (Style.Language == FormatStyle::LK_TextProto || - (Style.Language == FormatStyle::LK_Proto && Left.is(TT_DictLiteral))) + if (Style.isTextProtoBuf() || + (Style.isProtoBuf() && Left.is(TT_DictLiteral))) return !Style.Cpp11BracedListStyle; return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) && (Style.Standard < FormatStyle::LS_Cpp11 || Style.SpacesInAngles); @@ -3268,7 +3273,7 @@ if (!Style.SpaceBeforeAssignmentOperators && Left.isNot(TT_TemplateCloser) && Right.getPrecedence() == prec::Assignment) return false; - if (Style.Language == FormatStyle::LK_Java && Right.is(tok::coloncolon) && + if (Style.isJava() && Right.is(tok::coloncolon) && (Left.is(tok::identifier) || Left.is(tok::kw_this))) return false; if (Right.is(tok::coloncolon) && Left.is(tok::identifier)) @@ -3381,7 +3386,7 @@ return false; if (Right.is(TT_CSharpGenericTypeConstraint)) return true; - } else if (Style.Language == FormatStyle::LK_JavaScript) { + } else if (Style.isJavaScript()) { // FIXME: This might apply to other languages and token kinds. if (Right.is(tok::string_literal) && Left.is(tok::plus) && Left.Previous && Left.Previous->is(tok::string_literal)) @@ -3431,15 +3436,12 @@ (Left.NestingLevel == 0 && Line.Level == 0 && Style.AllowShortFunctionsOnASingleLine & FormatStyle::SFS_InlineOnly); - } else if (Style.Language == FormatStyle::LK_Java) { + } else if (Style.isJava()) { if (Right.is(tok::plus) && Left.is(tok::string_literal) && Right.Next && Right.Next->is(tok::string_literal)) return true; - } else if (Style.Language == FormatStyle::LK_Cpp || - Style.Language == FormatStyle::LK_ObjC || - Style.Language == FormatStyle::LK_Proto || - Style.Language == FormatStyle::LK_TableGen || - Style.Language == FormatStyle::LK_TextProto) { + } else if (Style.isCpp() || Style.isProtoBuf() || Style.isTableGen() || + Style.isTextProtoBuf()) { if (Left.isStringLiteral() && Right.isStringLiteral()) return true; } @@ -3451,15 +3453,13 @@ if (Style.JavaScriptWrapImports || Line.Type != LT_ImportStatement) { const FormatToken *BeforeClosingBrace = nullptr; if ((Left.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || - (Style.Language == FormatStyle::LK_JavaScript && - Left.is(tok::l_paren))) && + (Style.isJavaScript() && Left.is(tok::l_paren))) && Left.BlockKind != BK_Block && Left.MatchingParen) BeforeClosingBrace = Left.MatchingParen->Previous; else if (Right.MatchingParen && (Right.MatchingParen->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || - (Style.Language == FormatStyle::LK_JavaScript && - Right.MatchingParen->is(tok::l_paren)))) + (Style.isJavaScript() && Right.MatchingParen->is(tok::l_paren)))) BeforeClosingBrace = &Left; if (BeforeClosingBrace && (BeforeClosingBrace->is(tok::comma) || BeforeClosingBrace->isTrailingComment())) @@ -3503,7 +3503,7 @@ if ((Right.Previous->is(tok::l_brace) || (Right.Previous->is(tok::less) && Right.Previous->Previous && Right.Previous->Previous->is(tok::equal))) && - Right.NestingLevel == 1 && Style.Language == FormatStyle::LK_Proto) { + Right.NestingLevel == 1 && Style.isProtoBuf()) { // Don't put enums or option definitions onto single lines in protocol // buffers. return true; @@ -3541,8 +3541,7 @@ } // Put multiple Java annotation on a new line. - if ((Style.Language == FormatStyle::LK_Java || - Style.Language == FormatStyle::LK_JavaScript) && + if ((Style.isJava() || Style.isJavaScript()) && Left.is(TT_LeadingJavaAnnotation) && Right.isNot(TT_LeadingJavaAnnotation) && Right.isNot(tok::l_paren) && (Line.Last->is(tok::l_brace) || Style.BreakAfterJavaFieldAnnotations)) @@ -3578,8 +3577,7 @@ // together. // // We ensure elsewhere that extensions are always on their own line. - if ((Style.Language == FormatStyle::LK_Proto || - Style.Language == FormatStyle::LK_TextProto) && + if ((Style.isProtoBuf() || Style.isTextProtoBuf()) && Right.is(TT_SelectorName) && !Right.is(tok::r_square) && Right.Next) { // Keep `@submessage` together in: // @submessage { key: value } @@ -3639,9 +3637,8 @@ // Deal with lambda arguments in C++ - we want consistent line breaks whether // they happen to be at arg0, arg1 or argN. The selection is a bit nuanced // as aggressive line breaks are placed when the lambda is not the last arg. - if ((Style.Language == FormatStyle::LK_Cpp || - Style.Language == FormatStyle::LK_ObjC) && - Left.is(tok::l_paren) && Left.BlockParameterCount > 0 && + if ((Style.isCpp()) && Left.is(tok::l_paren) && + Left.BlockParameterCount > 0 && !Right.isOneOf(tok::l_paren, TT_LambdaLSquare)) { // Multiple lambdas in the same function call force line breaks. if (Left.BlockParameterCount > 1) @@ -3674,14 +3671,14 @@ // Only break after commas for generic type constraints. if (Line.First->is(TT_CSharpGenericTypeConstraint)) return Left.is(TT_CSharpGenericTypeConstraintComma); - } else if (Style.Language == FormatStyle::LK_Java) { + } else if (Style.isJava()) { if (Left.isOneOf(Keywords.kw_throws, Keywords.kw_extends, Keywords.kw_implements)) return false; if (Right.isOneOf(Keywords.kw_throws, Keywords.kw_extends, Keywords.kw_implements)) return true; - } else if (Style.Language == FormatStyle::LK_JavaScript) { + } else if (Style.isJavaScript()) { const FormatToken *NonComment = Right.getPreviousNonComment(); if (NonComment && NonComment->isOneOf( @@ -3798,8 +3795,7 @@ !Right.isOneOf(TT_CtorInitializerColon, TT_InlineASMColon)) return false; if (Left.is(tok::colon) && Left.isOneOf(TT_DictLiteral, TT_ObjCMethodExpr)) { - if (Style.Language == FormatStyle::LK_Proto || - Style.Language == FormatStyle::LK_TextProto) { + if (Style.isProtoBuf() || Style.isTextProtoBuf()) { if (!Style.AlwaysBreakBeforeMultilineStrings && Right.isStringLiteral()) return false; // Prevent cases like: