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