1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | #include "ASTPrint.h" |
22 | #include "clang/AST/ASTContext.h" |
23 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
24 | #include "clang/Tooling/Tooling.h" |
25 | #include "llvm/ADT/SmallString.h" |
26 | #include "gtest/gtest.h" |
27 | |
28 | using namespace clang; |
29 | using namespace ast_matchers; |
30 | using namespace tooling; |
31 | |
32 | namespace { |
33 | |
34 | enum class StdVer { CXX98, CXX11, CXX14, CXX17, CXX2a }; |
35 | |
36 | DeclarationMatcher FunctionBodyMatcher(StringRef ContainingFunction) { |
37 | return functionDecl(hasName(ContainingFunction), |
38 | has(compoundStmt(has(stmt().bind("id"))))); |
39 | } |
40 | |
41 | template <typename T> |
42 | ::testing::AssertionResult |
43 | PrintedStmtCXXMatches(StdVer Standard, StringRef Code, const T &NodeMatch, |
44 | StringRef ExpectedPrinted, |
45 | PolicyAdjusterType PolicyAdjuster = None) { |
46 | const char *StdOpt; |
47 | switch (Standard) { |
48 | case StdVer::CXX98: StdOpt = "-std=c++98"; break; |
49 | case StdVer::CXX11: StdOpt = "-std=c++11"; break; |
50 | case StdVer::CXX14: StdOpt = "-std=c++14"; break; |
51 | case StdVer::CXX17: StdOpt = "-std=c++17"; break; |
52 | case StdVer::CXX2a: StdOpt = "-std=c++2a"; break; |
53 | } |
54 | |
55 | std::vector<std::string> Args = { |
56 | StdOpt, |
57 | "-Wno-unused-value", |
58 | }; |
59 | return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted, |
60 | PolicyAdjuster); |
61 | } |
62 | |
63 | template <typename T> |
64 | ::testing::AssertionResult |
65 | PrintedStmtMSMatches(StringRef Code, const T &NodeMatch, |
66 | StringRef ExpectedPrinted, |
67 | PolicyAdjusterType PolicyAdjuster = None) { |
68 | std::vector<std::string> Args = { |
69 | "-std=c++98", |
70 | "-target", "i686-pc-win32", |
71 | "-fms-extensions", |
72 | "-Wno-unused-value", |
73 | }; |
74 | return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted, |
75 | PolicyAdjuster); |
76 | } |
77 | |
78 | template <typename T> |
79 | ::testing::AssertionResult |
80 | PrintedStmtObjCMatches(StringRef Code, const T &NodeMatch, |
81 | StringRef ExpectedPrinted, |
82 | PolicyAdjusterType PolicyAdjuster = None) { |
83 | std::vector<std::string> Args = { |
84 | "-ObjC", |
85 | "-fobjc-runtime=macosx-10.12.0", |
86 | }; |
87 | return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted, |
88 | PolicyAdjuster); |
89 | } |
90 | |
91 | } |
92 | |
93 | TEST(StmtPrinter, TestIntegerLiteral) { |
94 | ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX98, |
95 | "void A() {" |
96 | " 1, -1, 1U, 1u," |
97 | " 1L, 1l, -1L, 1UL, 1ul," |
98 | " 1LL, -1LL, 1ULL;" |
99 | "}", |
100 | FunctionBodyMatcher("A"), |
101 | "1 , -1 , 1U , 1U , " |
102 | "1L , 1L , -1L , 1UL , 1UL , " |
103 | "1LL , -1LL , 1ULL")); |
104 | |
105 | } |
106 | |
107 | TEST(StmtPrinter, TestMSIntegerLiteral) { |
108 | ASSERT_TRUE(PrintedStmtMSMatches( |
109 | "void A() {" |
110 | " 1i8, -1i8, 1ui8, " |
111 | " 1i16, -1i16, 1ui16, " |
112 | " 1i32, -1i32, 1ui32, " |
113 | " 1i64, -1i64, 1ui64;" |
114 | "}", |
115 | FunctionBodyMatcher("A"), |
116 | "1i8 , -1i8 , 1Ui8 , " |
117 | "1i16 , -1i16 , 1Ui16 , " |
118 | "1 , -1 , 1U , " |
119 | "1LL , -1LL , 1ULL")); |
120 | |
121 | } |
122 | |
123 | TEST(StmtPrinter, TestFloatingPointLiteral) { |
124 | ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX98, |
125 | "void A() { 1.0f, -1.0f, 1.0, -1.0, 1.0l, -1.0l; }", |
126 | FunctionBodyMatcher("A"), |
127 | "1.F , -1.F , 1. , -1. , 1.L , -1.L")); |
128 | |
129 | } |
130 | |
131 | TEST(StmtPrinter, TestCXXConversionDeclImplicit) { |
132 | ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX98, |
133 | "struct A {" |
134 | "operator void *();" |
135 | "A operator&(A);" |
136 | "};" |
137 | "void bar(void *);" |
138 | "void foo(A a, A b) {" |
139 | " bar(a & b);" |
140 | "}", |
141 | cxxMemberCallExpr(anything()).bind("id"), |
142 | "a & b")); |
143 | } |
144 | |
145 | TEST(StmtPrinter, TestCXXConversionDeclExplicit) { |
146 | ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11, |
147 | "struct A {" |
148 | "operator void *();" |
149 | "A operator&(A);" |
150 | "};" |
151 | "void bar(void *);" |
152 | "void foo(A a, A b) {" |
153 | " auto x = (a & b).operator void *();" |
154 | "}", |
155 | cxxMemberCallExpr(anything()).bind("id"), |
156 | "(a & b)")); |
157 | |
158 | } |
159 | |
160 | TEST(StmtPrinter, TestNoImplicitBases) { |
161 | const char *CPPSource = R"( |
162 | class A { |
163 | int field; |
164 | int member() { return field; } |
165 | }; |
166 | )"; |
167 | |
168 | ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11, |
169 | CPPSource, memberExpr(anything()).bind("id"), "field", |
170 | PolicyAdjusterType( |
171 | [](PrintingPolicy &PP) { PP.SuppressImplicitBase = true; }))); |
172 | |
173 | ASSERT_TRUE(PrintedStmtCXXMatches(StdVer::CXX11, |
174 | CPPSource, memberExpr(anything()).bind("id"), "this->field")); |
175 | |
176 | const char *ObjCSource = R"( |
177 | @interface I { |
178 | int ivar; |
179 | } |
180 | @end |
181 | @implementation I |
182 | - (int) method { |
183 | return ivar; |
184 | } |
185 | @end |
186 | )"; |
187 | |
188 | ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"), |
189 | "return ivar;\n", |
190 | PolicyAdjusterType([](PrintingPolicy &PP) { |
191 | PP.SuppressImplicitBase = true; |
192 | }))); |
193 | |
194 | ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"), |
195 | "return self->ivar;\n")); |
196 | } |
197 | |