forked from OSchip/llvm-project
clang-format: Support configurable list of foreach-macros.
This fixes llvm.org/PR17242. Patch by Brian Green, thank you! llvm-svn: 205307
This commit is contained in:
parent
1087f2980d
commit
e1e4319ab7
|
@ -212,6 +212,14 @@ the configuration (without a prefix: ``Auto``).
|
|||
NOTE: This is an experimental flag, that might go away or be renamed. Do
|
||||
not use this in config files, etc. Use at your own risk.
|
||||
|
||||
**ForEachMacros** (``std::vector<std::string>``)
|
||||
A list of macros that should be interpreted as foreach loops instead of as
|
||||
function calls.
|
||||
|
||||
For example, ``ForEachMacros: [BOOST_FOREACH, Q_FOREACH]`` tells
|
||||
clang-format to treat ``BOOST_FOREACH`` and ``Q_FOREACH`` as loop control
|
||||
statements.
|
||||
|
||||
**IndentCaseLabels** (``bool``)
|
||||
Indent case labels one level from the switch statement.
|
||||
|
||||
|
|
|
@ -302,6 +302,18 @@ struct FormatStyle {
|
|||
/// which should not be split into lines or otherwise changed.
|
||||
std::string CommentPragmas;
|
||||
|
||||
/// \brief A vector of macros that should be interpreted as foreach loops
|
||||
/// instead of as function calls.
|
||||
///
|
||||
/// These are expected to be macros of the form:
|
||||
/// \code
|
||||
/// FOREACH(<variable-declaration>, ...)
|
||||
/// <loop-body>
|
||||
/// \endcode
|
||||
///
|
||||
/// For example: BOOST_FOREACH.
|
||||
std::vector<std::string> ForEachMacros;
|
||||
|
||||
bool operator==(const FormatStyle &R) const {
|
||||
return AccessModifierOffset == R.AccessModifierOffset &&
|
||||
ConstructorInitializerIndentWidth ==
|
||||
|
@ -358,7 +370,8 @@ struct FormatStyle {
|
|||
SpaceBeforeParens == R.SpaceBeforeParens &&
|
||||
SpaceBeforeAssignmentOperators == R.SpaceBeforeAssignmentOperators &&
|
||||
ContinuationIndentWidth == R.ContinuationIndentWidth &&
|
||||
CommentPragmas == R.CommentPragmas;
|
||||
CommentPragmas == R.CommentPragmas &&
|
||||
ForEachMacros == R.ForEachMacros;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
|
||||
using clang::format::FormatStyle;
|
||||
|
||||
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
|
||||
|
@ -200,6 +202,7 @@ template <> struct MappingTraits<FormatStyle> {
|
|||
Style.SpaceBeforeAssignmentOperators);
|
||||
IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);
|
||||
IO.mapOptional("CommentPragmas", Style.CommentPragmas);
|
||||
IO.mapOptional("ForEachMacros", Style.ForEachMacros);
|
||||
|
||||
// For backward compatibility.
|
||||
if (!IO.outputting()) {
|
||||
|
@ -259,11 +262,16 @@ FormatStyle getLLVMStyle() {
|
|||
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
|
||||
LLVMStyle.BreakConstructorInitializersBeforeComma = false;
|
||||
LLVMStyle.ColumnLimit = 80;
|
||||
LLVMStyle.CommentPragmas = "^ IWYU pragma:";
|
||||
LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
|
||||
LLVMStyle.ConstructorInitializerIndentWidth = 4;
|
||||
LLVMStyle.ContinuationIndentWidth = 4;
|
||||
LLVMStyle.Cpp11BracedListStyle = true;
|
||||
LLVMStyle.DerivePointerBinding = false;
|
||||
LLVMStyle.ExperimentalAutoDetectBinPacking = false;
|
||||
LLVMStyle.ForEachMacros.push_back("foreach");
|
||||
LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
|
||||
LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");
|
||||
LLVMStyle.IndentCaseLabels = false;
|
||||
LLVMStyle.IndentFunctionDeclarationAfterType = false;
|
||||
LLVMStyle.IndentWidth = 2;
|
||||
|
@ -283,9 +291,7 @@ FormatStyle getLLVMStyle() {
|
|||
LLVMStyle.SpacesInCStyleCastParentheses = false;
|
||||
LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
|
||||
LLVMStyle.SpaceBeforeAssignmentOperators = true;
|
||||
LLVMStyle.ContinuationIndentWidth = 4;
|
||||
LLVMStyle.SpacesInAngles = false;
|
||||
LLVMStyle.CommentPragmas = "^ IWYU pragma:";
|
||||
|
||||
LLVMStyle.PenaltyBreakComment = 300;
|
||||
LLVMStyle.PenaltyBreakFirstLessLess = 120;
|
||||
|
@ -1131,6 +1137,10 @@ public:
|
|||
TrailingWhitespace(0), Lex(Lex), SourceMgr(SourceMgr), Style(Style),
|
||||
IdentTable(getFormattingLangOpts()), Encoding(Encoding) {
|
||||
Lex.SetKeepWhitespaceMode(true);
|
||||
|
||||
for (const std::string& ForEachMacro : Style.ForEachMacros)
|
||||
ForEachMacros.push_back(&IdentTable.get(ForEachMacro));
|
||||
std::sort(ForEachMacros.begin(), ForEachMacros.end());
|
||||
}
|
||||
|
||||
ArrayRef<FormatToken *> lex() {
|
||||
|
@ -1351,6 +1361,10 @@ private:
|
|||
Column = FormatTok->LastLineColumnWidth;
|
||||
}
|
||||
|
||||
FormatTok->IsForEachMacro =
|
||||
std::binary_search(ForEachMacros.begin(), ForEachMacros.end(),
|
||||
FormatTok->Tok.getIdentifierInfo());
|
||||
|
||||
return FormatTok;
|
||||
}
|
||||
|
||||
|
@ -1366,6 +1380,7 @@ private:
|
|||
encoding::Encoding Encoding;
|
||||
llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
|
||||
SmallVector<FormatToken *, 16> Tokens;
|
||||
SmallVector<IdentifierInfo*, 8> ForEachMacros;
|
||||
|
||||
void readRawToken(FormatToken &Tok) {
|
||||
Lex.LexFromRawLexer(Tok.Tok);
|
||||
|
|
|
@ -104,7 +104,7 @@ struct FormatToken {
|
|||
SplitPenalty(0), LongestObjCSelectorName(0), FakeRParens(0),
|
||||
StartsBinaryExpression(false), EndsBinaryExpression(false),
|
||||
LastInChainOfCalls(false), PartOfMultiVariableDeclStmt(false),
|
||||
MatchingParen(NULL), Previous(NULL), Next(NULL),
|
||||
IsForEachMacro(false), MatchingParen(NULL), Previous(NULL), Next(NULL),
|
||||
Decision(FD_Unformatted), Finalized(false) {}
|
||||
|
||||
/// \brief The \c Token.
|
||||
|
@ -247,6 +247,9 @@ struct FormatToken {
|
|||
/// Only set if \c Type == \c TT_StartOfName.
|
||||
bool PartOfMultiVariableDeclStmt;
|
||||
|
||||
/// \brief Is this a foreach macro?
|
||||
bool IsForEachMacro;
|
||||
|
||||
bool is(tok::TokenKind Kind) const { return Tok.is(Kind); }
|
||||
|
||||
bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const {
|
||||
|
|
|
@ -120,6 +120,10 @@ private:
|
|||
Contexts.back().IsExpression = false;
|
||||
} else if (Left->Previous && Left->Previous->is(tok::kw___attribute)) {
|
||||
Left->Type = TT_AttributeParen;
|
||||
} else if (Left->Previous && Left->Previous->IsForEachMacro) {
|
||||
// The first argument to a foreach macro is a declaration.
|
||||
Contexts.back().IsForEachMacro = true;
|
||||
Contexts.back().IsExpression = false;
|
||||
}
|
||||
|
||||
if (StartsObjCMethodExpr) {
|
||||
|
@ -464,6 +468,8 @@ private:
|
|||
Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true;
|
||||
if (Contexts.back().InCtorInitializer)
|
||||
Tok->Type = TT_CtorInitializerComma;
|
||||
if (Contexts.back().IsForEachMacro)
|
||||
Contexts.back().IsExpression = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -625,7 +631,7 @@ private:
|
|||
ColonIsObjCMethodExpr(false), FirstObjCSelectorName(NULL),
|
||||
FirstStartOfName(NULL), IsExpression(IsExpression),
|
||||
CanBeExpression(true), InTemplateArgument(false),
|
||||
InCtorInitializer(false), CaretFound(false) {}
|
||||
InCtorInitializer(false), CaretFound(false), IsForEachMacro(false) {}
|
||||
|
||||
tok::TokenKind ContextKind;
|
||||
unsigned BindingStrength;
|
||||
|
@ -641,6 +647,7 @@ private:
|
|||
bool InTemplateArgument;
|
||||
bool InCtorInitializer;
|
||||
bool CaretFound;
|
||||
bool IsForEachMacro;
|
||||
};
|
||||
|
||||
/// \brief Puts a new \c Context onto the stack \c Contexts for the lifetime
|
||||
|
@ -1408,8 +1415,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
|
|||
Left.isOneOf(tok::kw_return, tok::kw_new, tok::kw_delete,
|
||||
tok::semi) ||
|
||||
(Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
|
||||
Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch,
|
||||
tok::kw_catch)) ||
|
||||
(Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while,
|
||||
tok::kw_switch, tok::kw_catch) ||
|
||||
Left.IsForEachMacro)) ||
|
||||
(Style.SpaceBeforeParens == FormatStyle::SBPO_Always &&
|
||||
Left.isOneOf(tok::identifier, tok::kw___attribute) &&
|
||||
Line.Type != LT_PreprocessorDirective);
|
||||
|
|
|
@ -654,6 +654,12 @@ void UnwrappedLineParser::parseStructuralElement() {
|
|||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case tok::identifier:
|
||||
if (FormatTok->IsForEachMacro) {
|
||||
parseForOrWhileLoop();
|
||||
return;
|
||||
}
|
||||
// In all other cases, parse the declaration.
|
||||
break;
|
||||
default:
|
||||
|
@ -1041,8 +1047,9 @@ void UnwrappedLineParser::parseNamespace() {
|
|||
}
|
||||
|
||||
void UnwrappedLineParser::parseForOrWhileLoop() {
|
||||
assert((FormatTok->Tok.is(tok::kw_for) || FormatTok->Tok.is(tok::kw_while)) &&
|
||||
"'for' or 'while' expected");
|
||||
assert((FormatTok->Tok.is(tok::kw_for) || FormatTok->Tok.is(tok::kw_while) ||
|
||||
FormatTok->IsForEachMacro) &&
|
||||
"'for', 'while' or foreach macro expected");
|
||||
nextToken();
|
||||
if (FormatTok->Tok.is(tok::l_paren))
|
||||
parseParens();
|
||||
|
|
|
@ -465,6 +465,15 @@ TEST_F(FormatTest, RangeBasedForLoops) {
|
|||
" aaaaaaaaaaaa.aaaaaaaaaaaa().aaaaaaaaa().a()) {\n}");
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, ForEachLoops) {
|
||||
verifyFormat("void f() {\n"
|
||||
" foreach (Item *item, itemlist) {}\n"
|
||||
" Q_FOREACH (Item *item, itemlist) {}\n"
|
||||
" BOOST_FOREACH (Item *item, itemlist) {}\n"
|
||||
" UNKNOWN_FORACH(Item * item, itemlist) {}\n"
|
||||
"}");
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, FormatsWhileLoop) {
|
||||
verifyFormat("while (true) {\n}");
|
||||
verifyFormat("while (true)\n"
|
||||
|
@ -7607,6 +7616,13 @@ TEST_F(FormatTest, ParsesConfiguration) {
|
|||
FormatStyle::NI_Inner);
|
||||
CHECK_PARSE("NamespaceIndentation: All", NamespaceIndentation,
|
||||
FormatStyle::NI_All);
|
||||
|
||||
Style.ForEachMacros.clear();
|
||||
std::vector<std::string> BoostForeach = { "BOOST_FOREACH" };
|
||||
CHECK_PARSE("ForEachMacros: [BOOST_FOREACH]", ForEachMacros, BoostForeach);
|
||||
std::vector<std::string> BoostAndQForeach = { "BOOST_FOREACH", "Q_FOREACH" };
|
||||
CHECK_PARSE("ForEachMacros: [BOOST_FOREACH, Q_FOREACH]", ForEachMacros,
|
||||
BoostAndQForeach);
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, ParsesConfigurationWithLanguages) {
|
||||
|
|
Loading…
Reference in New Issue