From 6f40e21a1601aa1b83a13282918ddae47e58b7d5 Mon Sep 17 00:00:00 2001 From: Francois Ferrand Date: Tue, 2 Oct 2018 16:37:51 +0000 Subject: clang-format: better handle statement macros Summary: Some macros are used in the body of function, and actually contain the trailing semicolon: they should thus be automatically followed by a new line, and not get merged with the next line. This is for example the case with Qt's Q_UNUSED macro: void foo(int a, int b) { Q_UNUSED(a) return b; } This patch deals with these cases by introducing a new option to specify list of statement macros. This re-uses the system already in place for foreach macros, to ensure there is no impact on performance. Reviewers: krasimir, djasper, klimek Reviewed By: krasimir Subscribers: acoomans, mgrang, alexfh, klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D33440 llvm-svn: 343602 --- clang/lib/Format/Format.cpp | 3 +++ clang/lib/Format/FormatToken.h | 1 + clang/lib/Format/FormatTokenLexer.cpp | 11 ++++++----- clang/lib/Format/FormatTokenLexer.h | 4 +++- clang/lib/Format/UnwrappedLineParser.cpp | 23 +++++++++++++++++++++++ clang/lib/Format/UnwrappedLineParser.h | 1 + 6 files changed, 37 insertions(+), 6 deletions(-) (limited to 'clang/lib') diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 0637f76f07c..adc19fb11a3 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -469,6 +469,7 @@ template <> struct MappingTraits { IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses); IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets); IO.mapOptional("Standard", Style.Standard); + IO.mapOptional("StatementMacros", Style.StatementMacros); IO.mapOptional("TabWidth", Style.TabWidth); IO.mapOptional("UseTab", Style.UseTab); } @@ -714,6 +715,8 @@ FormatStyle getLLVMStyle() { LLVMStyle.DisableFormat = false; LLVMStyle.SortIncludes = true; LLVMStyle.SortUsingDeclarations = true; + LLVMStyle.StatementMacros.push_back("Q_UNUSED"); + LLVMStyle.StatementMacros.push_back("QT_REQUIRE_VERSION"); return LLVMStyle; } diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index f65fe5b0049..6e801a346b8 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -86,6 +86,7 @@ namespace format { TYPE(RegexLiteral) \ TYPE(SelectorName) \ TYPE(StartOfName) \ + TYPE(StatementMacro) \ TYPE(StructuredBindingLSquare) \ TYPE(TemplateCloser) \ TYPE(TemplateOpener) \ diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 7f2edf102c7..146f5d68b55 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -37,8 +37,9 @@ FormatTokenLexer::FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, Lex->SetKeepWhitespaceMode(true); for (const std::string &ForEachMacro : Style.ForEachMacros) - ForEachMacros.push_back(&IdentTable.get(ForEachMacro)); - llvm::sort(ForEachMacros); + Macros.insert({&IdentTable.get(ForEachMacro), TT_ForEachMacro}); + for (const std::string &StatementMacro : Style.StatementMacros) + Macros.insert({&IdentTable.get(StatementMacro), TT_StatementMacro}); } ArrayRef FormatTokenLexer::lex() { @@ -657,12 +658,12 @@ FormatToken *FormatTokenLexer::getNextToken() { } if (Style.isCpp()) { + auto it = Macros.find(FormatTok->Tok.getIdentifierInfo()); 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->Type = TT_ForEachMacro; + it != Macros.end()) { + FormatTok->Type = it->second; } else if (FormatTok->is(tok::identifier)) { if (MacroBlockBeginRegex.match(Text)) { FormatTok->Type = TT_MacroBlockBegin; diff --git a/clang/lib/Format/FormatTokenLexer.h b/clang/lib/Format/FormatTokenLexer.h index 3b79d27480e..0cf357c85f3 100644 --- a/clang/lib/Format/FormatTokenLexer.h +++ b/clang/lib/Format/FormatTokenLexer.h @@ -22,6 +22,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" #include "llvm/Support/Regex.h" +#include "llvm/ADT/MapVector.h" #include @@ -99,7 +100,8 @@ private: // Index (in 'Tokens') of the last token that starts a new line. unsigned FirstInLineIndex; SmallVector Tokens; - SmallVector ForEachMacros; + + llvm::SmallMapVector Macros; bool FormattingDisabled; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 09cd660e6de..6c81d8b60e9 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -480,6 +480,10 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { } LBraceStack.pop_back(); break; + case tok::identifier: + if (!Tok->is(TT_StatementMacro)) + break; + LLVM_FALLTHROUGH; case tok::at: case tok::semi: case tok::kw_if: @@ -1108,6 +1112,10 @@ void UnwrappedLineParser::parseStructuralElement() { return; } } + if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) { + parseStatementMacro(); + return; + } // In all other cases, parse the declaration. break; default: @@ -1309,6 +1317,11 @@ void UnwrappedLineParser::parseStructuralElement() { return; } + if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) { + parseStatementMacro(); + return; + } + // See if the following token should start a new unwrapped line. StringRef Text = FormatTok->TokenText; nextToken(); @@ -2328,6 +2341,16 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() { } } +void UnwrappedLineParser::parseStatementMacro() +{ + nextToken(); + if (FormatTok->is(tok::l_paren)) + parseParens(); + if (FormatTok->is(tok::semi)) + nextToken(); + addUnwrappedLine(); +} + LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line, StringRef Prefix = "") { llvm::dbgs() << Prefix << "Line(" << Line.Level diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index 87254832c63..55d60dff915 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -126,6 +126,7 @@ private: void parseObjCInterfaceOrImplementation(); bool parseObjCProtocol(); void parseJavaScriptEs6ImportExport(); + void parseStatementMacro(); bool tryToParseLambda(); bool tryToParseLambdaIntroducer(); void tryToParseJSFunction(); -- cgit v1.2.3