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
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits