diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-07-13 19:25:38 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-07-13 19:25:38 +0000 |
| commit | 8746d127c04f5bbaf6c6e88cef8606ca5a6a54e9 (patch) | |
| tree | 84c9d77f8c764f04bcef0b1da4eedfa233d67a46 /lib/Format | |
| parent | cf1b401909b5e54edfd80656b1a18eaa31f9f6f1 (diff) | |
Diffstat (limited to 'lib/Format')
| -rw-r--r-- | lib/Format/ContinuationIndenter.cpp | 42 | ||||
| -rw-r--r-- | lib/Format/Format.cpp | 7 | ||||
| -rw-r--r-- | lib/Format/FormatToken.h | 27 | ||||
| -rw-r--r-- | lib/Format/TokenAnnotator.cpp | 65 | ||||
| -rw-r--r-- | lib/Format/UnwrappedLineParser.cpp | 33 |
5 files changed, 135 insertions, 39 deletions
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index 4197587a74c0..3bf1cd8f7c13 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -66,6 +66,16 @@ static bool startsNextParameter(const FormatToken &Current, !Style.BreakBeforeInheritanceComma)); } +static bool opensProtoMessageField(const FormatToken &LessTok, + const FormatStyle &Style) { + if (LessTok.isNot(tok::less)) + return false; + return Style.Language == FormatStyle::LK_TextProto || + (Style.Language == FormatStyle::LK_Proto && + (LessTok.NestingLevel > 0 || + (LessTok.Previous && LessTok.Previous->is(tok::equal)))); +} + ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style, const AdditionalKeywords &Keywords, const SourceManager &SourceMgr, @@ -94,6 +104,13 @@ LineState ContinuationIndenter::getInitialState(unsigned FirstIndent, State.LowestLevelOnLine = 0; State.IgnoreStackForComparison = false; + if (Style.Language == FormatStyle::LK_TextProto) { + // We need this in order to deal with the bin packing of text fields at + // global scope. + State.Stack.back().AvoidBinPacking = true; + State.Stack.back().BreakBeforeParameter = true; + } + // The first token has already been indented and thus consumed. moveStateToNextToken(State, DryRun, /*Newline=*/false); return State; @@ -176,7 +193,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { return true; if (((Previous.is(TT_DictLiteral) && Previous.is(tok::l_brace)) || (Previous.is(TT_ArrayInitializerLSquare) && - Previous.ParameterCount > 1)) && + Previous.ParameterCount > 1) || + opensProtoMessageField(Previous, Style)) && Style.ColumnLimit > 0 && getLengthToMatchingParen(Previous) + State.Column - 1 > getColumnLimit(State)) @@ -501,13 +519,6 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, } } -static bool lessOpensProtoMessageField(const FormatToken &LessTok, - const LineState &State) { - assert(LessTok.is(tok::less)); - return LessTok.NestingLevel > 0 || - (LessTok.Previous && LessTok.Previous->is(tok::equal)); -} - unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, bool DryRun) { FormatToken &Current = *State.NextToken; @@ -650,9 +661,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, // before the corresponding } or ]. if (PreviousNonComment && (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || - (Style.Language == FormatStyle::LK_Proto && - PreviousNonComment->is(tok::less) && - lessOpensProtoMessageField(*PreviousNonComment, State)) || + opensProtoMessageField(*PreviousNonComment, Style) || (PreviousNonComment->is(TT_TemplateString) && PreviousNonComment->opensScope()))) State.Stack.back().BreakBeforeClosingBrace = true; @@ -695,7 +704,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { return Current.NestingLevel == 0 ? State.FirstIndent : State.Stack.back().Indent; if ((Current.isOneOf(tok::r_brace, tok::r_square) || - (Current.is(tok::greater) && Style.Language == FormatStyle::LK_Proto)) && + (Current.is(tok::greater) && + (Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto))) && State.Stack.size() > 1) { if (Current.closesBlockOrBlockTypeList(Style)) return State.Stack[State.Stack.size() - 2].NestedBlockIndent; @@ -1050,8 +1061,7 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall, State.Stack.back().NestedBlockIndent); if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || - (Style.Language == FormatStyle::LK_Proto && Current.is(tok::less) && - lessOpensProtoMessageField(Current, State))) { + opensProtoMessageField(Current, Style)) { if (Current.opensBlockOrBlockTypeList(Style)) { NewIndent = Style.IndentWidth + std::min(State.Column, State.Stack.back().NestedBlockIndent); @@ -1064,7 +1074,9 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, Current.MatchingParen->Previous->is(tok::comma); AvoidBinPacking = EndsInComma || Current.is(TT_DictLiteral) || - Style.Language == FormatStyle::LK_Proto || !Style.BinPackArguments || + Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto || + !Style.BinPackArguments || (NextNoComment && NextNoComment->isOneOf(TT_DesignatedInitializerPeriod, TT_DesignatedInitializerLSquare)); diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index bb6781d79517..aa4ed8c42a70 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -56,6 +56,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> { IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC); IO.enumCase(Value, "Proto", FormatStyle::LK_Proto); IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen); + IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto); } }; @@ -631,6 +632,12 @@ FormatStyle getLLVMStyle() { } FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { + if (Language == FormatStyle::LK_TextProto) { + FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_Proto); + GoogleStyle.Language = FormatStyle::LK_TextProto; + return GoogleStyle; + } + FormatStyle GoogleStyle = getLLVMStyle(); GoogleStyle.Language = Language; diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h index 0fe91adcd472..a60361a8e5fa 100644 --- a/lib/Format/FormatToken.h +++ b/lib/Format/FormatToken.h @@ -21,6 +21,7 @@ #include "clang/Format/Format.h" #include "clang/Lex/Lexer.h" #include <memory> +#include <unordered_set> namespace clang { namespace format { @@ -466,7 +467,8 @@ struct FormatToken { (is(tok::l_brace) && (BlockKind == BK_Block || is(TT_DictLiteral) || (!Style.Cpp11BracedListStyle && NestingLevel == 0))) || - (is(tok::less) && Style.Language == FormatStyle::LK_Proto); + (is(tok::less) && (Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto)); } /// \brief Same as opensBlockOrBlockTypeList, but for the closing token. @@ -639,6 +641,7 @@ struct AdditionalKeywords { kw_is = &IdentTable.get("is"); kw_let = &IdentTable.get("let"); kw_module = &IdentTable.get("module"); + kw_readonly = &IdentTable.get("readonly"); kw_set = &IdentTable.get("set"); kw_type = &IdentTable.get("type"); kw_var = &IdentTable.get("var"); @@ -671,6 +674,15 @@ struct AdditionalKeywords { kw_qsignals = &IdentTable.get("Q_SIGNALS"); kw_slots = &IdentTable.get("slots"); kw_qslots = &IdentTable.get("Q_SLOTS"); + + // Keep this at the end of the constructor to make sure everything here is + // already initialized. + JsExtraKeywords = std::unordered_set<IdentifierInfo *>( + {kw_as, kw_async, kw_await, kw_declare, kw_finally, kw_from, + kw_function, kw_get, kw_import, kw_is, kw_let, kw_module, kw_readonly, + kw_set, kw_type, kw_var, kw_yield, + // Keywords from the Java section. + kw_abstract, kw_extends, kw_implements, kw_instanceof, kw_interface}); } // Context sensitive keywords. @@ -699,6 +711,7 @@ struct AdditionalKeywords { IdentifierInfo *kw_is; IdentifierInfo *kw_let; IdentifierInfo *kw_module; + IdentifierInfo *kw_readonly; IdentifierInfo *kw_set; IdentifierInfo *kw_type; IdentifierInfo *kw_var; @@ -732,6 +745,18 @@ struct AdditionalKeywords { IdentifierInfo *kw_qsignals; IdentifierInfo *kw_slots; IdentifierInfo *kw_qslots; + + /// \brief Returns \c true if \p Tok is a true JavaScript identifier, returns + /// \c false if it is a keyword or a pseudo keyword. + bool IsJavaScriptIdentifier(const FormatToken &Tok) const { + return Tok.is(tok::identifier) && + JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) == + JsExtraKeywords.end(); + } + +private: + /// \brief The JavaScript keywords beyond the C++ keyword set. + std::unordered_set<IdentifierInfo *> JsExtraKeywords; }; } // namespace format diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index d78a37532fe8..c6e90a9175e1 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -90,7 +90,8 @@ private: } if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) || (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext && - Style.Language != FormatStyle::LK_Proto)) + Style.Language != FormatStyle::LK_Proto && + Style.Language != FormatStyle::LK_TextProto)) 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 @@ -453,7 +454,8 @@ private: FormatToken *Previous = CurrentToken->getPreviousNonComment(); if (((CurrentToken->is(tok::colon) && (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) || - Style.Language == FormatStyle::LK_Proto) && + Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) && (Previous->Tok.getIdentifierInfo() || Previous->is(tok::string_literal))) Previous->Type = TT_SelectorName; @@ -536,8 +538,13 @@ private: } } if (Contexts.back().ColonIsDictLiteral || - Style.Language == FormatStyle::LK_Proto) { + Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) { Tok->Type = TT_DictLiteral; + if (Style.Language == FormatStyle::LK_TextProto) { + if (FormatToken *Previous = Tok->getPreviousNonComment()) + Previous->Type = TT_SelectorName; + } } else if (Contexts.back().ColonIsObjCMethodExpr || Line.startsWith(TT_ObjCMethodSpecifier)) { Tok->Type = TT_ObjCMethodExpr; @@ -635,12 +642,22 @@ private: return false; break; case tok::l_brace: + if (Style.Language == FormatStyle::LK_TextProto) { + FormatToken *Previous =Tok->getPreviousNonComment(); + if (Previous && Previous->Type != TT_DictLiteral) + Previous->Type = TT_SelectorName; + } if (!parseBrace()) return false; break; case tok::less: if (parseAngle()) { Tok->Type = TT_TemplateOpener; + if (Style.Language == FormatStyle::LK_TextProto) { + FormatToken *Previous = Tok->getPreviousNonComment(); + if (Previous && Previous->Type != TT_DictLiteral) + Previous->Type = TT_SelectorName; + } } else { Tok->Type = TT_BinaryOperator; NonTemplateLess.insert(Tok); @@ -1572,7 +1589,8 @@ private: return prec::Conditional; if (NextNonComment && Current->is(TT_SelectorName) && (NextNonComment->is(TT_DictLiteral) || - (Style.Language == FormatStyle::LK_Proto && + ((Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) && NextNonComment->is(tok::less)))) return prec::Assignment; if (Current->is(TT_JsComputedPropertyName)) @@ -1676,17 +1694,26 @@ void TokenAnnotator::setCommentLineLevels( for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(), E = Lines.rend(); I != E; ++I) { - bool CommentLine = (*I)->First; + bool CommentLine = true; for (const FormatToken *Tok = (*I)->First; Tok; Tok = Tok->Next) { if (!Tok->is(tok::comment)) { CommentLine = false; break; } } - if (NextNonCommentLine && CommentLine) - (*I)->Level = NextNonCommentLine->Level; - else + + if (NextNonCommentLine && CommentLine) { + // If the comment is currently aligned with the line immediately following + // it, that's probably intentional and we should keep it. + bool AlignedWithNextLine = + NextNonCommentLine->First->NewlinesBefore <= 1 && + NextNonCommentLine->First->OriginalColumn == + (*I)->First->OriginalColumn; + if (AlignedWithNextLine) + (*I)->Level = NextNonCommentLine->Level; + } else { NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr; + } setCommentLineLevels((*I)->Children); } @@ -2274,7 +2301,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Style.isCpp()) { if (Left.is(tok::kw_operator)) return Right.is(tok::coloncolon); - } else if (Style.Language == FormatStyle::LK_Proto) { + } else if (Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) { if (Right.is(tok::period) && Left.isOneOf(Keywords.kw_optional, Keywords.kw_required, Keywords.kw_repeated, Keywords.kw_extend)) @@ -2282,6 +2310,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Right.is(tok::l_paren) && Left.isOneOf(Keywords.kw_returns, Keywords.kw_option)) return true; + if (Right.isOneOf(tok::l_brace, tok::less) && Left.is(TT_SelectorName)) + return true; } else if (Style.Language == FormatStyle::LK_JavaScript) { if (Left.is(TT_JsFatArrow)) return true; @@ -2300,7 +2330,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || (Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) return false; - if (Left.is(tok::identifier) && Right.is(TT_TemplateString)) + // In tagged template literals ("html`bar baz`"), there is no space between + // the tag identifier and the template string. getIdentifierInfo makes sure + // that the identifier is not a pseudo keyword like `yield`, either. + if (Left.is(tok::identifier) && Keywords.IsJavaScriptIdentifier(Left) && + Right.is(TT_TemplateString)) return false; if (Right.is(tok::star) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) @@ -2604,11 +2638,12 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, } else if (Style.Language == FormatStyle::LK_JavaScript) { const FormatToken *NonComment = Right.getPreviousNonComment(); if (NonComment && - NonComment->isOneOf( - tok::kw_return, tok::kw_continue, tok::kw_break, tok::kw_throw, - Keywords.kw_interface, Keywords.kw_type, tok::kw_static, - tok::kw_public, tok::kw_private, tok::kw_protected, - Keywords.kw_abstract, Keywords.kw_get, Keywords.kw_set)) + NonComment->isOneOf(tok::kw_return, tok::kw_continue, tok::kw_break, + tok::kw_throw, Keywords.kw_interface, + Keywords.kw_type, tok::kw_static, tok::kw_public, + tok::kw_private, tok::kw_protected, + Keywords.kw_readonly, Keywords.kw_abstract, + Keywords.kw_get, Keywords.kw_set)) return false; // Otherwise automatic semicolon insertion would trigger. if (Left.is(TT_JsFatArrow) && Right.is(tok::l_brace)) return false; diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index ba3a4c17ee12..4b57919d1929 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -286,7 +286,10 @@ void UnwrappedLineParser::parseFile() { !Line->InPPDirective && Style.Language != FormatStyle::LK_JavaScript; ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, MustBeDeclaration); - parseLevel(/*HasOpeningBrace=*/false); + if (Style.Language == FormatStyle::LK_TextProto) + parseBracedList(); + else + parseLevel(/*HasOpeningBrace=*/false); // Make sure to format the remaining tokens. flushComments(true); addUnwrappedLine(); @@ -832,6 +835,7 @@ void UnwrappedLineParser::parseStructuralElement() { case tok::at: nextToken(); if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); break; } @@ -996,8 +1000,10 @@ void UnwrappedLineParser::parseStructuralElement() { switch (FormatTok->Tok.getKind()) { case tok::at: nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) + if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); + } break; case tok::kw_enum: // Ignore if this is part of "template <enum ...". @@ -1176,12 +1182,15 @@ void UnwrappedLineParser::parseStructuralElement() { } nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) + if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); - else if (Style.Language == FormatStyle::LK_Proto && - FormatTok->Tok.is(tok::less)) + } else if (Style.Language == FormatStyle::LK_Proto && + FormatTok->Tok.is(tok::less)) { + nextToken(); parseBracedList(/*ContinueOnSemicolons=*/false, /*ClosingBraceKind=*/tok::greater); + } break; case tok::l_square: parseSquare(); @@ -1345,6 +1354,7 @@ bool UnwrappedLineParser::tryToParseBracedList() { assert(FormatTok->BlockKind != BK_Unknown); if (FormatTok->BlockKind == BK_Block) return false; + nextToken(); parseBracedList(); return true; } @@ -1352,7 +1362,6 @@ bool UnwrappedLineParser::tryToParseBracedList() { bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons, tok::TokenKind ClosingBraceKind) { bool HasError = false; - nextToken(); // FIXME: Once we have an expression parser in the UnwrappedLineParser, // replace this by using parseAssigmentExpression() inside. @@ -1407,6 +1416,7 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons, // Assume there are no blocks inside a braced init list apart // from the ones we explicitly parse out (like lambdas). FormatTok->BlockKind = BK_BracedInit; + nextToken(); parseBracedList(); break; case tok::semi: @@ -1459,8 +1469,10 @@ void UnwrappedLineParser::parseParens() { break; case tok::at: nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) + if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); + } break; case tok::kw_class: if (Style.Language == FormatStyle::LK_JavaScript) @@ -1508,8 +1520,10 @@ void UnwrappedLineParser::parseSquare() { } case tok::at: nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) + if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); + } break; default: nextToken(); @@ -1836,6 +1850,7 @@ bool UnwrappedLineParser::parseEnum() { } // Parse enum body. + nextToken(); bool HasError = !parseBracedList(/*ContinueOnSemicolons=*/true); if (HasError) { if (FormatTok->is(tok::semi)) @@ -1870,6 +1885,7 @@ void UnwrappedLineParser::parseJavaEnumBody() { FormatTok = Tokens->setPosition(StoredPosition); if (IsSimple) { + nextToken(); parseBracedList(); addUnwrappedLine(); return; @@ -2081,6 +2097,7 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() { } if (FormatTok->is(tok::l_brace)) { FormatTok->BlockKind = BK_Block; + nextToken(); parseBracedList(); } else { nextToken(); |
