Use tabs whenever we need to fill whitespace that spans at least from
one tab stop to the next one.
+**WhitespaceSensitiveMacros** (``std::vector<std::string>``)
+ A vector of macros which are whitespace-sensitive and should not be touched.
+
+ These are expected to be macros of the form:
+
+ .. code-block:: c++
+
+ STRINGIZE(...)
+
+ In the .clang-format configuration file, this can be configured like:
+
+ .. code-block:: yaml
+
+ WhitespaceSensitiveMacros: ['STRINGIZE', 'PP_STRINGIZE']
+
+ For example: BOOST_PP_STRINGIZE.
+
.. END_FORMAT_STYLE_OPTIONS
/// For example: TESTSUITE
std::vector<std::string> NamespaceMacros;
+ /// A vector of macros which are whitespace-sensitive and shouldn't be
+ /// touched.
+ ///
+ /// These are expected to be macros of the form:
+ /// \code
+ /// STRINGIZE(...)
+ /// \endcode
+ ///
+ /// For example: STRINGIZE
+ std::vector<std::string> WhitespaceSensitiveMacros;
+
tooling::IncludeStyle IncludeStyle;
/// Indent case labels one level from the switch statement.
IO.mapOptional("TypenameMacros", Style.TypenameMacros);
IO.mapOptional("UseCRLF", Style.UseCRLF);
IO.mapOptional("UseTab", Style.UseTab);
+ IO.mapOptional("WhitespaceSensitiveMacros",
+ Style.WhitespaceSensitiveMacros);
}
};
LLVMStyle.SortUsingDeclarations = true;
LLVMStyle.StatementMacros.push_back("Q_UNUSED");
LLVMStyle.StatementMacros.push_back("QT_REQUIRE_VERSION");
+ LLVMStyle.WhitespaceSensitiveMacros.push_back("STRINGIZE");
+ LLVMStyle.WhitespaceSensitiveMacros.push_back("PP_STRINGIZE");
+ LLVMStyle.WhitespaceSensitiveMacros.push_back("BOOST_PP_STRINGIZE");
// Defaults that differ when not C++.
if (Language == FormatStyle::LK_TableGen) {
TYPE(TrailingUnaryOperator) \
TYPE(TypenameMacro) \
TYPE(UnaryOperator) \
+ TYPE(UntouchableMacroFunc) \
TYPE(CSharpStringLiteral) \
TYPE(CSharpNamedArgumentColon) \
TYPE(CSharpNullable) \
Macros.insert({&IdentTable.get(TypenameMacro), TT_TypenameMacro});
for (const std::string &NamespaceMacro : Style.NamespaceMacros)
Macros.insert({&IdentTable.get(NamespaceMacro), TT_NamespaceMacro});
+ for (const std::string &WhitespaceSensitiveMacro :
+ Style.WhitespaceSensitiveMacros) {
+ Macros.insert(
+ {&IdentTable.get(WhitespaceSensitiveMacro), TT_UntouchableMacroFunc});
+ }
}
ArrayRef<FormatToken *> FormatTokenLexer::lex() {
return false;
}
+ bool parseUntouchableParens() {
+ while (CurrentToken) {
+ CurrentToken->Finalized = true;
+ switch (CurrentToken->Tok.getKind()) {
+ case tok::l_paren:
+ next();
+ if (!parseUntouchableParens())
+ return false;
+ continue;
+ case tok::r_paren:
+ next();
+ return true;
+ default:
+ // no-op
+ break;
+ }
+ next();
+ }
+ return false;
+ }
+
bool parseParens(bool LookForDecls = false) {
if (!CurrentToken)
return false;
Contexts.back().ColonIsForRangeExpr =
Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr;
+ if (Left->Previous && Left->Previous->is(TT_UntouchableMacroFunc)) {
+ Left->Finalized = true;
+ return parseUntouchableParens();
+ }
+
bool StartsObjCMethodExpr = false;
if (FormatToken *MaybeSel = Left->Previous) {
// @selector( starts a selector.
TT_TypenameMacro, TT_FunctionLBrace, TT_ImplicitStringLiteral,
TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow, TT_NamespaceMacro,
TT_OverloadedOperator, TT_RegexLiteral, TT_TemplateString,
- TT_ObjCStringLiteral))
+ TT_ObjCStringLiteral, TT_UntouchableMacroFunc))
CurrentToken->setType(TT_Unknown);
CurrentToken->Role.reset();
CurrentToken->MatchingParen = nullptr;
<< " C=" << Tok->CanBreakBefore
<< " T=" << getTokenTypeName(Tok->getType())
<< " S=" << Tok->SpacesRequiredBefore
- << " B=" << Tok->BlockParameterCount
+ << " F=" << Tok->Finalized << " B=" << Tok->BlockParameterCount
<< " BK=" << Tok->BlockKind << " P=" << Tok->SplitPenalty
<< " Name=" << Tok->Tok.getName() << " L=" << Tok->TotalLength
<< " PPK=" << Tok->PackingKind << " FakeLParens=";
CHECK_PARSE("NamespaceMacros: [TESTSUITE, SUITE]", NamespaceMacros,
std::vector<std::string>({"TESTSUITE", "SUITE"}));
+ Style.WhitespaceSensitiveMacros.clear();
+ CHECK_PARSE("WhitespaceSensitiveMacros: [STRINGIZE]",
+ WhitespaceSensitiveMacros, std::vector<std::string>{"STRINGIZE"});
+ CHECK_PARSE("WhitespaceSensitiveMacros: [STRINGIZE, ASSERT]",
+ WhitespaceSensitiveMacros,
+ std::vector<std::string>({"STRINGIZE", "ASSERT"}));
+ Style.WhitespaceSensitiveMacros.clear();
+ CHECK_PARSE("WhitespaceSensitiveMacros: ['STRINGIZE']",
+ WhitespaceSensitiveMacros, std::vector<std::string>{"STRINGIZE"});
+ CHECK_PARSE("WhitespaceSensitiveMacros: ['STRINGIZE', 'ASSERT']",
+ WhitespaceSensitiveMacros,
+ std::vector<std::string>({"STRINGIZE", "ASSERT"}));
+
Style.IncludeStyle.IncludeCategories.clear();
std::vector<tooling::IncludeStyle::IncludeCategory> ExpectedCategories = {
{"abc/.*", 2, 0}, {".*", 1, 0}};
verifyFormat("foo(operator, , -42);", Style);
}
+TEST_F(FormatTest, WhitespaceSensitiveMacros) {
+ FormatStyle Style = getLLVMStyle();
+ Style.WhitespaceSensitiveMacros.push_back("FOO");
+
+ // Don't use the helpers here, since 'mess up' will change the whitespace
+ // and these are all whitespace sensitive by definition
+ EXPECT_EQ("FOO(String-ized&Messy+But(: :Still)=Intentional);",
+ format("FOO(String-ized&Messy+But(: :Still)=Intentional);", Style));
+ EXPECT_EQ(
+ "FOO(String-ized&Messy+But\\(: :Still)=Intentional);",
+ format("FOO(String-ized&Messy+But\\(: :Still)=Intentional);", Style));
+ EXPECT_EQ("FOO(String-ized&Messy+But,: :Still=Intentional);",
+ format("FOO(String-ized&Messy+But,: :Still=Intentional);", Style));
+ EXPECT_EQ("FOO(String-ized&Messy+But,: :\n"
+ " Still=Intentional);",
+ format("FOO(String-ized&Messy+But,: :\n"
+ " Still=Intentional);",
+ Style));
+ Style.AlignConsecutiveAssignments = true;
+ EXPECT_EQ("FOO(String-ized=&Messy+But,: :\n"
+ " Still=Intentional);",
+ format("FOO(String-ized=&Messy+But,: :\n"
+ " Still=Intentional);",
+ Style));
+
+ Style.ColumnLimit = 21;
+ EXPECT_EQ("FOO(String-ized&Messy+But: :Still=Intentional);",
+ format("FOO(String-ized&Messy+But: :Still=Intentional);", Style));
+}
+
TEST_F(FormatTest, VeryLongNamespaceCommentSplit) {
// These tests are not in NamespaceFixer because that doesn't
// test its interaction with line wrapping