1 #include "../../lib/Format/Macros.h" 2 #include "TestLexer.h" 3 #include "clang/Basic/FileManager.h" 4 5 #include "gtest/gtest.h" 6 7 namespace clang { 8 namespace format { 9 10 namespace { 11 12 class MacroExpanderTest : public ::testing::Test { 13 public: 14 MacroExpanderTest() : Lex(Allocator, Buffers) {} 15 std::unique_ptr<MacroExpander> 16 create(const std::vector<std::string> &MacroDefinitions) { 17 return std::make_unique<MacroExpander>(MacroDefinitions, 18 Lex.SourceMgr.get(), Lex.Style, 19 Lex.Allocator, Lex.IdentTable); 20 } 21 22 std::string expand(MacroExpander &Macros, llvm::StringRef Name) { 23 EXPECT_TRUE(Macros.defined(Name)) 24 << "Macro not defined: \"" << Name << "\""; 25 return text(Macros.expand(Lex.id(Name), {})); 26 } 27 28 std::string expand(MacroExpander &Macros, llvm::StringRef Name, 29 const std::vector<std::string> &Args) { 30 EXPECT_TRUE(Macros.defined(Name)) 31 << "Macro not defined: \"" << Name << "\""; 32 return text(Macros.expand(Lex.id(Name), lexArgs(Args))); 33 } 34 35 llvm::SmallVector<TokenList, 1> 36 lexArgs(const std::vector<std::string> &Args) { 37 llvm::SmallVector<TokenList, 1> Result; 38 for (const auto &Arg : Args) 39 Result.push_back(uneof(Lex.lex(Arg))); 40 return Result; 41 } 42 43 struct MacroAttributes { 44 clang::tok::TokenKind Kind; 45 MacroRole Role; 46 unsigned Start; 47 unsigned End; 48 llvm::SmallVector<FormatToken *, 1> ExpandedFrom; 49 }; 50 51 void expectAttributes(const TokenList &Tokens, 52 const std::vector<MacroAttributes> &Attributes, 53 const std::string &File, unsigned Line) { 54 EXPECT_EQ(Tokens.size(), Attributes.size()) << text(Tokens); 55 for (size_t I = 0, E = Tokens.size(); I != E; ++I) { 56 if (I >= Attributes.size()) 57 continue; 58 std::string Context = 59 ("for token " + llvm::Twine(I) + ": " + Tokens[I]->Tok.getName() + 60 " / " + Tokens[I]->TokenText) 61 .str(); 62 EXPECT_TRUE(Tokens[I]->is(Attributes[I].Kind)) 63 << Context << " in " << text(Tokens) << " at " << File << ":" << Line; 64 EXPECT_EQ(Tokens[I]->MacroCtx->Role, Attributes[I].Role) 65 << Context << " in " << text(Tokens) << " at " << File << ":" << Line; 66 EXPECT_EQ(Tokens[I]->MacroCtx->StartOfExpansion, Attributes[I].Start) 67 << Context << " in " << text(Tokens) << " at " << File << ":" << Line; 68 EXPECT_EQ(Tokens[I]->MacroCtx->EndOfExpansion, Attributes[I].End) 69 << Context << " in " << text(Tokens) << " at " << File << ":" << Line; 70 EXPECT_EQ(Tokens[I]->MacroCtx->ExpandedFrom, Attributes[I].ExpandedFrom) 71 << Context << " in " << text(Tokens) << " at " << File << ":" << Line; 72 } 73 } 74 75 protected: 76 llvm::SpecificBumpPtrAllocator<FormatToken> Allocator; 77 std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers; 78 TestLexer Lex; 79 }; 80 81 #define EXPECT_ATTRIBUTES(Tokens, Attributes) \ 82 expectAttributes(Tokens, Attributes, __FILE__, __LINE__) 83 84 TEST_F(MacroExpanderTest, SkipsDefinitionOnError) { 85 auto Macros = 86 create({"A(", "B(,", "C(a,", "D(a a", "E(a, a", "F(,)", "G(a;"}); 87 for (const auto *Name : {"A", "B", "C", "D", "E", "F", "G"}) 88 EXPECT_FALSE(Macros->defined(Name)) << "for Name " << Name; 89 } 90 91 TEST_F(MacroExpanderTest, ExpandsWithoutArguments) { 92 auto Macros = create({ 93 "A", 94 "B=b", 95 "C=c + c", 96 "D()", 97 }); 98 EXPECT_TRUE(Macros->objectLike("A")); 99 EXPECT_TRUE(Macros->objectLike("B")); 100 EXPECT_TRUE(Macros->objectLike("C")); 101 EXPECT_TRUE(!Macros->objectLike("D")); 102 EXPECT_EQ("", expand(*Macros, "A")); 103 EXPECT_EQ("b", expand(*Macros, "B")); 104 EXPECT_EQ("c+c", expand(*Macros, "C")); 105 EXPECT_EQ("", expand(*Macros, "D", {})); 106 } 107 108 TEST_F(MacroExpanderTest, ExpandsWithArguments) { 109 auto Macros = create({ 110 "A(x)", 111 "B(x, y)=x + y", 112 }); 113 EXPECT_EQ("", expand(*Macros, "A", {"a"})); 114 EXPECT_EQ("b1+b2+b3", expand(*Macros, "B", {"b1", "b2 + b3"})); 115 } 116 117 TEST_F(MacroExpanderTest, AttributizesTokens) { 118 auto Macros = create({ 119 "A(x, y)={ x + y; }", 120 "B(x, y)=x + 3 + y", 121 }); 122 auto *A = Lex.id("A"); 123 auto AArgs = lexArgs({"a1 * a2", "a3 * a4"}); 124 auto Result = Macros->expand(A, AArgs); 125 EXPECT_EQ(11U, Result.size()) << text(Result) << " / " << Result; 126 EXPECT_EQ("{a1*a2+a3*a4;}", text(Result)); 127 std::vector<MacroAttributes> Attributes = { 128 {tok::l_brace, MR_Hidden, 1, 0, {A}}, 129 {tok::identifier, MR_ExpandedArg, 0, 0, {A}}, 130 {tok::star, MR_ExpandedArg, 0, 0, {A}}, 131 {tok::identifier, MR_ExpandedArg, 0, 0, {A}}, 132 {tok::plus, MR_Hidden, 0, 0, {A}}, 133 {tok::identifier, MR_ExpandedArg, 0, 0, {A}}, 134 {tok::star, MR_ExpandedArg, 0, 0, {A}}, 135 {tok::identifier, MR_ExpandedArg, 0, 0, {A}}, 136 {tok::semi, MR_Hidden, 0, 0, {A}}, 137 {tok::r_brace, MR_Hidden, 0, 1, {A}}, 138 {tok::eof, MR_Hidden, 0, 0, {A}}, 139 }; 140 EXPECT_ATTRIBUTES(Result, Attributes); 141 142 auto *B = Lex.id("B"); 143 auto BArgs = lexArgs({"b1", "b2"}); 144 Result = Macros->expand(B, BArgs); 145 EXPECT_EQ(6U, Result.size()) << text(Result) << " / " << Result; 146 EXPECT_EQ("b1+3+b2", text(Result)); 147 Attributes = { 148 {tok::identifier, MR_ExpandedArg, 1, 0, {B}}, 149 {tok::plus, MR_Hidden, 0, 0, {B}}, 150 {tok::numeric_constant, MR_Hidden, 0, 0, {B}}, 151 {tok::plus, MR_Hidden, 0, 0, {B}}, 152 {tok::identifier, MR_ExpandedArg, 0, 1, {B}}, 153 {tok::eof, MR_Hidden, 0, 0, {B}}, 154 }; 155 EXPECT_ATTRIBUTES(Result, Attributes); 156 } 157 158 TEST_F(MacroExpanderTest, RecursiveExpansion) { 159 auto Macros = create({ 160 "A(x)=x", 161 "B(x)=x", 162 "C(x)=x", 163 }); 164 165 auto *A = Lex.id("A"); 166 auto *B = Lex.id("B"); 167 auto *C = Lex.id("C"); 168 169 auto Args = lexArgs({"id"}); 170 auto CResult = uneof(Macros->expand(C, Args)); 171 auto BResult = uneof(Macros->expand(B, CResult)); 172 auto AResult = uneof(Macros->expand(A, BResult)); 173 174 std::vector<MacroAttributes> Attributes = { 175 {tok::identifier, MR_ExpandedArg, 3, 3, {C, B, A}}, 176 }; 177 EXPECT_ATTRIBUTES(AResult, Attributes); 178 } 179 180 TEST_F(MacroExpanderTest, SingleExpansion) { 181 auto Macros = create({"A(x)=x+x"}); 182 auto *A = Lex.id("A"); 183 auto Args = lexArgs({"id"}); 184 auto Result = uneof(Macros->expand(A, Args)); 185 std::vector<MacroAttributes> Attributes = { 186 {tok::identifier, MR_ExpandedArg, 1, 0, {A}}, 187 {tok::plus, MR_Hidden, 0, 0, {A}}, 188 {tok::identifier, MR_Hidden, 0, 1, {A}}, 189 }; 190 EXPECT_ATTRIBUTES(Result, Attributes); 191 } 192 193 TEST_F(MacroExpanderTest, UnderstandsCppTokens) { 194 auto Macros = create({"A(T,name)=T name = 0;"}); 195 auto *A = Lex.id("A"); 196 auto Args = lexArgs({"const int", "x"}); 197 auto Result = uneof(Macros->expand(A, Args)); 198 std::vector<MacroAttributes> Attributes = { 199 {tok::kw_const, MR_ExpandedArg, 1, 0, {A}}, 200 {tok::kw_int, MR_ExpandedArg, 0, 0, {A}}, 201 {tok::identifier, MR_ExpandedArg, 0, 0, {A}}, 202 {tok::equal, MR_Hidden, 0, 0, {A}}, 203 {tok::numeric_constant, MR_Hidden, 0, 0, {A}}, 204 {tok::semi, MR_Hidden, 0, 1, {A}}, 205 }; 206 EXPECT_ATTRIBUTES(Result, Attributes); 207 } 208 209 TEST_F(MacroExpanderTest, Overloads) { 210 auto Macros = create({"A=x", "A()=y", "A(a)=a", "A(a, b)=a b"}); 211 EXPECT_EQ("x", expand(*Macros, "A")); 212 EXPECT_EQ("y", expand(*Macros, "A", {})); 213 EXPECT_EQ("z", expand(*Macros, "A", {"z"})); 214 EXPECT_EQ("xy", expand(*Macros, "A", {"x", "y"})); 215 } 216 217 } // namespace 218 } // namespace format 219 } // namespace clang 220