//===- 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 { typedef std::vector 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 testing::AssertionResult testImport(const std::string &FromCode, Language FromLang, const std::string &ToCode, Language ToLang, MatchVerifier &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 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( ToCtx.getSourceManager().getFileManager().getVirtualFileSystem().get()); vfs::InMemoryFileSystem *MFS = static_cast( 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 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 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 Verifier; EXPECT_TRUE(testImport("void declToImport() { __null; }", Lang_CXX, "", Lang_CXX, Verifier, functionDecl( hasBody( compoundStmt( has( gnuNullExpr( hasType(isInteger())))))))); } TEST(ImportExpr, ImportCXXNullPtrLiteralExpr) { MatchVerifier Verifier; EXPECT_TRUE(testImport("void declToImport() { nullptr; }", Lang_CXX11, "", Lang_CXX11, Verifier, functionDecl( hasBody( compoundStmt( has( cxxNullPtrLiteralExpr())))))); } TEST(ImportExpr, ImportFloatinglLiteralExpr) { MatchVerifier 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 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 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 Verifier; EXPECT_TRUE(testImport( "void declToImport() { int *ptr; __atomic_load_n(ptr, 1); }", Lang_CXX, "", Lang_CXX, Verifier, functionDecl(hasBody(compoundStmt(has(atomicExpr( has(ignoringParenImpCasts( declRefExpr(hasDeclaration(varDecl(hasName("ptr"))), hasType(asString("int *"))))), has(integerLiteral(equals(1), hasType(asString("int"))))))))))); } TEST(ImportExpr, ImportLabelDeclAndAddrLabelExpr) { MatchVerifier 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, InnerMatcher) { const NamedDecl *Template = Node.getTemplatedDecl(); return Template && InnerMatcher.matches(*Template, Finder, Builder); } TEST(ImportExpr, ImportParenListExpr) { MatchVerifier Verifier; EXPECT_TRUE( testImport( "template class dummy { void f() { dummy X(*this); } };" "typedef dummy declToImport;" "template class dummy;", 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 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 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 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 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 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 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