[clang-format] Add experimental option to remove LLVM braces

See the style examples at:
https://llvm.org/docs/CodingStandards.html#don-t-use-braces-on-simple-single-statement-bodies-of-if-else-loop-statements

Differential Revision: https://reviews.llvm.org/D116316
This commit is contained in:
Owen Pan 2021-12-12 18:25:33 -08:00 committed by owenca
parent a4e255f9c6
commit 533fbae8d8
9 changed files with 774 additions and 28 deletions

View File

@ -3402,6 +3402,62 @@ the configuration (without a prefix: ``Auto``).
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
* information */ * information */
**RemoveBracesLLVM** (``Boolean``) :versionbadge:`clang-format 14`
Remove optional braces of control statements (``if``, ``else``, ``for``,
and ``while``) in C++ according to the LLVM coding style.
.. warning::
This option will be renamed and expanded to support other styles.
.. warning::
Setting this option to `true` could lead to incorrect code formatting due
to clang-format's lack of complete semantic information. As such, extra
care should be taken to review code changes made by this option.
.. code-block:: c++
false: true:
if (isa<FunctionDecl>(D)) { vs. if (isa<FunctionDecl>(D))
handleFunctionDecl(D); handleFunctionDecl(D);
} else if (isa<VarDecl>(D)) { else if (isa<VarDecl>(D))
handleVarDecl(D); handleVarDecl(D);
}
if (isa<VarDecl>(D)) { vs. if (isa<VarDecl>(D)) {
for (auto *A : D.attrs()) { for (auto *A : D.attrs())
if (shouldProcessAttr(A)) { if (shouldProcessAttr(A))
handleAttr(A); handleAttr(A);
} }
}
}
if (isa<FunctionDecl>(D)) { vs. if (isa<FunctionDecl>(D))
for (auto *A : D.attrs()) { for (auto *A : D.attrs())
handleAttr(A); handleAttr(A);
}
}
if (auto *D = (T)(D)) { vs. if (auto *D = (T)(D)) {
if (shouldProcess(D)) { if (shouldProcess(D))
handleVarDecl(D); handleVarDecl(D);
} else { else
markAsIgnored(D); markAsIgnored(D);
} }
}
if (a) { vs. if (a)
b(); b();
} else { else if (c)
if (c) { d();
d(); else
} else { e();
e();
}
}
**SeparateDefinitionBlocks** (``SeparateDefinitionStyle``) :versionbadge:`clang-format 14` **SeparateDefinitionBlocks** (``SeparateDefinitionStyle``) :versionbadge:`clang-format 14`
Specifies the use of empty lines to separate definition blocks, including Specifies the use of empty lines to separate definition blocks, including
classes, structs, enums, and functions. classes, structs, enums, and functions.

View File

@ -310,6 +310,9 @@ clang-format
`const` `volatile` `static` `inline` `constexpr` `restrict` `const` `volatile` `static` `inline` `constexpr` `restrict`
to be controlled relative to the `type`. to be controlled relative to the `type`.
- Option ``RemoveBracesLLVM`` has been added to remove optional braces of
control statements for the LLVM style.
- Option ``SeparateDefinitionBlocks`` has been added to insert or remove empty - Option ``SeparateDefinitionBlocks`` has been added to insert or remove empty
lines between definition blocks including functions, classes, structs, enums, lines between definition blocks including functions, classes, structs, enums,
and namespaces. and namespaces.

View File

