1 //===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Tests for the correct import of AST nodes from one AST context to another.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "clang/AST/ASTContext.h"
15 #include "clang/AST/ASTImporter.h"
16 #include "MatchVerifier.h"
17 #include "clang/ASTMatchers/ASTMatchFinder.h"
18 #include "clang/ASTMatchers/ASTMatchers.h"
19 #include "clang/Tooling/Tooling.h"
20 #include "gtest/gtest.h"
21
22 namespace clang {
23 namespace ast_matchers {
24
25 typedef std::vector<std::string> StringVector;
26
getLangArgs(Language Lang,StringVector & Args)27 void getLangArgs(Language Lang, StringVector &Args) {
28 switch (Lang) {
29 case Lang_C:
30 Args.insert(Args.end(), { "-x", "c", "-std=c99" });
31 break;
32 case Lang_C89:
33 Args.insert(Args.end(), { "-x", "c", "-std=c89" });
34 break;
35 case Lang_CXX:
36 Args.push_back("-std=c++98");
37 break;
38 case Lang_CXX11:
39 Args.push_back("-std=c++11");
40 break;
41 case Lang_OpenCL:
42 case Lang_OBJCXX:
43 break;
44 }
45 }
46
47 template<typename NodeType, typename MatcherType>
48 testing::AssertionResult
testImport(const std::string & FromCode,Language FromLang,const std::string & ToCode,Language ToLang,MatchVerifier<NodeType> & Verifier,const MatcherType & AMatcher)49 testImport(const std::string &FromCode, Language FromLang,
50 const std::string &ToCode, Language ToLang,
51 MatchVerifier<NodeType> &Verifier,
52 const MatcherType &AMatcher) {
53 StringVector FromArgs, ToArgs;
54 getLangArgs(FromLang, FromArgs);
55 getLangArgs(ToLang, ToArgs);
56
57 const char *const InputFileName = "input.cc";
58 const char *const OutputFileName = "output.cc";
59
60 std::unique_ptr<ASTUnit>
61 FromAST = tooling::buildASTFromCodeWithArgs(
62 FromCode, FromArgs, InputFileName),
63 ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, OutputFileName);
64
65 ASTContext &FromCtx = FromAST->getASTContext(),
66 &ToCtx = ToAST->getASTContext();
67
68 // Add input.cc to virtual file system so importer can 'find' it
69 // while importing SourceLocations.
70 vfs::OverlayFileSystem *OFS = static_cast<vfs::OverlayFileSystem *>(
71 ToCtx.getSourceManager().getFileManager().getVirtualFileSystem().get());
72 vfs::InMemoryFileSystem *MFS = static_cast<vfs::InMemoryFileSystem *>(
73 OFS->overlays_begin()->get());
74 MFS->addFile(InputFileName, 0,
75 llvm::MemoryBuffer::getMemBuffer(FromCode.c_str()));
76
77 ASTImporter Importer(ToCtx, ToAST->getFileManager(),
78 FromCtx, FromAST->getFileManager(), false);
79
80 IdentifierInfo *ImportedII = &FromCtx.Idents.get("declToImport");
81 assert(ImportedII && "Declaration with 'declToImport' name"
82 "should be specified in test!");
83 DeclarationName ImportDeclName(ImportedII);
84 SmallVector<NamedDecl *, 4> FoundDecls;
85 FromCtx.getTranslationUnitDecl()->localUncachedLookup(
86 ImportDeclName, FoundDecls);
87
88 if (FoundDecls.size() != 1)
89 return testing::AssertionFailure() << "Multiple declarations were found!";
90
91 auto Imported = Importer.Import(*FoundDecls.begin());
92 if (!Imported)
93 return testing::AssertionFailure() << "Import failed, nullptr returned!";
94
95 // This should dump source locations and assert if some source locations
96 // were not imported
97 SmallString<1024> ImportChecker;
98 llvm::raw_svector_ostream ToNothing(ImportChecker);
99 ToCtx.getTranslationUnitDecl()->print(ToNothing);
100
101 return Verifier.match(Imported, AMatcher);
102 }
103
TEST(ImportExpr,ImportStringLiteral)104 TEST(ImportExpr, ImportStringLiteral) {
105 MatchVerifier<Decl> Verifier;
106 EXPECT_TRUE(testImport("void declToImport() { \"foo\"; }",
107 Lang_CXX, "", Lang_CXX, Verifier,
108 functionDecl(
109 hasBody(
110 compoundStmt(
111 has(
112 stringLiteral(
113 hasType(
114 asString("const char [4]")))))))));
115 EXPECT_TRUE(testImport("void declToImport() { L\"foo\"; }",
116 Lang_CXX, "", Lang_CXX, Verifier,
117 functionDecl(
118 hasBody(
119 compoundStmt(
120 has(
121 stringLiteral(
122 hasType(
123 asString("const wchar_t [4]")))))))));
124 EXPECT_TRUE(testImport("void declToImport() { \"foo\" \"bar\"; }",
125 Lang_CXX, "", Lang_CXX, Verifier,
126 functionDecl(
127 hasBody(
128 compoundStmt(
129 has(
130 stringLiteral(
131 hasType(
132 asString("const char [7]")))))))));
133 }
134
TEST(ImportExpr,ImportGNUNullExpr)135 TEST(ImportExpr, ImportGNUNullExpr) {
136 MatchVerifier<Decl> Verifier;
137 EXPECT_TRUE(testImport("void declToImport() { __null; }",
138 Lang_CXX, "", Lang_CXX, Verifier,
139 functionDecl(
140 hasBody(
141 compoundStmt(
142 has(
143 gnuNullExpr(
144 hasType(isInteger()))))))));
145 }
146
TEST(ImportExpr,ImportCXXNullPtrLiteralExpr)147 TEST(ImportExpr, ImportCXXNullPtrLiteralExpr) {
148 MatchVerifier<Decl> Verifier;
149 EXPECT_TRUE(testImport("void declToImport() { nullptr; }",
150 Lang_CXX11, "", Lang_CXX11, Verifier,
151 functionDecl(
152 hasBody(
153 compoundStmt(
154 has(
155 cxxNullPtrLiteralExpr()))))));
156 }
157
158
TEST(ImportExpr,ImportFloatinglLiteralExpr)159 TEST(ImportExpr, ImportFloatinglLiteralExpr) {
160 MatchVerifier<Decl> Verifier;
161 EXPECT_TRUE(testImport("void declToImport() { 1.0; }",
162 Lang_CXX, "", Lang_CXX, Verifier,
163 functionDecl(
164 hasBody(
165 compoundStmt(
166 has(
167 floatLiteral(
168 equals(1.0),
169 hasType(asString("double")))))))));
170 EXPECT_TRUE(testImport("void declToImport() { 1.0e-5f; }",
171 Lang_CXX, "", Lang_CXX, Verifier,
172 functionDecl(
173 hasBody(
174 compoundStmt(
175 has(
176 floatLiteral(
177 equals(1.0e-5f),
178 hasType(asString("float")))))))));
179 }
180
TEST(ImportExpr,ImportCompoundLiteralExpr)181 TEST(ImportExpr, ImportCompoundLiteralExpr) {
182 MatchVerifier<Decl> Verifier;
183 EXPECT_TRUE(
184 testImport(
185 "void declToImport() {"
186 " struct s { int x; long y; unsigned z; }; "
187 " (struct s){ 42, 0L, 1U }; }",
188 Lang_CXX, "", Lang_CXX, Verifier,
189 functionDecl(
190 hasBody(
191 compoundStmt(
192 has(
193 compoundLiteralExpr(
194 hasType(asString("struct s")),
195 has(initListExpr(
196 hasType(asString("struct s")),
197 has(integerLiteral(
198 equals(42), hasType(asString("int")))),
199 has(integerLiteral(
200 equals(0), hasType(asString("long")))),
201 has(integerLiteral(
202 equals(1),
203 hasType(asString("unsigned int"))))
204 )))))))));
205 }
206
TEST(ImportExpr,ImportCXXThisExpr)207 TEST(ImportExpr, ImportCXXThisExpr) {
208 MatchVerifier<Decl> Verifier;
209 EXPECT_TRUE(
210 testImport("class declToImport { void f() { this; } };",
211 Lang_CXX, "", Lang_CXX, Verifier,
212 cxxRecordDecl(
213 hasMethod(
214 hasBody(
215 compoundStmt(
216 has(
217 cxxThisExpr(
218 hasType(
219 asString("class declToImport *"))))))))));
220 }
221
TEST(ImportExpr,ImportAtomicExpr)222 TEST(ImportExpr, ImportAtomicExpr) {
223 MatchVerifier<Decl> Verifier;
224 EXPECT_TRUE(testImport(
225 "void declToImport() { int *ptr; __atomic_load_n(ptr, 1); }", Lang_CXX,
226 "", Lang_CXX, Verifier,
227 functionDecl(hasBody(compoundStmt(has(atomicExpr(
228 has(ignoringParenImpCasts(
229 declRefExpr(hasDeclaration(varDecl(hasName("ptr"))),
230 hasType(asString("int *"))))),
231 has(integerLiteral(equals(1), hasType(asString("int")))))))))));
232 }
233
TEST(ImportExpr,ImportLabelDeclAndAddrLabelExpr)234 TEST(ImportExpr, ImportLabelDeclAndAddrLabelExpr) {
235 MatchVerifier<Decl> Verifier;
236 EXPECT_TRUE(
237 testImport(
238 "void declToImport() { loop: goto loop; &&loop; }",
239 Lang_CXX, "", Lang_CXX, Verifier,
240 functionDecl(
241 hasBody(
242 compoundStmt(
243 has(labelStmt(hasDeclaration(labelDecl(hasName("loop"))))),
244 has(addrLabelExpr(hasDeclaration(labelDecl(hasName("loop")))))
245 )))));
246 }
247
AST_MATCHER_P(TemplateDecl,hasTemplateDecl,internal::Matcher<NamedDecl>,InnerMatcher)248 AST_MATCHER_P(TemplateDecl, hasTemplateDecl,
249 internal::Matcher<NamedDecl>, InnerMatcher) {
250 const NamedDecl *Template = Node.getTemplatedDecl();
251 return Template && InnerMatcher.matches(*Template, Finder, Builder);
252 }
253
TEST(ImportExpr,ImportParenListExpr)254 TEST(ImportExpr, ImportParenListExpr) {
255 MatchVerifier<Decl> Verifier;
256 EXPECT_TRUE(
257 testImport(
258 "template<typename T> class dummy { void f() { dummy X(*this); } };"
259 "typedef dummy<int> declToImport;"
260 "template class dummy<int>;",
261 Lang_CXX, "", Lang_CXX, Verifier,
262 typedefDecl(
263 hasType(
264 templateSpecializationType(
265 hasDeclaration(
266 classTemplateDecl(
267 hasTemplateDecl(
268 cxxRecordDecl(
269 hasMethod(
270 allOf(
271 hasName("f"),
272 hasBody(
273 compoundStmt(
274 has(
275 declStmt(
276 hasSingleDecl(
277 varDecl(
278 hasInitializer(
279 parenListExpr(
280 has(
281 unaryOperator(
282 hasOperatorName("*"),
283 hasUnaryOperand(cxxThisExpr())
284 )))))))))))))))))))));
285 }
286
TEST(ImportExpr,ImportStmtExpr)287 TEST(ImportExpr, ImportStmtExpr) {
288 MatchVerifier<Decl> Verifier;
289 // NOTE: has() ignores implicit casts, using hasDescendant() to match it
290 EXPECT_TRUE(
291 testImport(
292 "void declToImport() { int b; int a = b ?: 1; int C = ({int X=4; X;}); }",
293 Lang_CXX, "", Lang_CXX, Verifier,
294 functionDecl(
295 hasBody(
296 compoundStmt(
297 has(
298 declStmt(
299 hasSingleDecl(
300 varDecl(
301 hasName("C"),
302 hasType(asString("int")),
303 hasInitializer(
304 stmtExpr(
305 hasAnySubstatement(
306 declStmt(
307 hasSingleDecl(
308 varDecl(
309 hasName("X"),
310 hasType(asString("int")),
311 hasInitializer(
312 integerLiteral(equals(4))))))),
313 hasDescendant(
314 implicitCastExpr()
315 ))))))))))));
316 }
317
TEST(ImportExpr,ImportConditionalOperator)318 TEST(ImportExpr, ImportConditionalOperator) {
319 MatchVerifier<Decl> Verifier;
320 EXPECT_TRUE(
321 testImport(
322 "void declToImport() { true ? 1 : -5; }",
323 Lang_CXX, "", Lang_CXX, Verifier,
324 functionDecl(
325 hasBody(
326 compoundStmt(
327 has(
328 conditionalOperator(
329 hasCondition(cxxBoolLiteral(equals(true))),
330 hasTrueExpression(integerLiteral(equals(1))),
331 hasFalseExpression(
332 unaryOperator(hasUnaryOperand(integerLiteral(equals(5))))
333 ))))))));
334 }
335
TEST(ImportExpr,ImportBinaryConditionalOperator)336 TEST(ImportExpr, ImportBinaryConditionalOperator) {
337 MatchVerifier<Decl> Verifier;
338 EXPECT_TRUE(
339 testImport(
340 "void declToImport() { 1 ?: -5; }",
341 Lang_CXX, "", Lang_CXX, Verifier,
342 functionDecl(
343 hasBody(
344 compoundStmt(
345 has(
346 binaryConditionalOperator(
347 hasCondition(
348 implicitCastExpr(
349 hasSourceExpression(
350 opaqueValueExpr(
351 hasSourceExpression(integerLiteral(equals(1))))),
352 hasType(booleanType()))),
353 hasTrueExpression(
354 opaqueValueExpr(hasSourceExpression(
355 integerLiteral(equals(1))))),
356 hasFalseExpression(
357 unaryOperator(hasOperatorName("-"),
358 hasUnaryOperand(integerLiteral(equals(5)))))
359 )))))));
360 }
361
TEST(ImportExpr,ImportDesignatedInitExpr)362 TEST(ImportExpr, ImportDesignatedInitExpr) {
363 MatchVerifier<Decl> Verifier;
364 EXPECT_TRUE(testImport("void declToImport() {"
365 " struct point { double x; double y; };"
366 " struct point ptarray[10] = "
367 "{ [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; }",
368 Lang_C, "", Lang_C, Verifier,
369 functionDecl(
370 hasBody(
371 compoundStmt(
372 has(
373 declStmt(
374 hasSingleDecl(
375 varDecl(
376 hasInitializer(
377 initListExpr(
378 hasSyntacticForm(
379 initListExpr(
380 has(
381 designatedInitExpr(
382 designatorCountIs(2),
383 has(floatLiteral(
384 equals(1.0))),
385 has(integerLiteral(
386 equals(2))))),
387 has(
388 designatedInitExpr(
389 designatorCountIs(2),
390 has(floatLiteral(
391 equals(2.0))),
392 has(integerLiteral(
393 equals(2))))),
394 has(
395 designatedInitExpr(
396 designatorCountIs(2),
397 has(floatLiteral(
398 equals(1.0))),
399 has(integerLiteral(
400 equals(0)))))
401 )))))))))))));
402 }
403
404
TEST(ImportExpr,ImportPredefinedExpr)405 TEST(ImportExpr, ImportPredefinedExpr) {
406 MatchVerifier<Decl> Verifier;
407 // __func__ expands as StringLiteral("declToImport")
408 EXPECT_TRUE(testImport("void declToImport() { __func__; }",
409 Lang_CXX, "", Lang_CXX, Verifier,
410 functionDecl(
411 hasBody(
412 compoundStmt(
413 has(
414 predefinedExpr(
415 hasType(
416 asString("const char [13]")),
417 has(
418 stringLiteral(
419 hasType(
420 asString("const char [13]")))))))))));
421 }
422
TEST(ImportExpr,ImportInitListExpr)423 TEST(ImportExpr, ImportInitListExpr) {
424 MatchVerifier<Decl> Verifier;
425 EXPECT_TRUE(
426 testImport(
427 "void declToImport() {"
428 " struct point { double x; double y; };"
429 " point ptarray[10] = { [2].y = 1.0, [2].x = 2.0,"
430 " [0].x = 1.0 }; }",
431 Lang_CXX, "", Lang_CXX, Verifier,
432 functionDecl(
433 hasBody(
434 compoundStmt(
435 has(
436 declStmt(
437 hasSingleDecl(
438 varDecl(
439 hasInitializer(
440 initListExpr(
441 has(
442 cxxConstructExpr(
443 requiresZeroInitialization())),
444 has(
445 initListExpr(
446 hasType(asString("struct point")),
447 has(floatLiteral(equals(1.0))),
448 has(implicitValueInitExpr(
449 hasType(asString("double")))))),
450 has(
451 initListExpr(
452 hasType(asString("struct point")),
453 has(floatLiteral(equals(2.0))),
454 has(floatLiteral(equals(1.0)))))
455 )))))))))));
456 }
457
458
459 } // end namespace ast_matchers
460 } // end namespace clang
461