//===- 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<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(ignoringParenImpCasts(
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