Hi djasper, This adds the BlockBeginMacros and BlockEndMacros options that can be used to make certain macros add indent levels similarly to '{' and '}', respectively.
Mozilla code, for example, uses several macros that begin and end a scope. Previously, Clang-Format removed the indentation resulting in: MACRO_BEGIN(...) MACRO_ENTRY(...) MACRO_ENTRY(...) MACRO_END Now, using e.g. 'BlockBeginMacros: "^[A-Z_]+_BEGIN$"' and 'BlockEndMacros: "^[A-Z_]+_END$"', the result is as expected: MACRO_BEGIN(...) MACRO_ENTRY(...) MACRO_ENTRY(...) MACRO_END http://reviews.llvm.org/D10840 Files: include/clang/Format/Format.h lib/Format/Format.cpp lib/Format/FormatToken.h lib/Format/UnwrappedLineParser.cpp unittests/Format/FormatTest.cpp EMAIL PREFERENCES http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -156,6 +156,12 @@ BOS_All, }; + /// \brief A regular expression matching macros that start a block. + std::string BlockBeginMacros; + + /// \brief A regular expression matching macros that end a block. + std::string BlockEndMacros; + /// \brief The way to wrap binary operators. BinaryOperatorStyle BreakBeforeBinaryOperators; @@ -456,6 +462,8 @@ R.AlwaysBreakTemplateDeclarations && BinPackArguments == R.BinPackArguments && BinPackParameters == R.BinPackParameters && + BlockBeginMacros == R.BlockBeginMacros && + BlockEndMacros == R.BlockEndMacros && BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators && BreakBeforeBraces == R.BreakBeforeBraces && BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators && Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -27,6 +27,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Regex.h" #include "llvm/Support/YAMLTraits.h" #include <queue> #include <string> @@ -218,6 +219,8 @@ Style.AlwaysBreakTemplateDeclarations); IO.mapOptional("BinPackArguments", Style.BinPackArguments); IO.mapOptional("BinPackParameters", Style.BinPackParameters); + IO.mapOptional("BlockBeginMacros", Style.BlockBeginMacros); + IO.mapOptional("BlockEndMacros", Style.BlockEndMacros); IO.mapOptional("BreakBeforeBinaryOperators", Style.BreakBeforeBinaryOperators); IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); @@ -620,7 +623,9 @@ LessStashed(false), Column(0), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID), Style(Style), IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable), - Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false) { + Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false), + BlockBeginMacrosRegex(Style.BlockBeginMacros), + BlockEndMacrosRegex(Style.BlockEndMacros) { Lex.reset(new Lexer(ID, SourceMgr.getBuffer(ID), SourceMgr, getFormattingLangOpts(Style))); Lex->SetKeepWhitespaceMode(true); @@ -1164,8 +1169,15 @@ Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() == tok::pp_define) && std::find(ForEachMacros.begin(), ForEachMacros.end(), - FormatTok->Tok.getIdentifierInfo()) != ForEachMacros.end()) + FormatTok->Tok.getIdentifierInfo()) != ForEachMacros.end()) { FormatTok->Type = TT_ForEachMacro; + } else if (FormatTok->is(tok::identifier)) { + if (BlockBeginMacrosRegex.match(Text)) { + FormatTok->Type = TT_MacroBlockBegin; + } else if (BlockEndMacrosRegex.match(Text)) { + FormatTok->Type = TT_MacroBlockEnd; + } + } return FormatTok; } @@ -1190,6 +1202,9 @@ bool FormattingDisabled; + llvm::Regex BlockBeginMacrosRegex; + llvm::Regex BlockEndMacrosRegex; + void readRawToken(FormatToken &Tok) { Lex->LexFromRawLexer(Tok.Tok); Tok.TokenText = StringRef(SourceMgr.getCharacterData(Tok.Tok.getLocation()), Index: lib/Format/FormatToken.h =================================================================== --- lib/Format/FormatToken.h +++ lib/Format/FormatToken.h @@ -59,6 +59,8 @@ TT_LambdaLSquare, TT_LeadingJavaAnnotation, TT_LineComment, + TT_MacroBlockBegin, + TT_MacroBlockEnd, TT_ObjCBlockLBrace, TT_ObjCBlockLParen, TT_ObjCDecl, Index: lib/Format/UnwrappedLineParser.cpp =================================================================== --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -269,7 +269,14 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { bool SwitchLabelEncountered = false; do { - switch (FormatTok->Tok.getKind()) { + tok::TokenKind kind = FormatTok->Tok.getKind(); + if (FormatTok->Type == TT_MacroBlockBegin) { + kind = tok::l_brace; + } else if (FormatTok->Type == TT_MacroBlockEnd) { + kind = tok::r_brace; + } + + switch (kind) { case tok::comment: nextToken(); addUnwrappedLine(); @@ -393,24 +400,35 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel, bool MunchSemi) { - assert(FormatTok->Tok.is(tok::l_brace) && "'{' expected"); + const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin); + assert((FormatTok->is(tok::l_brace) || MacroBlock) && + "'{' or macro block token expected"); + unsigned InitialLevel = Line->Level; nextToken(); + if (MacroBlock && FormatTok->is(tok::l_paren)) + parseParens(); + addUnwrappedLine(); ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, MustBeDeclaration); if (AddLevel) ++Line->Level; parseLevel(/*HasOpeningBrace=*/true); - if (!FormatTok->Tok.is(tok::r_brace)) { + if (!(MacroBlock ? FormatTok->is(TT_MacroBlockEnd) + : FormatTok->is(tok::r_brace))) { Line->Level = InitialLevel; return; } nextToken(); // Munch the closing brace. + + if (MacroBlock && FormatTok->is(tok::l_paren)) + parseParens(); + if (MunchSemi && FormatTok->Tok.is(tok::semi)) nextToken(); Line->Level = InitialLevel; @@ -757,6 +775,11 @@ parseForOrWhileLoop(); return; } + if (FormatTok->is(TT_MacroBlockBegin)) { + parseBlock(/*MustBeDeclaration=*/false, /*AddLevel=*/true, + /*MunchSemi=*/false); + return; + } if (Style.Language == FormatStyle::LK_JavaScript && FormatTok->is(Keywords.kw_import)) { parseJavaScriptEs6ImportExport(); @@ -860,6 +883,11 @@ parseTryCatch(); return; case tok::identifier: { + if (FormatTok->is(TT_MacroBlockEnd)) { + addUnwrappedLine(); + return; + } + // Parse function literal unless 'function' is the first token in a line // in which case this should be treated as a free-standing function. if (Style.Language == FormatStyle::LK_JavaScript && Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -3214,6 +3214,24 @@ verifyFormat("enum E {}"); } +TEST_F(FormatTest, FormatBeginBlockEndMacros) { + FormatStyle Style = getLLVMStyle(); + Style.BlockBeginMacros = "^[A-Z_]+_BEGIN$"; + Style.BlockEndMacros = "^[A-Z_]+_END$"; + verifyFormat("FOO_BEGIN\n" + " FOO_ENTRY\n" + "FOO_END", Style); + verifyFormat("FOO_BEGIN\n" + " NESTED_FOO_BEGIN\n" + " NESTED_FOO_ENTRY\n" + " NESTED_FOO_END\n" + "FOO_END", Style); + verifyFormat("FOO_BEGIN(Foo, Bar)\n" + " int x;\n" + " x = 1;\n" + "FOO_END(Baz)", Style); +} + //===----------------------------------------------------------------------===// // Line break tests. //===----------------------------------------------------------------------===//
_______________________________________________ cfe-commits mailing list cfe-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits