forked from OSchip/llvm-project
clang-format: Add MacroBlock{Begin,End} options
The MacroBlockBegin and MacroBlockEnd options make matching macro identifiers behave like '{' and '}', respectively, in terms of indentation. 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 the options MacroBlockBegin: "^[A-Z_]+_BEGIN$" MacroBlockEnd: "^[A-Z_]+_END$" will yield the expected result: MACRO_BEGIN(...) MACRO_ENTRY(...) MACRO_ENTRY(...) MACRO_END Differential Revision: http://reviews.llvm.org/D10840 llvm-svn: 241363
This commit is contained in:
parent
15b86155c9
commit
b001a0ba5e
|
@ -394,6 +394,12 @@ the configuration (without a prefix: ``Auto``).
|
|||
(https://developers.google.com/protocol-buffers/).
|
||||
|
||||
|
||||
**MacroBlockBegin** (``std::string``)
|
||||
A regular expression matching macros that start a block.
|
||||
|
||||
**MacroBlockEnd** (``std::string``)
|
||||
A regular expression matching macros that end a block.
|
||||
|
||||
**MaxEmptyLinesToKeep** (``unsigned``)
|
||||
The maximum number of consecutive empty lines to keep.
|
||||
|
||||
|
|
|
@ -290,6 +290,12 @@ struct FormatStyle {
|
|||
/// \brief Language, this format style is targeted at.
|
||||
LanguageKind Language;
|
||||
|
||||
/// \brief A regular expression matching macros that start a block.
|
||||
std::string MacroBlockBegin;
|
||||
|
||||
/// \brief A regular expression matching macros that end a block.
|
||||
std::string MacroBlockEnd;
|
||||
|
||||
/// \brief The maximum number of consecutive empty lines to keep.
|
||||
unsigned MaxEmptyLinesToKeep;
|
||||
|
||||
|
@ -479,6 +485,8 @@ struct FormatStyle {
|
|||
IndentWrappedFunctionNames == R.IndentWrappedFunctionNames &&
|
||||
KeepEmptyLinesAtTheStartOfBlocks ==
|
||||
R.KeepEmptyLinesAtTheStartOfBlocks &&
|
||||
MacroBlockBegin == R.MacroBlockBegin &&
|
||||
MacroBlockEnd == R.MacroBlockEnd &&
|
||||
MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep &&
|
||||
NamespaceIndentation == R.NamespaceIndentation &&
|
||||
ObjCBlockIndentWidth == R.ObjCBlockIndentWidth &&
|
||||
|
|
|
@ -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>
|
||||
|
@ -244,6 +245,8 @@ template <> struct MappingTraits<FormatStyle> {
|
|||
Style.IndentWrappedFunctionNames);
|
||||
IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
|
||||
Style.KeepEmptyLinesAtTheStartOfBlocks);
|
||||
IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin);
|
||||
IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd);
|
||||
IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
|
||||
IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
|
||||
IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth);
|
||||
|
@ -468,6 +471,8 @@ FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
|
|||
ChromiumStyle.BinPackParameters = false;
|
||||
ChromiumStyle.DerivePointerAlignment = false;
|
||||
}
|
||||
ChromiumStyle.MacroBlockBegin = "^IPC_BEGIN_MESSAGE_MAP$";
|
||||
ChromiumStyle.MacroBlockBegin = "^IPC_END_MESSAGE_MAP$";
|
||||
return ChromiumStyle;
|
||||
}
|
||||
|
||||
|
@ -620,7 +625,9 @@ public:
|
|||
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),
|
||||
MacroBlockBeginRegex(Style.MacroBlockBegin),
|
||||
MacroBlockEndRegex(Style.MacroBlockEnd) {
|
||||
Lex.reset(new Lexer(ID, SourceMgr.getBuffer(ID), SourceMgr,
|
||||
getFormattingLangOpts(Style)));
|
||||
Lex->SetKeepWhitespaceMode(true);
|
||||
|
@ -1168,12 +1175,21 @@ private:
|
|||
Column = FormatTok->LastLineColumnWidth;
|
||||
}
|
||||
|
||||
if (Style.Language == FormatStyle::LK_Cpp) {
|
||||
if (!(Tokens.size() > 0 && Tokens.back()->Tok.getIdentifierInfo() &&
|
||||
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 (MacroBlockBeginRegex.match(Text)) {
|
||||
FormatTok->Type = TT_MacroBlockBegin;
|
||||
} else if (MacroBlockEndRegex.match(Text)) {
|
||||
FormatTok->Type = TT_MacroBlockEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FormatTok;
|
||||
}
|
||||
|
@ -1198,6 +1214,9 @@ private:
|
|||
|
||||
bool FormattingDisabled;
|
||||
|
||||
llvm::Regex MacroBlockBeginRegex;
|
||||
llvm::Regex MacroBlockEndRegex;
|
||||
|
||||
void readRawToken(FormatToken &Tok) {
|
||||
Lex->LexFromRawLexer(Tok.Tok);
|
||||
Tok.TokenText = StringRef(SourceMgr.getCharacterData(Tok.Tok.getLocation()),
|
||||
|
|
|
@ -59,6 +59,8 @@ enum TokenType {
|
|||
TT_LambdaLSquare,
|
||||
TT_LeadingJavaAnnotation,
|
||||
TT_LineComment,
|
||||
TT_MacroBlockBegin,
|
||||
TT_MacroBlockEnd,
|
||||
TT_ObjCBlockLBrace,
|
||||
TT_ObjCBlockLParen,
|
||||
TT_ObjCDecl,
|
||||
|
|
|
@ -269,7 +269,14 @@ void UnwrappedLineParser::parseFile() {
|
|||
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,10 +400,16 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
|
|||
|
||||
void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
|
||||
bool MunchSemi) {
|
||||
assert(FormatTok->Tok.is(tok::l_brace) && "'{' expected");
|
||||
assert(FormatTok->isOneOf(tok::l_brace, TT_MacroBlockBegin) &&
|
||||
"'{' or macro block token expected");
|
||||
const bool MacroBlock = FormatTok->is(TT_MacroBlockBegin);
|
||||
|
||||
unsigned InitialLevel = Line->Level;
|
||||
nextToken();
|
||||
|
||||
if (MacroBlock && FormatTok->is(tok::l_paren))
|
||||
parseParens();
|
||||
|
||||
addUnwrappedLine();
|
||||
|
||||
ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
|
||||
|
@ -405,12 +418,17 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool 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 @@ void UnwrappedLineParser::parseStructuralElement() {
|
|||
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 @@ void UnwrappedLineParser::parseStructuralElement() {
|
|||
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 &&
|
||||
|
|
|
@ -3216,6 +3216,24 @@ TEST_F(FormatTest, PutEmptyBlocksIntoOneLine) {
|
|||
verifyFormat("enum E {}");
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, FormatBeginBlockEndMacros) {
|
||||
FormatStyle Style = getLLVMStyle();
|
||||
Style.MacroBlockBegin = "^[A-Z_]+_BEGIN$";
|
||||
Style.MacroBlockEnd = "^[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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
Loading…
Reference in New Issue