summaryrefslogtreecommitdiffstats
path: root/lib/Format/UnwrappedLineParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Format/UnwrappedLineParser.cpp')
-rw-r--r--lib/Format/UnwrappedLineParser.cpp244
1 files changed, 186 insertions, 58 deletions
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 20dd573..ec04af5 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -122,14 +122,13 @@ class ScopedLineState {
public:
ScopedLineState(UnwrappedLineParser &Parser,
bool SwitchToPreprocessorLines = false)
- : Parser(Parser) {
- OriginalLines = Parser.CurrentLines;
+ : Parser(Parser), OriginalLines(Parser.CurrentLines) {
if (SwitchToPreprocessorLines)
Parser.CurrentLines = &Parser.PreprocessorDirectives;
else if (!Parser.Line->Tokens.empty())
Parser.CurrentLines = &Parser.Line->Tokens.back().Children;
- PreBlockLine = Parser.Line.release();
- Parser.Line.reset(new UnwrappedLine());
+ PreBlockLine = std::move(Parser.Line);
+ Parser.Line = llvm::make_unique<UnwrappedLine>();
Parser.Line->Level = PreBlockLine->Level;
Parser.Line->InPPDirective = PreBlockLine->InPPDirective;
}
@@ -139,7 +138,7 @@ public:
Parser.addUnwrappedLine();
}
assert(Parser.Line->Tokens.empty());
- Parser.Line.reset(PreBlockLine);
+ Parser.Line = std::move(PreBlockLine);
if (Parser.CurrentLines == &Parser.PreprocessorDirectives)
Parser.MustBreakBeforeNextToken = true;
Parser.CurrentLines = OriginalLines;
@@ -148,7 +147,7 @@ public:
private:
UnwrappedLineParser &Parser;
- UnwrappedLine *PreBlockLine;
+ std::unique_ptr<UnwrappedLine> PreBlockLine;
SmallVectorImpl<UnwrappedLine> *OriginalLines;
};
@@ -203,12 +202,13 @@ private:
} // end anonymous namespace
UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
+ const AdditionalKeywords &Keywords,
ArrayRef<FormatToken *> Tokens,
UnwrappedLineConsumer &Callback)
: Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
CurrentLines(&Lines), StructuralError(false), Style(Style),
- Tokens(nullptr), Callback(Callback), AllTokens(Tokens),
- PPBranchLevel(-1) {}
+ Keywords(Keywords), Tokens(nullptr), Callback(Callback),
+ AllTokens(Tokens), PPBranchLevel(-1) {}
void UnwrappedLineParser::reset() {
PPBranchLevel = -1;
@@ -311,7 +311,6 @@ void UnwrappedLineParser::calculateBraceTypes() {
// parse macros, so this will magically work inside macro
// definitions, too.
unsigned StoredPosition = Tokens->getPosition();
- unsigned Position = StoredPosition;
FormatToken *Tok = FormatTok;
// Keep a stack of positions of lbrace tokens. We will
// update information about whether an lbrace starts a
@@ -354,7 +353,7 @@ void UnwrappedLineParser::calculateBraceTypes() {
ProbablyBracedList =
NextTok->isOneOf(tok::comma, tok::semi, tok::period, tok::colon,
tok::r_paren, tok::r_square, tok::l_brace,
- tok::l_paren) ||
+ tok::l_paren, tok::ellipsis) ||
(NextTok->isBinaryOperator() && !NextIsObjCMethod);
}
if (ProbablyBracedList) {
@@ -382,7 +381,6 @@ void UnwrappedLineParser::calculateBraceTypes() {
break;
}
Tok = NextTok;
- Position += ReadTokens;
} 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) {
@@ -420,6 +418,8 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
}
static bool IsGoogScope(const UnwrappedLine &Line) {
+ // FIXME: Closure-library specific stuff should not be hard-coded but be
+ // configurable.
if (Line.Tokens.size() < 4)
return false;
auto I = Line.Tokens.begin();
@@ -435,6 +435,19 @@ static bool IsGoogScope(const UnwrappedLine &Line) {
return I->Tok->is(tok::l_paren);
}
+static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
+ const FormatToken &InitialToken) {
+ switch (Style.BreakBeforeBraces) {
+ case FormatStyle::BS_Linux:
+ return InitialToken.isOneOf(tok::kw_namespace, tok::kw_class);
+ case FormatStyle::BS_Allman:
+ case FormatStyle::BS_GNU:
+ return true;
+ default:
+ return false;
+ }
+}
+
void UnwrappedLineParser::parseChildBlock() {
FormatTok->BlockKind = BK_Block;
nextToken();
@@ -646,6 +659,20 @@ void UnwrappedLineParser::parseStructuralElement() {
break;
}
break;
+ case tok::kw_asm:
+ nextToken();
+ if (FormatTok->is(tok::l_brace)) {
+ nextToken();
+ while (FormatTok && FormatTok->isNot(tok::eof)) {
+ if (FormatTok->is(tok::r_brace)) {
+ nextToken();
+ break;
+ }
+ FormatTok->Finalized = true;
+ nextToken();
+ }
+ }
+ break;
case tok::kw_namespace:
parseNamespace();
return;
@@ -659,7 +686,10 @@ void UnwrappedLineParser::parseStructuralElement() {
case tok::kw_public:
case tok::kw_protected:
case tok::kw_private:
- parseAccessSpecifier();
+ if (Style.Language == FormatStyle::LK_Java)
+ nextToken();
+ else
+ parseAccessSpecifier();
return;
case tok::kw_if:
parseIfThenElse();
@@ -717,8 +747,8 @@ void UnwrappedLineParser::parseStructuralElement() {
break;
case tok::kw_typedef:
nextToken();
- // FIXME: Use the IdentifierTable instead.
- if (FormatTok->TokenText == "NS_ENUM")
+ if (FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS,
+ Keywords.kw_CF_ENUM, Keywords.kw_CF_OPTIONS))
parseEnum();
break;
case tok::kw_struct:
@@ -728,6 +758,13 @@ void UnwrappedLineParser::parseStructuralElement() {
// A record declaration or definition is always the start of a structural
// element.
break;
+ case tok::period:
+ nextToken();
+ // In Java, classes have an implicit static member "class".
+ if (Style.Language == FormatStyle::LK_Java && FormatTok &&
+ FormatTok->is(tok::kw_class))
+ nextToken();
+ break;
case tok::semi:
nextToken();
addUnwrappedLine();
@@ -783,17 +820,14 @@ void UnwrappedLineParser::parseStructuralElement() {
parseLabel();
return;
}
- // Recognize function-like macro usages without trailing semicolon.
- if (FormatTok->Tok.is(tok::l_paren)) {
+ // Recognize function-like macro usages without trailing semicolon as
+ // well as free-standing macrose like Q_OBJECT.
+ bool FunctionLike = FormatTok->is(tok::l_paren);
+ if (FunctionLike)
parseParens();
- if (FormatTok->NewlinesBefore > 0 &&
- tokenCanStartNewLine(FormatTok->Tok) && Text == Text.upper()) {
- addUnwrappedLine();
- return;
- }
- } else if (FormatTok->HasUnescapedNewline && Text.size() >= 5 &&
- Text == Text.upper()) {
- // Recognize free-standing macros like Q_OBJECT.
+ if (FormatTok->NewlinesBefore > 0 &&
+ (Text.size() >= 5 || FunctionLike) &&
+ tokenCanStartNewLine(FormatTok->Tok) && Text == Text.upper()) {
addUnwrappedLine();
return;
}
@@ -820,7 +854,8 @@ bool UnwrappedLineParser::tryToParseLambda() {
// 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) ||
+ (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())) {
nextToken();
@@ -842,6 +877,10 @@ bool UnwrappedLineParser::tryToParseLambda() {
case tok::l_paren:
parseParens();
break;
+ case tok::amp:
+ case tok::star:
+ case tok::kw_const:
+ case tok::comma:
case tok::less:
case tok::greater:
case tok::identifier:
@@ -947,7 +986,7 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
// replace this by using parseAssigmentExpression() inside.
do {
if (Style.Language == FormatStyle::LK_JavaScript &&
- FormatTok->TokenText == "function") {
+ FormatTok->is(Keywords.kw_function)) {
tryToParseJSFunction();
continue;
}
@@ -994,6 +1033,8 @@ void UnwrappedLineParser::parseParens() {
switch (FormatTok->Tok.getKind()) {
case tok::l_paren:
parseParens();
+ if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_brace))
+ parseChildBlock();
break;
case tok::r_paren:
nextToken();
@@ -1004,17 +1045,23 @@ void UnwrappedLineParser::parseParens() {
case tok::l_square:
tryToParseLambda();
break;
- case tok::l_brace: {
+ case tok::l_brace:
if (!tryToParseBracedList()) {
parseChildBlock();
}
break;
- }
case tok::at:
nextToken();
if (FormatTok->Tok.is(tok::l_brace))
parseBracedList();
break;
+ case tok::identifier:
+ if (Style.Language == FormatStyle::LK_JavaScript &&
+ FormatTok->is(Keywords.kw_function))
+ tryToParseJSFunction();
+ else
+ nextToken();
+ break;
default:
nextToken();
break;
@@ -1080,6 +1127,8 @@ void UnwrappedLineParser::parseIfThenElse() {
--Line->Level;
}
if (FormatTok->Tok.is(tok::kw_else)) {
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup)
+ addUnwrappedLine();
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
CompoundStatementIndenter Indenter(this, Style, Line->Level);
@@ -1115,6 +1164,10 @@ void UnwrappedLineParser::parseTryCatch() {
nextToken();
}
}
+ // Parse try with resource.
+ if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_paren)) {
+ parseParens();
+ }
if (FormatTok->is(tok::l_brace)) {
CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(/*MustBeDeclaration=*/false);
@@ -1136,8 +1189,9 @@ void UnwrappedLineParser::parseTryCatch() {
--Line->Level;
}
while (FormatTok->is(tok::kw_catch) ||
- (Style.Language == FormatStyle::LK_JavaScript &&
- FormatTok->TokenText == "finally")) {
+ ((Style.Language == FormatStyle::LK_Java ||
+ Style.Language == FormatStyle::LK_JavaScript) &&
+ FormatTok->is(Keywords.kw_finally))) {
nextToken();
while (FormatTok->isNot(tok::l_brace)) {
if (FormatTok->is(tok::l_paren)) {
@@ -1166,13 +1220,13 @@ void UnwrappedLineParser::parseTryCatch() {
void UnwrappedLineParser::parseNamespace() {
assert(FormatTok->Tok.is(tok::kw_namespace) && "'namespace' expected");
+
+ const FormatToken &InitialToken = *FormatTok;
nextToken();
if (FormatTok->Tok.is(tok::identifier))
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Linux ||
- Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
- Style.BreakBeforeBraces == FormatStyle::BS_GNU)
+ if (ShouldBreakBeforeBrace(Style, InitialToken))
addUnwrappedLine();
bool AddLevel = Style.NamespaceIndentation == FormatStyle::NI_All ||
@@ -1294,43 +1348,115 @@ void UnwrappedLineParser::parseAccessSpecifier() {
}
void UnwrappedLineParser::parseEnum() {
- if (FormatTok->Tok.is(tok::kw_enum)) {
- // Won't be 'enum' for NS_ENUMs.
+ // Won't be 'enum' for NS_ENUMs.
+ if (FormatTok->Tok.is(tok::kw_enum))
nextToken();
- }
+
// Eat up enum class ...
if (FormatTok->Tok.is(tok::kw_class) || FormatTok->Tok.is(tok::kw_struct))
nextToken();
while (FormatTok->Tok.getIdentifierInfo() ||
- FormatTok->isOneOf(tok::colon, tok::coloncolon)) {
+ FormatTok->isOneOf(tok::colon, tok::coloncolon, tok::less,
+ tok::greater, tok::comma, tok::question)) {
nextToken();
// We can have macros or attributes in between 'enum' and the enum name.
- if (FormatTok->Tok.is(tok::l_paren)) {
+ if (FormatTok->is(tok::l_paren))
parseParens();
- }
- if (FormatTok->Tok.is(tok::identifier))
+ if (FormatTok->is(tok::identifier))
nextToken();
}
- if (FormatTok->Tok.is(tok::l_brace)) {
- FormatTok->BlockKind = BK_Block;
- bool HasError = !parseBracedList(/*ContinueOnSemicolons=*/true);
- if (HasError) {
- if (FormatTok->is(tok::semi))
- nextToken();
- addUnwrappedLine();
- }
+
+ // Just a declaration or something is wrong.
+ if (FormatTok->isNot(tok::l_brace))
+ return;
+ FormatTok->BlockKind = BK_Block;
+
+ if (Style.Language == FormatStyle::LK_Java) {
+ // Java enums are different.
+ parseJavaEnumBody();
+ return;
}
+
+ // Parse enum body.
+ bool HasError = !parseBracedList(/*ContinueOnSemicolons=*/true);
+ if (HasError) {
+ if (FormatTok->is(tok::semi))
+ nextToken();
+ addUnwrappedLine();
+ }
+
// We fall through to parsing a structural element afterwards, so that in
// enum A {} n, m;
// "} n, m;" will end up in one unwrapped line.
}
+void UnwrappedLineParser::parseJavaEnumBody() {
+ // Determine whether the enum is simple, i.e. does not have a semicolon or
+ // constants with class bodies. Simple enums can be formatted like braced
+ // lists, contracted to a single line, etc.
+ unsigned StoredPosition = Tokens->getPosition();
+ bool IsSimple = true;
+ FormatToken *Tok = Tokens->getNextToken();
+ while (Tok) {
+ if (Tok->is(tok::r_brace))
+ break;
+ if (Tok->isOneOf(tok::l_brace, tok::semi)) {
+ IsSimple = false;
+ break;
+ }
+ // FIXME: This will also mark enums with braces in the arguments to enum
+ // constants as "not simple". This is probably fine in practice, though.
+ Tok = Tokens->getNextToken();
+ }
+ FormatTok = Tokens->setPosition(StoredPosition);
+
+ if (IsSimple) {
+ parseBracedList();
+ addUnwrappedLine();
+ return;
+ }
+
+ // Parse the body of a more complex enum.
+ // First add a line for everything up to the "{".
+ nextToken();
+ addUnwrappedLine();
+ ++Line->Level;
+
+ // Parse the enum constants.
+ while (FormatTok) {
+ if (FormatTok->is(tok::l_brace)) {
+ // Parse the constant's class body.
+ parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/true,
+ /*MunchSemi=*/false);
+ } else if (FormatTok->is(tok::l_paren)) {
+ parseParens();
+ } else if (FormatTok->is(tok::comma)) {
+ nextToken();
+ addUnwrappedLine();
+ } else if (FormatTok->is(tok::semi)) {
+ nextToken();
+ addUnwrappedLine();
+ break;
+ } else if (FormatTok->is(tok::r_brace)) {
+ addUnwrappedLine();
+ break;
+ } else {
+ nextToken();
+ }
+ }
+
+ // Parse the class body after the enum's ";" if any.
+ parseLevel(/*HasOpeningBrace=*/true);
+ nextToken();
+ --Line->Level;
+ addUnwrappedLine();
+}
+
void UnwrappedLineParser::parseRecord() {
+ const FormatToken &InitialToken = *FormatTok;
nextToken();
- if (FormatTok->Tok.is(tok::identifier) ||
- FormatTok->Tok.is(tok::kw___attribute) ||
- FormatTok->Tok.is(tok::kw___declspec) ||
- FormatTok->Tok.is(tok::kw_alignas)) {
+ if (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw___attribute,
+ tok::kw___declspec, tok::kw_alignas)) {
nextToken();
// We can have macros or attributes in between 'class' and the class name.
if (FormatTok->Tok.is(tok::l_paren)) {
@@ -1338,9 +1464,10 @@ void UnwrappedLineParser::parseRecord() {
}
// The actual identifier can be a nested name specifier, and in macros
// it is often token-pasted.
- while (FormatTok->Tok.is(tok::identifier) ||
- FormatTok->Tok.is(tok::coloncolon) ||
- FormatTok->Tok.is(tok::hashhash))
+ while (FormatTok->is(tok::identifier) || FormatTok->is(tok::coloncolon) ||
+ FormatTok->is(tok::hashhash) ||
+ (Style.Language == FormatStyle::LK_Java &&
+ FormatTok->isOneOf(tok::period, tok::comma)))
nextToken();
// Note that parsing away template declarations here leads to incorrectly
@@ -1362,9 +1489,7 @@ void UnwrappedLineParser::parseRecord() {
}
}
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BreakBeforeBraces == FormatStyle::BS_Linux ||
- Style.BreakBeforeBraces == FormatStyle::BS_Allman ||
- Style.BreakBeforeBraces == FormatStyle::BS_GNU)
+ if (ShouldBreakBeforeBrace(Style, InitialToken))
addUnwrappedLine();
parseBlock(/*MustBeDeclaration=*/true, /*AddLevel=*/true,
@@ -1373,6 +1498,9 @@ void UnwrappedLineParser::parseRecord() {
// We fall through to parsing a structural element afterwards, so
// class A {} n, m;
// will end up in one unwrapped line.
+ // This does not apply for Java.
+ if (Style.Language == FormatStyle::LK_Java)
+ addUnwrappedLine();
}
void UnwrappedLineParser::parseObjCProtocolList() {
OpenPOWER on IntegriCloud