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 
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
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, llvm::MemoryBuffer::getMemBuffer(FromCode));
75 
76   ASTImporter Importer(ToCtx, ToAST->getFileManager(),
77                        FromCtx, FromAST->getFileManager(), false);
78 
79   IdentifierInfo *ImportedII = &FromCtx.Idents.get("declToImport");
80   assert(ImportedII && "Declaration with 'declToImport' name"
81                        "should be specified in test!");
82   DeclarationName ImportDeclName(ImportedII);
83   SmallVector<NamedDecl *, 4> FoundDecls;
84   FromCtx.getTranslationUnitDecl()->localUncachedLookup(
85         ImportDeclName, FoundDecls);
86 
87   if (FoundDecls.size() != 1)
88     return testing::AssertionFailure() << "Multiple declarations were found!";
89 
90   auto Imported = Importer.Import(*FoundDecls.begin());
91   if (!Imported)
92     return testing::AssertionFailure() << "Import failed, nullptr returned!";
93 
94   // This should dump source locations and assert if some source locations
95   // were not imported
96   SmallString<1024> ImportChecker;
97   llvm::raw_svector_ostream ToNothing(ImportChecker);
98   ToCtx.getTranslationUnitDecl()->print(ToNothing);
99 
100   return Verifier.match(Imported, AMatcher);
101 }
102 
103 TEST(ImportExpr, ImportStringLiteral) {
104   MatchVerifier<Decl> Verifier;
105   EXPECT_TRUE(testImport("void declToImport() { \"foo\"; }",
106                          Lang_CXX, "", Lang_CXX, Verifier,
107                          functionDecl(
108                            hasBody(
109                              compoundStmt(
110                                has(
111                                  stringLiteral(
112                                    hasType(
113                                      asString("const char [4]")))))))));
114   EXPECT_TRUE(testImport("void declToImport() { L\"foo\"; }",
115                          Lang_CXX, "", Lang_CXX, Verifier,
116                          functionDecl(
117                            hasBody(
118                              compoundStmt(
119                                has(
120                                  stringLiteral(
121                                    hasType(
122                                      asString("const wchar_t [4]")))))))));
123   EXPECT_TRUE(testImport("void declToImport() { \"foo\" \"bar\"; }",
124                          Lang_CXX, "", Lang_CXX, Verifier,
125                          functionDecl(
126                            hasBody(
127                              compoundStmt(
128                                has(
129                                  stringLiteral(
130                                    hasType(
131                                      asString("const char [7]")))))))));
132 }
133 
134 TEST(ImportExpr, ImportGNUNullExpr) {
135   MatchVerifier<Decl> Verifier;
136   EXPECT_TRUE(testImport("void declToImport() { __null; }",
137                          Lang_CXX, "", Lang_CXX, Verifier,
138                          functionDecl(
139                            hasBody(
140                              compoundStmt(
141                                has(
142                                  gnuNullExpr(
143                                    hasType(isInteger()))))))));
144 }
145 
146 TEST(ImportExpr, ImportCXXNullPtrLiteralExpr) {
147   MatchVerifier<Decl> Verifier;
148   EXPECT_TRUE(testImport("void declToImport() { nullptr; }",
149                          Lang_CXX11, "", Lang_CXX11, Verifier,
150                          functionDecl(
151                            hasBody(
152                              compoundStmt(
153                                has(
154                                  cxxNullPtrLiteralExpr()))))));
155 }
156 
157 
158 TEST(ImportExpr, ImportFloatinglLiteralExpr) {
159   MatchVerifier<Decl> Verifier;
160   EXPECT_TRUE(testImport("void declToImport() { 1.0; }",
161                          Lang_CXX, "", Lang_CXX, Verifier,
162                          functionDecl(
163                            hasBody(
164                              compoundStmt(
165                                has(
166                                  floatLiteral(
167                                    equals(1.0),
168                                    hasType(asString("double")))))))));
169   EXPECT_TRUE(testImport("void declToImport() { 1.0e-5f; }",
170                          Lang_CXX, "", Lang_CXX, Verifier,
171                          functionDecl(
172                            hasBody(
173                              compoundStmt(
174                                has(
175                                  floatLiteral(
176                                    equals(1.0e-5f),
177                                    hasType(asString("float")))))))));
178 }
179 
180 TEST(ImportExpr, ImportCompoundLiteralExpr) {
181   MatchVerifier<Decl> Verifier;
182   EXPECT_TRUE(
183         testImport(
184           "void declToImport() {"
185           "  struct s { int x; long y; unsigned z; }; "
186           "  (struct s){ 42, 0L, 1U }; }",
187           Lang_CXX, "", Lang_CXX, Verifier,
188           functionDecl(
189             hasBody(
190               compoundStmt(
191                 has(
192                   compoundLiteralExpr(
193                     hasType(asString("struct s")),
194                     has(initListExpr(
195                       hasType(asString("struct s")),
196                       has(integerLiteral(
197                             equals(42), hasType(asString("int")))),
198                       has(integerLiteral(
199                             equals(0), hasType(asString("long")))),
200                       has(integerLiteral(
201                             equals(1),
202                             hasType(asString("unsigned int"))))
203                       )))))))));
204 }
205 
206 TEST(ImportExpr, ImportCXXThisExpr) {
207   MatchVerifier<Decl> Verifier;
208   EXPECT_TRUE(
209         testImport("class declToImport { void f() { this; } };",
210                    Lang_CXX, "", Lang_CXX, Verifier,
211                    cxxRecordDecl(
212                      hasMethod(
213                        hasBody(
214                          compoundStmt(
215                            has(
216                              cxxThisExpr(
217                                hasType(
218                                  asString("class declToImport *"))))))))));
219 }
220 
221 TEST(ImportExpr, ImportAtomicExpr) {
222   MatchVerifier<Decl> Verifier;
223   EXPECT_TRUE(testImport(
224       "void declToImport() { int *ptr; __atomic_load_n(ptr, 1); }", Lang_CXX,
225       "", Lang_CXX, Verifier,
226       functionDecl(hasBody(compoundStmt(has(atomicExpr(
227           has(ignoringParenImpCasts(
228               declRefExpr(hasDeclaration(varDecl(hasName("ptr"))),
229                           hasType(asString("int *"))))),
230           has(integerLiteral(equals(1), hasType(asString("int")))))))))));
231 }
232 
233 TEST(ImportExpr, ImportLabelDeclAndAddrLabelExpr) {
234   MatchVerifier<Decl> Verifier;
235   EXPECT_TRUE(
236         testImport(
237           "void declToImport() { loop: goto loop; &&loop; }",
238           Lang_CXX, "", Lang_CXX, Verifier,
239           functionDecl(
240             hasBody(
241               compoundStmt(
242                 has(labelStmt(hasDeclaration(labelDecl(hasName("loop"))))),
243                 has(addrLabelExpr(hasDeclaration(labelDecl(hasName("loop")))))
244                 )))));
245 }
246 
247 AST_MATCHER_P(TemplateDecl, hasTemplateDecl,
248               internal::Matcher<NamedDecl>, InnerMatcher) {
249   const NamedDecl *Template = Node.getTemplatedDecl();
250   return Template && InnerMatcher.matches(*Template, Finder, Builder);
251 }
252 
253 TEST(ImportExpr, ImportParenListExpr) {
254   MatchVerifier<Decl> Verifier;
255   EXPECT_TRUE(
256         testImport(
257           "template<typename T> class dummy { void f() { dummy X(*this); } };"
258           "typedef dummy<int> declToImport;"
259           "template class dummy<int>;",
260           Lang_CXX, "", Lang_CXX, Verifier,
261           typedefDecl(
262             hasType(
263               templateSpecializationType(
264                 hasDeclaration(
265                   classTemplateDecl(
266                     hasTemplateDecl(
267                       cxxRecordDecl(
268                         hasMethod(
269                         allOf(
270                           hasName("f"),
271                           hasBody(
272                             compoundStmt(
273                               has(
274                                 declStmt(
275                                   hasSingleDecl(
276                                     varDecl(
277                                       hasInitializer(
278                                         parenListExpr(
279                                           has(
280                                             unaryOperator(
281                                               hasOperatorName("*"),
282                                               hasUnaryOperand(cxxThisExpr())
283                                               )))))))))))))))))))));
284 }
285 
286 TEST(ImportExpr, ImportStmtExpr) {
287   MatchVerifier<Decl> Verifier;
288   // NOTE: has() ignores implicit casts, using hasDescendant() to match it
289   EXPECT_TRUE(
290         testImport(
291           "void declToImport() { int b; int a = b ?: 1; int C = ({int X=4; X;}); }",
292           Lang_CXX, "", Lang_CXX, Verifier,
293           functionDecl(
294             hasBody(
295               compoundStmt(
296                 has(
297                   declStmt(
298                     hasSingleDecl(
299                       varDecl(
300                         hasName("C"),
301                         hasType(asString("int")),
302                         hasInitializer(
303                           stmtExpr(
304                             hasAnySubstatement(
305                               declStmt(
306                                 hasSingleDecl(
307                                   varDecl(
308                                     hasName("X"),
309                                     hasType(asString("int")),
310                                     hasInitializer(
311                                       integerLiteral(equals(4))))))),
312                             hasDescendant(
313                               implicitCastExpr()
314                               ))))))))))));
315 }
316 
317 TEST(ImportExpr, ImportConditionalOperator) {
318   MatchVerifier<Decl> Verifier;
319   EXPECT_TRUE(
320         testImport(
321           "void declToImport() { true ? 1 : -5; }",
322           Lang_CXX, "", Lang_CXX, Verifier,
323           functionDecl(
324             hasBody(
325               compoundStmt(
326                 has(
327                   conditionalOperator(
328                     hasCondition(cxxBoolLiteral(equals(true))),
329                     hasTrueExpression(integerLiteral(equals(1))),
330                     hasFalseExpression(
331                       unaryOperator(hasUnaryOperand(integerLiteral(equals(5))))
332                       ))))))));
333 }
334 
335 TEST(ImportExpr, ImportBinaryConditionalOperator) {
336   MatchVerifier<Decl> Verifier;
337   EXPECT_TRUE(
338         testImport(
339           "void declToImport() { 1 ?: -5; }",
340           Lang_CXX, "", Lang_CXX, Verifier,
341           functionDecl(
342             hasBody(
343               compoundStmt(
344                 has(
345                   binaryConditionalOperator(
346                     hasCondition(
347                       implicitCastExpr(
348                         hasSourceExpression(
349                           opaqueValueExpr(
350                             hasSourceExpression(integerLiteral(equals(1))))),
351                         hasType(booleanType()))),
352                     hasTrueExpression(
353                       opaqueValueExpr(hasSourceExpression(
354                                         integerLiteral(equals(1))))),
355                     hasFalseExpression(
356                       unaryOperator(hasOperatorName("-"),
357                                     hasUnaryOperand(integerLiteral(equals(5)))))
358                       )))))));
359 }
360 
361 TEST(ImportExpr, ImportDesignatedInitExpr) {
362   MatchVerifier<Decl> Verifier;
363   EXPECT_TRUE(testImport("void declToImport() {"
364                          "  struct point { double x; double y; };"
365                          "  struct point ptarray[10] = "
366                                 "{ [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; }",
367                          Lang_C, "", Lang_C, Verifier,
368                          functionDecl(
369                            hasBody(
370                              compoundStmt(
371                                has(
372                                  declStmt(
373                                    hasSingleDecl(
374                                      varDecl(
375                                        hasInitializer(
376                                          initListExpr(
377                                            hasSyntacticForm(
378                                              initListExpr(
379                                                has(
380                                                  designatedInitExpr(
381                                                    designatorCountIs(2),
382                                                    has(floatLiteral(
383                                                          equals(1.0))),
384                                                    has(integerLiteral(
385                                                          equals(2))))),
386                                                has(
387                                                  designatedInitExpr(
388                                                    designatorCountIs(2),
389                                                    has(floatLiteral(
390                                                          equals(2.0))),
391                                                    has(integerLiteral(
392                                                          equals(2))))),
393                                                has(
394                                                  designatedInitExpr(
395                                                    designatorCountIs(2),
396                                                    has(floatLiteral(
397                                                          equals(1.0))),
398                                                    has(integerLiteral(
399                                                          equals(0)))))
400                                                )))))))))))));
401 }
402 
403 
404 TEST(ImportExpr, ImportPredefinedExpr) {
405   MatchVerifier<Decl> Verifier;
406   // __func__ expands as StringLiteral("declToImport")
407   EXPECT_TRUE(testImport("void declToImport() { __func__; }",
408                          Lang_CXX, "", Lang_CXX, Verifier,
409                          functionDecl(
410                            hasBody(
411                              compoundStmt(
412                                has(
413                                  predefinedExpr(
414                                    hasType(
415                                      asString("const char [13]")),
416                                    has(
417                                      stringLiteral(
418                                        hasType(
419                                          asString("const char [13]")))))))))));
420 }
421 
422 TEST(ImportExpr, ImportInitListExpr) {
423   MatchVerifier<Decl> Verifier;
424   EXPECT_TRUE(
425         testImport(
426           "void declToImport() {"
427           "  struct point { double x; double y; };"
428           "  point ptarray[10] = { [2].y = 1.0, [2].x = 2.0,"
429           "                        [0].x = 1.0 }; }",
430           Lang_CXX, "", Lang_CXX, Verifier,
431           functionDecl(
432             hasBody(
433               compoundStmt(
434                 has(
435                   declStmt(
436                     hasSingleDecl(
437                       varDecl(
438                         hasInitializer(
439                           initListExpr(
440                             has(
441                               cxxConstructExpr(
442                                 requiresZeroInitialization())),
443                             has(
444                               initListExpr(
445                                 hasType(asString("struct point")),
446                                 has(floatLiteral(equals(1.0))),
447                                 has(implicitValueInitExpr(
448                                       hasType(asString("double")))))),
449                             has(
450                               initListExpr(
451                                 hasType(asString("struct point")),
452                                 has(floatLiteral(equals(2.0))),
453                                 has(floatLiteral(equals(1.0)))))
454                               )))))))))));
455 }
456 
457 
458 const internal::VariadicDynCastAllOfMatcher<Expr, VAArgExpr> vaArgExpr;
459 
460 TEST(ImportExpr, ImportVAArgExpr) {
461   MatchVerifier<Decl> Verifier;
462   EXPECT_TRUE(
463         testImport(
464           "void declToImport(__builtin_va_list list, ...) {"
465           "  (void)__builtin_va_arg(list, int); }",
466           Lang_CXX, "", Lang_CXX, Verifier,
467           functionDecl(
468             hasBody(
469               compoundStmt(
470                 has(
471                   cStyleCastExpr(
472                     hasSourceExpression(
473                       vaArgExpr()))))))));
474 }
475 
476 
477 TEST(ImportType, ImportAtomicType) {
478   MatchVerifier<Decl> Verifier;
479   EXPECT_TRUE(testImport("void declToImport() { typedef _Atomic(int) a_int; }",
480                          Lang_CXX11, "", Lang_CXX11, Verifier,
481                          functionDecl(
482                            hasBody(
483                              compoundStmt(
484                                has(
485                                  declStmt(
486                                    has(
487                                      typedefDecl(
488                                        has(atomicType()))))))))));
489 }
490 
491 
492 } // end namespace ast_matchers
493 } // end namespace clang
494