I tried to go with the approach that djasper outlined: support a static list
of macros parsed into an identifier table used for lookup.
I'm sorry for the delay in updating this.
http://llvm-reviews.chandlerc.com/D2919
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D2919?vs=7491&id=8223#toc
Files:
docs/ClangFormatStyleOptions.rst
include/clang/Format/Format.h
lib/Format/Format.cpp
lib/Format/FormatToken.h
lib/Format/TokenAnnotator.cpp
lib/Format/UnwrappedLineParser.cpp
lib/Format/UnwrappedLineParser.h
unittests/Format/FormatTest.cpp
Index: docs/ClangFormatStyleOptions.rst
===================================================================
--- docs/ClangFormatStyleOptions.rst
+++ docs/ClangFormatStyleOptions.rst
@@ -212,6 +212,14 @@
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.
Index: include/clang/Format/Format.h
===================================================================
--- include/clang/Format/Format.h
+++ include/clang/Format/Format.h
@@ -302,6 +302,18 @@
/// which should not be split into lines or otherwise changed.
std::string CommentPragmas;
+ /// \brief An array 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 @@
SpaceBeforeParens == R.SpaceBeforeParens &&
SpaceBeforeAssignmentOperators == R.SpaceBeforeAssignmentOperators &&
ContinuationIndentWidth == R.ContinuationIndentWidth &&
- CommentPragmas == R.CommentPragmas;
+ CommentPragmas == R.CommentPragmas &&
+ ForEachMacros == R.ForEachMacros;
}
};
Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -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 @@
Style.SpaceBeforeAssignmentOperators);
IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);
IO.mapOptional("CommentPragmas", Style.CommentPragmas);
+ IO.mapOptional("ForEachMacros", Style.ForEachMacros);
// For backward compatibility.
if (!IO.outputting()) {
@@ -1131,6 +1134,10 @@
TrailingWhitespace(0), Lex(Lex), SourceMgr(SourceMgr), Style(Style),
IdentTable(getFormattingLangOpts()), Encoding(Encoding) {
Lex.SetKeepWhitespaceMode(true);
+
+ for (auto I : Style.ForEachMacros)
+ ForEachMacros.push_back(&IdentTable.get(I));
+ std::sort(ForEachMacros.begin(), ForEachMacros.end());
}
ArrayRef<FormatToken *> lex() {
@@ -1351,6 +1358,10 @@
Column = FormatTok->LastLineColumnWidth;
}
+ FormatTok->IsForEachMacro =
+ std::binary_search(ForEachMacros.begin(), ForEachMacros.end(),
+ FormatTok->Tok.getIdentifierInfo());
+
return FormatTok;
}
@@ -1366,6 +1377,7 @@
encoding::Encoding Encoding;
llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
SmallVector<FormatToken *, 16> Tokens;
+ SmallVector<IdentifierInfo*, 8> ForEachMacros;
void readRawToken(FormatToken &Tok) {
Lex.LexFromRawLexer(Tok.Tok);
Index: lib/Format/FormatToken.h
===================================================================
--- lib/Format/FormatToken.h
+++ lib/Format/FormatToken.h
@@ -104,7 +104,7 @@
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 @@
/// Only set if \c Type == \c TT_StartOfName.
bool PartOfMultiVariableDeclStmt;
+ /// \brief Is this a for each macro?
+ bool IsForEachMacro;
+
bool is(tok::TokenKind Kind) const { return Tok.is(Kind); }
bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const {
Index: lib/Format/TokenAnnotator.cpp
===================================================================
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -120,6 +120,10 @@
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 @@
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 @@
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 @@
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 @@
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);
Index: lib/Format/UnwrappedLineParser.cpp
===================================================================
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -629,7 +629,7 @@
return;
case tok::kw_for:
case tok::kw_while:
- parseForOrWhileLoop();
+ parseForOrWhileOrForEachLoop();
return;
case tok::kw_do:
parseDoWhile();
@@ -656,6 +656,11 @@
}
// In all other cases, parse the declaration.
break;
+ case tok::identifier:
+ if (FormatTok->IsForEachMacro) {
+ parseForOrWhileOrForEachLoop();
+ return;
+ }
default:
break;
}
@@ -1040,9 +1045,10 @@
// FIXME: Add error handling.
}
-void UnwrappedLineParser::parseForOrWhileLoop() {
- assert((FormatTok->Tok.is(tok::kw_for) || FormatTok->Tok.is(tok::kw_while)) &&
- "'for' or 'while' expected");
+void UnwrappedLineParser::parseForOrWhileOrForEachLoop() {
+ assert((FormatTok->Tok.is(tok::kw_for) || FormatTok->Tok.is(tok::kw_while) ||
+ FormatTok->IsForEachMacro) &&
+ "'for' or 'while' or foreach macro expected");
nextToken();
if (FormatTok->Tok.is(tok::l_paren))
parseParens();
Index: lib/Format/UnwrappedLineParser.h
===================================================================
--- lib/Format/UnwrappedLineParser.h
+++ lib/Format/UnwrappedLineParser.h
@@ -85,7 +85,7 @@
void parseParens();
void parseSquare();
void parseIfThenElse();
- void parseForOrWhileLoop();
+ void parseForOrWhileOrForEachLoop();
void parseDoWhile();
void parseLabel();
void parseCaseLabel();
Index: unittests/Format/FormatTest.cpp
===================================================================
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -7607,6 +7607,12 @@
FormatStyle::NI_Inner);
CHECK_PARSE("NamespaceIndentation: All", NamespaceIndentation,
FormatStyle::NI_All);
+
+ 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) {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits