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