//===- unittest/Format/FormatMacroExpansion.cpp - Formatting unit tests ---===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "FormatTestBase.h" #define DEBUG_TYPE "format-test-macro-expansion" namespace clang { namespace format { namespace test { namespace { class FormatTestMacroExpansion : public FormatTestBase {}; TEST_F(FormatTestMacroExpansion, UnexpandConfiguredMacros) { FormatStyle Style = getLLVMStyle(); Style.Macros.push_back("CLASS=class C {"); Style.Macros.push_back("SEMI=;"); Style.Macros.push_back("STMT=f();"); Style.Macros.push_back("ID(x)=x"); Style.Macros.push_back("ID3(x, y, z)=x y z"); Style.Macros.push_back("CALL(x)=f([] { x })"); Style.Macros.push_back("ASSIGN_OR_RETURN(a, b)=a = (b)"); Style.Macros.push_back("ASSIGN_OR_RETURN(a, b, c)=a = (b); if (x) return c"); Style.Macros.push_back("MOCK_METHOD(r, n, a, s)=r n a s"); verifyFormat("ID(nested(a(b, c), d))", Style); verifyFormat("CLASS\n" " a *b;\n" "};", Style); verifyFormat("SEMI\n" "SEMI\n" "SEMI", Style); verifyFormat("STMT\n" "STMT\n" "STMT", Style); verifyFormat("void f() { ID(a *b); }", Style); verifyFormat("ID(\n" " {\n" " ID(a *b);\n" " });", Style); verifyIncompleteFormat("ID3({, ID(a *b),\n" " ;\n" " });", Style); verifyFormat("ID(CALL(CALL(return a * b;)));", Style); verifyFormat("ASSIGN_OR_RETURN(MySomewhatLongType *variable,\n" " MySomewhatLongFunction(SomethingElse()));", Style); verifyFormat("ASSIGN_OR_RETURN(MySomewhatLongType *variable,\n" " MySomewhatLongFunction(SomethingElse()), " "ReturnMe());", Style); verifyFormat(R"( #define MACRO(a, b) ID(a + b) )", Style); EXPECT_EQ(R"( int a; int b; int c; int d; int e; int f; ID( namespace foo { int a; } ) // namespace k )", format(R"( int a; int b; int c; int d; int e; int f; ID(namespace foo { int a; }) // namespace k )", Style)); verifyFormat(R"(ID( // ({ ; })) )", Style); Style.ColumnLimit = 35; // FIXME: Arbitrary formatting of macros where the end of the logical // line is in the middle of a macro call are not working yet. verifyFormat(R"(ID( void f(); void) ID(g) ID(()) ID( ; void g();) )", Style); Style.ColumnLimit = 10; verifyFormat("STMT\n" "STMT\n" "STMT", Style); EXPECT_EQ(R"( ID(CALL(CALL( a *b))); )", format(R"( ID(CALL(CALL(a * b))); )", Style)); // FIXME: If we want to support unbalanced braces or parens from macro // expansions we need to re-think how we propagate errors in // TokenAnnotator::parseLine; for investigation, switching the inner loop of // TokenAnnotator::parseLine to return LT_Other instead of LT_Invalid in case // of !consumeToken() changes the formatting of the test below and makes it // believe it has a fully correct formatting. EXPECT_EQ(R"( ID3( { CLASS a *b; }; }, ID(x *y); , STMT STMT STMT) void f(); )", format(R"( ID3({CLASS a*b; };}, ID(x*y);, STMT STMT STMT) void f(); )", Style)); verifyFormat("ID(a(\n" "#ifdef A\n" " b, c\n" "#else\n" " d(e)\n" "#endif\n" " ))", Style); Style.ColumnLimit = 80; verifyFormat(R"(ASSIGN_OR_RETURN( // Comment a b, c); )", Style); Style.ColumnLimit = 30; verifyFormat(R"(ASSIGN_OR_RETURN( // Comment // a b, xxxxxxxxxxxx( yyyyyyyyyyyyyyyyy, zzzzzzzzzzzzzzzzzz), f([]() { a(); b(); })); )", Style); verifyFormat(R"(int a = []() { ID( x; y; z;) ; }(); )", Style); EXPECT_EQ( R"(ASSIGN_OR_RETURN(( ==== #)) })", format(R"(ASSIGN_OR_RETURN(( ==== #)) })", Style, SC_ExpectIncomplete)); EXPECT_EQ(R"(ASSIGN_OR_RETURN( } ( ==== #), a))", format(R"(ASSIGN_OR_RETURN( } ( ==== #), a))", Style, SC_ExpectIncomplete)); EXPECT_EQ(R"(ASSIGN_OR_RETURN(a // ==== # <))", format(R"(ASSIGN_OR_RETURN(a // ==== # <))", Style)); verifyFormat("class C {\n" " MOCK_METHOD(R, f,\n" " (a *b, c *d),\n" " (override));\n" "};", Style); } TEST_F(FormatTestMacroExpansion, KeepParensWhenExpandingObjectLikeMacros) { FormatStyle Style = getLLVMStyle(); Style.Macros.push_back("FN=class C { int f"); verifyFormat("void f() {\n" " FN(a *b);\n" " };\n" "}", Style); } TEST_F(FormatTestMacroExpansion, DoesNotExpandFunctionLikeMacrosWithoutParens) { FormatStyle Style = getLLVMStyle(); Style.Macros.push_back("CLASS()=class C {"); verifyFormat("CLASS void f();\n" "}\n" ";", Style); } TEST_F(FormatTestMacroExpansion, ContinueFormattingAfterUnclosedParensAfterObjectLikeMacro) { FormatStyle Style = getLLVMStyle(); Style.Macros.push_back("O=class {"); verifyIncompleteFormat("O(auto x = [](){\n" " f();}", Style); } TEST_F(FormatTestMacroExpansion, CommaAsOperator) { FormatStyle Style = getGoogleStyleWithColumns(42); Style.Macros.push_back("MACRO(a, b, c)=a=(b); if(x) c"); verifyFormat("MACRO(auto a,\n" " looooongfunction(first, second,\n" " third),\n" " fourth);", Style); } TEST_F(FormatTestMacroExpansion, ForcedBreakDiffers) { FormatStyle Style = getGoogleStyleWithColumns(40); Style.Macros.push_back("MACRO(a, b)=a=(b)"); verifyFormat("//\n" "MACRO(const type variable,\n" " functtioncall(\n" " first, longsecondarg, third));", Style); } TEST_F(FormatTestMacroExpansion, PreferNotBreakingBetweenReturnTypeAndFunction) { FormatStyle Style = getGoogleStyleWithColumns(22); Style.Macros.push_back("MOCK_METHOD(r, n, a)=r n a"); // In the expanded code, we parse a full function signature, and afterwards // know that we prefer not to break before the function name. verifyFormat("MOCK_METHOD(\n" " type, variable,\n" " (type));", Style); } TEST_F(FormatTestMacroExpansion, IndentChildrenWithinMacroCall) { FormatStyle Style = getGoogleStyleWithColumns(22); Style.Macros.push_back("MACRO(a, b)=a=(b)"); verifyFormat("void f() {\n" " MACRO(a b, call([] {\n" " if (expr) {\n" " indent();\n" " }\n" " }));\n" "}", Style); } } // namespace } // namespace test } // namespace format } // namespace clang