On Tue, Apr 1, 2014 at 8:55 AM, Daniel Jasper <[email protected]> wrote: > Author: djasper > Date: Tue Apr 1 07:55:11 2014 > New Revision: 205307 > > URL: http://llvm.org/viewvc/llvm-project?rev=205307&view=rev > Log: > clang-format: Support configurable list of foreach-macros. > > This fixes llvm.org/PR17242. > > Patch by Brian Green, thank you! > > Modified: > cfe/trunk/docs/ClangFormatStyleOptions.rst > cfe/trunk/include/clang/Format/Format.h > cfe/trunk/lib/Format/Format.cpp > cfe/trunk/lib/Format/FormatToken.h > cfe/trunk/lib/Format/TokenAnnotator.cpp > cfe/trunk/lib/Format/UnwrappedLineParser.cpp > cfe/trunk/unittests/Format/FormatTest.cpp > > Modified: cfe/trunk/docs/ClangFormatStyleOptions.rst > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/ClangFormatStyleOptions.rst?rev=205307&r1=205306&r2=205307&view=diff > ============================================================================== > --- cfe/trunk/docs/ClangFormatStyleOptions.rst (original) > +++ cfe/trunk/docs/ClangFormatStyleOptions.rst Tue Apr 1 07:55:11 2014 > @@ -212,6 +212,14 @@ the configuration (without a prefix: ``A > 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. > > > Modified: cfe/trunk/include/clang/Format/Format.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Format/Format.h?rev=205307&r1=205306&r2=205307&view=diff > ============================================================================== > --- cfe/trunk/include/clang/Format/Format.h (original) > +++ cfe/trunk/include/clang/Format/Format.h Tue Apr 1 07:55:11 2014 > @@ -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; > } > }; > > > Modified: cfe/trunk/lib/Format/Format.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=205307&r1=205306&r2=205307&view=diff > ============================================================================== > --- cfe/trunk/lib/Format/Format.cpp (original) > +++ cfe/trunk/lib/Format/Format.cpp Tue Apr 1 07:55:11 2014 > @@ -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<FormatS > 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); > > Modified: cfe/trunk/lib/Format/FormatToken.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatToken.h?rev=205307&r1=205306&r2=205307&view=diff > ============================================================================== > --- cfe/trunk/lib/Format/FormatToken.h (original) > +++ cfe/trunk/lib/Format/FormatToken.h Tue Apr 1 07:55:11 2014 > @@ -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 { > > Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=205307&r1=205306&r2=205307&view=diff > ============================================================================== > --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) > +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue Apr 1 07:55:11 2014 > @@ -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::spaceRequiredBetwee > 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); > > Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=205307&r1=205306&r2=205307&view=diff > ============================================================================== > --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original) > +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Tue Apr 1 07:55:11 2014 > @@ -654,6 +654,12 @@ void UnwrappedLineParser::parseStructura > 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(); > > Modified: cfe/trunk/unittests/Format/FormatTest.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=205307&r1=205306&r2=205307&view=diff > ============================================================================== > --- cfe/trunk/unittests/Format/FormatTest.cpp (original) > +++ cfe/trunk/unittests/Format/FormatTest.cpp Tue Apr 1 07:55:11 2014 > @@ -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); > }
MSVC 2012 cannot use std::initializer_list, so the initialization of the std::vector was causing the build bot to go red. I've fixed in r205325. ~Aaron _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