@ -3049,6 +3049,60 @@ struct FormatStyle {
bool ReflowComments; bool ReflowComments;
// clang-format on // clang-format on
/// Remove optional braces of control statements (``if``, ``else``, ``for``,
/// and ``while``) in C++ according to the LLVM coding style.
/// \warning
/// This option will be renamed and expanded to support other styles.
/// \endwarning
/// \warning
/// Setting this option to `true` could lead to incorrect code formatting due
/// to clang-format's lack of complete semantic information. As such, extra
/// care should be taken to review code changes made by this option.
/// \endwarning
/// \code
/// false: true:
///
/// if (isa<FunctionDecl>(D)) { vs. if (isa<FunctionDecl>(D))
/// handleFunctionDecl(D); handleFunctionDecl(D);
/// } else if (isa<VarDecl>(D)) { else if (isa<VarDecl>(D))
/// handleVarDecl(D); handleVarDecl(D);
/// }
///
/// if (isa<VarDecl>(D)) { vs. if (isa<VarDecl>(D)) {
/// for (auto *A : D.attrs()) { for (auto *A : D.attrs())
/// if (shouldProcessAttr(A)) { if (shouldProcessAttr(A))
/// handleAttr(A); handleAttr(A);
/// } }
/// }
/// }
///
/// if (isa<FunctionDecl>(D)) { vs. if (isa<FunctionDecl>(D))
/// for (auto *A : D.attrs()) { for (auto *A : D.attrs())
/// handleAttr(A); handleAttr(A);
/// }
/// }
///
/// if (auto *D = (T)(D)) { vs. if (auto *D = (T)(D)) {
/// if (shouldProcess(D)) { if (shouldProcess(D))
/// handleVarDecl(D); handleVarDecl(D);
/// } else { else
/// markAsIgnored(D); markAsIgnored(D);
/// } }
/// }
///
/// if (a) { vs. if (a)
/// b(); b();
/// } else { else if (c)
/// if (c) { d();
/// d(); else
/// } else { e();
/// e();
/// }
/// }
/// \endcode
/// \version 14
bool RemoveBracesLLVM;
/// \brief The style if definition blocks should be separated. /// \brief The style if definition blocks should be separated.
enum SeparateDefinitionStyle { enum SeparateDefinitionStyle {
/// Leave definition blocks as they are. /// Leave definition blocks as they are.
@ -3858,6 +3912,7 @@ struct FormatStyle {
QualifierOrder == R.QualifierOrder && QualifierOrder == R.QualifierOrder &&
RawStringFormats == R.RawStringFormats && RawStringFormats == R.RawStringFormats &&
ReferenceAlignment == R.ReferenceAlignment && ReferenceAlignment == R.ReferenceAlignment &&
RemoveBracesLLVM == R.RemoveBracesLLVM &&
SeparateDefinitionBlocks == R.SeparateDefinitionBlocks && SeparateDefinitionBlocks == R.SeparateDefinitionBlocks &&
ShortNamespaceLines == R.ShortNamespaceLines && ShortNamespaceLines == R.ShortNamespaceLines &&
SortIncludes == R.SortIncludes && SortIncludes == R.SortIncludes &&

View File

@ -781,6 +781,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("RawStringFormats", Style.RawStringFormats); IO.mapOptional("RawStringFormats", Style.RawStringFormats);
IO.mapOptional("ReferenceAlignment", Style.ReferenceAlignment); IO.mapOptional("ReferenceAlignment", Style.ReferenceAlignment);
IO.mapOptional("ReflowComments", Style.ReflowComments); IO.mapOptional("ReflowComments", Style.ReflowComments);
IO.mapOptional("RemoveBracesLLVM", Style.RemoveBracesLLVM);
IO.mapOptional("SeparateDefinitionBlocks", Style.SeparateDefinitionBlocks); IO.mapOptional("SeparateDefinitionBlocks", Style.SeparateDefinitionBlocks);
IO.mapOptional("ShortNamespaceLines", Style.ShortNamespaceLines); IO.mapOptional("ShortNamespaceLines", Style.ShortNamespaceLines);
IO.mapOptional("SortIncludes", Style.SortIncludes); IO.mapOptional("SortIncludes", Style.SortIncludes);
@ -1214,6 +1215,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.UseCRLF = false; LLVMStyle.UseCRLF = false;
LLVMStyle.UseTab = FormatStyle::UT_Never; LLVMStyle.UseTab = FormatStyle::UT_Never;
LLVMStyle.ReflowComments = true; LLVMStyle.ReflowComments = true;
LLVMStyle.RemoveBracesLLVM = false;
LLVMStyle.SpacesInParentheses = false; LLVMStyle.SpacesInParentheses = false;
LLVMStyle.SpacesInSquareBrackets = false; LLVMStyle.SpacesInSquareBrackets = false;
LLVMStyle.SpaceInEmptyBlock = false; LLVMStyle.SpaceInEmptyBlock = false;
@ -1748,6 +1750,45 @@ FormatStyle::GetLanguageStyle(FormatStyle::LanguageKind Language) const {
namespace { namespace {
class BracesRemover : public TokenAnalyzer {
public:
BracesRemover(const Environment &Env, const FormatStyle &Style)
: TokenAnalyzer(Env, Style) {}
std::pair<tooling::Replacements, unsigned>
analyze(TokenAnnotator &Annotator,
SmallVectorImpl<AnnotatedLine *> &AnnotatedLines,
FormatTokenLexer &Tokens) override {
AffectedRangeMgr.computeAffectedLines(AnnotatedLines);
tooling::Replacements Result;
removeBraces(AnnotatedLines, Result);
return {Result, 0};
}
private:
// Remove optional braces.
void removeBraces(SmallVectorImpl<AnnotatedLine *> &Lines,
tooling::Replacements &Result) {
const auto &SourceMgr = Env.getSourceManager();
for (AnnotatedLine *Line : Lines) {
removeBraces(Line->Children, Result);
if (!Line->Affected)
continue;
for (FormatToken *Token = Line->First; Token; Token = Token->Next) {
if (!Token->Optional)
continue;
assert(Token->isOneOf(tok::l_brace, tok::r_brace));
const auto Start = Token == Line->Last
? Token->WhitespaceRange.getBegin()
: Token->Tok.getLocation();
const auto Range =
CharSourceRange::getCharRange(Start, Token->Tok.getEndLoc());
cantFail(Result.add(tooling::Replacement(SourceMgr, Range, "")));
}
}
}
};
class JavaScriptRequoter : public TokenAnalyzer { class JavaScriptRequoter : public TokenAnalyzer {
public: public:
JavaScriptRequoter(const Environment &Env, const FormatStyle &Style) JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
@ -3049,6 +3090,11 @@ reformat(const FormatStyle &Style, StringRef Code,
}); });
} }
if (Style.isCpp() && Style.RemoveBracesLLVM)
Passes.emplace_back([&](const Environment &Env) {
return BracesRemover(Env, Expanded).process();
});
if (Style.Language == FormatStyle::LK_Cpp) { if (Style.Language == FormatStyle::LK_Cpp) {
if (Style.FixNamespaceComments) if (Style.FixNamespaceComments)
Passes.emplace_back([&](const Environment &Env) { Passes.emplace_back([&](const Environment &Env) {

View File

@ -442,6 +442,9 @@ public:
/// This starts an array initializer. /// This starts an array initializer.
bool IsArrayInitializer = false; bool IsArrayInitializer = false;
/// Is optional and can be removed.
bool Optional = false;
/// If this token starts a block, this contains all the unwrapped lines /// If this token starts a block, this contains all the unwrapped lines
/// in it. /// in it.
SmallVector<AnnotatedLine *, 1> Children; SmallVector<AnnotatedLine *, 1> Children;

View File

@ -780,6 +780,7 @@ private:
unsigned CommaCount = 0; unsigned CommaCount = 0;
while (CurrentToken) { while (CurrentToken) {
if (CurrentToken->is(tok::r_brace)) { if (CurrentToken->is(tok::r_brace)) {
assert(Left->Optional == CurrentToken->Optional);
Left->MatchingParen = CurrentToken; Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left; CurrentToken->MatchingParen = Left;
if (Style.AlignArrayOfStructures != FormatStyle::AIAS_None) { if (Style.AlignArrayOfStructures != FormatStyle::AIAS_None) {

View File

@ -14,6 +14,7 @@
#include "UnwrappedLineParser.h" #include "UnwrappedLineParser.h"
#include "FormatToken.h" #include "FormatToken.h"
#include "TokenAnnotator.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
@ -315,6 +316,7 @@ void UnwrappedLineParser::reset() {
PreprocessorDirectives.clear(); PreprocessorDirectives.clear();
CurrentLines = &Lines; CurrentLines = &Lines;
DeclarationScopeStack.clear(); DeclarationScopeStack.clear();
NestedTooDeep.clear();
PPStack.clear(); PPStack.clear();
Line->FirstStartColumn = FirstStartColumn; Line->FirstStartColumn = FirstStartColumn;
} }
@ -428,7 +430,47 @@ void UnwrappedLineParser::parseCSharpAttribute() {
} while (!eof()); } while (!eof());
} }
void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { bool UnwrappedLineParser::precededByCommentOrPPDirective() const {
if (!Lines.empty() && Lines.back().InPPDirective)
return true;
const FormatToken *Previous = Tokens->getPreviousToken();
return Previous && Previous->is(tok::comment) &&
(Previous->IsMultiline || Previous->NewlinesBefore > 0);
}
bool UnwrappedLineParser::mightFitOnOneLine() const {
const auto ColumnLimit = Style.ColumnLimit;
if (ColumnLimit == 0)
return true;
if (Lines.empty())
return true;
const auto &PreviousLine = Lines.back();
const auto &Tokens = PreviousLine.Tokens;
assert(!Tokens.empty());
const auto *LastToken = Tokens.back().Tok;
assert(LastToken);
if (!LastToken->isOneOf(tok::semi, tok::comment))
return true;
AnnotatedLine Line(PreviousLine);
assert(Line.Last == LastToken);
TokenAnnotator Annotator(Style, Keywords);
Annotator.annotate(Line);
Annotator.calculateFormattingInformation(Line);
return Line.Level * Style.IndentWidth + LastToken->TotalLength <= ColumnLimit;
}
// Returns true if a simple block, or false otherwise. (A simple block has a
// single statement that fits on a single line.)
bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace, IfStmtKind *IfKind) {
const bool IsPrecededByCommentOrPPDirective =
!Style.RemoveBracesLLVM || precededByCommentOrPPDirective();
unsigned StatementCount = 0;
bool SwitchLabelEncountered = false; bool SwitchLabelEncountered = false;
do { do {
tok::TokenKind kind = FormatTok->Tok.getKind(); tok::TokenKind kind = FormatTok->Tok.getKind();
@ -449,11 +491,24 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
if (!FormatTok->is(TT_MacroBlockBegin) && tryToParseBracedList()) if (!FormatTok->is(TT_MacroBlockBegin) && tryToParseBracedList())
continue; continue;
parseBlock(); parseBlock();
++StatementCount;
assert(StatementCount > 0 && "StatementCount overflow!");
addUnwrappedLine(); addUnwrappedLine();
break; break;
case tok::r_brace: case tok::r_brace:
if (HasOpeningBrace) if (HasOpeningBrace) {
return; if (!Style.RemoveBracesLLVM)
return false;
if (FormatTok->isNot(tok::r_brace) || StatementCount != 1 ||
IsPrecededByCommentOrPPDirective ||
precededByCommentOrPPDirective()) {
return false;
}
const FormatToken *Next = Tokens->peekNextToken();
if (Next->is(tok::comment) && Next->NewlinesBefore == 0)
return false;
return mightFitOnOneLine();
}
nextToken(); nextToken();
addUnwrappedLine(); addUnwrappedLine();
break; break;
@ -493,10 +548,13 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
} }
LLVM_FALLTHROUGH; LLVM_FALLTHROUGH;
default: default:
parseStructuralElement(!HasOpeningBrace); parseStructuralElement(IfKind, !HasOpeningBrace);
++StatementCount;
assert(StatementCount > 0 && "StatementCount overflow!");
break; break;
} }
} while (!eof()); } while (!eof());
return false;
} }
void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
@ -652,11 +710,13 @@ size_t UnwrappedLineParser::computePPHash() const {
return h; return h;
} }
void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels, UnwrappedLineParser::IfStmtKind
bool MunchSemi, UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels,
bool UnindentWhitesmithsBraces) { bool MunchSemi,
bool UnindentWhitesmithsBraces) {
assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) && assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) &&
"'{' or macro block token expected"); "'{' or macro block token expected");
FormatToken *Tok = FormatTok;
const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin); const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin);
FormatTok->setBlockKind(BK_Block); FormatTok->setBlockKind(BK_Block);
@ -691,16 +751,28 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels,
MustBeDeclaration); MustBeDeclaration);
if (AddLevels > 0u && Style.BreakBeforeBraces != FormatStyle::BS_Whitesmiths) if (AddLevels > 0u && Style.BreakBeforeBraces != FormatStyle::BS_Whitesmiths)
Line->Level += AddLevels; Line->Level += AddLevels;
parseLevel(/*HasOpeningBrace=*/true);
IfStmtKind IfKind = IfStmtKind::NotIf;
const bool SimpleBlock = parseLevel(/*HasOpeningBrace=*/true, &IfKind);
if (eof()) if (eof())
return; return IfKind;
if (MacroBlock ? !FormatTok->is(TT_MacroBlockEnd) if (MacroBlock ? !FormatTok->is(TT_MacroBlockEnd)
: !FormatTok->is(tok::r_brace)) { : !FormatTok->is(tok::r_brace)) {
Line->Level = InitialLevel; Line->Level = InitialLevel;
FormatTok->setBlockKind(BK_Block); FormatTok->setBlockKind(BK_Block);
return; return IfKind;
}
if (SimpleBlock && Tok->is(tok::l_brace)) {
assert(FormatTok->is(tok::r_brace));
const FormatToken *Previous = Tokens->getPreviousToken();
assert(Previous);
if (Previous->isNot(tok::r_brace) || Previous->Optional) {
Tok->MatchingParen = FormatTok;
FormatTok->MatchingParen = Tok;
}
} }
size_t PPEndHash = computePPHash(); size_t PPEndHash = computePPHash();
@ -731,6 +803,8 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, unsigned AddLevels,
CurrentLines->size() - 1; CurrentLines->size() - 1;
} }
} }
return IfKind;
} }
static bool isGoogScope(const UnwrappedLine &Line) { static bool isGoogScope(const UnwrappedLine &Line) {
@ -1185,7 +1259,8 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() {
return addUnwrappedLine(); return addUnwrappedLine();
} }
void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { void UnwrappedLineParser::parseStructuralElement(IfStmtKind *IfKind,
bool IsTopLevel) {
if (Style.Language == FormatStyle::LK_TableGen && if (Style.Language == FormatStyle::LK_TableGen &&
FormatTok->is(tok::pp_include)) { FormatTok->is(tok::pp_include)) {
nextToken(); nextToken();
@ -1228,7 +1303,7 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) {
if (Style.isJavaScript() && Line->MustBeDeclaration) if (Style.isJavaScript() && Line->MustBeDeclaration)
// field/method declaration. // field/method declaration.
break; break;
parseIfThenElse(); parseIfThenElse(IfKind);
return; return;
case tok::kw_for: case tok::kw_for:
case tok::kw_while: case tok::kw_while:
@ -2138,7 +2213,39 @@ void UnwrappedLineParser::parseSquare(bool LambdaIntroducer) {
} while (!eof()); } while (!eof());
} }
void UnwrappedLineParser::parseIfThenElse() { void UnwrappedLineParser::keepAncestorBraces() {
if (!Style.RemoveBracesLLVM)
return;
const int MaxNestingLevels = 2;
const int Size = NestedTooDeep.size();
if (Size >= MaxNestingLevels)
NestedTooDeep[Size - MaxNestingLevels] = true;
NestedTooDeep.push_back(false);
}
static void markOptionalBraces(FormatToken *LeftBrace) {
if (!LeftBrace)
return;
assert(LeftBrace->is(tok::l_brace));
FormatToken *RightBrace = LeftBrace->MatchingParen;
if (!RightBrace) {
assert(!LeftBrace->Optional);
return;
}
assert(RightBrace->is(tok::r_brace));
assert(RightBrace->MatchingParen == LeftBrace);
assert(LeftBrace->Optional == RightBrace->Optional);
LeftBrace->Optional = true;
RightBrace->Optional = true;
}
FormatToken *UnwrappedLineParser::parseIfThenElse(IfStmtKind *IfKind,
bool KeepBraces) {
auto HandleAttributes = [this]() { auto HandleAttributes = [this]() {
// Handle AttributeMacro, e.g. `if (x) UNLIKELY`. // Handle AttributeMacro, e.g. `if (x) UNLIKELY`.
if (FormatTok->is(TT_AttributeMacro)) if (FormatTok->is(TT_AttributeMacro))
@ -2155,10 +2262,17 @@ void UnwrappedLineParser::parseIfThenElse() {
if (FormatTok->Tok.is(tok::l_paren)) if (FormatTok->Tok.is(tok::l_paren))
parseParens(); parseParens();
HandleAttributes(); HandleAttributes();
bool NeedsUnwrappedLine = false; bool NeedsUnwrappedLine = false;
keepAncestorBraces();
FormatToken *IfLeftBrace = nullptr;
IfStmtKind IfBlockKind = IfStmtKind::NotIf;
if (FormatTok->Tok.is(tok::l_brace)) { if (FormatTok->Tok.is(tok::l_brace)) {
IfLeftBrace = FormatTok;
CompoundStatementIndenter Indenter(this, Style, Line->Level); CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(); IfBlockKind = parseBlock();
if (Style.BraceWrapping.BeforeElse) if (Style.BraceWrapping.BeforeElse)
addUnwrappedLine(); addUnwrappedLine();
else else
@ -2169,22 +2283,48 @@ void UnwrappedLineParser::parseIfThenElse() {
parseStructuralElement(); parseStructuralElement();
--Line->Level; --Line->Level;
} }
bool KeepIfBraces = false;
if (Style.RemoveBracesLLVM) {
assert(!NestedTooDeep.empty());
KeepIfBraces = (IfLeftBrace && !IfLeftBrace->MatchingParen) ||
NestedTooDeep.back() || IfBlockKind == IfStmtKind::IfOnly ||
IfBlockKind == IfStmtKind::IfElseIf;
}
FormatToken *ElseLeftBrace = nullptr;
IfStmtKind Kind = IfStmtKind::IfOnly;
if (FormatTok->Tok.is(tok::kw_else)) { if (FormatTok->Tok.is(tok::kw_else)) {
if (Style.RemoveBracesLLVM) {
NestedTooDeep.back() = false;
Kind = IfStmtKind::IfElse;
}
nextToken(); nextToken();
HandleAttributes(); HandleAttributes();
if (FormatTok->Tok.is(tok::l_brace)) { if (FormatTok->Tok.is(tok::l_brace)) {
ElseLeftBrace = FormatTok;
CompoundStatementIndenter Indenter(this, Style, Line->Level); CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(); if (parseBlock() == IfStmtKind::IfOnly)
Kind = IfStmtKind::IfElseIf;
addUnwrappedLine(); addUnwrappedLine();
} else if (FormatTok->Tok.is(tok::kw_if)) { } else if (FormatTok->Tok.is(tok::kw_if)) {
FormatToken *Previous = Tokens->getPreviousToken(); FormatToken *Previous = Tokens->getPreviousToken();
bool PrecededByComment = Previous && Previous->is(tok::comment); const bool IsPrecededByComment = Previous && Previous->is(tok::comment);
if (PrecededByComment) { if (IsPrecededByComment) {
addUnwrappedLine(); addUnwrappedLine();
++Line->Level; ++Line->Level;
} }
parseIfThenElse(); bool TooDeep = true;
if (PrecededByComment) if (Style.RemoveBracesLLVM) {
Kind = IfStmtKind::IfElseIf;
TooDeep = NestedTooDeep.pop_back_val();
}
ElseLeftBrace =
parseIfThenElse(/*IfKind=*/nullptr, KeepBraces || KeepIfBraces);
if (Style.RemoveBracesLLVM)
NestedTooDeep.push_back(TooDeep);
if (IsPrecededByComment)
--Line->Level; --Line->Level;
} else { } else {
addUnwrappedLine(); addUnwrappedLine();
@ -2194,9 +2334,40 @@ void UnwrappedLineParser::parseIfThenElse() {
addUnwrappedLine(); addUnwrappedLine();
--Line->Level; --Line->Level;
} }
} else if (NeedsUnwrappedLine) { } else {
addUnwrappedLine(); if (Style.RemoveBracesLLVM)
KeepIfBraces = KeepIfBraces || IfBlockKind == IfStmtKind::IfElse;
if (NeedsUnwrappedLine)
addUnwrappedLine();
} }
if (!Style.RemoveBracesLLVM)
return nullptr;
assert(!NestedTooDeep.empty());
const bool KeepElseBraces =
(ElseLeftBrace && !ElseLeftBrace->MatchingParen) || NestedTooDeep.back();
NestedTooDeep.pop_back();
if (!KeepBraces && !KeepIfBraces && !KeepElseBraces) {
markOptionalBraces(IfLeftBrace);
markOptionalBraces(ElseLeftBrace);
} else if (IfLeftBrace) {
FormatToken *IfRightBrace = IfLeftBrace->MatchingParen;
if (IfRightBrace) {
assert(IfRightBrace->MatchingParen == IfLeftBrace);
assert(!IfLeftBrace->Optional);
assert(!IfRightBrace->Optional);
IfLeftBrace->MatchingParen = nullptr;
IfRightBrace->MatchingParen = nullptr;
}
}
if (IfKind)
*IfKind = Kind;
return IfLeftBrace;
} }
void UnwrappedLineParser::parseTryCatch() { void UnwrappedLineParser::parseTryCatch() {
@ -2234,6 +2405,9 @@ void UnwrappedLineParser::parseTryCatch() {
if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_paren)) { if (Style.Language == FormatStyle::LK_Java && FormatTok->is(tok::l_paren)) {
parseParens(); parseParens();
} }
keepAncestorBraces();
if (FormatTok->is(tok::l_brace)) { if (FormatTok->is(tok::l_brace)) {
CompoundStatementIndenter Indenter(this, Style, Line->Level); CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(); parseBlock();
@ -2267,8 +2441,11 @@ void UnwrappedLineParser::parseTryCatch() {
parseParens(); parseParens();
continue; continue;
} }
if (FormatTok->isOneOf(tok::semi, tok::r_brace, tok::eof)) if (FormatTok->isOneOf(tok::semi, tok::r_brace, tok::eof)) {
if (Style.RemoveBracesLLVM)
NestedTooDeep.pop_back();
return; return;
}
nextToken(); nextToken();
} }
NeedsUnwrappedLine = false; NeedsUnwrappedLine = false;
@ -2279,6 +2456,10 @@ void UnwrappedLineParser::parseTryCatch() {
else else
NeedsUnwrappedLine = true; NeedsUnwrappedLine = true;
} }
if (Style.RemoveBracesLLVM)
NestedTooDeep.pop_back();
if (NeedsUnwrappedLine) if (NeedsUnwrappedLine)
addUnwrappedLine(); addUnwrappedLine();
} }
@ -2385,9 +2566,18 @@ void UnwrappedLineParser::parseForOrWhileLoop() {
nextToken(); nextToken();
if (FormatTok->Tok.is(tok::l_paren)) if (FormatTok->Tok.is(tok::l_paren))
parseParens(); parseParens();
keepAncestorBraces();
if (FormatTok->Tok.is(tok::l_brace)) { if (FormatTok->Tok.is(tok::l_brace)) {
FormatToken *LeftBrace = FormatTok;
CompoundStatementIndenter Indenter(this, Style, Line->Level); CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(); parseBlock();
if (Style.RemoveBracesLLVM) {
assert(!NestedTooDeep.empty());
if (!NestedTooDeep.back())
markOptionalBraces(LeftBrace);
}
addUnwrappedLine(); addUnwrappedLine();
} else { } else {
addUnwrappedLine(); addUnwrappedLine();
@ -2395,11 +2585,17 @@ void UnwrappedLineParser::parseForOrWhileLoop() {
parseStructuralElement(); parseStructuralElement();
--Line->Level; --Line->Level;
} }
if (Style.RemoveBracesLLVM)
NestedTooDeep.pop_back();
} }
void UnwrappedLineParser::parseDoWhile() { void UnwrappedLineParser::parseDoWhile() {
assert(FormatTok->Tok.is(tok::kw_do) && "'do' expected"); assert(FormatTok->Tok.is(tok::kw_do) && "'do' expected");
nextToken(); nextToken();
keepAncestorBraces();
if (FormatTok->Tok.is(tok::l_brace)) { if (FormatTok->Tok.is(tok::l_brace)) {
CompoundStatementIndenter Indenter(this, Style, Line->Level); CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(); parseBlock();
@ -2412,6 +2608,9 @@ void UnwrappedLineParser::parseDoWhile() {
--Line->Level; --Line->Level;
} }
if (Style.RemoveBracesLLVM)
NestedTooDeep.pop_back();
// FIXME: Add error handling. // FIXME: Add error handling.
if (!FormatTok->Tok.is(tok::kw_while)) { if (!FormatTok->Tok.is(tok::kw_while)) {
addUnwrappedLine(); addUnwrappedLine();
@ -2481,6 +2680,9 @@ void UnwrappedLineParser::parseSwitch() {
nextToken(); nextToken();
if (FormatTok->Tok.is(tok::l_paren)) if (FormatTok->Tok.is(tok::l_paren))
parseParens(); parseParens();
keepAncestorBraces();
if (FormatTok->Tok.is(tok::l_brace)) { if (FormatTok->Tok.is(tok::l_brace)) {
CompoundStatementIndenter Indenter(this, Style, Line->Level); CompoundStatementIndenter Indenter(this, Style, Line->Level);
parseBlock(); parseBlock();
@ -2491,6 +2693,9 @@ void UnwrappedLineParser::parseSwitch() {
parseStructuralElement(); parseStructuralElement();
--Line->Level; --Line->Level;
} }
if (Style.RemoveBracesLLVM)
NestedTooDeep.pop_back();
} }
void UnwrappedLineParser::parseAccessSpecifier() { void UnwrappedLineParser::parseAccessSpecifier() {

View File

@ -81,12 +81,21 @@ public:
void parse(); void parse();
private: private:
enum class IfStmtKind {
NotIf, // Not an if statement.
IfOnly, // An if statement without the else clause.
IfElse, // An if statement followed by else but not else if.
IfElseIf // An if statement followed by else if.
};
void reset(); void reset();
void parseFile(); void parseFile();
void parseLevel(bool HasOpeningBrace); bool precededByCommentOrPPDirective() const;
void parseBlock(bool MustBeDeclaration = false, unsigned AddLevels = 1u, bool mightFitOnOneLine() const;
bool MunchSemi = true, bool parseLevel(bool HasOpeningBrace, IfStmtKind *IfKind = nullptr);
bool UnindentWhitesmithsBraces = false); IfStmtKind parseBlock(bool MustBeDeclaration = false, unsigned AddLevels = 1u,
bool MunchSemi = true,
bool UnindentWhitesmithsBraces = false);
void parseChildBlock(); void parseChildBlock();
void parsePPDirective(); void parsePPDirective();
void parsePPDefine(); void parsePPDefine();
@ -96,13 +105,15 @@ private:
void parsePPEndIf(); void parsePPEndIf();
void parsePPUnknown(); void parsePPUnknown();
void readTokenWithJavaScriptASI(); void readTokenWithJavaScriptASI();
void parseStructuralElement(bool IsTopLevel = false); void parseStructuralElement(IfStmtKind *IfKind = nullptr,
bool IsTopLevel = false);
bool tryToParseBracedList(); bool tryToParseBracedList();
bool parseBracedList(bool ContinueOnSemicolons = false, bool IsEnum = false, bool parseBracedList(bool ContinueOnSemicolons = false, bool IsEnum = false,
tok::TokenKind ClosingBraceKind = tok::r_brace); tok::TokenKind ClosingBraceKind = tok::r_brace);
void parseParens(); void parseParens();
void parseSquare(bool LambdaIntroducer = false); void parseSquare(bool LambdaIntroducer = false);
void parseIfThenElse(); void keepAncestorBraces();
FormatToken *parseIfThenElse(IfStmtKind *IfKind, bool KeepBraces = false);
void parseTryCatch(); void parseTryCatch();
void parseForOrWhileLoop(); void parseForOrWhileLoop();
void parseDoWhile(); void parseDoWhile();
@ -235,6 +246,10 @@ private:
// owned outside of and handed into the UnwrappedLineParser. // owned outside of and handed into the UnwrappedLineParser.
ArrayRef<FormatToken *> AllTokens; ArrayRef<FormatToken *> AllTokens;
// Keeps a stack of the states of nested control statements (true if the
// statement contains more than some predefined number of nested statements).
SmallVector<bool, 8> NestedTooDeep;
// Represents preprocessor branch type, so we can find matching // Represents preprocessor branch type, so we can find matching
// #if/#else/#endif directives. // #if/#else/#endif directives.
enum PPBranchKind { enum PPBranchKind {

View File

@ -18889,6 +18889,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList); CHECK_PARSE_BOOL(ObjCSpaceBeforeProtocolList);
CHECK_PARSE_BOOL(Cpp11BracedListStyle); CHECK_PARSE_BOOL(Cpp11BracedListStyle);
CHECK_PARSE_BOOL(ReflowComments); CHECK_PARSE_BOOL(ReflowComments);
CHECK_PARSE_BOOL(RemoveBracesLLVM);
CHECK_PARSE_BOOL(SortUsingDeclarations); CHECK_PARSE_BOOL(SortUsingDeclarations);
CHECK_PARSE_BOOL(SpacesInParentheses); CHECK_PARSE_BOOL(SpacesInParentheses);
CHECK_PARSE_BOOL(SpacesInSquareBrackets); CHECK_PARSE_BOOL(SpacesInSquareBrackets);
@ -23334,6 +23335,367 @@ TEST_F(FormatTest, ShortTemplatedArgumentLists) {
verifyFormat("struct Z : X<decltype([] { return 0; }){}> {};", Style); verifyFormat("struct Z : X<decltype([] { return 0; }){}> {};", Style);
} }
TEST_F(FormatTest, RemoveBraces) {
FormatStyle Style = getLLVMStyle();
Style.RemoveBracesLLVM = true;
// The following eight test cases are fully-braced versions of the examples at
// "llvm.org/docs/CodingStandards.html#don-t-use-braces-on-simple-single-
// statement-bodies-of-if-else-loop-statements".
// 1. Omit the braces, since the body is simple and clearly associated with
// the if.
verifyFormat("if (isa<FunctionDecl>(D))\n"
" handleFunctionDecl(D);\n"
"else if (isa<VarDecl>(D))\n"
" handleVarDecl(D);",
"if (isa<FunctionDecl>(D)) {\n"
" handleFunctionDecl(D);\n"
"} else if (isa<VarDecl>(D)) {\n"
" handleVarDecl(D);\n"
"}",
Style);
// 2. Here we document the condition itself and not the body.
verifyFormat("if (isa<VarDecl>(D)) {\n"
" // It is necessary that we explain the situation with this\n"
" // surprisingly long comment, so it would be unclear\n"
" // without the braces whether the following statement is in\n"
" // the scope of the `if`.\n"
" // Because the condition is documented, we can't really\n"
" // hoist this comment that applies to the body above the\n"
" // if.\n"
" handleOtherDecl(D);\n"
"}",
Style);
// 3. Use braces on the outer `if` to avoid a potential dangling else
// situation.
verifyFormat("if (isa<VarDecl>(D)) {\n"
" for (auto *A : D.attrs())\n"
" if (shouldProcessAttr(A))\n"
" handleAttr(A);\n"
"}",
"if (isa<VarDecl>(D)) {\n"
" for (auto *A : D.attrs()) {\n"
" if (shouldProcessAttr(A)) {\n"
" handleAttr(A);\n"
" }\n"
" }\n"
"}",
Style);
// 4. Use braces for the `if` block to keep it uniform with the else block.
verifyFormat("if (isa<FunctionDecl>(D)) {\n"
" handleFunctionDecl(D);\n"
"} else {\n"
" // In this else case, it is necessary that we explain the\n"
" // situation with this surprisingly long comment, so it\n"
" // would be unclear without the braces whether the\n"
" // following statement is in the scope of the `if`.\n"
" handleOtherDecl(D);\n"
"}",
Style);
// 5. This should also omit braces. The `for` loop contains only a single
// statement, so it shouldn't have braces. The `if` also only contains a
// single simple statement (the for loop), so it also should omit braces.
verifyFormat("if (isa<FunctionDecl>(D))\n"
" for (auto *A : D.attrs())\n"
" handleAttr(A);",
"if (isa<FunctionDecl>(D)) {\n"
" for (auto *A : D.attrs()) {\n"
" handleAttr(A);\n"
" }\n"
"}",
Style);
// 6. Use braces for the outer `if` since the nested `for` is braced.
verifyFormat("if (isa<FunctionDecl>(D)) {\n"
" for (auto *A : D.attrs()) {\n"
" // In this for loop body, it is necessary that we explain\n"
" // the situation with this surprisingly long comment,\n"
" // forcing braces on the `for` block.\n"
" handleAttr(A);\n"
" }\n"
"}",
Style);
// 7. Use braces on the outer block because there are more than two levels of
// nesting.
verifyFormat("if (isa<FunctionDecl>(D)) {\n"
" for (auto *A : D.attrs())\n"
" for (ssize_t i : llvm::seq<ssize_t>(count))\n"
" handleAttrOnDecl(D, A, i);\n"
"}",
"if (isa<FunctionDecl>(D)) {\n"
" for (auto *A : D.attrs()) {\n"
" for (ssize_t i : llvm::seq<ssize_t>(count)) {\n"
" handleAttrOnDecl(D, A, i);\n"
" }\n"
" }\n"
"}",
Style);
// 8. Use braces on the outer block because of a nested `if`, otherwise the
// compiler would warn: `add explicit braces to avoid dangling else`
verifyFormat("if (auto *D = dyn_cast<FunctionDecl>(D)) {\n"
" if (shouldProcess(D))\n"
" handleVarDecl(D);\n"
" else\n"
" markAsIgnored(D);\n"
"}",
"if (auto *D = dyn_cast<FunctionDecl>(D)) {\n"
" if (shouldProcess(D)) {\n"
" handleVarDecl(D);\n"
" } else {\n"
" markAsIgnored(D);\n"
" }\n"
"}",
Style);
verifyFormat("if (a)\n"
" b; // comment\n"
"else if (c)\n"
" d; /* comment */\n"
"else\n"
" e;",
"if (a) {\n"
" b; // comment\n"
"} else if (c) {\n"
" d; /* comment */\n"
"} else {\n"
" e;\n"
"}",
Style);
verifyFormat("if (a) {\n"
" b;\n"
" c;\n"
"} else if (d) {\n"
" e;\n"
"}",
Style);
verifyFormat("if (a) {\n"
"#undef NDEBUG\n"
" b;\n"
"} else {\n"
" c;\n"
"}",
Style);
verifyFormat("if (a) {\n"
" // comment\n"
"} else if (b) {\n"
" c;\n"
"}",
Style);
verifyFormat("if (a) {\n"
" b;\n"
"} else {\n"
" { c; }\n"
"}",
Style);
verifyFormat("if (a) {\n"
" if (b) // comment\n"
" c;\n"
"} else if (d) {\n"
" e;\n"
"}",
"if (a) {\n"
" if (b) { // comment\n"
" c;\n"
" }\n"
"} else if (d) {\n"
" e;\n"
"}",
Style);
verifyFormat("if (a) {\n"
" if (b) {\n"
" c;\n"
" // comment\n"
" } else if (d) {\n"
" e;\n"
" }\n"
"}",
Style);
verifyFormat("if (a) {\n"
" if (b)\n"
" c;\n"
"}",
"if (a) {\n"
" if (b) {\n"
" c;\n"
" }\n"
"}",
Style);
verifyFormat("if (a)\n"
" if (b)\n"
" c;\n"
" else\n"
" d;\n"
"else\n"
" e;",
"if (a) {\n"
" if (b) {\n"
" c;\n"
" } else {\n"
" d;\n"
" }\n"
"} else {\n"
" e;\n"
"}",
Style);
verifyFormat("if (a) {\n"
" // comment\n"
" if (b)\n"
" c;\n"
" else if (d)\n"
" e;\n"
"} else {\n"
" g;\n"
"}",
"if (a) {\n"
" // comment\n"
" if (b) {\n"
" c;\n"
" } else if (d) {\n"
" e;\n"
" }\n"
"} else {\n"
" g;\n"
"}",
Style);
verifyFormat("if (a)\n"
" b;\n"
"else if (c)\n"
" d;\n"
"else\n"
" e;",
"if (a) {\n"
" b;\n"
"} else {\n"
" if (c) {\n"
" d;\n"
" } else {\n"
" e;\n"
" }\n"
"}",
Style);
verifyFormat("if (a) {\n"
" if (b)\n"
" c;\n"
" else if (d)\n"
" e;\n"
"} else {\n"
" g;\n"
"}",
"if (a) {\n"
" if (b)\n"
" c;\n"
" else {\n"
" if (d)\n"
" e;\n"
" }\n"
"} else {\n"
" g;\n"
"}",
Style);
verifyFormat("if (a)\n"
" b;\n"
"else if (c)\n"
" while (d)\n"
" e;\n"
"// comment",
"if (a)\n"
"{\n"
" b;\n"
"} else if (c) {\n"
" while (d) {\n"
" e;\n"
" }\n"
"}\n"
"// comment",
Style);
verifyFormat("if (a) {\n"
" b;\n"
"} else if (c) {\n"
" d;\n"
"} else {\n"
" e;\n"
" g;\n"
"}",
Style);
verifyFormat("if (a) {\n"
" b;\n"
"} else if (c) {\n"
" d;\n"
"} else {\n"
" e;\n"
"} // comment",
Style);
verifyFormat("int abs = [](int i) {\n"
" if (i >= 0)\n"
" return i;\n"
" return -i;\n"
"};",
"int abs = [](int i) {\n"
" if (i >= 0) {\n"
" return i;\n"
" }\n"
" return -i;\n"
"};",
Style);
Style.ColumnLimit = 20;
verifyFormat("if (a) {\n"
" b = c + // 1 -\n"
" d;\n"
"}",
Style);
verifyFormat("if (a) {\n"
" b = c >= 0 ? d\n"
" : e;\n"
"}",
"if (a) {\n"
" b = c >= 0 ? d : e;\n"
"}",
Style);
verifyFormat("if (a)\n"
" b = c > 0 ? d : e;",
"if (a) {\n"
" b = c > 0 ? d : e;\n"
"}",
Style);
Style.ColumnLimit = 0;
verifyFormat("if (a)\n"
" b234567890223456789032345678904234567890 = "
"c234567890223456789032345678904234567890;",
"if (a) {\n"
" b234567890223456789032345678904234567890 = "
"c234567890223456789032345678904234567890;\n"
"}",
Style);
}
} // namespace } // namespace
} // namespace format } // namespace format
} // namespace clang } // namespace clang