<div dir="ltr">Thank you and sorry for missing that. I actually knew that and correspondingly did not use an init list in Format.cpp, but forget to cleanup the test. Sorry for the inconvenience!</div><div class="gmail_extra">
<br><br><div class="gmail_quote">On Tue, Apr 1, 2014 at 6:37 PM, Aaron Ballman <span dir="ltr"><<a href="mailto:aaron@aaronballman.com" target="_blank">aaron@aaronballman.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="HOEnZb"><div class="h5">On Tue, Apr 1, 2014 at 8:55 AM, Daniel Jasper <<a href="mailto:djasper@google.com">djasper@google.com</a>> wrote:<br>
> Author: djasper<br>
> Date: Tue Apr 1 07:55:11 2014<br>
> New Revision: 205307<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=205307&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=205307&view=rev</a><br>
> Log:<br>
> clang-format: Support configurable list of foreach-macros.<br>
><br>
> This fixes <a href="http://llvm.org/PR17242" target="_blank">llvm.org/PR17242</a>.<br>
><br>
> Patch by Brian Green, thank you!<br>
><br>
> Modified:<br>
> cfe/trunk/docs/ClangFormatStyleOptions.rst<br>
> cfe/trunk/include/clang/Format/Format.h<br>
> cfe/trunk/lib/Format/Format.cpp<br>
> cfe/trunk/lib/Format/FormatToken.h<br>
> cfe/trunk/lib/Format/TokenAnnotator.cpp<br>
> cfe/trunk/lib/Format/UnwrappedLineParser.cpp<br>
> cfe/trunk/unittests/Format/FormatTest.cpp<br>
><br>
> Modified: cfe/trunk/docs/ClangFormatStyleOptions.rst<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/ClangFormatStyleOptions.rst?rev=205307&r1=205306&r2=205307&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/ClangFormatStyleOptions.rst?rev=205307&r1=205306&r2=205307&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/docs/ClangFormatStyleOptions.rst (original)<br>
> +++ cfe/trunk/docs/ClangFormatStyleOptions.rst Tue Apr 1 07:55:11 2014<br>
> @@ -212,6 +212,14 @@ the configuration (without a prefix: ``A<br>
> NOTE: This is an experimental flag, that might go away or be renamed. Do<br>
> not use this in config files, etc. Use at your own risk.<br>
><br>
> +**ForEachMacros** (``std::vector<std::string>``)<br>
> + A list of macros that should be interpreted as foreach loops instead of as<br>
> + function calls.<br>
> +<br>
> + For example, ``ForEachMacros: [BOOST_FOREACH, Q_FOREACH]`` tells<br>
> + clang-format to treat ``BOOST_FOREACH`` and ``Q_FOREACH`` as loop control<br>
> + statements.<br>
> +<br>
> **IndentCaseLabels** (``bool``)<br>
> Indent case labels one level from the switch statement.<br>
><br>
><br>
> Modified: cfe/trunk/include/clang/Format/Format.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Format/Format.h?rev=205307&r1=205306&r2=205307&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Format/Format.h?rev=205307&r1=205306&r2=205307&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/include/clang/Format/Format.h (original)<br>
> +++ cfe/trunk/include/clang/Format/Format.h Tue Apr 1 07:55:11 2014<br>
> @@ -302,6 +302,18 @@ struct FormatStyle {<br>
> /// which should not be split into lines or otherwise changed.<br>
> std::string CommentPragmas;<br>
><br>
> + /// \brief A vector of macros that should be interpreted as foreach loops<br>
> + /// instead of as function calls.<br>
> + ///<br>
> + /// These are expected to be macros of the form:<br>
> + /// \code<br>
> + /// FOREACH(<variable-declaration>, ...)<br>
> + /// <loop-body><br>
> + /// \endcode<br>
> + ///<br>
> + /// For example: BOOST_FOREACH.<br>
> + std::vector<std::string> ForEachMacros;<br>
> +<br>
> bool operator==(const FormatStyle &R) const {<br>
> return AccessModifierOffset == R.AccessModifierOffset &&<br>
> ConstructorInitializerIndentWidth ==<br>
> @@ -358,7 +370,8 @@ struct FormatStyle {<br>
> SpaceBeforeParens == R.SpaceBeforeParens &&<br>
> SpaceBeforeAssignmentOperators == R.SpaceBeforeAssignmentOperators &&<br>
> ContinuationIndentWidth == R.ContinuationIndentWidth &&<br>
> - CommentPragmas == R.CommentPragmas;<br>
> + CommentPragmas == R.CommentPragmas &&<br>
> + ForEachMacros == R.ForEachMacros;<br>
> }<br>
> };<br>
><br>
><br>
> Modified: cfe/trunk/lib/Format/Format.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=205307&r1=205306&r2=205307&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=205307&r1=205306&r2=205307&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/lib/Format/Format.cpp (original)<br>
> +++ cfe/trunk/lib/Format/Format.cpp Tue Apr 1 07:55:11 2014<br>
> @@ -33,6 +33,8 @@<br>
><br>
> using clang::format::FormatStyle;<br>
><br>
> +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)<br>
> +<br>
> namespace llvm {<br>
> namespace yaml {<br>
> template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {<br>
> @@ -200,6 +202,7 @@ template <> struct MappingTraits<FormatS<br>
> Style.SpaceBeforeAssignmentOperators);<br>
> IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth);<br>
> IO.mapOptional("CommentPragmas", Style.CommentPragmas);<br>
> + IO.mapOptional("ForEachMacros", Style.ForEachMacros);<br>
><br>
> // For backward compatibility.<br>
> if (!IO.outputting()) {<br>
> @@ -259,11 +262,16 @@ FormatStyle getLLVMStyle() {<br>
> LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;<br>
> LLVMStyle.BreakConstructorInitializersBeforeComma = false;<br>
> LLVMStyle.ColumnLimit = 80;<br>
> + LLVMStyle.CommentPragmas = "^ IWYU pragma:";<br>
> LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;<br>
> LLVMStyle.ConstructorInitializerIndentWidth = 4;<br>
> + LLVMStyle.ContinuationIndentWidth = 4;<br>
> LLVMStyle.Cpp11BracedListStyle = true;<br>
> LLVMStyle.DerivePointerBinding = false;<br>
> LLVMStyle.ExperimentalAutoDetectBinPacking = false;<br>
> + LLVMStyle.ForEachMacros.push_back("foreach");<br>
> + LLVMStyle.ForEachMacros.push_back("Q_FOREACH");<br>
> + LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");<br>
> LLVMStyle.IndentCaseLabels = false;<br>
> LLVMStyle.IndentFunctionDeclarationAfterType = false;<br>
> LLVMStyle.IndentWidth = 2;<br>
> @@ -283,9 +291,7 @@ FormatStyle getLLVMStyle() {<br>
> LLVMStyle.SpacesInCStyleCastParentheses = false;<br>
> LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;<br>
> LLVMStyle.SpaceBeforeAssignmentOperators = true;<br>
> - LLVMStyle.ContinuationIndentWidth = 4;<br>
> LLVMStyle.SpacesInAngles = false;<br>
> - LLVMStyle.CommentPragmas = "^ IWYU pragma:";<br>
><br>
> LLVMStyle.PenaltyBreakComment = 300;<br>
> LLVMStyle.PenaltyBreakFirstLessLess = 120;<br>
> @@ -1131,6 +1137,10 @@ public:<br>
> TrailingWhitespace(0), Lex(Lex), SourceMgr(SourceMgr), Style(Style),<br>
> IdentTable(getFormattingLangOpts()), Encoding(Encoding) {<br>
> Lex.SetKeepWhitespaceMode(true);<br>
> +<br>
> + for (const std::string& ForEachMacro : Style.ForEachMacros)<br>
> + ForEachMacros.push_back(&IdentTable.get(ForEachMacro));<br>
> + std::sort(ForEachMacros.begin(), ForEachMacros.end());<br>
> }<br>
><br>
> ArrayRef<FormatToken *> lex() {<br>
> @@ -1351,6 +1361,10 @@ private:<br>
> Column = FormatTok->LastLineColumnWidth;<br>
> }<br>
><br>
> + FormatTok->IsForEachMacro =<br>
> + std::binary_search(ForEachMacros.begin(), ForEachMacros.end(),<br>
> + FormatTok->Tok.getIdentifierInfo());<br>
> +<br>
> return FormatTok;<br>
> }<br>
><br>
> @@ -1366,6 +1380,7 @@ private:<br>
> encoding::Encoding Encoding;<br>
> llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;<br>
> SmallVector<FormatToken *, 16> Tokens;<br>
> + SmallVector<IdentifierInfo*, 8> ForEachMacros;<br>
><br>
> void readRawToken(FormatToken &Tok) {<br>
> Lex.LexFromRawLexer(Tok.Tok);<br>
><br>
> Modified: cfe/trunk/lib/Format/FormatToken.h<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatToken.h?rev=205307&r1=205306&r2=205307&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatToken.h?rev=205307&r1=205306&r2=205307&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/lib/Format/FormatToken.h (original)<br>
> +++ cfe/trunk/lib/Format/FormatToken.h Tue Apr 1 07:55:11 2014<br>
> @@ -104,7 +104,7 @@ struct FormatToken {<br>
> SplitPenalty(0), LongestObjCSelectorName(0), FakeRParens(0),<br>
> StartsBinaryExpression(false), EndsBinaryExpression(false),<br>
> LastInChainOfCalls(false), PartOfMultiVariableDeclStmt(false),<br>
> - MatchingParen(NULL), Previous(NULL), Next(NULL),<br>
> + IsForEachMacro(false), MatchingParen(NULL), Previous(NULL), Next(NULL),<br>
> Decision(FD_Unformatted), Finalized(false) {}<br>
><br>
> /// \brief The \c Token.<br>
> @@ -247,6 +247,9 @@ struct FormatToken {<br>
> /// Only set if \c Type == \c TT_StartOfName.<br>
> bool PartOfMultiVariableDeclStmt;<br>
><br>
> + /// \brief Is this a foreach macro?<br>
> + bool IsForEachMacro;<br>
> +<br>
> bool is(tok::TokenKind Kind) const { return Tok.is(Kind); }<br>
><br>
> bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const {<br>
><br>
> Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=205307&r1=205306&r2=205307&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=205307&r1=205306&r2=205307&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original)<br>
> +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue Apr 1 07:55:11 2014<br>
> @@ -120,6 +120,10 @@ private:<br>
> Contexts.back().IsExpression = false;<br>
> } else if (Left->Previous && Left->Previous->is(tok::kw___attribute)) {<br>
> Left->Type = TT_AttributeParen;<br>
> + } else if (Left->Previous && Left->Previous->IsForEachMacro) {<br>
> + // The first argument to a foreach macro is a declaration.<br>
> + Contexts.back().IsForEachMacro = true;<br>
> + Contexts.back().IsExpression = false;<br>
> }<br>
><br>
> if (StartsObjCMethodExpr) {<br>
> @@ -464,6 +468,8 @@ private:<br>
> Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true;<br>
> if (Contexts.back().InCtorInitializer)<br>
> Tok->Type = TT_CtorInitializerComma;<br>
> + if (Contexts.back().IsForEachMacro)<br>
> + Contexts.back().IsExpression = true;<br>
> break;<br>
> default:<br>
> break;<br>
> @@ -625,7 +631,7 @@ private:<br>
> ColonIsObjCMethodExpr(false), FirstObjCSelectorName(NULL),<br>
> FirstStartOfName(NULL), IsExpression(IsExpression),<br>
> CanBeExpression(true), InTemplateArgument(false),<br>
> - InCtorInitializer(false), CaretFound(false) {}<br>
> + InCtorInitializer(false), CaretFound(false), IsForEachMacro(false) {}<br>
><br>
> tok::TokenKind ContextKind;<br>
> unsigned BindingStrength;<br>
> @@ -641,6 +647,7 @@ private:<br>
> bool InTemplateArgument;<br>
> bool InCtorInitializer;<br>
> bool CaretFound;<br>
> + bool IsForEachMacro;<br>
> };<br>
><br>
> /// \brief Puts a new \c Context onto the stack \c Contexts for the lifetime<br>
> @@ -1408,8 +1415,9 @@ bool TokenAnnotator::spaceRequiredBetwee<br>
> Left.isOneOf(tok::kw_return, tok::kw_new, tok::kw_delete,<br>
> tok::semi) ||<br>
> (Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&<br>
> - Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch,<br>
> - tok::kw_catch)) ||<br>
> + (Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while,<br>
> + tok::kw_switch, tok::kw_catch) ||<br>
> + Left.IsForEachMacro)) ||<br>
> (Style.SpaceBeforeParens == FormatStyle::SBPO_Always &&<br>
> Left.isOneOf(tok::identifier, tok::kw___attribute) &&<br>
> Line.Type != LT_PreprocessorDirective);<br>
><br>
> Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=205307&r1=205306&r2=205307&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=205307&r1=205306&r2=205307&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original)<br>
> +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Tue Apr 1 07:55:11 2014<br>
> @@ -654,6 +654,12 @@ void UnwrappedLineParser::parseStructura<br>
> return;<br>
> }<br>
> }<br>
> + break;<br>
> + case tok::identifier:<br>
> + if (FormatTok->IsForEachMacro) {<br>
> + parseForOrWhileLoop();<br>
> + return;<br>
> + }<br>
> // In all other cases, parse the declaration.<br>
> break;<br>
> default:<br>
> @@ -1041,8 +1047,9 @@ void UnwrappedLineParser::parseNamespace<br>
> }<br>
><br>
> void UnwrappedLineParser::parseForOrWhileLoop() {<br>
> - assert((FormatTok->Tok.is(tok::kw_for) || FormatTok->Tok.is(tok::kw_while)) &&<br>
> - "'for' or 'while' expected");<br>
> + assert((FormatTok->Tok.is(tok::kw_for) || FormatTok->Tok.is(tok::kw_while) ||<br>
> + FormatTok->IsForEachMacro) &&<br>
> + "'for', 'while' or foreach macro expected");<br>
> nextToken();<br>
> if (FormatTok->Tok.is(tok::l_paren))<br>
> parseParens();<br>
><br>
> Modified: cfe/trunk/unittests/Format/FormatTest.cpp<br>
> URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=205307&r1=205306&r2=205307&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=205307&r1=205306&r2=205307&view=diff</a><br>
> ==============================================================================<br>
> --- cfe/trunk/unittests/Format/FormatTest.cpp (original)<br>
> +++ cfe/trunk/unittests/Format/FormatTest.cpp Tue Apr 1 07:55:11 2014<br>
> @@ -465,6 +465,15 @@ TEST_F(FormatTest, RangeBasedForLoops) {<br>
> " aaaaaaaaaaaa.aaaaaaaaaaaa().aaaaaaaaa().a()) {\n}");<br>
> }<br>
><br>
> +TEST_F(FormatTest, ForEachLoops) {<br>
> + verifyFormat("void f() {\n"<br>
> + " foreach (Item *item, itemlist) {}\n"<br>
> + " Q_FOREACH (Item *item, itemlist) {}\n"<br>
> + " BOOST_FOREACH (Item *item, itemlist) {}\n"<br>
> + " UNKNOWN_FORACH(Item * item, itemlist) {}\n"<br>
> + "}");<br>
> +}<br>
> +<br>
> TEST_F(FormatTest, FormatsWhileLoop) {<br>
> verifyFormat("while (true) {\n}");<br>
> verifyFormat("while (true)\n"<br>
> @@ -7607,6 +7616,13 @@ TEST_F(FormatTest, ParsesConfiguration)<br>
> FormatStyle::NI_Inner);<br>
> CHECK_PARSE("NamespaceIndentation: All", NamespaceIndentation,<br>
> FormatStyle::NI_All);<br>
> +<br>
> + Style.ForEachMacros.clear();<br>
> + std::vector<std::string> BoostForeach = { "BOOST_FOREACH" };<br>
> + CHECK_PARSE("ForEachMacros: [BOOST_FOREACH]", ForEachMacros, BoostForeach);<br>
> + std::vector<std::string> BoostAndQForeach = { "BOOST_FOREACH", "Q_FOREACH" };<br>
> + CHECK_PARSE("ForEachMacros: [BOOST_FOREACH, Q_FOREACH]", ForEachMacros,<br>
> + BoostAndQForeach);<br>
> }<br>
<br>
</div></div>MSVC 2012 cannot use std::initializer_list, so the initialization of<br>
the std::vector was causing the build bot to go red. I've fixed in<br>
r205325.<br>
<span class="HOEnZb"><font color="#888888"><br>
~Aaron<br>
</font></span></blockquote></div><br></div>