Author: djasper Date: Sat Jan 9 09:56:28 2016 New Revision: 257255 URL: http://llvm.org/viewvc/llvm-project?rev=257255&view=rev Log: clang-format: [JS] Support semicolons in TypeScript's TypeMemberLists.
Before: var x: { a: string; b: number; } = {}; After: var x: {a: string; b: number;} = {}; Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp cfe/trunk/lib/Format/UnwrappedLineParser.h cfe/trunk/unittests/Format/FormatTestJS.cpp Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=257255&r1=257254&r2=257255&view=diff ============================================================================== --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original) +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Sat Jan 9 09:56:28 2016 @@ -315,6 +315,7 @@ void UnwrappedLineParser::calculateBrace // definitions, too. unsigned StoredPosition = Tokens->getPosition(); FormatToken *Tok = FormatTok; + const FormatToken *PrevTok = getPreviousToken(); // Keep a stack of positions of lbrace tokens. We will // update information about whether an lbrace starts a // braced init list or a different block during the loop. @@ -331,47 +332,53 @@ void UnwrappedLineParser::calculateBrace switch (Tok->Tok.getKind()) { case tok::l_brace: - Tok->BlockKind = BK_Unknown; + if (Style.Language == FormatStyle::LK_JavaScript && PrevTok && + PrevTok->is(tok::colon)) + // In TypeScript's TypeMemberLists, there can be semicolons between the + // individual members. + Tok->BlockKind = BK_BracedInit; + else + Tok->BlockKind = BK_Unknown; LBraceStack.push_back(Tok); break; case tok::r_brace: - if (!LBraceStack.empty()) { - if (LBraceStack.back()->BlockKind == BK_Unknown) { - bool ProbablyBracedList = false; - if (Style.Language == FormatStyle::LK_Proto) { - ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square); - } else { - // Using OriginalColumn to distinguish between ObjC methods and - // binary operators is a bit hacky. - bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) && - NextTok->OriginalColumn == 0; - - // If there is a comma, semicolon or right paren after the closing - // brace, we assume this is a braced initializer list. Note that - // regardless how we mark inner braces here, we will overwrite the - // BlockKind later if we parse a braced list (where all blocks - // inside are by default braced lists), or when we explicitly detect - // blocks (for example while parsing lambdas). - // - // We exclude + and - as they can be ObjC visibility modifiers. - ProbablyBracedList = - NextTok->isOneOf(tok::comma, tok::period, tok::colon, - tok::r_paren, tok::r_square, tok::l_brace, - tok::l_square, tok::l_paren, tok::ellipsis) || - (NextTok->is(tok::semi) && - (!ExpectClassBody || LBraceStack.size() != 1)) || - (NextTok->isBinaryOperator() && !NextIsObjCMethod); - } - if (ProbablyBracedList) { - Tok->BlockKind = BK_BracedInit; - LBraceStack.back()->BlockKind = BK_BracedInit; - } else { - Tok->BlockKind = BK_Block; - LBraceStack.back()->BlockKind = BK_Block; - } + if (LBraceStack.empty()) + break; + if (LBraceStack.back()->BlockKind == BK_Unknown) { + bool ProbablyBracedList = false; + if (Style.Language == FormatStyle::LK_Proto) { + ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square); + } else { + // Using OriginalColumn to distinguish between ObjC methods and + // binary operators is a bit hacky. + bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) && + NextTok->OriginalColumn == 0; + + // If there is a comma, semicolon or right paren after the closing + // brace, we assume this is a braced initializer list. Note that + // regardless how we mark inner braces here, we will overwrite the + // BlockKind later if we parse a braced list (where all blocks + // inside are by default braced lists), or when we explicitly detect + // blocks (for example while parsing lambdas). + // + // We exclude + and - as they can be ObjC visibility modifiers. + ProbablyBracedList = + NextTok->isOneOf(tok::comma, tok::period, tok::colon, + tok::r_paren, tok::r_square, tok::l_brace, + tok::l_square, tok::l_paren, tok::ellipsis) || + (NextTok->is(tok::semi) && + (!ExpectClassBody || LBraceStack.size() != 1)) || + (NextTok->isBinaryOperator() && !NextIsObjCMethod); + } + if (ProbablyBracedList) { + Tok->BlockKind = BK_BracedInit; + LBraceStack.back()->BlockKind = BK_BracedInit; + } else { + Tok->BlockKind = BK_Block; + LBraceStack.back()->BlockKind = BK_Block; } - LBraceStack.pop_back(); } + LBraceStack.pop_back(); break; case tok::at: case tok::semi: @@ -381,14 +388,16 @@ void UnwrappedLineParser::calculateBrace case tok::kw_switch: case tok::kw_try: case tok::kw___try: - if (!LBraceStack.empty()) + if (!LBraceStack.empty() && LBraceStack.back()->BlockKind == BK_Unknown) LBraceStack.back()->BlockKind = BK_Block; break; default: break; } + PrevTok = Tok; Tok = NextTok; } while (Tok->Tok.isNot(tok::eof) && !LBraceStack.empty()); + // Assume other blocks for all unclosed opening braces. for (unsigned i = 0, e = LBraceStack.size(); i != e; ++i) { if (LBraceStack[i]->BlockKind == BK_Unknown) @@ -988,13 +997,11 @@ bool UnwrappedLineParser::tryToParseLamb nextToken(); return false; } - // FIXME: This is a dirty way to access the previous token. Find a better - // solution. - if (!Line->Tokens.empty() && - (Line->Tokens.back().Tok->isOneOf(tok::identifier, tok::kw_operator, - tok::kw_new, tok::kw_delete) || - Line->Tokens.back().Tok->closesScope() || - Line->Tokens.back().Tok->isSimpleTypeSpecifier())) { + const FormatToken* Previous = getPreviousToken(); + if (Previous && + (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new, + tok::kw_delete) || + Previous->closesScope() || Previous->isSimpleTypeSpecifier())) { nextToken(); return false; } @@ -1176,6 +1183,14 @@ bool UnwrappedLineParser::parseBracedLis nextToken(); return !HasError; case tok::semi: + // JavaScript (or more precisely TypeScript) can have semicolons in braced + // lists (in so-called TypeMemberLists). Thus, the semicolon cannot be + // used for error recovery if we have otherwise determined that this is + // a braced list. + if (Style.Language == FormatStyle::LK_JavaScript) { + nextToken(); + break; + } HasError = true; if (!ContinueOnSemicolons) return !HasError; @@ -1878,6 +1893,14 @@ void UnwrappedLineParser::nextToken() { readToken(); } +const FormatToken *UnwrappedLineParser::getPreviousToken() { + // FIXME: This is a dirty way to access the previous token. Find a better + // solution. + if (!Line || Line->Tokens.empty()) + return nullptr; + return Line->Tokens.back().Tok; +} + void UnwrappedLineParser::readToken() { bool CommentsInCurrentLine = true; do { Modified: cfe/trunk/lib/Format/UnwrappedLineParser.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.h?rev=257255&r1=257254&r2=257255&view=diff ============================================================================== --- cfe/trunk/lib/Format/UnwrappedLineParser.h (original) +++ cfe/trunk/lib/Format/UnwrappedLineParser.h Sat Jan 9 09:56:28 2016 @@ -110,6 +110,7 @@ private: void addUnwrappedLine(); bool eof() const; void nextToken(); + const FormatToken *getPreviousToken(); void readToken(); void flushComments(bool NewlineBeforeNext); void pushToken(FormatToken *Tok); Modified: cfe/trunk/unittests/Format/FormatTestJS.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestJS.cpp?rev=257255&r1=257254&r2=257255&view=diff ============================================================================== --- cfe/trunk/unittests/Format/FormatTestJS.cpp (original) +++ cfe/trunk/unittests/Format/FormatTestJS.cpp Sat Jan 9 09:56:28 2016 @@ -731,10 +731,14 @@ TEST_F(FormatTestJS, RegexLiteralExample TEST_F(FormatTestJS, TypeAnnotations) { verifyFormat("var x: string;"); + verifyFormat("var x: {a: string; b: number;} = {};"); verifyFormat("function x(): string {\n return 'x';\n}"); verifyFormat("function x(): {x: string} {\n return {x: 'x'};\n}"); verifyFormat("function x(y: string): string {\n return 'x';\n}"); verifyFormat("for (var y: string in x) {\n x();\n}"); + verifyFormat("function x(y: {a?: number;} = {}): number {\n" + " return 12;\n" + "}"); verifyFormat("((a: string, b: number): string => a + b);"); verifyFormat("var x: (y: number) => string;"); verifyFormat("var x: P<string, (a: number) => string>;"); @@ -764,6 +768,10 @@ TEST_F(FormatTestJS, ClassDeclarations) verifyFormat("foo = class {\n" " constructor() {}\n" "};"); + verifyFormat("class C {\n" + " x: {y: Z;} = {};\n" + " private y: {y: Z;} = {};\n" + "}"); // ':' is not a type declaration here. verifyFormat("class X {\n" _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits