//===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Tests for the correct import of AST nodes from one AST context to another. // //===----------------------------------------------------------------------===// #include "clang/AST/RecordLayout.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Testing/CommandLineArgs.h" #include "llvm/Support/SmallVectorMemoryBuffer.h" #include "clang/AST/DeclContextInternals.h" #include "gtest/gtest.h" #include "ASTImporterFixtures.h" #include namespace clang { namespace ast_matchers { using internal::Matcher; static const RecordDecl *getRecordDeclOfFriend(FriendDecl *FD) { QualType Ty = FD->getFriendType()->getType().getCanonicalType(); return cast(Ty)->getDecl(); } struct ImportExpr : TestImportBase {}; struct ImportType : TestImportBase {}; struct ImportDecl : TestImportBase {}; struct ImportFixedPointExpr : ImportExpr {}; struct CanonicalRedeclChain : ASTImporterOptionSpecificTestBase {}; TEST_P(CanonicalRedeclChain, ShouldBeConsequentWithMatchers) { Decl *FromTU = getTuDecl("void f();", Lang_CXX03); auto Pattern = functionDecl(hasName("f")); auto *D0 = FirstDeclMatcher().match(FromTU, Pattern); auto Redecls = getCanonicalForwardRedeclChain(D0); ASSERT_EQ(Redecls.size(), 1u); EXPECT_EQ(D0, Redecls[0]); } TEST_P(CanonicalRedeclChain, ShouldBeConsequentWithMatchers2) { Decl *FromTU = getTuDecl("void f(); void f(); void f();", Lang_CXX03); auto Pattern = functionDecl(hasName("f")); auto *D0 = FirstDeclMatcher().match(FromTU, Pattern); auto *D2 = LastDeclMatcher().match(FromTU, Pattern); FunctionDecl *D1 = D2->getPreviousDecl(); auto Redecls = getCanonicalForwardRedeclChain(D0); ASSERT_EQ(Redecls.size(), 3u); EXPECT_EQ(D0, Redecls[0]); EXPECT_EQ(D1, Redecls[1]); EXPECT_EQ(D2, Redecls[2]); } TEST_P(CanonicalRedeclChain, ShouldBeSameForAllDeclInTheChain) { Decl *FromTU = getTuDecl("void f(); void f(); void f();", Lang_CXX03); auto Pattern = functionDecl(hasName("f")); auto *D0 = FirstDeclMatcher().match(FromTU, Pattern); auto *D2 = LastDeclMatcher().match(FromTU, Pattern); FunctionDecl *D1 = D2->getPreviousDecl(); auto RedeclsD0 = getCanonicalForwardRedeclChain(D0); auto RedeclsD1 = getCanonicalForwardRedeclChain(D1); auto RedeclsD2 = getCanonicalForwardRedeclChain(D2); EXPECT_THAT(RedeclsD0, ::testing::ContainerEq(RedeclsD1)); EXPECT_THAT(RedeclsD1, ::testing::ContainerEq(RedeclsD2)); } namespace { struct RedirectingImporter : public ASTImporter { using ASTImporter::ASTImporter; protected: llvm::Expected ImportImpl(Decl *FromD) override { auto *ND = dyn_cast(FromD); if (!ND || ND->getName() != "shouldNotBeImported") return ASTImporter::ImportImpl(FromD); for (Decl *D : getToContext().getTranslationUnitDecl()->decls()) { if (auto *ND = dyn_cast(D)) if (ND->getName() == "realDecl") { RegisterImportedDecl(FromD, ND); return ND; } } return ASTImporter::ImportImpl(FromD); } }; } // namespace struct RedirectingImporterTest : ASTImporterOptionSpecificTestBase { RedirectingImporterTest() { Creator = [](ASTContext &ToContext, FileManager &ToFileManager, ASTContext &FromContext, FileManager &FromFileManager, bool MinimalImport, const std::shared_ptr &SharedState) { return new RedirectingImporter(ToContext, ToFileManager, FromContext, FromFileManager, MinimalImport, SharedState); }; } }; // Test that an ASTImporter subclass can intercept an import call. TEST_P(RedirectingImporterTest, InterceptImport) { Decl *From, *To; std::tie(From, To) = getImportedDecl("class shouldNotBeImported {};", Lang_CXX03, "class realDecl {};", Lang_CXX03, "shouldNotBeImported"); auto *Imported = cast(To); EXPECT_EQ(Imported->getQualifiedNameAsString(), "realDecl"); // Make sure our importer prevented the importing of the decl. auto *ToTU = Imported->getTranslationUnitDecl(); auto Pattern = functionDecl(hasName("shouldNotBeImported")); unsigned count = DeclCounterWithPredicate().match(ToTU, Pattern); EXPECT_EQ(0U, count); } // Test that when we indirectly import a declaration the custom ASTImporter // is still intercepting the import. TEST_P(RedirectingImporterTest, InterceptIndirectImport) { Decl *From, *To; std::tie(From, To) = getImportedDecl("class shouldNotBeImported {};" "class F { shouldNotBeImported f; };", Lang_CXX03, "class realDecl {};", Lang_CXX03, "F"); // Make sure our ASTImporter prevented the importing of the decl. auto *ToTU = To->getTranslationUnitDecl(); auto Pattern = functionDecl(hasName("shouldNotBeImported")); unsigned count = DeclCounterWithPredicate().match(ToTU, Pattern); EXPECT_EQ(0U, count); } struct ImportPath : ASTImporterOptionSpecificTestBase { Decl *FromTU; FunctionDecl *D0, *D1, *D2; ImportPath() { FromTU = getTuDecl("void f(); void f(); void f();", Lang_CXX03); auto Pattern = functionDecl(hasName("f")); D0 = FirstDeclMatcher().match(FromTU, Pattern); D2 = LastDeclMatcher().match(FromTU, Pattern); D1 = D2->getPreviousDecl(); } }; TEST_P(ImportPath, Push) { ASTImporter::ImportPathTy path; path.push(D0); EXPECT_FALSE(path.hasCycleAtBack()); } TEST_P(ImportPath, SmallCycle) { ASTImporter::ImportPathTy path; path.push(D0); path.push(D0); EXPECT_TRUE(path.hasCycleAtBack()); path.pop(); EXPECT_FALSE(path.hasCycleAtBack()); path.push(D0); EXPECT_TRUE(path.hasCycleAtBack()); } TEST_P(ImportPath, GetSmallCycle) { ASTImporter::ImportPathTy path; path.push(D0); path.push(D0); EXPECT_TRUE(path.hasCycleAtBack()); std::array Res; int i = 0; for (Decl *Di : path.getCycleAtBack()) { Res[i++] = Di; } ASSERT_EQ(i, 2); EXPECT_EQ(Res[0], D0); EXPECT_EQ(Res[1], D0); } TEST_P(ImportPath, GetCycle) { ASTImporter::ImportPathTy path; path.push(D0); path.push(D1); path.push(D2); path.push(D0); EXPECT_TRUE(path.hasCycleAtBack()); std::array Res; int i = 0; for (Decl *Di : path.getCycleAtBack()) { Res[i++] = Di; } ASSERT_EQ(i, 4); EXPECT_EQ(Res[0], D0); EXPECT_EQ(Res[1], D2); EXPECT_EQ(Res[2], D1); EXPECT_EQ(Res[3], D0); } TEST_P(ImportPath, CycleAfterCycle) { ASTImporter::ImportPathTy path; path.push(D0); path.push(D1); path.push(D0); path.push(D1); path.push(D2); path.push(D0); EXPECT_TRUE(path.hasCycleAtBack()); std::array Res; int i = 0; for (Decl *Di : path.getCycleAtBack()) { Res[i++] = Di; } ASSERT_EQ(i, 4); EXPECT_EQ(Res[0], D0); EXPECT_EQ(Res[1], D2); EXPECT_EQ(Res[2], D1); EXPECT_EQ(Res[3], D0); path.pop(); path.pop(); path.pop(); EXPECT_TRUE(path.hasCycleAtBack()); i = 0; for (Decl *Di : path.getCycleAtBack()) { Res[i++] = Di; } ASSERT_EQ(i, 3); EXPECT_EQ(Res[0], D0); EXPECT_EQ(Res[1], D1); EXPECT_EQ(Res[2], D0); path.pop(); EXPECT_FALSE(path.hasCycleAtBack()); } const internal::VariadicDynCastAllOfMatcher sourceLocExpr; AST_MATCHER_P(SourceLocExpr, hasBuiltinStr, StringRef, Str) { return Node.getBuiltinStr() == Str; } TEST_P(ImportExpr, ImportSourceLocExpr) { MatchVerifier Verifier; testImport("void declToImport() { (void)__builtin_FILE(); }", Lang_CXX03, "", Lang_CXX03, Verifier, functionDecl(hasDescendant( sourceLocExpr(hasBuiltinStr("__builtin_FILE"))))); testImport("void declToImport() { (void)__builtin_FILE_NAME(); }", Lang_CXX03, "", Lang_CXX03, Verifier, functionDecl(hasDescendant( sourceLocExpr(hasBuiltinStr("__builtin_FILE_NAME"))))); testImport("void declToImport() { (void)__builtin_COLUMN(); }", Lang_CXX03, "", Lang_CXX03, Verifier, functionDecl(hasDescendant( sourceLocExpr(hasBuiltinStr("__builtin_COLUMN"))))); } TEST_P(ImportExpr, ImportStringLiteral) { MatchVerifier Verifier; testImport("void declToImport() { (void)\"foo\"; }", Lang_CXX03, "", Lang_CXX03, Verifier, functionDecl(hasDescendant( stringLiteral(hasType(asString("const char[4]")))))); testImport("void declToImport() { (void)L\"foo\"; }", Lang_CXX03, "", Lang_CXX03, Verifier, functionDecl(hasDescendant( stringLiteral(hasType(asString("const wchar_t[4]")))))); testImport("void declToImport() { (void) \"foo\" \"bar\"; }", Lang_CXX03, "", Lang_CXX03, Verifier, functionDecl(hasDescendant( stringLiteral(hasType(asString("const char[7]")))))); } TEST_P(ImportExpr, ImportChooseExpr) { MatchVerifier Verifier; // This case tests C code that is not condition-dependent and has a true // condition. testImport("void declToImport() { (void)__builtin_choose_expr(1, 2, 3); }", Lang_C99, "", Lang_C99, Verifier, functionDecl(hasDescendant(chooseExpr()))); } const internal::VariadicDynCastAllOfMatcher shuffleVectorExpr; TEST_P(ImportExpr, ImportShuffleVectorExpr) { MatchVerifier Verifier; constexpr auto Code = R"code( typedef double vector4double __attribute__((__vector_size__(32))); vector4double declToImport(vector4double a, vector4double b) { return __builtin_shufflevector(a, b, 0, 1, 2, 3); } )code"; const auto Pattern = functionDecl(hasDescendant(shuffleVectorExpr( allOf(has(declRefExpr(to(parmVarDecl(hasName("a"))))), has(declRefExpr(to(parmVarDecl(hasName("b"))))), has(integerLiteral(equals(0))), has(integerLiteral(equals(1))), has(integerLiteral(equals(2))), has(integerLiteral(equals(3))))))); testImport(Code, Lang_C99, "", Lang_C99, Verifier, Pattern); } TEST_P(ImportExpr, ImportGNUNullExpr) { MatchVerifier Verifier; testImport("void declToImport() { (void)__null; }", Lang_CXX03, "", Lang_CXX03, Verifier, functionDecl(hasDescendant(gnuNullExpr(hasType(isInteger()))))); } TEST_P(ImportExpr, ImportGenericSelectionExpr) { MatchVerifier Verifier; testImport( "void declToImport() { int x; (void)_Generic(x, int: 0, float: 1); }", Lang_C99, "", Lang_C99, Verifier, functionDecl(hasDescendant(genericSelectionExpr()))); } TEST_P(ImportExpr, ImportCXXNullPtrLiteralExpr) { MatchVerifier Verifier; testImport( "void declToImport() { (void)nullptr; }", Lang_CXX11, "", Lang_CXX11, Verifier, functionDecl(hasDescendant(cxxNullPtrLiteralExpr()))); } TEST_P(ImportExpr, ImportFloatinglLiteralExpr) { MatchVerifier Verifier; testImport("void declToImport() { (void)1.0; }", Lang_C99, "", Lang_C99, Verifier, functionDecl(hasDescendant( floatLiteral(equals(1.0), hasType(asString("double")))))); testImport("void declToImport() { (void)1.0e-5f; }", Lang_C99, "", Lang_C99, Verifier, functionDecl(hasDescendant( floatLiteral(equals(1.0e-5f), hasType(asString("float")))))); } TEST_P(ImportFixedPointExpr, ImportFixedPointerLiteralExpr) { MatchVerifier Verifier; testImport("void declToImport() { (void)1.0k; }", Lang_C99, "", Lang_C99, Verifier, functionDecl(hasDescendant(fixedPointLiteral()))); testImport("void declToImport() { (void)0.75r; }", Lang_C99, "", Lang_C99, Verifier, functionDecl(hasDescendant(fixedPointLiteral()))); } TEST_P(ImportExpr, ImportImaginaryLiteralExpr) { MatchVerifier Verifier; testImport( "void declToImport() { (void)1.0i; }", Lang_CXX14, "", Lang_CXX14, Verifier, functionDecl(hasDescendant(imaginaryLiteral()))); } TEST_P(ImportExpr, ImportCompoundLiteralExpr) { MatchVerifier Verifier; testImport("void declToImport() {" " struct s { int x; long y; unsigned z; }; " " (void)(struct s){ 42, 0L, 1U }; }", Lang_CXX03, "", Lang_CXX03, Verifier, functionDecl(hasDescendant(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_P(ImportExpr, ImportCXXThisExpr) { MatchVerifier Verifier; testImport("class declToImport { void f() { (void)this; } };", Lang_CXX03, "", Lang_CXX03, Verifier, cxxRecordDecl(hasMethod(hasDescendant( cxxThisExpr(hasType(asString("class declToImport *"))))))); } TEST_P(ImportExpr, ImportAtomicExpr) { MatchVerifier Verifier; testImport("void declToImport() { int *ptr; __atomic_load_n(ptr, 1); }", Lang_C99, "", Lang_C99, Verifier, functionDecl(hasDescendant(atomicExpr( has(ignoringParenImpCasts( declRefExpr(hasDeclaration(varDecl(hasName("ptr"))), hasType(asString("int *"))))), has(integerLiteral(equals(1), hasType(asString("int")))))))); } TEST_P(ImportExpr, ImportLabelDeclAndAddrLabelExpr) { MatchVerifier Verifier; testImport("void declToImport() { loop: goto loop; (void)&&loop; }", Lang_C99, "", Lang_C99, Verifier, functionDecl(hasDescendant(labelStmt( hasDeclaration(labelDecl(hasName("loop"))))), hasDescendant(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_P(ImportExpr, ImportParenListExpr) { MatchVerifier Verifier; testImport( "template class dummy { void f() { dummy X(*this); } };" "typedef dummy declToImport;" "template class dummy;", Lang_CXX03, "", Lang_CXX03, Verifier, typedefDecl(hasType(elaboratedType(namesType(templateSpecializationType( hasDeclaration(classTemplateSpecializationDecl(hasSpecializedTemplate( classTemplateDecl(hasTemplateDecl(cxxRecordDecl(hasMethod( allOf(hasName("f"), hasBody(compoundStmt(has(declStmt(hasSingleDecl(varDecl( hasInitializer(parenListExpr(has(unaryOperator( hasOperatorName("*"), hasUnaryOperand( cxxThisExpr()))))))))))))))))))))))))); } TEST_P(ImportExpr, ImportSwitch) { MatchVerifier Verifier; testImport("void declToImport() { int b; switch (b) { case 1: break; } }", Lang_C99, "", Lang_C99, Verifier, functionDecl(hasDescendant( switchStmt(has(compoundStmt(has(caseStmt()))))))); } TEST_P(ImportExpr, ImportStmtExpr) { MatchVerifier Verifier; testImport( "void declToImport() { int b; int a = b ?: 1; int C = ({int X=4; X;}); }", Lang_C99, "", Lang_C99, Verifier, traverse(TK_AsIs, functionDecl(hasDescendant(varDecl( hasName("C"), hasType(asString("int")), hasInitializer(stmtExpr( hasAnySubstatement(declStmt(hasSingleDecl(varDecl( hasName("X"), hasType(asString("int")), hasInitializer(integerLiteral(equals(4))))))), hasDescendant(implicitCastExpr())))))))); } TEST_P(ImportExpr, ImportConditionalOperator) { MatchVerifier Verifier; testImport("void declToImport() { (void)(true ? 1 : -5); }", Lang_CXX03, "", Lang_CXX03, Verifier, functionDecl(hasDescendant(conditionalOperator( hasCondition(cxxBoolLiteral(equals(true))), hasTrueExpression(integerLiteral(equals(1))), hasFalseExpression(unaryOperator( hasUnaryOperand(integerLiteral(equals(5))))))))); } TEST_P(ImportExpr, ImportBinaryConditionalOperator) { MatchVerifier Verifier; testImport( "void declToImport() { (void)(1 ?: -5); }", Lang_CXX03, "", Lang_CXX03, Verifier, traverse(TK_AsIs, functionDecl(hasDescendant(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_P(ImportExpr, ImportDesignatedInitExpr) { MatchVerifier Verifier; 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_C99, "", Lang_C99, Verifier, functionDecl(hasDescendant(initListExpr( has(designatedInitExpr(designatorCountIs(2), hasDescendant(floatLiteral(equals(1.0))), hasDescendant(integerLiteral(equals(2))))), has(designatedInitExpr(designatorCountIs(2), hasDescendant(floatLiteral(equals(2.0))), hasDescendant(integerLiteral(equals(2))))), has(designatedInitExpr(designatorCountIs(2), hasDescendant(floatLiteral(equals(1.0))), hasDescendant(integerLiteral(equals(0))))))))); } TEST_P(ImportExpr, ImportPredefinedExpr) { MatchVerifier Verifier; // __func__ expands as StringLiteral("declToImport") testImport("void declToImport() { (void)__func__; }", Lang_CXX03, "", Lang_CXX03, Verifier, functionDecl(hasDescendant(predefinedExpr( hasType(asString("const char[13]")), has(stringLiteral(hasType(asString("const char[13]")))))))); } TEST_P(ImportExpr, ImportInitListExpr) { MatchVerifier Verifier; 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_CXX03, "", Lang_CXX03, Verifier, functionDecl(hasDescendant(initListExpr( has(cxxConstructExpr(requiresZeroInitialization())), has(initListExpr( hasType(asString("point")), has(floatLiteral(equals(1.0))), has(implicitValueInitExpr(hasType(asString("double")))))), has(initListExpr(hasType(asString("point")), has(floatLiteral(equals(2.0))), has(floatLiteral(equals(1.0))))))))); } const internal::VariadicDynCastAllOfMatcher cxxDefaultInitExpr; TEST_P(ImportExpr, ImportCXXDefaultInitExpr) { MatchVerifier Verifier; testImport("class declToImport { int DefInit = 5; }; declToImport X;", Lang_CXX11, "", Lang_CXX11, Verifier, cxxRecordDecl(hasDescendant(cxxConstructorDecl( hasAnyConstructorInitializer(cxxCtorInitializer( withInitializer(cxxDefaultInitExpr()))))))); testImport( "struct X { int A = 5; }; X declToImport{};", Lang_CXX17, "", Lang_CXX17, Verifier, varDecl(hasInitializer(initListExpr(hasInit(0, cxxDefaultInitExpr()))))); } const internal::VariadicDynCastAllOfMatcher vaArgExpr; TEST_P(ImportExpr, ImportVAArgExpr) { MatchVerifier Verifier; testImport("void declToImport(__builtin_va_list list, ...) {" " (void)__builtin_va_arg(list, int); }", Lang_CXX03, "", Lang_CXX03, Verifier, functionDecl(hasDescendant( cStyleCastExpr(hasSourceExpression(vaArgExpr()))))); } const internal::VariadicDynCastAllOfMatcher builtinBitCastExpr; TEST_P(ImportExpr, ImportBuiltinBitCastExpr) { MatchVerifier Verifier; testImport("void declToImport(int X) {" " (void)__builtin_bit_cast(float, X); }", Lang_CXX20, "", Lang_CXX20, Verifier, functionDecl(hasDescendant( cStyleCastExpr(hasSourceExpression(builtinBitCastExpr()))))); } TEST_P(ImportExpr, CXXTemporaryObjectExpr) { MatchVerifier Verifier; testImport( "struct C {};" "void declToImport() { C c = C(); }", Lang_CXX03, "", Lang_CXX03, Verifier, traverse(TK_AsIs, functionDecl(hasDescendant(exprWithCleanups(has(cxxConstructExpr( has(materializeTemporaryExpr(has(implicitCastExpr( has(cxxTemporaryObjectExpr())))))))))))); } TEST_P(ImportType, ImportAtomicType) { MatchVerifier Verifier; testImport( "void declToImport() { typedef _Atomic(int) a_int; }", Lang_CXX11, "", Lang_CXX11, Verifier, functionDecl(hasDescendant(typedefDecl(has(atomicType()))))); } TEST_P(ImportType, ImportBitIntType) { const AstTypeMatcher bitIntType; MatchVerifier Verifier; testImport("_BitInt(10) declToImport;", Lang_CXX11, "", Lang_CXX11, Verifier, varDecl(hasType(bitIntType()))); } TEST_P(ImportType, ImportDependentBitIntType) { const AstTypeMatcher dependentBitIntType; MatchVerifier Verifier; testImport("template using declToImport = _BitInt(Width);", Lang_CXX11, "", Lang_CXX11, Verifier, typeAliasTemplateDecl( has(typeAliasDecl(hasType(dependentBitIntType()))))); } TEST_P(ImportType, ImportDependentAddressSpaceType) { const AstTypeMatcher dependentAddressSpaceType; MatchVerifier Verifier; testImport( R"( template using declToImport = T __attribute__((address_space(AddrSpace))); )", Lang_CXX11, "", Lang_CXX11, Verifier, typeAliasTemplateDecl( has(typeAliasDecl(hasType(dependentAddressSpaceType()))))); } TEST_P(ImportType, ImportVectorType) { const AstTypeMatcher vectorType; MatchVerifier Verifier; testImport("typedef int __attribute__((vector_size(12))) declToImport;", Lang_CXX11, "", Lang_CXX11, Verifier, typedefDecl(hasType(vectorType()))); } TEST_P(ImportType, ImportDependentVectorType) { const AstTypeMatcher dependentVectorType; MatchVerifier Verifier; testImport( R"( template using declToImport = T __attribute__((vector_size(Size))); )", Lang_CXX11, "", Lang_CXX11, Verifier, typeAliasTemplateDecl( has(typeAliasDecl(hasType(dependentVectorType()))))); } struct ImportOpenCLPipe : ImportType { std::vector getExtraArgs() const override { return {"-x", "cl", "-cl-no-stdinc", "-cl-std=CL2.0"}; } }; TEST_P(ImportOpenCLPipe, ImportPipeType) { const AstTypeMatcher pipeType; MatchVerifier Verifier; testImport("typedef pipe int declToImport;", Lang_OpenCL, "", Lang_OpenCL, Verifier, typedefDecl(hasType(pipeType()))); } struct ImportMatrixType : ImportType { std::vector getExtraArgs() const override { return {"-fenable-matrix"}; } }; TEST_P(ImportMatrixType, ImportConstantMatrixType) { const AstTypeMatcher constantMatrixType; MatchVerifier Verifier; testImport("typedef int __attribute__((matrix_type(5, 5))) declToImport;", Lang_CXX11, "", Lang_CXX11, Verifier, typedefDecl(hasType(constantMatrixType()))); } TEST_P(ImportMatrixType, ImportDependentSizedMatrixType) { const AstTypeMatcher dependentSizedMatrixType; MatchVerifier Verifier; testImport( R"( template using declToImport = T __attribute__((matrix_type(Rows, Cols))); )", Lang_CXX11, "", Lang_CXX11, Verifier, typeAliasTemplateDecl( has(typeAliasDecl(hasType(dependentSizedMatrixType()))))); } TEST_P(ImportType, ImportUsingType) { MatchVerifier Verifier; testImport("struct C {};" "void declToImport() { using ::C; new C{}; }", Lang_CXX11, "", Lang_CXX11, Verifier, functionDecl(hasDescendant(cxxNewExpr(hasType(pointerType( pointee(elaboratedType(namesType(usingType()))))))))); } TEST_P(ImportDecl, ImportFunctionTemplateDecl) { MatchVerifier Verifier; testImport("template void declToImport() { };", Lang_CXX03, "", Lang_CXX03, Verifier, functionTemplateDecl()); } TEST_P(ImportExpr, ImportCXXDependentScopeMemberExpr) { MatchVerifier Verifier; testImport("template struct C { T t; };" "template void declToImport() {" " C d;" " (void)d.t;" "}" "void instantiate() { declToImport(); }", Lang_CXX03, "", Lang_CXX03, Verifier, functionTemplateDecl(hasDescendant( cStyleCastExpr(has(cxxDependentScopeMemberExpr()))))); testImport("template struct C { T t; };" "template void declToImport() {" " C d;" " (void)(&d)->t;" "}" "void instantiate() { declToImport(); }", Lang_CXX03, "", Lang_CXX03, Verifier, functionTemplateDecl(hasDescendant( cStyleCastExpr(has(cxxDependentScopeMemberExpr()))))); } TEST_P(ImportType, ImportTypeAliasTemplate) { MatchVerifier Verifier; testImport( "template " "struct dummy { static const int i = K; };" "template using dummy2 = dummy;" "int declToImport() { return dummy2<3>::i; }", Lang_CXX11, "", Lang_CXX11, Verifier, traverse(TK_AsIs, functionDecl(hasDescendant(implicitCastExpr(has(declRefExpr()))), unless(hasAncestor( translationUnitDecl(has(typeAliasDecl()))))))); } const internal::VariadicDynCastAllOfMatcher varTemplateSpecializationDecl; TEST_P(ImportDecl, ImportVarTemplate) { MatchVerifier Verifier; testImport( "template " "T pi = T(3.1415926535897932385L);" "void declToImport() { (void)pi; }", Lang_CXX14, "", Lang_CXX14, Verifier, functionDecl( hasDescendant(declRefExpr(to(varTemplateSpecializationDecl()))), unless(hasAncestor(translationUnitDecl(has(varDecl( hasName("pi"), unless(varTemplateSpecializationDecl())))))))); } TEST_P(ImportType, ImportPackExpansion) { MatchVerifier Verifier; testImport("template " "struct dummy {" " dummy(Args... args) {}" " static const int i = 4;" "};" "int declToImport() { return dummy::i; }", Lang_CXX11, "", Lang_CXX11, Verifier, traverse(TK_AsIs, functionDecl(hasDescendant(returnStmt(has( implicitCastExpr(has(declRefExpr())))))))); } TEST_P(ImportType, ImportDependentTemplateSpecialization) { MatchVerifier Verifier; testImport("template" "struct A;" "template" "struct declToImport {" " typename A::template B a;" "};", Lang_CXX03, "", Lang_CXX03, Verifier, classTemplateDecl(has(cxxRecordDecl(has( fieldDecl(hasType(dependentTemplateSpecializationType()))))))); } TEST_P(ImportType, ImportDeducedTemplateSpecialization) { MatchVerifier Verifier; testImport("template " "class C { public: C(T); };" "C declToImport(123);", Lang_CXX17, "", Lang_CXX17, Verifier, varDecl(hasType(elaboratedType( namesType(deducedTemplateSpecializationType()))))); } const internal::VariadicDynCastAllOfMatcher sizeOfPackExpr; TEST_P(ImportExpr, ImportSizeOfPackExpr) { MatchVerifier Verifier; testImport( "template " "void declToImport() {" " const int i = sizeof...(Ts);" "};" "void g() { declToImport(); }", Lang_CXX11, "", Lang_CXX11, Verifier, functionTemplateDecl(hasDescendant(sizeOfPackExpr()))); testImport( "template " "using X = int[sizeof...(Ts)];" "template " "struct Y {" " X f;" "};" "Y declToImport;", Lang_CXX11, "", Lang_CXX11, Verifier, varDecl(hasType(classTemplateSpecializationDecl(has(fieldDecl(hasType( hasUnqualifiedDesugaredType(constantArrayType(hasSize(7)))))))))); } TEST_P(ImportExpr, ImportCXXFoldExpr) { auto Match1 = cxxFoldExpr(hasOperatorName("+"), isLeftFold(), unless(hasFoldInit(expr()))); auto Match2 = cxxFoldExpr(hasOperatorName("-"), isLeftFold(), hasFoldInit(expr())); auto Match3 = cxxFoldExpr(hasOperatorName("*"), isRightFold(), unless(hasFoldInit(expr()))); auto Match4 = cxxFoldExpr(hasOperatorName("/"), isRightFold(), hasFoldInit(expr())); MatchVerifier Verifier; testImport("template " "void declToImport(Ts... args) {" " const int i1 = (... + args);" " const int i2 = (1 - ... - args);" " const int i3 = (args * ...);" " const int i4 = (args / ... / 1);" "};" "void g() { declToImport(1, 2, 3, 4, 5); }", Lang_CXX17, "", Lang_CXX17, Verifier, functionTemplateDecl(hasDescendant(Match1), hasDescendant(Match2), hasDescendant(Match3), hasDescendant(Match4))); } /// \brief Matches __builtin_types_compatible_p: /// GNU extension to check equivalent types /// Given /// \code /// __builtin_types_compatible_p(int, int) /// \endcode // will generate TypeTraitExpr <...> 'int' const internal::VariadicDynCastAllOfMatcher typeTraitExpr; TEST_P(ImportExpr, ImportTypeTraitExpr) { MatchVerifier Verifier; testImport( "void declToImport() { " " (void)__builtin_types_compatible_p(int, int);" "}", Lang_C99, "", Lang_C99, Verifier, functionDecl(hasDescendant(typeTraitExpr(hasType(asString("int")))))); } const internal::VariadicDynCastAllOfMatcher cxxTypeidExpr; TEST_P(ImportExpr, ImportCXXTypeidExpr) { MatchVerifier Verifier; testImport( "namespace std { class type_info {}; }" "void declToImport() {" " int x;" " auto a = typeid(int); auto b = typeid(x);" "}", Lang_CXX11, "", Lang_CXX11, Verifier, traverse( TK_AsIs, functionDecl( hasDescendant(varDecl(hasName("a"), hasInitializer(hasDescendant( cxxTypeidExpr())))), hasDescendant(varDecl(hasName("b"), hasInitializer(hasDescendant( cxxTypeidExpr()))))))); } TEST_P(ImportExpr, ImportTypeTraitExprValDep) { MatchVerifier Verifier; testImport( "template struct declToImport {" " void m() { (void)__is_pod(T); }" "};" "void f() { declToImport().m(); }", Lang_CXX11, "", Lang_CXX11, Verifier, classTemplateDecl(has(cxxRecordDecl(has( functionDecl(hasDescendant( typeTraitExpr(hasType(booleanType()))))))))); } TEST_P(ImportDecl, ImportRecordDeclInFunc) { MatchVerifier Verifier; testImport("int declToImport() { " " struct data_t {int a;int b;};" " struct data_t d;" " return 0;" "}", Lang_C99, "", Lang_C99, Verifier, functionDecl(hasBody(compoundStmt( has(declStmt(hasSingleDecl(varDecl(hasName("d"))))))))); } TEST_P(ImportDecl, ImportedVarDeclPreservesThreadLocalStorage) { MatchVerifier Verifier; testImport("thread_local int declToImport;", Lang_CXX11, "", Lang_CXX11, Verifier, varDecl(hasThreadStorageDuration())); } TEST_P(ASTImporterOptionSpecificTestBase, ImportRecordTypeInFunc) { Decl *FromTU = getTuDecl("int declToImport() { " " struct data_t {int a;int b;};" " struct data_t d;" " return 0;" "}", Lang_C99, "input.c"); auto *FromVar = FirstDeclMatcher().match(FromTU, varDecl(hasName("d"))); ASSERT_TRUE(FromVar); auto ToType = ImportType(FromVar->getType().getCanonicalType(), FromVar, Lang_C99); EXPECT_FALSE(ToType.isNull()); } TEST_P(ASTImporterOptionSpecificTestBase, ImportRecordDeclInFuncParams) { // This construct is not supported by ASTImporter. Decl *FromTU = getTuDecl( "int declToImport(struct data_t{int a;int b;} ***d){ return 0; }", Lang_C99, "input.c"); auto *From = FirstDeclMatcher().match( FromTU, functionDecl(hasName("declToImport"))); ASSERT_TRUE(From); auto *To = Import(From, Lang_C99); EXPECT_EQ(To, nullptr); } TEST_P(ASTImporterOptionSpecificTestBase, ImportRecordDeclInFuncFromMacro) { Decl *FromTU = getTuDecl("#define NONAME_SIZEOF(type) sizeof(struct{type *dummy;}) \n" "int declToImport(){ return NONAME_SIZEOF(int); }", Lang_C99, "input.c"); auto *From = FirstDeclMatcher().match( FromTU, functionDecl(hasName("declToImport"))); ASSERT_TRUE(From); auto *To = Import(From, Lang_C99); ASSERT_TRUE(To); EXPECT_TRUE(MatchVerifier().match( To, functionDecl(hasName("declToImport"), hasDescendant(unaryExprOrTypeTraitExpr())))); } TEST_P(ASTImporterOptionSpecificTestBase, ImportRecordDeclInFuncParamsFromMacro) { // This construct is not supported by ASTImporter. Decl *FromTU = getTuDecl("#define PAIR_STRUCT(type) struct data_t{type a;type b;} \n" "int declToImport(PAIR_STRUCT(int) ***d){ return 0; }", Lang_C99, "input.c"); auto *From = FirstDeclMatcher().match( FromTU, functionDecl(hasName("declToImport"))); ASSERT_TRUE(From); auto *To = Import(From, Lang_C99); EXPECT_EQ(To, nullptr); } const internal::VariadicDynCastAllOfMatcher cxxPseudoDestructorExpr; TEST_P(ImportExpr, ImportCXXPseudoDestructorExpr) { MatchVerifier Verifier; testImport( "typedef int T;" "void declToImport(int *p) {" " T t;" " p->T::~T();" "}", Lang_CXX03, "", Lang_CXX03, Verifier, functionDecl(hasDescendant(callExpr(has(cxxPseudoDestructorExpr()))))); } TEST_P(ImportDecl, ImportUsingDecl) { MatchVerifier Verifier; testImport("namespace foo { int bar; }" "void declToImport() { using foo::bar; }", Lang_CXX03, "", Lang_CXX03, Verifier, functionDecl(hasDescendant(usingDecl(hasName("bar"))))); } TEST_P(ImportDecl, ImportUsingTemplate) { MatchVerifier Verifier; testImport("namespace ns { template struct S {}; }" "template