[ASTImporter] Implement some expression-related AST node import.

Introduce ASTImporter unit test framework.

Fix a memory leak introduced in cf8ccff5: an array is allocated
in ImportArray and never freed.

Support new node kinds:

- GCCAsmStmt

- AddrLabelExpr
- AtomicExpr
- CompoundLiteralExpr
- CXXBoolLiteralExpr
- CXXNullPtrLiteralExpr
- CXXThisExpr
- DesignatedInitExpr
- GNUNullExpr
- ImplicitValueInitExpr
- InitListExpr
- OpaqueValueExpr
- PredefinedExpr
- ParenListExpr
- StmtExpr
- VAArgExpr

- BinaryConditionalOperator
- ConditionalOperator

- FloatingLiteral
- StringLiteral

- InjectedClassNameType
- TemplateTypeParmType

- LabelDecl

Patch by Aleksei Sidorin!

Differential Revision: http://reviews.llvm.org/D14286

llvm-svn: 266292
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
new file mode 100644
index 0000000..f5dee65
--- /dev/null
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -0,0 +1,470 @@
+//===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for the correct import of AST nodes from one AST context to another.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTImporter.h"
+#include "MatchVerifier.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+
+using clang::tooling::newFrontendActionFactory;
+using clang::tooling::runToolOnCodeWithArgs;
+using clang::tooling::FrontendActionFactory;
+
+typedef std::vector<std::string> StringVector;
+
+void getLangArgs(Language Lang, StringVector &Args) {
+  switch (Lang) {
+  case Lang_C:
+    Args.insert(Args.end(), { "-x", "c", "-std=c99" });
+    break;
+  case Lang_C89:
+    Args.insert(Args.end(), { "-x", "c", "-std=c89" });
+    break;
+  case Lang_CXX:
+    Args.push_back("-std=c++98");
+    break;
+  case Lang_CXX11:
+    Args.push_back("-std=c++11");
+    break;
+  case Lang_OpenCL:
+  case Lang_OBJCXX:
+    break;
+  }
+}
+
+template<typename NodeType, typename MatcherType>
+testing::AssertionResult
+testImport(const std::string &FromCode, Language FromLang,
+           const std::string &ToCode, Language ToLang,
+           MatchVerifier<NodeType> &Verifier,
+           const MatcherType &AMatcher) {
+  StringVector FromArgs, ToArgs;
+  getLangArgs(FromLang, FromArgs);
+  getLangArgs(ToLang, ToArgs);
+
+  const char *const InputFileName = "input.cc";
+  const char *const OutputFileName = "output.cc";
+
+  std::unique_ptr<ASTUnit>
+      FromAST = tooling::buildASTFromCodeWithArgs(
+        FromCode, FromArgs, InputFileName),
+      ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, OutputFileName);
+
+  ASTContext &FromCtx = FromAST->getASTContext(),
+      &ToCtx = ToAST->getASTContext();
+
+  // Add input.cc to virtual file system so importer can 'find' it
+  // while importing SourceLocations.
+  vfs::OverlayFileSystem *OFS = static_cast<vfs::OverlayFileSystem *>(
+        ToCtx.getSourceManager().getFileManager().getVirtualFileSystem().get());
+  vfs::InMemoryFileSystem *MFS = static_cast<vfs::InMemoryFileSystem *>(
+        OFS->overlays_begin()->get());
+  MFS->addFile(InputFileName, 0,
+               llvm::MemoryBuffer::getMemBuffer(FromCode.c_str()));
+
+  ASTImporter Importer(ToCtx, ToAST->getFileManager(),
+                       FromCtx, FromAST->getFileManager(), false);
+
+  IdentifierInfo *ImportedII = &FromCtx.Idents.get("declToImport");
+  assert(ImportedII && "Declaration with 'declToImport' name"
+                       "should be specified in test!");
+  DeclarationName ImportDeclName(ImportedII);
+  SmallVector<NamedDecl *, 4> FoundDecls;
+  FromCtx.getTranslationUnitDecl()->localUncachedLookup(
+        ImportDeclName, FoundDecls);
+
+  if (FoundDecls.size() != 1)
+    return testing::AssertionFailure() << "Multiple declarations were found!";
+
+  auto Imported = Importer.Import(*FoundDecls.begin());
+  if (!Imported)
+    return testing::AssertionFailure() << "Import failed, nullptr returned!";
+
+  // This should dump source locations and assert if some source locations
+  // were not imported
+  SmallString<1024> ImportChecker;
+  llvm::raw_svector_ostream ToNothing(ImportChecker);
+  ToCtx.getTranslationUnitDecl()->print(ToNothing);
+
+  return Verifier.match(Imported, AMatcher);
+}
+
+TEST(ImportExpr, ImportStringLiteral) {
+  MatchVerifier<Decl> Verifier;
+  EXPECT_TRUE(testImport("void declToImport() { \"foo\"; }",
+                         Lang_CXX, "", Lang_CXX, Verifier,
+                         functionDecl(
+                           hasBody(
+                             compoundStmt(
+                               has(
+                                 stringLiteral(
+                                   hasType(
+                                     asString("const char [4]")))))))));
+  EXPECT_TRUE(testImport("void declToImport() { L\"foo\"; }",
+                         Lang_CXX, "", Lang_CXX, Verifier,
+                         functionDecl(
+                           hasBody(
+                             compoundStmt(
+                               has(
+                                 stringLiteral(
+                                   hasType(
+                                     asString("const wchar_t [4]")))))))));
+  EXPECT_TRUE(testImport("void declToImport() { \"foo\" \"bar\"; }",
+                         Lang_CXX, "", Lang_CXX, Verifier,
+                         functionDecl(
+                           hasBody(
+                             compoundStmt(
+                               has(
+                                 stringLiteral(
+                                   hasType(
+                                     asString("const char [7]")))))))));
+}
+
+TEST(ImportExpr, ImportGNUNullExpr) {
+  MatchVerifier<Decl> Verifier;
+  EXPECT_TRUE(testImport("void declToImport() { __null; }",
+                         Lang_CXX, "", Lang_CXX, Verifier,
+                         functionDecl(
+                           hasBody(
+                             compoundStmt(
+                               has(
+                                 gnuNullExpr(
+                                   hasType(isInteger()))))))));
+}
+
+TEST(ImportExpr, ImportCXXNullPtrLiteralExpr) {
+  MatchVerifier<Decl> Verifier;
+  EXPECT_TRUE(testImport("void declToImport() { nullptr; }",
+                         Lang_CXX11, "", Lang_CXX11, Verifier,
+                         functionDecl(
+                           hasBody(
+                             compoundStmt(
+                               has(
+                                 cxxNullPtrLiteralExpr()))))));
+}
+
+
+TEST(ImportExpr, ImportFloatinglLiteralExpr) {
+  MatchVerifier<Decl> Verifier;
+  EXPECT_TRUE(testImport("void declToImport() { 1.0; }",
+                         Lang_CXX, "", Lang_CXX, Verifier,
+                         functionDecl(
+                           hasBody(
+                             compoundStmt(
+                               has(
+                                 floatLiteral(
+                                   equals(1.0),
+                                   hasType(asString("double")))))))));
+  EXPECT_TRUE(testImport("void declToImport() { 1.0e-5f; }",
+                         Lang_CXX, "", Lang_CXX, Verifier,
+                         functionDecl(
+                           hasBody(
+                             compoundStmt(
+                               has(
+                                 floatLiteral(
+                                   equals(1.0e-5f),
+                                   hasType(asString("float")))))))));
+}
+
+TEST(ImportExpr, ImportCompoundLiteralExpr) {
+  MatchVerifier<Decl> Verifier;
+  EXPECT_TRUE(
+        testImport(
+          "void declToImport() {"
+          "  struct s { int x; long y; unsigned z; }; "
+          "  (struct s){ 42, 0L, 1U }; }",
+          Lang_CXX, "", Lang_CXX, Verifier,
+          functionDecl(
+            hasBody(
+              compoundStmt(
+                has(
+                  compoundLiteralExpr(
+                    hasType(asString("struct s")),
+                    has(initListExpr(
+                      hasType(asString("struct s")),
+                      has(integerLiteral(
+                            equals(42), hasType(asString("int")))),
+                      has(integerLiteral(
+                            equals(0), hasType(asString("long")))),
+                      has(integerLiteral(
+                            equals(1),
+                            hasType(asString("unsigned int"))))
+                      )))))))));
+}
+
+TEST(ImportExpr, ImportCXXThisExpr) {
+  MatchVerifier<Decl> Verifier;
+  EXPECT_TRUE(
+        testImport("class declToImport { void f() { this; } };",
+                   Lang_CXX, "", Lang_CXX, Verifier,
+                   cxxRecordDecl(
+                     hasMethod(
+                       hasBody(
+                         compoundStmt(
+                           has(
+                             cxxThisExpr(
+                               hasType(
+                                 asString("class declToImport *"))))))))));
+}
+
+TEST(ImportExpr, ImportAtomicExpr) {
+  MatchVerifier<Decl> Verifier;
+  EXPECT_TRUE(
+        testImport(
+          "void declToImport() { int *ptr; __atomic_load_n(ptr, 1); }",
+          Lang_CXX, "", Lang_CXX, Verifier,
+          functionDecl(
+            hasBody(
+              compoundStmt(
+                has(
+                  atomicExpr(
+                    has(declRefExpr(
+                          hasDeclaration(varDecl(hasName("ptr"))),
+                          hasType(asString("int *")))),
+                    has(integerLiteral(equals(1), hasType(asString("int"))))
+                    )))))));
+}
+
+TEST(ImportExpr, ImportLabelDeclAndAddrLabelExpr) {
+  MatchVerifier<Decl> Verifier;
+  EXPECT_TRUE(
+        testImport(
+          "void declToImport() { loop: goto loop; &&loop; }",
+          Lang_CXX, "", Lang_CXX, Verifier,
+          functionDecl(
+            hasBody(
+              compoundStmt(
+                has(labelStmt(hasDeclaration(labelDecl(hasName("loop"))))),
+                has(addrLabelExpr(hasDeclaration(labelDecl(hasName("loop")))))
+                )))));
+}
+
+AST_MATCHER_P(TemplateDecl, hasTemplateDecl,
+              internal::Matcher<NamedDecl>, InnerMatcher) {
+  const NamedDecl *Template = Node.getTemplatedDecl();
+  return Template && InnerMatcher.matches(*Template, Finder, Builder);
+}
+
+TEST(ImportExpr, ImportParenListExpr) {
+  MatchVerifier<Decl> Verifier;
+  EXPECT_TRUE(
+        testImport(
+          "template<typename T> class dummy { void f() { dummy X(*this); } };"
+          "typedef dummy<int> declToImport;"
+          "template class dummy<int>;",
+          Lang_CXX, "", Lang_CXX, Verifier,
+          typedefDecl(
+            hasType(
+              templateSpecializationType(
+                hasDeclaration(
+                  classTemplateDecl(
+                    hasTemplateDecl(
+                      cxxRecordDecl(
+                        hasMethod(
+                        allOf(
+                          hasName("f"),
+                          hasBody(
+                            compoundStmt(
+                              has(
+                                declStmt(
+                                  hasSingleDecl(
+                                    varDecl(
+                                      hasInitializer(
+                                        parenListExpr(
+                                          has(
+                                            unaryOperator(
+                                              hasOperatorName("*"),
+                                              hasUnaryOperand(cxxThisExpr())
+                                              )))))))))))))))))))));
+}
+
+TEST(ImportExpr, ImportStmtExpr) {
+  MatchVerifier<Decl> Verifier;
+  // NOTE: has() ignores implicit casts, using hasDescendant() to match it
+  EXPECT_TRUE(
+        testImport(
+          "void declToImport() { int b; int a = b ?: 1; int C = ({int X=4; X;}); }",
+          Lang_CXX, "", Lang_CXX, Verifier,
+          functionDecl(
+            hasBody(
+              compoundStmt(
+                has(
+                  declStmt(
+                    hasSingleDecl(
+                      varDecl(
+                        hasName("C"),
+                        hasType(asString("int")),
+                        hasInitializer(
+                          stmtExpr(
+                            hasAnySubstatement(
+                              declStmt(
+                                hasSingleDecl(
+                                  varDecl(
+                                    hasName("X"),
+                                    hasType(asString("int")),
+                                    hasInitializer(
+                                      integerLiteral(equals(4))))))),
+                            hasDescendant(
+                              implicitCastExpr()
+                              ))))))))))));
+}
+
+TEST(ImportExpr, ImportConditionalOperator) {
+  MatchVerifier<Decl> Verifier;
+  EXPECT_TRUE(
+        testImport(
+          "void declToImport() { true ? 1 : -5; }",
+          Lang_CXX, "", Lang_CXX, Verifier,
+          functionDecl(
+            hasBody(
+              compoundStmt(
+                has(
+                  conditionalOperator(
+                    hasCondition(cxxBoolLiteral(equals(true))),
+                    hasTrueExpression(integerLiteral(equals(1))),
+                    hasFalseExpression(
+                      unaryOperator(hasUnaryOperand(integerLiteral(equals(5))))
+                      ))))))));
+}
+
+TEST(ImportExpr, ImportBinaryConditionalOperator) {
+  MatchVerifier<Decl> Verifier;
+  EXPECT_TRUE(
+        testImport(
+          "void declToImport() { 1 ?: -5; }",
+          Lang_CXX, "", Lang_CXX, Verifier,
+          functionDecl(
+            hasBody(
+              compoundStmt(
+                has(
+                  binaryConditionalOperator(
+                    hasCondition(
+                      implicitCastExpr(
+                        hasSourceExpression(
+                          opaqueValueExpr(
+                            hasSourceExpression(integerLiteral(equals(1))))),
+                        hasType(booleanType()))),
+                    hasTrueExpression(
+                      opaqueValueExpr(hasSourceExpression(
+                                        integerLiteral(equals(1))))),
+                    hasFalseExpression(
+                      unaryOperator(hasOperatorName("-"),
+                                    hasUnaryOperand(integerLiteral(equals(5)))))
+                      )))))));
+}
+
+TEST(ImportExpr, ImportDesignatedInitExpr) {
+  MatchVerifier<Decl> Verifier;
+  EXPECT_TRUE(testImport("void declToImport() {"
+                         "  struct point { double x; double y; };"
+                         "  struct point ptarray[10] = "
+                                "{ [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; }",
+                         Lang_C, "", Lang_C, Verifier,
+                         functionDecl(
+                           hasBody(
+                             compoundStmt(
+                               has(
+                                 declStmt(
+                                   hasSingleDecl(
+                                     varDecl(
+                                       hasInitializer(
+                                         initListExpr(
+                                           hasSyntacticForm(
+                                             initListExpr(
+                                               has(
+                                                 designatedInitExpr(
+                                                   designatorCountIs(2),
+                                                   has(floatLiteral(
+                                                         equals(1.0))),
+                                                   has(integerLiteral(
+                                                         equals(2))))),
+                                               has(
+                                                 designatedInitExpr(
+                                                   designatorCountIs(2),
+                                                   has(floatLiteral(
+                                                         equals(2.0))),
+                                                   has(integerLiteral(
+                                                         equals(2))))),
+                                               has(
+                                                 designatedInitExpr(
+                                                   designatorCountIs(2),
+                                                   has(floatLiteral(
+                                                         equals(1.0))),
+                                                   has(integerLiteral(
+                                                         equals(0)))))
+                                               )))))))))))));
+}
+
+
+TEST(ImportExpr, ImportPredefinedExpr) {
+  MatchVerifier<Decl> Verifier;
+  // __func__ expands as StringLiteral("declToImport")
+  EXPECT_TRUE(testImport("void declToImport() { __func__; }",
+                         Lang_CXX, "", Lang_CXX, Verifier,
+                         functionDecl(
+                           hasBody(
+                             compoundStmt(
+                               has(
+                                 predefinedExpr(
+                                   hasType(
+                                     asString("const char [13]")),
+                                   has(
+                                     stringLiteral(
+                                       hasType(
+                                         asString("const char [13]")))))))))));
+}
+
+TEST(ImportExpr, ImportInitListExpr) {
+  MatchVerifier<Decl> Verifier;
+  EXPECT_TRUE(
+        testImport(
+          "void declToImport() {"
+          "  struct point { double x; double y; };"
+          "  point ptarray[10] = { [2].y = 1.0, [2].x = 2.0,"
+          "                        [0].x = 1.0 }; }",
+          Lang_CXX, "", Lang_CXX, Verifier,
+          functionDecl(
+            hasBody(
+              compoundStmt(
+                has(
+                  declStmt(
+                    hasSingleDecl(
+                      varDecl(
+                        hasInitializer(
+                          initListExpr(
+                            has(
+                              cxxConstructExpr(
+                                requiresZeroInitialization())),
+                            has(
+                              initListExpr(
+                                hasType(asString("struct point")),
+                                has(floatLiteral(equals(1.0))),
+                                has(implicitValueInitExpr(
+                                      hasType(asString("double")))))),
+                            has(
+                              initListExpr(
+                                hasType(asString("struct point")),
+                                has(floatLiteral(equals(2.0))),
+                                has(floatLiteral(equals(1.0)))))
+                              )))))))))));
+}
+
+
+} // end namespace ast_matchers
+} // end namespace clang