| //===- 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 <optional> |
| |
| namespace clang { |
| namespace ast_matchers { |
| |
| using internal::Matcher; |
| |
| static const RecordDecl *getRecordDeclOfFriend(FriendDecl *FD) { |
| QualType Ty = FD->getFriendType()->getType().getCanonicalType(); |
| return cast<RecordType>(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<FunctionDecl>().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<FunctionDecl>().match(FromTU, Pattern); |
| auto *D2 = LastDeclMatcher<FunctionDecl>().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<FunctionDecl>().match(FromTU, Pattern); |
| auto *D2 = LastDeclMatcher<FunctionDecl>().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<Decl *> ImportImpl(Decl *FromD) override { |
| auto *ND = dyn_cast<NamedDecl>(FromD); |
| if (!ND || ND->getName() != "shouldNotBeImported") |
| return ASTImporter::ImportImpl(FromD); |
| for (Decl *D : getToContext().getTranslationUnitDecl()->decls()) { |
| if (auto *ND = dyn_cast<NamedDecl>(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<ASTImporterSharedState> &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<CXXRecordDecl>(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<CXXRecordDecl>().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<CXXRecordDecl>().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<FunctionDecl>().match(FromTU, Pattern); |
| D2 = LastDeclMatcher<FunctionDecl>().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<Decl* ,2> 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<Decl* ,4> 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<Decl* ,4> 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<Stmt, SourceLocExpr> sourceLocExpr; |
| |
| AST_MATCHER_P(SourceLocExpr, hasBuiltinStr, StringRef, Str) { |
| return Node.getBuiltinStr() == Str; |
| } |
| |
| TEST_P(ImportExpr, ImportSourceLocExpr) { |
| MatchVerifier<Decl> 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<Decl> 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<Decl> 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<Stmt, ShuffleVectorExpr> |
| shuffleVectorExpr; |
| |
| TEST_P(ImportExpr, ImportShuffleVectorExpr) { |
| MatchVerifier<Decl> 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<Decl> Verifier; |
| testImport("void declToImport() { (void)__null; }", Lang_CXX03, "", |
| Lang_CXX03, Verifier, |
| functionDecl(hasDescendant(gnuNullExpr(hasType(isInteger()))))); |
| } |
| |
| TEST_P(ImportExpr, ImportGenericSelectionExpr) { |
| MatchVerifier<Decl> 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<Decl> Verifier; |
| testImport( |
| "void declToImport() { (void)nullptr; }", |
| Lang_CXX11, "", Lang_CXX11, Verifier, |
| functionDecl(hasDescendant(cxxNullPtrLiteralExpr()))); |
| } |
| |
| |
| TEST_P(ImportExpr, ImportFloatinglLiteralExpr) { |
| MatchVerifier<Decl> 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<Decl> 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<Decl> Verifier; |
| testImport( |
| "void declToImport() { (void)1.0i; }", |
| Lang_CXX14, "", Lang_CXX14, Verifier, |
| functionDecl(hasDescendant(imaginaryLiteral()))); |
| } |
| |
| TEST_P(ImportExpr, ImportCompoundLiteralExpr) { |
| MatchVerifier<Decl> 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<Decl> 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<Decl> 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<Decl> 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<NamedDecl>, InnerMatcher) { |
| const NamedDecl *Template = Node.getTemplatedDecl(); |
| return Template && InnerMatcher.matches(*Template, Finder, Builder); |
| } |
| |
| TEST_P(ImportExpr, ImportParenListExpr) { |
| MatchVerifier<Decl> Verifier; |
| testImport( |
| "template<typename T> class dummy { void f() { dummy X(*this); } };" |
| "typedef dummy<int> declToImport;" |
| "template class dummy<int>;", |
| 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<Decl> 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<Decl> 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<Decl> 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<Decl> 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<Decl> 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<Decl> 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<Decl> 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<Expr, CXXDefaultInitExpr> |
| cxxDefaultInitExpr; |
| |
| TEST_P(ImportExpr, ImportCXXDefaultInitExpr) { |
| MatchVerifier<Decl> 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<Expr, VAArgExpr> vaArgExpr; |
| |
| TEST_P(ImportExpr, ImportVAArgExpr) { |
| MatchVerifier<Decl> 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<Stmt, BuiltinBitCastExpr> |
| builtinBitCastExpr; |
| |
| TEST_P(ImportExpr, ImportBuiltinBitCastExpr) { |
| MatchVerifier<Decl> 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<Decl> 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<Decl> 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> bitIntType; |
| MatchVerifier<Decl> Verifier; |
| testImport("_BitInt(10) declToImport;", Lang_CXX11, "", Lang_CXX11, Verifier, |
| varDecl(hasType(bitIntType()))); |
| } |
| |
| TEST_P(ImportType, ImportDependentBitIntType) { |
| const AstTypeMatcher<DependentBitIntType> dependentBitIntType; |
| MatchVerifier<Decl> Verifier; |
| testImport("template<int Width> using declToImport = _BitInt(Width);", |
| Lang_CXX11, "", Lang_CXX11, Verifier, |
| typeAliasTemplateDecl( |
| has(typeAliasDecl(hasType(dependentBitIntType()))))); |
| } |
| |
| TEST_P(ImportType, ImportDependentAddressSpaceType) { |
| const AstTypeMatcher<DependentAddressSpaceType> dependentAddressSpaceType; |
| MatchVerifier<Decl> Verifier; |
| testImport( |
| R"( |
| template<typename T, int AddrSpace> |
| using declToImport = T __attribute__((address_space(AddrSpace))); |
| )", |
| Lang_CXX11, "", Lang_CXX11, Verifier, |
| typeAliasTemplateDecl( |
| has(typeAliasDecl(hasType(dependentAddressSpaceType()))))); |
| } |
| |
| TEST_P(ImportType, ImportVectorType) { |
| const AstTypeMatcher<VectorType> vectorType; |
| MatchVerifier<Decl> Verifier; |
| testImport("typedef int __attribute__((vector_size(12))) declToImport;", |
| Lang_CXX11, "", Lang_CXX11, Verifier, |
| typedefDecl(hasType(vectorType()))); |
| } |
| |
| TEST_P(ImportType, ImportDependentVectorType) { |
| const AstTypeMatcher<DependentVectorType> dependentVectorType; |
| MatchVerifier<Decl> Verifier; |
| testImport( |
| R"( |
| template<typename T, int Size> |
| using declToImport = T __attribute__((vector_size(Size))); |
| )", |
| Lang_CXX11, "", Lang_CXX11, Verifier, |
| typeAliasTemplateDecl( |
| has(typeAliasDecl(hasType(dependentVectorType()))))); |
| } |
| |
| struct ImportOpenCLPipe : ImportType { |
| std::vector<std::string> getExtraArgs() const override { |
| return {"-x", "cl", "-cl-no-stdinc", "-cl-std=CL2.0"}; |
| } |
| }; |
| |
| TEST_P(ImportOpenCLPipe, ImportPipeType) { |
| const AstTypeMatcher<PipeType> pipeType; |
| MatchVerifier<Decl> Verifier; |
| testImport("typedef pipe int declToImport;", Lang_OpenCL, "", Lang_OpenCL, |
| Verifier, typedefDecl(hasType(pipeType()))); |
| } |
| |
| struct ImportMatrixType : ImportType { |
| std::vector<std::string> getExtraArgs() const override { |
| return {"-fenable-matrix"}; |
| } |
| }; |
| |
| TEST_P(ImportMatrixType, ImportConstantMatrixType) { |
| const AstTypeMatcher<ConstantMatrixType> constantMatrixType; |
| MatchVerifier<Decl> 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> dependentSizedMatrixType; |
| MatchVerifier<Decl> Verifier; |
| testImport( |
| R"( |
| template<typename T, int Rows, int Cols> |
| using declToImport = T __attribute__((matrix_type(Rows, Cols))); |
| )", |
| Lang_CXX11, "", Lang_CXX11, Verifier, |
| typeAliasTemplateDecl( |
| has(typeAliasDecl(hasType(dependentSizedMatrixType()))))); |
| } |
| |
| TEST_P(ImportType, ImportUsingType) { |
| MatchVerifier<Decl> 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<Decl> Verifier; |
| testImport("template <typename T> void declToImport() { };", Lang_CXX03, "", |
| Lang_CXX03, Verifier, functionTemplateDecl()); |
| } |
| |
| TEST_P(ImportExpr, ImportCXXDependentScopeMemberExpr) { |
| MatchVerifier<Decl> Verifier; |
| testImport("template <typename T> struct C { T t; };" |
| "template <typename T> void declToImport() {" |
| " C<T> d;" |
| " (void)d.t;" |
| "}" |
| "void instantiate() { declToImport<int>(); }", |
| Lang_CXX03, "", Lang_CXX03, Verifier, |
| functionTemplateDecl(hasDescendant( |
| cStyleCastExpr(has(cxxDependentScopeMemberExpr()))))); |
| testImport("template <typename T> struct C { T t; };" |
| "template <typename T> void declToImport() {" |
| " C<T> d;" |
| " (void)(&d)->t;" |
| "}" |
| "void instantiate() { declToImport<int>(); }", |
| Lang_CXX03, "", Lang_CXX03, Verifier, |
| functionTemplateDecl(hasDescendant( |
| cStyleCastExpr(has(cxxDependentScopeMemberExpr()))))); |
| } |
| |
| TEST_P(ImportType, ImportTypeAliasTemplate) { |
| MatchVerifier<Decl> Verifier; |
| testImport( |
| "template <int K>" |
| "struct dummy { static const int i = K; };" |
| "template <int K> using dummy2 = dummy<K>;" |
| "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<Decl, VarTemplateSpecializationDecl> |
| varTemplateSpecializationDecl; |
| |
| TEST_P(ImportDecl, ImportVarTemplate) { |
| MatchVerifier<Decl> Verifier; |
| testImport( |
| "template <typename T>" |
| "T pi = T(3.1415926535897932385L);" |
| "void declToImport() { (void)pi<int>; }", |
| Lang_CXX14, "", Lang_CXX14, Verifier, |
| functionDecl( |
| hasDescendant(declRefExpr(to(varTemplateSpecializationDecl()))), |
| unless(hasAncestor(translationUnitDecl(has(varDecl( |
| hasName("pi"), unless(varTemplateSpecializationDecl())))))))); |
| } |
| |
| TEST_P(ImportType, ImportPackExpansion) { |
| MatchVerifier<Decl> Verifier; |
| testImport("template <typename... Args>" |
| "struct dummy {" |
| " dummy(Args... args) {}" |
| " static const int i = 4;" |
| "};" |
| "int declToImport() { return dummy<int>::i; }", |
| Lang_CXX11, "", Lang_CXX11, Verifier, |
| traverse(TK_AsIs, functionDecl(hasDescendant(returnStmt(has( |
| implicitCastExpr(has(declRefExpr())))))))); |
| } |
| |
| TEST_P(ImportType, ImportDependentTemplateSpecialization) { |
| MatchVerifier<Decl> Verifier; |
| testImport("template<typename T>" |
| "struct A;" |
| "template<typename T>" |
| "struct declToImport {" |
| " typename A<T>::template B<T> a;" |
| "};", |
| Lang_CXX03, "", Lang_CXX03, Verifier, |
| classTemplateDecl(has(cxxRecordDecl(has( |
| fieldDecl(hasType(dependentTemplateSpecializationType()))))))); |
| } |
| |
| TEST_P(ImportType, ImportDeducedTemplateSpecialization) { |
| MatchVerifier<Decl> Verifier; |
| testImport("template <typename T>" |
| "class C { public: C(T); };" |
| "C declToImport(123);", |
| Lang_CXX17, "", Lang_CXX17, Verifier, |
| varDecl(hasType(elaboratedType( |
| namesType(deducedTemplateSpecializationType()))))); |
| } |
| |
| const internal::VariadicDynCastAllOfMatcher<Stmt, SizeOfPackExpr> |
| sizeOfPackExpr; |
| |
| TEST_P(ImportExpr, ImportSizeOfPackExpr) { |
| MatchVerifier<Decl> Verifier; |
| testImport( |
| "template <typename... Ts>" |
| "void declToImport() {" |
| " const int i = sizeof...(Ts);" |
| "};" |
| "void g() { declToImport<int>(); }", |
| Lang_CXX11, "", Lang_CXX11, Verifier, |
| functionTemplateDecl(hasDescendant(sizeOfPackExpr()))); |
| testImport( |
| "template <typename... Ts>" |
| "using X = int[sizeof...(Ts)];" |
| "template <typename... Us>" |
| "struct Y {" |
| " X<Us..., int, double, int, Us...> f;" |
| "};" |
| "Y<float, int> 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<Decl> Verifier; |
| testImport("template <typename... Ts>" |
| "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<Stmt, TypeTraitExpr> typeTraitExpr; |
| |
| TEST_P(ImportExpr, ImportTypeTraitExpr) { |
| MatchVerifier<Decl> 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<Stmt, CXXTypeidExpr> cxxTypeidExpr; |
| |
| TEST_P(ImportExpr, ImportCXXTypeidExpr) { |
| MatchVerifier<Decl> 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<Decl> Verifier; |
| testImport( |
| "template<typename T> struct declToImport {" |
| " void m() { (void)__is_pod(T); }" |
| "};" |
| "void f() { declToImport<int>().m(); }", |
| Lang_CXX11, "", Lang_CXX11, Verifier, |
| classTemplateDecl(has(cxxRecordDecl(has( |
| functionDecl(hasDescendant( |
| typeTraitExpr(hasType(booleanType()))))))))); |
| } |
| |
| TEST_P(ImportDecl, ImportRecordDeclInFunc) { |
| MatchVerifier<Decl> 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<Decl> 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<VarDecl>().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<FunctionDecl>().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<FunctionDecl>().match( |
| FromTU, functionDecl(hasName("declToImport"))); |
| ASSERT_TRUE(From); |
| auto *To = Import(From, Lang_C99); |
| ASSERT_TRUE(To); |
| EXPECT_TRUE(MatchVerifier<FunctionDecl>().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<FunctionDecl>().match( |
| FromTU, functionDecl(hasName("declToImport"))); |
| ASSERT_TRUE(From); |
| auto *To = Import(From, Lang_C99); |
| EXPECT_EQ(To, nullptr); |
| } |
| |
| const internal::VariadicDynCastAllOfMatcher<Expr, CXXPseudoDestructorExpr> |
| cxxPseudoDestructorExpr; |
| |
| TEST_P(ImportExpr, ImportCXXPseudoDestructorExpr) { |
| MatchVerifier<Decl> 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<Decl> 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<Decl> Verifier; |
| testImport("namespace ns { template <typename T> struct S {}; }" |
| "template <template <typename> class T> class X {};" |
| "void declToImport() {" |
| "using ns::S; X<S> xi; }", |
| Lang_CXX11, "", Lang_CXX11, Verifier, |
| functionDecl(hasDescendant(varDecl(hasTypeLoc(elaboratedTypeLoc( |
| hasNamedTypeLoc(templateSpecializationTypeLoc( |
| hasAnyTemplateArgumentLoc(templateArgumentLoc()))))))))); |
| } |
| |
| TEST_P(ImportDecl, ImportUsingEnumDecl) { |
| MatchVerifier<Decl> Verifier; |
| testImport("namespace foo { enum bar { baz, toto, quux }; }" |
| "void declToImport() { using enum foo::bar; }", |
| Lang_CXX20, "", Lang_CXX20, Verifier, |
| functionDecl(hasDescendant(usingEnumDecl(hasName("bar"))))); |
| } |
| |
| const internal::VariadicDynCastAllOfMatcher<Decl, UsingPackDecl> usingPackDecl; |
| |
| TEST_P(ImportDecl, ImportUsingPackDecl) { |
| MatchVerifier<Decl> Verifier; |
| testImport( |
| "struct A { int operator()() { return 1; } };" |
| "struct B { int operator()() { return 2; } };" |
| "template<typename ...T> struct C : T... { using T::operator()...; };" |
| "C<A, B> declToImport;", |
| Lang_CXX20, "", Lang_CXX20, Verifier, |
| varDecl(hasType(elaboratedType(namesType(templateSpecializationType( |
| hasDeclaration(classTemplateSpecializationDecl( |
| hasDescendant(usingPackDecl()))))))))); |
| } |
| |
| /// \brief Matches shadow declarations introduced into a scope by a |
| /// (resolved) using declaration. |
| /// |
| /// Given |
| /// \code |
| /// namespace n { int f; } |
| /// namespace declToImport { using n::f; } |
| /// \endcode |
| /// usingShadowDecl() |
| /// matches \code f \endcode |
| const internal::VariadicDynCastAllOfMatcher<Decl, |
| UsingShadowDecl> usingShadowDecl; |
| |
| TEST_P(ImportDecl, ImportUsingShadowDecl) { |
| MatchVerifier<Decl> Verifier; |
| // from using-decl |
| testImport("namespace foo { int bar; }" |
| "namespace declToImport { using foo::bar; }", |
| Lang_CXX03, "", Lang_CXX03, Verifier, |
| namespaceDecl(has(usingShadowDecl(hasName("bar"))))); |
| // from using-enum-decl |
| testImport("namespace foo { enum bar {baz, toto, quux }; }" |
| "namespace declToImport { using enum foo::bar; }", |
| Lang_CXX20, "", Lang_CXX20, Verifier, |
| namespaceDecl(has(usingShadowDecl(hasName("baz"))))); |
| } |
| |
| TEST_P(ImportExpr, ImportUnresolvedLookupExpr) { |
| MatchVerifier<Decl> Verifier; |
| testImport("template<typename T> int foo();" |
| "template <typename T> void declToImport() {" |
| " (void)::foo<T>;" |
| " (void)::template foo<T>;" |
| "}" |
| "void instantiate() { declToImport<int>(); }", |
| Lang_CXX03, "", Lang_CXX03, Verifier, |
| functionTemplateDecl(hasDescendant(unresolvedLookupExpr()))); |
| } |
| |
| TEST_P(ImportExpr, ImportCXXUnresolvedConstructExpr) { |
| MatchVerifier<Decl> Verifier; |
| testImport("template <typename T> struct C { T t; };" |
| "template <typename T> void declToImport() {" |
| " C<T> d;" |
| " d.t = T();" |
| "}" |
| "void instantiate() { declToImport<int>(); }", |
| Lang_CXX03, "", Lang_CXX03, Verifier, |
| functionTemplateDecl(hasDescendant( |
| binaryOperator(has(cxxUnresolvedConstructExpr()))))); |
| testImport("template <typename T> struct C { T t; };" |
| "template <typename T> void declToImport() {" |
| " C<T> d;" |
| " (&d)->t = T();" |
| "}" |
| "void instantiate() { declToImport<int>(); }", |
| Lang_CXX03, "", Lang_CXX03, Verifier, |
| functionTemplateDecl(hasDescendant( |
| binaryOperator(has(cxxUnresolvedConstructExpr()))))); |
| } |
| |
| /// Check that function "declToImport()" (which is the templated function |
| /// for corresponding FunctionTemplateDecl) is not added into DeclContext. |
| /// Same for class template declarations. |
| TEST_P(ImportDecl, ImportTemplatedDeclForTemplate) { |
| MatchVerifier<Decl> Verifier; |
| testImport("template <typename T> void declToImport() { T a = 1; }" |
| "void instantiate() { declToImport<int>(); }", |
| Lang_CXX03, "", Lang_CXX03, Verifier, |
| functionTemplateDecl(hasAncestor(translationUnitDecl( |
| unless(has(functionDecl(hasName("declToImport")))))))); |
| testImport("template <typename T> struct declToImport { T t; };" |
| "void instantiate() { declToImport<int>(); }", |
| Lang_CXX03, "", Lang_CXX03, Verifier, |
| classTemplateDecl(hasAncestor(translationUnitDecl( |
| unless(has(cxxRecordDecl(hasName("declToImport")))))))); |
| } |
| |
| TEST_P(ImportDecl, ImportClassTemplatePartialSpecialization) { |
| MatchVerifier<Decl> Verifier; |
| auto Code = |
| R"s( |
| struct declToImport { |
| template <typename T0> struct X; |
| template <typename T0> struct X<T0 *> {}; |
| }; |
| )s"; |
| testImport(Code, Lang_CXX03, "", Lang_CXX03, Verifier, |
| recordDecl(has(classTemplateDecl()), |
| has(classTemplateSpecializationDecl()))); |
| } |
| |
| TEST_P(ImportExpr, CXXOperatorCallExpr) { |
| MatchVerifier<Decl> Verifier; |
| testImport( |
| "class declToImport {" |
| " void f() { *this = declToImport(); }" |
| "};", |
| Lang_CXX03, "", Lang_CXX03, Verifier, |
| cxxRecordDecl(has(cxxMethodDecl(hasDescendant(cxxOperatorCallExpr()))))); |
| } |
| |
| TEST_P(ImportExpr, DependentSizedArrayType) { |
| MatchVerifier<Decl> Verifier; |
| testImport("template<typename T, int Size> class declToImport {" |
| " T data[Size];" |
| "};", |
| Lang_CXX03, "", Lang_CXX03, Verifier, |
| classTemplateDecl(has(cxxRecordDecl( |
| has(fieldDecl(hasType(dependentSizedArrayType()))))))); |
| } |
| |
| TEST_P(ImportExpr, DependentSizedExtVectorType) { |
| MatchVerifier<Decl> Verifier; |
| testImport("template<typename T, int Size>" |
| "class declToImport {" |
| " typedef T __attribute__((ext_vector_type(Size))) type;" |
| "};", |
| Lang_CXX03, "", Lang_CXX03, Verifier, |
| classTemplateDecl(has(cxxRecordDecl( |
| has(typedefDecl(hasType(dependentSizedExtVectorType()))))))); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, ImportUsingPackDecl) { |
| Decl *FromTU = getTuDecl( |
| "struct A { int operator()() { return 1; } };" |
| "struct B { int operator()() { return 2; } };" |
| "template<typename ...T> struct C : T... { using T::operator()...; };" |
| "C<A, B> Var;", |
| Lang_CXX20); |
| |
| auto From = FirstDeclMatcher<UsingPackDecl>().match(FromTU, usingPackDecl()); |
| ASSERT_TRUE(From); |
| auto To = cast<UsingPackDecl>(Import(From, Lang_CXX20)); |
| ASSERT_TRUE(To); |
| |
| ArrayRef<NamedDecl *> FromExpansions = From->expansions(); |
| ArrayRef<NamedDecl *> ToExpansions = To->expansions(); |
| ASSERT_EQ(FromExpansions.size(), ToExpansions.size()); |
| for (unsigned int I = 0; I < FromExpansions.size(); ++I) { |
| auto ImportedExpansion = Import(FromExpansions[I], Lang_CXX20); |
| EXPECT_EQ(ImportedExpansion, ToExpansions[I]); |
| } |
| |
| auto ImportedDC = cast<Decl>(Import(From->getDeclContext(), Lang_CXX20)); |
| EXPECT_EQ(ImportedDC, cast<Decl>(To->getDeclContext())); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, TemplateTypeParmDeclNoDefaultArg) { |
| Decl *FromTU = getTuDecl("template<typename T> struct X {};", Lang_CXX03); |
| auto From = FirstDeclMatcher<TemplateTypeParmDecl>().match( |
| FromTU, templateTypeParmDecl(hasName("T"))); |
| TemplateTypeParmDecl *To = Import(From, Lang_CXX03); |
| ASSERT_FALSE(To->hasDefaultArgument()); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, TemplateTypeParmDeclDefaultArg) { |
| Decl *FromTU = |
| getTuDecl("template<typename T = int> struct X {};", Lang_CXX03); |
| auto From = FirstDeclMatcher<TemplateTypeParmDecl>().match( |
| FromTU, templateTypeParmDecl(hasName("T"))); |
| TemplateTypeParmDecl *To = Import(From, Lang_CXX03); |
| ASSERT_TRUE(To->hasDefaultArgument()); |
| QualType ToArg = To->getDefaultArgument().getArgument().getAsType(); |
| ASSERT_EQ(ToArg, QualType(To->getASTContext().IntTy)); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, ImportBeginLocOfDeclRefExpr) { |
| Decl *FromTU = |
| getTuDecl("class A { public: static int X; }; void f() { (void)A::X; }", |
| Lang_CXX03); |
| auto From = FirstDeclMatcher<FunctionDecl>().match( |
| FromTU, functionDecl(hasName("f"))); |
| ASSERT_TRUE(From); |
| ASSERT_TRUE( |
| cast<CStyleCastExpr>(cast<CompoundStmt>(From->getBody())->body_front()) |
| ->getSubExpr() |
| ->getBeginLoc() |
| .isValid()); |
| FunctionDecl *To = Import(From, Lang_CXX03); |
| ASSERT_TRUE(To); |
| ASSERT_TRUE( |
| cast<CStyleCastExpr>(cast<CompoundStmt>(To->getBody())->body_front()) |
| ->getSubExpr() |
| ->getBeginLoc() |
| .isValid()); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| TemplateTemplateParmDeclNoDefaultArg) { |
| Decl *FromTU = getTuDecl(R"( |
| template<template<typename> typename TT> struct Y {}; |
| )", |
| Lang_CXX17); |
| auto From = FirstDeclMatcher<TemplateTemplateParmDecl>().match( |
| FromTU, templateTemplateParmDecl(hasName("TT"))); |
| TemplateTemplateParmDecl *To = Import(From, Lang_CXX17); |
| ASSERT_FALSE(To->hasDefaultArgument()); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, TemplateTemplateParmDeclDefaultArg) { |
| Decl *FromTU = getTuDecl(R"( |
| template<typename T> struct X {}; |
| template<template<typename> typename TT = X> struct Y {}; |
| )", |
| Lang_CXX17); |
| auto From = FirstDeclMatcher<TemplateTemplateParmDecl>().match( |
| FromTU, templateTemplateParmDecl(hasName("TT"))); |
| TemplateTemplateParmDecl *To = Import(From, Lang_CXX17); |
| ASSERT_TRUE(To->hasDefaultArgument()); |
| const TemplateArgument &ToDefaultArg = To->getDefaultArgument().getArgument(); |
| ASSERT_TRUE(To->isTemplateDecl()); |
| TemplateDecl *ToTemplate = ToDefaultArg.getAsTemplate().getAsTemplateDecl(); |
| |
| // Find the default argument template 'X' in the AST and compare it against |
| // the default argument we got. |
| auto ToExpectedDecl = FirstDeclMatcher<ClassTemplateDecl>().match( |
| To->getTranslationUnitDecl(), classTemplateDecl(hasName("X"))); |
| ASSERT_EQ(ToTemplate, ToExpectedDecl); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, NonTypeTemplateParmDeclNoDefaultArg) { |
| Decl *FromTU = getTuDecl("template<int N> struct X {};", Lang_CXX03); |
| auto From = FirstDeclMatcher<NonTypeTemplateParmDecl>().match( |
| FromTU, nonTypeTemplateParmDecl(hasName("N"))); |
| NonTypeTemplateParmDecl *To = Import(From, Lang_CXX03); |
| ASSERT_FALSE(To->hasDefaultArgument()); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, NonTypeTemplateParmDeclDefaultArg) { |
| Decl *FromTU = getTuDecl("template<int S = 1> struct X {};", Lang_CXX03); |
| auto From = FirstDeclMatcher<NonTypeTemplateParmDecl>().match( |
| FromTU, nonTypeTemplateParmDecl(hasName("S"))); |
| NonTypeTemplateParmDecl *To = Import(From, Lang_CXX03); |
| ASSERT_TRUE(To->hasDefaultArgument()); |
| Stmt *ToArg = To->getDefaultArgument().getArgument().getAsExpr(); |
| ASSERT_TRUE(isa<IntegerLiteral>(ToArg)); |
| ASSERT_EQ(cast<IntegerLiteral>(ToArg)->getValue().getLimitedValue(), 1U); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, TemplateArgumentsDefaulted) { |
| Decl *FromTU = getTuDecl(R"( |
| template<typename T> struct X {}; |
| template<typename TP = double, |
| int NTTP = 50, |
| template<typename> typename TT = X> struct S {}; |
| S<> s; |
| )", |
| Lang_CXX17); |
| auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( |
| FromTU, classTemplateSpecializationDecl(hasName("S"))); |
| ASSERT_TRUE(FromSpec); |
| auto *ToSpec = Import(FromSpec, Lang_CXX03); |
| ASSERT_TRUE(ToSpec); |
| auto const &TList = ToSpec->getTemplateArgs(); |
| for (auto const &Arg : TList.asArray()) { |
| ASSERT_TRUE(Arg.getIsDefaulted()); |
| } |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| ImportOfTemplatedDeclOfClassTemplateDecl) { |
| Decl *FromTU = getTuDecl("template<class X> struct S{};", Lang_CXX03); |
| auto From = |
| FirstDeclMatcher<ClassTemplateDecl>().match(FromTU, classTemplateDecl()); |
| ASSERT_TRUE(From); |
| auto To = cast<ClassTemplateDecl>(Import(From, Lang_CXX03)); |
| ASSERT_TRUE(To); |
| Decl *ToTemplated = To->getTemplatedDecl(); |
| Decl *ToTemplated1 = Import(From->getTemplatedDecl(), Lang_CXX03); |
| EXPECT_TRUE(ToTemplated1); |
| EXPECT_EQ(ToTemplated1, ToTemplated); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| ImportOfTemplatedDeclOfFunctionTemplateDecl) { |
| Decl *FromTU = getTuDecl("template<class X> void f(){}", Lang_CXX03); |
| auto From = FirstDeclMatcher<FunctionTemplateDecl>().match( |
| FromTU, functionTemplateDecl()); |
| ASSERT_TRUE(From); |
| auto To = cast<FunctionTemplateDecl>(Import(From, Lang_CXX03)); |
| ASSERT_TRUE(To); |
| Decl *ToTemplated = To->getTemplatedDecl(); |
| Decl *ToTemplated1 = Import(From->getTemplatedDecl(), Lang_CXX03); |
| EXPECT_TRUE(ToTemplated1); |
| EXPECT_EQ(ToTemplated1, ToTemplated); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| ImportOfTemplatedDeclShouldImportTheClassTemplateDecl) { |
| Decl *FromTU = getTuDecl("template<class X> struct S{};", Lang_CXX03); |
| auto FromFT = |
| FirstDeclMatcher<ClassTemplateDecl>().match(FromTU, classTemplateDecl()); |
| ASSERT_TRUE(FromFT); |
| |
| auto ToTemplated = |
| cast<CXXRecordDecl>(Import(FromFT->getTemplatedDecl(), Lang_CXX03)); |
| EXPECT_TRUE(ToTemplated); |
| auto ToTU = ToTemplated->getTranslationUnitDecl(); |
| auto ToFT = |
| FirstDeclMatcher<ClassTemplateDecl>().match(ToTU, classTemplateDecl()); |
| EXPECT_TRUE(ToFT); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| ImportOfTemplatedDeclShouldImportTheFunctionTemplateDecl) { |
| Decl *FromTU = getTuDecl("template<class X> void f(){}", Lang_CXX03); |
| auto FromFT = FirstDeclMatcher<FunctionTemplateDecl>().match( |
| FromTU, functionTemplateDecl()); |
| ASSERT_TRUE(FromFT); |
| |
| auto ToTemplated = |
| cast<FunctionDecl>(Import(FromFT->getTemplatedDecl(), Lang_CXX03)); |
| EXPECT_TRUE(ToTemplated); |
| auto ToTU = ToTemplated->getTranslationUnitDecl(); |
| auto ToFT = FirstDeclMatcher<FunctionTemplateDecl>().match( |
| ToTU, functionTemplateDecl()); |
| EXPECT_TRUE(ToFT); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplatedDecl) { |
| auto Code = |
| R"( |
| namespace x { |
| template<class X> struct S1{}; |
| template<class X> struct S2{}; |
| template<class X> struct S3{}; |
| } |
| )"; |
| Decl *FromTU = getTuDecl(Code, Lang_CXX03); |
| auto FromNs = |
| FirstDeclMatcher<NamespaceDecl>().match(FromTU, namespaceDecl()); |
| auto ToNs = cast<NamespaceDecl>(Import(FromNs, Lang_CXX03)); |
| ASSERT_TRUE(ToNs); |
| auto From = |
| FirstDeclMatcher<ClassTemplateDecl>().match(FromTU, |
| classTemplateDecl( |
| hasName("S2"))); |
| auto To = |
| FirstDeclMatcher<ClassTemplateDecl>().match(ToNs, |
| classTemplateDecl( |
| hasName("S2"))); |
| ASSERT_TRUE(From); |
| ASSERT_TRUE(To); |
| auto ToTemplated = To->getTemplatedDecl(); |
| auto ToTemplated1 = |
| cast<CXXRecordDecl>(Import(From->getTemplatedDecl(), Lang_CXX03)); |
| EXPECT_TRUE(ToTemplated1); |
| ASSERT_EQ(ToTemplated1, ToTemplated); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| ImportTemplateSpecializationStaticMember) { |
| auto FromCode = |
| R"( |
| template <typename H> class Test{ |
| public: |
| static const unsigned int length; |
| }; |
| |
| template<> const unsigned int Test<int>::length; |
| template<> const unsigned int Test<int>::length = 0; |
| )"; |
| auto ToCode = |
| R"( |
| template <typename H> class Test { |
| public: |
| static const unsigned int length; |
| }; |
| |
| template <> const unsigned int Test<int>::length; |
| |
| void foo() { int i = 1 / Test<int>::length; } |
| )"; |
| Decl *FromTU = getTuDecl(FromCode, Lang_CXX14); |
| auto FromDecl = FirstDeclMatcher<VarDecl>().match( |
| FromTU, varDecl(hasName("length"), isDefinition())); |
| Decl *ToTu = getToTuDecl(ToCode, Lang_CXX14); |
| auto ToX = Import(FromDecl, Lang_CXX03); |
| auto ToDecl = FirstDeclMatcher<VarDecl>().match( |
| ToTu, varDecl(hasName("length"), isDefinition())); |
| EXPECT_TRUE(ToX); |
| EXPECT_EQ(ToX, ToDecl); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, ImportChooseExpr) { |
| // This tests the import of isConditionTrue directly to make sure the importer |
| // gets it right. |
| Decl *From, *To; |
| std::tie(From, To) = getImportedDecl( |
| "void declToImport() { (void)__builtin_choose_expr(1, 0, 1); }", Lang_C99, |
| "", Lang_C99); |
| |
| auto ToResults = match(chooseExpr().bind("choose"), To->getASTContext()); |
| auto FromResults = match(chooseExpr().bind("choose"), From->getASTContext()); |
| |
| const ChooseExpr *FromChooseExpr = |
| selectFirst<ChooseExpr>("choose", FromResults); |
| ASSERT_TRUE(FromChooseExpr); |
| |
| const ChooseExpr *ToChooseExpr = selectFirst<ChooseExpr>("choose", ToResults); |
| ASSERT_TRUE(ToChooseExpr); |
| |
| EXPECT_EQ(FromChooseExpr->isConditionTrue(), ToChooseExpr->isConditionTrue()); |
| EXPECT_EQ(FromChooseExpr->isConditionDependent(), |
| ToChooseExpr->isConditionDependent()); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, ImportConvertVectorExpr) { |
| Decl *From, *To; |
| std::tie(From, To) = getImportedDecl( |
| "typedef double v4double __attribute__((__vector_size__(32)));" |
| "typedef float v4float __attribute__((__vector_size__(16)));" |
| "v4float vf;" |
| "void declToImport() { (void)__builtin_convertvector(vf, v4double); }", |
| Lang_CXX03, "", Lang_CXX03); |
| |
| auto ToResults = |
| match(convertVectorExpr().bind("convert"), To->getASTContext()); |
| auto FromResults = |
| match(convertVectorExpr().bind("convert"), From->getASTContext()); |
| |
| const ConvertVectorExpr *FromConvertVectorExpr = |
| selectFirst<ConvertVectorExpr>("convert", FromResults); |
| ASSERT_TRUE(FromConvertVectorExpr); |
| |
| const ConvertVectorExpr *ToConvertVectorExpr = |
| selectFirst<ConvertVectorExpr>("convert", ToResults); |
| ASSERT_TRUE(ToConvertVectorExpr); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, ImportGenericSelectionExpr) { |
| Decl *From, *To; |
| std::tie(From, To) = getImportedDecl( |
| R"( |
| int declToImport() { |
| int x; |
| return _Generic(x, int: 0, default: 1); |
| } |
| )", |
| Lang_C99, "", Lang_C99); |
| |
| auto ToResults = |
| match(genericSelectionExpr().bind("expr"), To->getASTContext()); |
| auto FromResults = |
| match(genericSelectionExpr().bind("expr"), From->getASTContext()); |
| |
| const GenericSelectionExpr *FromGenericSelectionExpr = |
| selectFirst<GenericSelectionExpr>("expr", FromResults); |
| ASSERT_TRUE(FromGenericSelectionExpr); |
| |
| const GenericSelectionExpr *ToGenericSelectionExpr = |
| selectFirst<GenericSelectionExpr>("expr", ToResults); |
| ASSERT_TRUE(ToGenericSelectionExpr); |
| |
| EXPECT_EQ(FromGenericSelectionExpr->isResultDependent(), |
| ToGenericSelectionExpr->isResultDependent()); |
| EXPECT_EQ(FromGenericSelectionExpr->getResultIndex(), |
| ToGenericSelectionExpr->getResultIndex()); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| ImportFunctionWithBackReferringParameter) { |
| Decl *From, *To; |
| std::tie(From, To) = getImportedDecl( |
| R"( |
| template <typename T> struct X {}; |
| |
| void declToImport(int y, X<int> &x) {} |
| |
| template <> struct X<int> { |
| void g() { |
| X<int> x; |
| declToImport(0, x); |
| } |
| }; |
| )", |
| Lang_CXX03, "", Lang_CXX03); |
| |
| MatchVerifier<Decl> Verifier; |
| auto Matcher = functionDecl(hasName("declToImport"), |
| parameterCountIs(2), |
| hasParameter(0, hasName("y")), |
| hasParameter(1, hasName("x")), |
| hasParameter(1, hasType(asString("X<int> &")))); |
| ASSERT_TRUE(Verifier.match(From, Matcher)); |
| EXPECT_TRUE(Verifier.match(To, Matcher)); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| TUshouldNotContainTemplatedDeclOfFunctionTemplates) { |
| Decl *From, *To; |
| std::tie(From, To) = |
| getImportedDecl("template <typename T> void declToImport() { T a = 1; }" |
| "void instantiate() { declToImport<int>(); }", |
| Lang_CXX03, "", Lang_CXX03); |
| |
| auto Check = [](Decl *D) -> bool { |
| auto TU = D->getTranslationUnitDecl(); |
| for (auto Child : TU->decls()) { |
| if (auto *FD = dyn_cast<FunctionDecl>(Child)) { |
| if (FD->getNameAsString() == "declToImport") { |
| GTEST_NONFATAL_FAILURE_( |
| "TU should not contain any FunctionDecl with name declToImport"); |
| return false; |
| } |
| } |
| } |
| return true; |
| }; |
| |
| ASSERT_TRUE(Check(From)); |
| EXPECT_TRUE(Check(To)); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| TUshouldNotContainTemplatedDeclOfClassTemplates) { |
| Decl *From, *To; |
| std::tie(From, To) = |
| getImportedDecl("template <typename T> struct declToImport { T t; };" |
| "void instantiate() { declToImport<int>(); }", |
| Lang_CXX03, "", Lang_CXX03); |
| |
| auto Check = [](Decl *D) -> bool { |
| auto TU = D->getTranslationUnitDecl(); |
| for (auto Child : TU->decls()) { |
| if (auto *RD = dyn_cast<CXXRecordDecl>(Child)) { |
| if (RD->getNameAsString() == "declToImport") { |
| GTEST_NONFATAL_FAILURE_( |
| "TU should not contain any CXXRecordDecl with name declToImport"); |
| return false; |
| } |
| } |
| } |
| return true; |
| }; |
| |
| ASSERT_TRUE(Check(From)); |
| EXPECT_TRUE(Check(To)); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| TUshouldNotContainTemplatedDeclOfTypeAlias) { |
| Decl *From, *To; |
| std::tie(From, To) = |
| getImportedDecl( |
| "template <typename T> struct X {};" |
| "template <typename T> using declToImport = X<T>;" |
| "void instantiate() { declToImport<int> a; }", |
| Lang_CXX11, "", Lang_CXX11); |
| |
| auto Check = [](Decl *D) -> bool { |
| auto TU = D->getTranslationUnitDecl(); |
| for (auto Child : TU->decls()) { |
| if (auto *AD = dyn_cast<TypeAliasDecl>(Child)) { |
| if (AD->getNameAsString() == "declToImport") { |
| GTEST_NONFATAL_FAILURE_( |
| "TU should not contain any TypeAliasDecl with name declToImport"); |
| return false; |
| } |
| } |
| } |
| return true; |
| }; |
| |
| ASSERT_TRUE(Check(From)); |
| EXPECT_TRUE(Check(To)); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| TUshouldNotContainClassTemplateSpecializationOfImplicitInstantiation) { |
| |
| Decl *From, *To; |
| std::tie(From, To) = getImportedDecl( |
| R"( |
| template<class T> |
| class Base {}; |
| class declToImport : public Base<declToImport> {}; |
| )", |
| Lang_CXX03, "", Lang_CXX03); |
| |
| // Check that the ClassTemplateSpecializationDecl is NOT the child of the TU. |
| auto Pattern = |
| translationUnitDecl(unless(has(classTemplateSpecializationDecl()))); |
| ASSERT_TRUE( |
| MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern)); |
| EXPECT_TRUE( |
| MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern)); |
| |
| // Check that the ClassTemplateSpecializationDecl is the child of the |
| // ClassTemplateDecl. |
| Pattern = translationUnitDecl(has(classTemplateDecl( |
| hasName("Base"), has(classTemplateSpecializationDecl())))); |
| ASSERT_TRUE( |
| MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern)); |
| EXPECT_TRUE( |
| MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern)); |
| } |
| |
| AST_MATCHER_P(RecordDecl, hasFieldOrder, std::vector<StringRef>, Order) { |
| size_t Index = 0; |
| for (Decl *D : Node.decls()) { |
| if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) { |
| auto *ND = cast<NamedDecl>(D); |
| if (Index == Order.size()) |
| return false; |
| if (ND->getName() != Order[Index]) |
| return false; |
| ++Index; |
| } |
| } |
| return Index == Order.size(); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| TUshouldContainClassTemplateSpecializationOfExplicitInstantiation) { |
| Decl *From, *To; |
| std::tie(From, To) = getImportedDecl( |
| R"( |
| namespace NS { |
| template<class T> |
| class X {}; |
| template class X<int>; |
| } |
| )", |
| Lang_CXX03, "", Lang_CXX03, "NS"); |
| |
| // Check that the ClassTemplateSpecializationDecl is NOT the child of the |
| // ClassTemplateDecl. |
| auto Pattern = namespaceDecl(has(classTemplateDecl( |
| hasName("X"), unless(has(classTemplateSpecializationDecl()))))); |
| ASSERT_TRUE(MatchVerifier<Decl>{}.match(From, Pattern)); |
| EXPECT_TRUE(MatchVerifier<Decl>{}.match(To, Pattern)); |
| |
| // Check that the ClassTemplateSpecializationDecl is the child of the |
| // NamespaceDecl. |
| Pattern = namespaceDecl(has(classTemplateSpecializationDecl(hasName("X")))); |
| ASSERT_TRUE(MatchVerifier<Decl>{}.match(From, Pattern)); |
| EXPECT_TRUE(MatchVerifier<Decl>{}.match(To, Pattern)); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| CXXRecordDeclFieldsShouldBeInCorrectOrder) { |
| Decl *From, *To; |
| std::tie(From, To) = |
| getImportedDecl( |
| "struct declToImport { int a; int b; };", |
| Lang_CXX11, "", Lang_CXX11); |
| |
| MatchVerifier<Decl> Verifier; |
| ASSERT_TRUE(Verifier.match(From, cxxRecordDecl(hasFieldOrder({"a", "b"})))); |
| EXPECT_TRUE(Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b"})))); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| CXXRecordDeclFieldOrderShouldNotDependOnImportOrder) { |
| Decl *From, *To; |
| std::tie(From, To) = getImportedDecl( |
| // The original recursive algorithm of ASTImporter first imports 'c' then |
| // 'b' and lastly 'a'. Therefore we must restore the order somehow. |
| R"s( |
| struct declToImport { |
| int a = c + b; |
| int b = 1; |
| int c = 2; |
| }; |
| )s", |
| Lang_CXX11, "", Lang_CXX11); |
| |
| MatchVerifier<Decl> Verifier; |
| ASSERT_TRUE( |
| Verifier.match(From, cxxRecordDecl(hasFieldOrder({"a", "b", "c"})))); |
| EXPECT_TRUE( |
| Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b", "c"})))); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| CXXRecordDeclFieldAndIndirectFieldOrder) { |
| Decl *From, *To; |
| std::tie(From, To) = getImportedDecl( |
| // First field is "a", then the field for unnamed union, then "b" and "c" |
| // from it (indirect fields), then "d". |
| R"s( |
| struct declToImport { |
| int a = d; |
| union { |
| int b; |
| int c; |
| }; |
| int d; |
| }; |
| )s", |
| Lang_CXX11, "", Lang_CXX11); |
| |
| MatchVerifier<Decl> Verifier; |
| ASSERT_TRUE(Verifier.match( |
| From, cxxRecordDecl(hasFieldOrder({"a", "", "b", "c", "d"})))); |
| EXPECT_TRUE(Verifier.match( |
| To, cxxRecordDecl(hasFieldOrder({"a", "", "b", "c", "d"})))); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, ShouldImportImplicitCXXRecordDecl) { |
| Decl *From, *To; |
| std::tie(From, To) = getImportedDecl( |
| R"( |
| struct declToImport { |
| }; |
| )", |
| Lang_CXX03, "", Lang_CXX03); |
| |
| MatchVerifier<Decl> Verifier; |
| // Match the implicit Decl. |
| auto Matcher = cxxRecordDecl(has(cxxRecordDecl())); |
| ASSERT_TRUE(Verifier.match(From, Matcher)); |
| EXPECT_TRUE(Verifier.match(To, Matcher)); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| ShouldImportImplicitCXXRecordDeclOfClassTemplate) { |
| Decl *From, *To; |
| std::tie(From, To) = getImportedDecl( |
| R"( |
| template <typename U> |
| struct declToImport { |
| }; |
| )", |
| Lang_CXX03, "", Lang_CXX03); |
| |
| MatchVerifier<Decl> Verifier; |
| // Match the implicit Decl. |
| auto Matcher = classTemplateDecl(has(cxxRecordDecl(has(cxxRecordDecl())))); |
| ASSERT_TRUE(Verifier.match(From, Matcher)); |
| EXPECT_TRUE(Verifier.match(To, Matcher)); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| ShouldImportImplicitCXXRecordDeclOfClassTemplateSpecializationDecl) { |
| Decl *From, *To; |
| std::tie(From, To) = getImportedDecl( |
| R"( |
| template<class T> |
| class Base {}; |
| class declToImport : public Base<declToImport> {}; |
| )", |
| Lang_CXX03, "", Lang_CXX03); |
| |
| auto hasImplicitClass = has(cxxRecordDecl()); |
| auto Pattern = translationUnitDecl(has(classTemplateDecl( |
| hasName("Base"), |
| has(classTemplateSpecializationDecl(hasImplicitClass))))); |
| ASSERT_TRUE( |
| MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern)); |
| EXPECT_TRUE( |
| MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern)); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, IDNSOrdinary) { |
| Decl *From, *To; |
| std::tie(From, To) = |
| getImportedDecl("void declToImport() {}", Lang_CXX03, "", Lang_CXX03); |
| |
| MatchVerifier<Decl> Verifier; |
| auto Matcher = functionDecl(); |
| ASSERT_TRUE(Verifier.match(From, Matcher)); |
| EXPECT_TRUE(Verifier.match(To, Matcher)); |
| EXPECT_EQ(From->getIdentifierNamespace(), To->getIdentifierNamespace()); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, IDNSOfNonmemberOperator) { |
| Decl *FromTU = getTuDecl( |
| R"( |
| struct X {}; |
| void operator<<(int, X); |
| )", |
| Lang_CXX03); |
| Decl *From = LastDeclMatcher<Decl>{}.match(FromTU, functionDecl()); |
| const Decl *To = Import(From, Lang_CXX03); |
| EXPECT_EQ(From->getIdentifierNamespace(), To->getIdentifierNamespace()); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| ShouldImportMembersOfClassTemplateSpecializationDecl) { |
| Decl *From, *To; |
| std::tie(From, To) = getImportedDecl( |
| R"( |
| template<class T> |
| class Base { int a; }; |
| class declToImport : Base<declToImport> {}; |
| )", |
| Lang_CXX03, "", Lang_CXX03); |
| |
| auto Pattern = translationUnitDecl(has(classTemplateDecl( |
| hasName("Base"), |
| has(classTemplateSpecializationDecl(has(fieldDecl(hasName("a")))))))); |
| ASSERT_TRUE( |
| MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern)); |
| EXPECT_TRUE( |
| MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern)); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| ImportDefinitionOfClassTemplateAfterFwdDecl) { |
| { |
| Decl *FromTU = getTuDecl( |
| R"( |
| template <typename T> |
| struct B; |
| )", |
| Lang_CXX03, "input0.cc"); |
| auto *FromD = FirstDeclMatcher<ClassTemplateDecl>().match( |
| FromTU, classTemplateDecl(hasName("B"))); |
| |
| Import(FromD, Lang_CXX03); |
| } |
| |
| { |
| Decl *FromTU = getTuDecl( |
| R"( |
| template <typename T> |
| struct B { |
| void f(); |
| }; |
| )", |
| Lang_CXX03, "input1.cc"); |
| FunctionDecl *FromD = FirstDeclMatcher<FunctionDecl>().match( |
| FromTU, functionDecl(hasName("f"))); |
| Import(FromD, Lang_CXX03); |
| auto *FromCTD = FirstDeclMatcher<ClassTemplateDecl>().match( |
| FromTU, classTemplateDecl(hasName("B"))); |
| auto *ToCTD = cast<ClassTemplateDecl>(Import(FromCTD, Lang_CXX03)); |
| EXPECT_TRUE(ToCTD->isThisDeclarationADefinition()); |
| } |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| ImportDefinitionOfClassTemplateIfThereIsAnExistingFwdDeclAndDefinition) { |
| Decl *ToTU = getToTuDecl( |
| R"( |
| template <typename T> |
| struct B { |
| void f(); |
| }; |
| |
| template <typename T> |
| struct B; |
| )", |
| Lang_CXX03); |
| ASSERT_EQ(1u, DeclCounterWithPredicate<ClassTemplateDecl>( |
| [](const ClassTemplateDecl *T) { |
| return T->isThisDeclarationADefinition(); |
| }) |
| .match(ToTU, classTemplateDecl())); |
| |
| Decl *FromTU = getTuDecl( |
| R"( |
| template <typename T> |
| struct B { |
| void f(); |
| }; |
| )", |
| Lang_CXX03, "input1.cc"); |
| ClassTemplateDecl *FromD = FirstDeclMatcher<ClassTemplateDecl>().match( |
| FromTU, classTemplateDecl(hasName("B"))); |
| |
| Import(FromD, Lang_CXX03); |
| |
| // We should have only one definition. |
| EXPECT_EQ(1u, DeclCounterWithPredicate<ClassTemplateDecl>( |
| [](const ClassTemplateDecl *T) { |
| return T->isThisDeclarationADefinition(); |
| }) |
| .match(ToTU, classTemplateDecl())); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| ImportDefinitionOfClassIfThereIsAnExistingFwdDeclAndDefinition) { |
| Decl *ToTU = getToTuDecl( |
| R"( |
| struct B { |
| void f(); |
| }; |
| |
| struct B; |
| )", |
| Lang_CXX03); |
| ASSERT_EQ(2u, DeclCounter<CXXRecordDecl>().match( |
| ToTU, cxxRecordDecl(unless(isImplicit())))); |
| |
| Decl *FromTU = getTuDecl( |
| R"( |
| struct B { |
| void f(); |
| }; |
| )", |
| Lang_CXX03, "input1.cc"); |
| auto *FromD = FirstDeclMatcher<CXXRecordDecl>().match( |
| FromTU, cxxRecordDecl(hasName("B"))); |
| |
| Import(FromD, Lang_CXX03); |
| |
| EXPECT_EQ(2u, DeclCounter<CXXRecordDecl>().match( |
| ToTU, cxxRecordDecl(unless(isImplicit())))); |
| } |
| |
| static void CompareSourceLocs(FullSourceLoc Loc1, FullSourceLoc Loc2) { |
| EXPECT_EQ(Loc1.getExpansionLineNumber(), Loc2.getExpansionLineNumber()); |
| EXPECT_EQ(Loc1.getExpansionColumnNumber(), Loc2.getExpansionColumnNumber()); |
| EXPECT_EQ(Loc1.getSpellingLineNumber(), Loc2.getSpellingLineNumber()); |
| EXPECT_EQ(Loc1.getSpellingColumnNumber(), Loc2.getSpellingColumnNumber()); |
| } |
| static void CompareSourceRanges(SourceRange Range1, SourceRange Range2, |
| SourceManager &SM1, SourceManager &SM2) { |
| CompareSourceLocs(FullSourceLoc{ Range1.getBegin(), SM1 }, |
| FullSourceLoc{ Range2.getBegin(), SM2 }); |
| CompareSourceLocs(FullSourceLoc{ Range1.getEnd(), SM1 }, |
| FullSourceLoc{ Range2.getEnd(), SM2 }); |
| } |
| TEST_P(ASTImporterOptionSpecificTestBase, ImportSourceLocs) { |
| Decl *FromTU = getTuDecl( |
| R"( |
| #define MFOO(arg) arg = arg + 1 |
| |
| void foo() { |
| int a = 5; |
| MFOO(a); |
| } |
| )", |
| Lang_CXX03); |
| auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, functionDecl()); |
| auto ToD = Import(FromD, Lang_CXX03); |
| |
| auto ToLHS = LastDeclMatcher<DeclRefExpr>().match(ToD, declRefExpr()); |
| auto FromLHS = LastDeclMatcher<DeclRefExpr>().match(FromTU, declRefExpr()); |
| auto ToRHS = LastDeclMatcher<IntegerLiteral>().match(ToD, integerLiteral()); |
| auto FromRHS = |
| LastDeclMatcher<IntegerLiteral>().match(FromTU, integerLiteral()); |
| |
| SourceManager &ToSM = ToAST->getASTContext().getSourceManager(); |
| SourceManager &FromSM = FromD->getASTContext().getSourceManager(); |
| CompareSourceRanges(ToD->getSourceRange(), FromD->getSourceRange(), ToSM, |
| FromSM); |
| CompareSourceRanges(ToLHS->getSourceRange(), FromLHS->getSourceRange(), ToSM, |
| FromSM); |
| CompareSourceRanges(ToRHS->getSourceRange(), FromRHS->getSourceRange(), ToSM, |
| FromSM); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, ImportNestedMacro) { |
| Decl *FromTU = getTuDecl( |
| R"( |
| #define FUNC_INT void declToImport |
| #define FUNC FUNC_INT |
| FUNC(int a); |
| )", |
| Lang_CXX03); |
| auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, functionDecl()); |
| auto ToD = Import(FromD, Lang_CXX03); |
| |
| SourceManager &ToSM = ToAST->getASTContext().getSourceManager(); |
| SourceManager &FromSM = FromD->getASTContext().getSourceManager(); |
| CompareSourceRanges(ToD->getSourceRange(), FromD->getSourceRange(), ToSM, |
| FromSM); |
| } |
| |
| TEST_P( |
| ASTImporterOptionSpecificTestBase, |
| ImportDefinitionOfClassTemplateSpecIfThereIsAnExistingFwdDeclAndDefinition) { |
| Decl *ToTU = getToTuDecl( |
| R"( |
| template <typename T> |
| struct B; |
| |
| template <> |
| struct B<int> {}; |
| |
| template <> |
| struct B<int>; |
| )", |
| Lang_CXX03); |
| // We should have only one definition. |
| ASSERT_EQ(1u, DeclCounterWithPredicate<ClassTemplateSpecializationDecl>( |
| [](const ClassTemplateSpecializationDecl *T) { |
| return T->isThisDeclarationADefinition(); |
| }) |
| .match(ToTU, classTemplateSpecializationDecl())); |
| |
| Decl *FromTU = getTuDecl( |
| R"( |
| template <typename T> |
| struct B; |
| |
| template <> |
| struct B<int> {}; |
| )", |
| Lang_CXX03, "input1.cc"); |
| auto *FromD = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( |
| FromTU, classTemplateSpecializationDecl(hasName("B"))); |
| |
| Import(FromD, Lang_CXX03); |
| |
| // We should have only one definition. |
| EXPECT_EQ(1u, DeclCounterWithPredicate<ClassTemplateSpecializationDecl>( |
| [](const ClassTemplateSpecializationDecl *T) { |
| return T->isThisDeclarationADefinition(); |
| }) |
| .match(ToTU, classTemplateSpecializationDecl())); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, ObjectsWithUnnamedStructType) { |
| Decl *FromTU = getTuDecl( |
| R"( |
| struct { int a; int b; } object0 = { 2, 3 }; |
| struct { int x; int y; int z; } object1; |
| )", |
| Lang_CXX03, "input0.cc"); |
| |
| auto *Obj0 = |
| FirstDeclMatcher<VarDecl>().match(FromTU, varDecl(hasName("object0"))); |
| auto *From0 = getRecordDecl(Obj0); |
| auto *Obj1 = |
| FirstDeclMatcher<VarDecl>().match(FromTU, varDecl(hasName("object1"))); |
| auto *From1 = getRecordDecl(Obj1); |
| |
| auto *To0 = Import(From0, Lang_CXX03); |
| auto *To1 = Import(From1, Lang_CXX03); |
| |
| EXPECT_TRUE(To0); |
| EXPECT_TRUE(To1); |
| EXPECT_NE(To0, To1); |
| EXPECT_NE(To0->getCanonicalDecl(), To1->getCanonicalDecl()); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, AnonymousRecords) { |
| auto *Code = |
| R"( |
| struct X { |
| struct { int a; }; |
| struct { int b; }; |
| }; |
| )"; |
| Decl *FromTU0 = getTuDecl(Code, Lang_C99, "input0.c"); |
| |
| Decl *FromTU1 = getTuDecl(Code, Lang_C99, "input1.c"); |
| |
| auto *X0 = |
| FirstDeclMatcher<RecordDecl>().match(FromTU0, recordDecl(hasName("X"))); |
| auto *X1 = |
| FirstDeclMatcher<RecordDecl>().match(FromTU1, recordDecl(hasName("X"))); |
| Import(X0, Lang_C99); |
| Import(X1, Lang_C99); |
| |
| auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); |
| // We expect no (ODR) warning during the import. |
| EXPECT_EQ(0u, ToTU->getASTContext().getDiagnostics().getNumWarnings()); |
| EXPECT_EQ(1u, |
| DeclCounter<RecordDecl>().match(ToTU, recordDecl(hasName("X")))); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, AnonymousRecordsReversed) { |
| Decl *FromTU0 = getTuDecl( |
| R"( |
| struct X { |
| struct { int a; }; |
| struct { int b; }; |
| }; |
| )", |
| Lang_C99, "input0.c"); |
| |
| Decl *FromTU1 = getTuDecl( |
| R"( |
| struct X { // reversed order |
| struct { int b; }; |
| struct { int a; }; |
| }; |
| )", |
| Lang_C99, "input1.c"); |
| |
| auto *X0 = |
| FirstDeclMatcher<RecordDecl>().match(FromTU0, recordDecl(hasName("X"))); |
| auto *X1 = |
| FirstDeclMatcher<RecordDecl>().match(FromTU1, recordDecl(hasName("X"))); |
| Import(X0, Lang_C99); |
| Import(X1, Lang_C99); |
| |
| auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); |
| // We expect one (ODR) warning during the import. |
| EXPECT_EQ(1u, ToTU->getASTContext().getDiagnostics().getNumWarnings()); |
| EXPECT_EQ(1u, |
| DeclCounter<RecordDecl>().match(ToTU, recordDecl(hasName("X")))); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, ImportDoesUpdateUsedFlag) { |
| auto Pattern = varDecl(hasName("x")); |
| VarDecl *Imported1; |
| { |
| Decl *FromTU = getTuDecl("extern int x;", Lang_CXX03, "input0.cc"); |
| auto *FromD = FirstDeclMatcher<VarDecl>().match(FromTU, Pattern); |
| Imported1 = cast<VarDecl>(Import(FromD, Lang_CXX03)); |
| } |
| VarDecl *Imported2; |
| { |
| Decl *FromTU = getTuDecl("int x;", Lang_CXX03, "input1.cc"); |
| auto *FromD = FirstDeclMatcher<VarDecl>().match(FromTU, Pattern); |
| Imported2 = cast<VarDecl>(Import(FromD, Lang_CXX03)); |
| } |
| EXPECT_EQ(Imported1->getCanonicalDecl(), Imported2->getCanonicalDecl()); |
| EXPECT_FALSE(Imported2->isUsed(false)); |
| { |
| Decl *FromTU = getTuDecl("extern int x; int f() { return x; }", Lang_CXX03, |
| "input2.cc"); |
| auto *FromD = FirstDeclMatcher<FunctionDecl>().match( |
| FromTU, functionDecl(hasName("f"))); |
| Import(FromD, Lang_CXX03); |
| } |
| EXPECT_TRUE(Imported2->isUsed(false)); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, ImportDoesUpdateUsedFlag2) { |
| auto Pattern = varDecl(hasName("x")); |
| VarDecl *ExistingD; |
| { |
| Decl *ToTU = getToTuDecl("int x = 1;", Lang_CXX03); |
| ExistingD = FirstDeclMatcher<VarDecl>().match(ToTU, Pattern); |
| } |
| EXPECT_FALSE(ExistingD->isUsed(false)); |
| { |
| Decl *FromTU = |
| getTuDecl("int x = 1; int f() { return x; }", Lang_CXX03, "input1.cc"); |
| auto *FromD = FirstDeclMatcher<FunctionDecl>().match( |
| FromTU, functionDecl(hasName("f"))); |
| Import(FromD, Lang_CXX03); |
| } |
| EXPECT_TRUE(ExistingD->isUsed(false)); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, ImportDoesUpdateUsedFlag3) { |
| auto Pattern = varDecl(hasName("a")); |
| VarDecl *ExistingD; |
| { |
| Decl *ToTU = getToTuDecl( |
| R"( |
| struct A { |
| static const int a = 1; |
| }; |
| )", |
| Lang_CXX03); |
| ExistingD = FirstDeclMatcher<VarDecl>().match(ToTU, Pattern); |
| } |
| EXPECT_FALSE(ExistingD->isUsed(false)); |
| { |
| Decl *FromTU = getTuDecl( |
| R"( |
| struct A { |
| static const int a = 1; |
| }; |
| const int *f() { return &A::a; } // requires storage, |
| // thus used flag will be set |
| )", |
| Lang_CXX03, "input1.cc"); |
| auto *FromFunD = FirstDeclMatcher<FunctionDecl>().match( |
| FromTU, functionDecl(hasName("f"))); |
| auto *FromD = FirstDeclMatcher<VarDecl>().match(FromTU, Pattern); |
| ASSERT_TRUE(FromD->isUsed(false)); |
| Import(FromFunD, Lang_CXX03); |
| } |
| EXPECT_TRUE(ExistingD->isUsed(false)); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, ReimportWithUsedFlag) { |
| auto Pattern = varDecl(hasName("x")); |
| |
| Decl *FromTU = getTuDecl("int x;", Lang_CXX03, "input0.cc"); |
| auto *FromD = FirstDeclMatcher<VarDecl>().match(FromTU, Pattern); |
| |
| auto *Imported1 = cast<VarDecl>(Import(FromD, Lang_CXX03)); |
| |
| ASSERT_FALSE(Imported1->isUsed(false)); |
| |
| FromD->setIsUsed(); |
| auto *Imported2 = cast<VarDecl>(Import(FromD, Lang_CXX03)); |
| |
| EXPECT_EQ(Imported1, Imported2); |
| EXPECT_TRUE(Imported2->isUsed(false)); |
| } |
| |
| struct ImportFunctions : ASTImporterOptionSpecificTestBase {}; |
| |
| TEST_P(ImportFunctions, ImportPrototypeOfRecursiveFunction) { |
| Decl *FromTU = getTuDecl("void f(); void f() { f(); }", Lang_CXX03); |
| auto Pattern = functionDecl(hasName("f")); |
| auto *From = |
| FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern); // Proto |
| |
| Decl *ImportedD = Import(From, Lang_CXX03); |
| Decl *ToTU = ImportedD->getTranslationUnitDecl(); |
| |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u); |
| auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern); |
| auto *To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern); |
| EXPECT_TRUE(ImportedD == To0); |
| EXPECT_FALSE(To0->doesThisDeclarationHaveABody()); |
| EXPECT_TRUE(To1->doesThisDeclarationHaveABody()); |
| EXPECT_EQ(To1->getPreviousDecl(), To0); |
| } |
| |
| TEST_P(ImportFunctions, ImportDefinitionOfRecursiveFunction) { |
| Decl *FromTU = getTuDecl("void f(); void f() { f(); }", Lang_CXX03); |
| auto Pattern = functionDecl(hasName("f")); |
| auto *From = |
| LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern); // Def |
| |
| Decl *ImportedD = Import(From, Lang_CXX03); |
| Decl *ToTU = ImportedD->getTranslationUnitDecl(); |
| |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u); |
| auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern); |
| auto *To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern); |
| EXPECT_TRUE(ImportedD == To1); |
| EXPECT_FALSE(To0->doesThisDeclarationHaveABody()); |
| EXPECT_TRUE(To1->doesThisDeclarationHaveABody()); |
| EXPECT_EQ(To1->getPreviousDecl(), To0); |
| } |
| |
| TEST_P(ImportFunctions, OverriddenMethodsShouldBeImported) { |
| auto Code = |
| R"( |
| struct B { virtual void f(); }; |
| void B::f() {} |
| struct D : B { void f(); }; |
| )"; |
| auto Pattern = |
| cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D")))); |
| Decl *FromTU = getTuDecl(Code, Lang_CXX03); |
| CXXMethodDecl *Proto = |
| FirstDeclMatcher<CXXMethodDecl>().match(FromTU, Pattern); |
| |
| ASSERT_EQ(Proto->size_overridden_methods(), 1u); |
| CXXMethodDecl *To = cast<CXXMethodDecl>(Import(Proto, Lang_CXX03)); |
| EXPECT_EQ(To->size_overridden_methods(), 1u); |
| } |
| |
| TEST_P(ImportFunctions, VirtualFlagShouldBePreservedWhenImportingPrototype) { |
| auto Code = |
| R"( |
| struct B { virtual void f(); }; |
| void B::f() {} |
| )"; |
| auto Pattern = |
| cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B")))); |
| Decl *FromTU = getTuDecl(Code, Lang_CXX03); |
| CXXMethodDecl *Proto = |
| FirstDeclMatcher<CXXMethodDecl>().match(FromTU, Pattern); |
| CXXMethodDecl *Def = LastDeclMatcher<CXXMethodDecl>().match(FromTU, Pattern); |
| |
| ASSERT_TRUE(Proto->isVirtual()); |
| ASSERT_TRUE(Def->isVirtual()); |
| CXXMethodDecl *To = cast<CXXMethodDecl>(Import(Proto, Lang_CXX03)); |
| EXPECT_TRUE(To->isVirtual()); |
| } |
| |
| TEST_P(ImportFunctions, |
| ImportDefinitionIfThereIsAnExistingDefinitionAndFwdDecl) { |
| Decl *ToTU = getToTuDecl( |
| R"( |
| void f() {} |
| void f(); |
| )", |
| Lang_CXX03); |
| ASSERT_EQ(1u, |
| DeclCounterWithPredicate<FunctionDecl>([](const FunctionDecl *FD) { |
| return FD->doesThisDeclarationHaveABody(); |
| }).match(ToTU, functionDecl())); |
| |
| Decl *FromTU = getTuDecl("void f() {}", Lang_CXX03, "input0.cc"); |
| auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, functionDecl()); |
| |
| Import(FromD, Lang_CXX03); |
| |
| EXPECT_EQ(1u, |
| DeclCounterWithPredicate<FunctionDecl>([](const FunctionDecl *FD) { |
| return FD->doesThisDeclarationHaveABody(); |
| }).match(ToTU, functionDecl())); |
| } |
| |
| TEST_P(ImportFunctions, ImportOverriddenMethodTwice) { |
| auto Code = |
| R"( |
| struct B { virtual void f(); }; |
| struct D:B { void f(); }; |
| )"; |
| auto BFP = |
| cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B")))); |
| auto DFP = |
| cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D")))); |
| |
| Decl *FromTU0 = getTuDecl(Code, Lang_CXX03); |
| auto *DF = FirstDeclMatcher<CXXMethodDecl>().match(FromTU0, DFP); |
| Import(DF, Lang_CXX03); |
| |
| Decl *FromTU1 = getTuDecl(Code, Lang_CXX03, "input1.cc"); |
| auto *BF = FirstDeclMatcher<CXXMethodDecl>().match(FromTU1, BFP); |
| Import(BF, Lang_CXX03); |
| |
| auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); |
| |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u); |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFP), 1u); |
| } |
| |
| TEST_P(ImportFunctions, ImportOverriddenMethodTwiceDefinitionFirst) { |
| auto CodeWithoutDef = |
| R"( |
| struct B { virtual void f(); }; |
| struct D:B { void f(); }; |
| )"; |
| auto CodeWithDef = |
| R"( |
| struct B { virtual void f(){}; }; |
| struct D:B { void f(){}; }; |
| )"; |
| auto BFP = |
| cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B")))); |
| auto DFP = |
| cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D")))); |
| auto BFDefP = cxxMethodDecl( |
| hasName("f"), hasParent(cxxRecordDecl(hasName("B"))), isDefinition()); |
| auto DFDefP = cxxMethodDecl( |
| hasName("f"), hasParent(cxxRecordDecl(hasName("D"))), isDefinition()); |
| auto FDefAllP = cxxMethodDecl(hasName("f"), isDefinition()); |
| |
| { |
| Decl *FromTU = getTuDecl(CodeWithDef, Lang_CXX03, "input0.cc"); |
| auto *FromD = FirstDeclMatcher<CXXMethodDecl>().match(FromTU, DFP); |
| Import(FromD, Lang_CXX03); |
| } |
| { |
| Decl *FromTU = getTuDecl(CodeWithoutDef, Lang_CXX03, "input1.cc"); |
| auto *FromB = FirstDeclMatcher<CXXMethodDecl>().match(FromTU, BFP); |
| Import(FromB, Lang_CXX03); |
| } |
| |
| auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); |
| |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u); |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFP), 1u); |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFDefP), 1u); |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFDefP), 1u); |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, FDefAllP), 2u); |
| } |
| |
| TEST_P(ImportFunctions, ImportOverriddenMethodTwiceOutOfClassDef) { |
| auto Code = |
| R"( |
| struct B { virtual void f(); }; |
| struct D:B { void f(); }; |
| void B::f(){}; |
| )"; |
| |
| auto BFP = |
| cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B")))); |
| auto BFDefP = cxxMethodDecl( |
| hasName("f"), hasParent(cxxRecordDecl(hasName("B"))), isDefinition()); |
| auto DFP = cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D"))), |
| unless(isDefinition())); |
| |
| Decl *FromTU0 = getTuDecl(Code, Lang_CXX03); |
| auto *D = FirstDeclMatcher<CXXMethodDecl>().match(FromTU0, DFP); |
| Import(D, Lang_CXX03); |
| |
| Decl *FromTU1 = getTuDecl(Code, Lang_CXX03, "input1.cc"); |
| auto *B = FirstDeclMatcher<CXXMethodDecl>().match(FromTU1, BFP); |
| Import(B, Lang_CXX03); |
| |
| auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); |
| |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u); |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFDefP), 0u); |
| |
| auto *ToB = FirstDeclMatcher<CXXRecordDecl>().match( |
| ToTU, cxxRecordDecl(hasName("B"))); |
| auto *ToBFInClass = FirstDeclMatcher<CXXMethodDecl>().match(ToTU, BFP); |
| auto *ToBFOutOfClass = FirstDeclMatcher<CXXMethodDecl>().match( |
| ToTU, cxxMethodDecl(hasName("f"), isDefinition())); |
| |
| // The definition should be out-of-class. |
| EXPECT_NE(ToBFInClass, ToBFOutOfClass); |
| EXPECT_NE(ToBFInClass->getLexicalDeclContext(), |
| ToBFOutOfClass->getLexicalDeclContext()); |
| EXPECT_EQ(ToBFOutOfClass->getDeclContext(), ToB); |
| EXPECT_EQ(ToBFOutOfClass->getLexicalDeclContext(), ToTU); |
| |
| // Check that the redecl chain is intact. |
| EXPECT_EQ(ToBFOutOfClass->getPreviousDecl(), ToBFInClass); |
| } |
| |
| TEST_P(ImportFunctions, |
| ImportOverriddenMethodTwiceOutOfClassDefInSeparateCode) { |
| auto CodeTU0 = |
| R"( |
| struct B { virtual void f(); }; |
| struct D:B { void f(); }; |
| )"; |
| auto CodeTU1 = |
| R"( |
| struct B { virtual void f(); }; |
| struct D:B { void f(); }; |
| void B::f(){} |
| void D::f(){} |
| void foo(B &b, D &d) { b.f(); d.f(); } |
| )"; |
| |
| auto BFP = |
| cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B")))); |
| auto BFDefP = cxxMethodDecl( |
| hasName("f"), hasParent(cxxRecordDecl(hasName("B"))), isDefinition()); |
| auto DFP = |
| cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D")))); |
| auto DFDefP = cxxMethodDecl( |
| hasName("f"), hasParent(cxxRecordDecl(hasName("D"))), isDefinition()); |
| auto FooDef = functionDecl(hasName("foo")); |
| |
| { |
| Decl *FromTU0 = getTuDecl(CodeTU0, Lang_CXX03, "input0.cc"); |
| auto *D = FirstDeclMatcher<CXXMethodDecl>().match(FromTU0, DFP); |
| Import(D, Lang_CXX03); |
| } |
| |
| { |
| Decl *FromTU1 = getTuDecl(CodeTU1, Lang_CXX03, "input1.cc"); |
| auto *Foo = FirstDeclMatcher<FunctionDecl>().match(FromTU1, FooDef); |
| Import(Foo, Lang_CXX03); |
| } |
| |
| auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); |
| |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u); |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFP), 1u); |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFDefP), 0u); |
| EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFDefP), 0u); |
| |
| auto *ToB = FirstDeclMatcher<CXXRecordDecl>().match( |
| ToTU, cxxRecordDecl(hasName("B"))); |
| auto *ToD = FirstDeclMatcher<CXXRecordDecl>().match( |
| ToTU, cxxRecordDecl(hasName("D"))); |
| auto *ToBFInClass = FirstDeclMatcher<CXXMethodDecl>().match(ToTU, BFP); |
| auto *ToBFOutOfClass = FirstDeclMatcher<CXXMethodDecl>().match( |
| ToTU, cxxMethodDecl(hasName("f"), isDefinition())); |
| auto *ToDFInClass = FirstDeclMatcher<CXXMethodDecl>().match(ToTU, DFP); |
| auto *ToDFOutOfClass = LastDeclMatcher<CXXMethodDecl>().match( |
| ToTU, cxxMethodDecl(hasName("f"), isDefinition())); |
| |
| // The definition should be out-of-class. |
| EXPECT_NE(ToBFInClass, ToBFOutOfClass); |
| EXPECT_NE(ToBFInClass->getLexicalDeclContext(), |
| ToBFOutOfClass->getLexicalDeclContext()); |
| EXPECT_EQ(ToBFOutOfClass->getDeclContext(), ToB); |
| EXPECT_EQ(ToBFOutOfClass->getLexicalDeclContext(), ToTU); |
| |
| EXPECT_NE(ToDFInClass, ToDFOutOfClass); |
| EXPECT_NE(ToDFInClass->getLexicalDeclContext(), |
| ToDFOutOfClass->getLexicalDeclContext()); |
| EXPECT_EQ(ToDFOutOfClass->getDeclContext(), ToD); |
| EXPECT_EQ(ToDFOutOfClass->getLexicalDeclContext(), ToTU); |
| |
| // Check that the redecl chain is intact. |
| EXPECT_EQ(ToBFOutOfClass->getPreviousDecl(), ToBFInClass); |
| EXPECT_EQ(ToDFOutOfClass->getPreviousDecl(), ToDFInClass); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, |
| ImportVirtualOverriddenMethodOnALoop) { |
| // B::f() calls => f1() ==> C ==> C::f() |
| // \ |
| // \---- A::f() |
| // |
| // C::f()'s ImportOverriddenMethods() asserts B::isVirtual(), so B::f()'s |
| // ImportOverriddenMethods() should be completed before B::f()'s body |
| const char *Code = |
| R"( |
| void f1(); |
| class A { |
| virtual void f(){} |
| }; |
| class B: public A { |
| void f() override { |
| f1(); |
| } |
| }; |
| class C: public B { |
| void f() override {} |
| }; |
| void f1() { C c; } |
| )"; |
| Decl *FromTU = getTuDecl(Code, Lang_CXX11); |
| |
| auto *FromF = FirstDeclMatcher<CXXMethodDecl>().match( |
| FromTU, cxxMethodDecl(hasName("B::f"))); |
| |
| auto *ToBF = Import(FromF, Lang_CXX11); |
| EXPECT_TRUE(ToBF->isVirtual()); |
| |
| auto *ToCF = FirstDeclMatcher<CXXMethodDecl>().match( |
| ToBF->getTranslationUnitDecl(), cxxMethodDecl(hasName("C::f"))); |
| EXPECT_TRUE(ToCF->isVirtual()); |
| } |
| |
| TEST_P(ASTImporterOptionSpecificTestBase, ImportVariableChainInC) { |
| std::string Code = "static int v; static int v = 0;"; |
| auto Pattern = varDecl(hasName("v")); |
| |
| TranslationUnitDecl *FromTu = getTuDecl(Code, Lang_C99, "input0.c"); |
| |
| auto *From0 = FirstDeclMatcher<VarDecl>().match(FromTu, Pattern); |
| auto *From1 = LastDeclMatcher<VarDecl>().match(FromTu, Pattern); |
| |
| auto *To0 = Import(From0, Lang_C99); |
| auto *To1 = Import(From1, Lang_C99); |
| |
| EXPECT_TRUE(To0); |
| ASSERT_TRUE(To1); |
| EXPECT_NE(To0, To1); |
| EXPECT_EQ(To1->getPreviousDecl(), To0); |
| } |
| |
| TEST_P(ImportFunctions, ImportFromDifferentScopedAnonNamespace) { |
| TranslationUnitDecl *FromTu = |
| getTuDecl("namespace NS0 { namespace { void f(); } }" |
| "namespace NS1 { namespace { void f(); } }", |
| Lang_CXX03, "input0.cc"); |
| auto Pattern = functionDecl(hasName("f")); |
| |
| auto *FromF0 = FirstDeclMatcher<FunctionDecl>().match(FromTu, Pattern); |
| auto *FromF1 = LastDeclMatcher<FunctionDecl>().match(FromTu, Pattern); |
| |
| auto *ToF0 = Import(FromF0, Lang_CXX03); |
| auto *ToF1 = Import(FromF1, Lang_CXX03); |
| |
| EXPECT_TRUE(ToF0); |
| ASSERT_TRUE(ToF1); |
| EXPECT_NE(ToF0, ToF1); |
| EXPECT_FALSE(ToF1->getPreviousDecl()); |
| } |
| |
| TEST_P(ImportFunctions, ImportFunctionFromUnnamedNamespace) { |
| { |
| Decl *FromTU = getTuDecl("namespace { void f() {} } void g0() { f(); }", |
| Lang_CXX03, "input0.cc"); |
| auto *FromD = FirstDeclMatcher<FunctionDecl>().match( |
| FromTU, functionDecl(hasName("g0"))); |
| |
| Import(FromD, Lang_CXX03); |
| } |
| { |
| Decl *FromTU = |
| getTuDecl("namespace { void f() { int a; } } void g1() { f(); }", |
| Lang_CXX03, "input1.cc"); |
| auto *FromD = FirstDeclMatcher<FunctionDecl>().match( |
| FromTU, functionDecl(hasName("g1"))); |
| Import(FromD, Lang_CXX03); |
| } |
| |
| Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); |
| ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, functionDecl(hasName("f"))), |
| 2u); |
| } |
| |
| TEST_P(ImportFunctions, ImportImplicitFunctionsInLambda) { |
| Decl *FromTU = getTuDecl( |
| R"( |
| void foo() { |
| (void)[]() { ; }; |
| } |
| )", |
| Lang_CXX11); |
| auto *FromD = FirstDeclMatcher<FunctionDecl>().match( |
| FromTU, functionDecl(hasName("foo"))); |
| auto *ToD = Import(FromD, Lang_CXX03); |
| EXPECT_TRUE(ToD); |
| CXXRecordDecl *LambdaRec = |
| cast<LambdaExpr>(cast<CStyleCastExpr>( |
| *cast<CompoundStmt>(ToD->getBody())->body_begin()) |
| ->getSubExpr()) |
| ->getLambdaClass(); |
| EXPECT_TRUE(LambdaRec->getDestructor()); |
| } |
| |
| TEST_P(ImportFunctions, |
| CallExprOfMemberFunctionTemplateWithExplicitTemplateArgs) { |
| Decl *FromTU = getTuDecl( |
| R"( |
| struct X { |
| template <typename T> |
| void foo(){} |
| }; |
| void f() { |
| X x; |
| x.foo<int>(); |
| } |
| )", |
| Lang_CXX03); |
| auto *FromD = FirstDeclMatcher<FunctionDecl>().match( |
| FromTU, functionDecl(hasName("f"))); |
| auto *ToD = Import(FromD, Lang_CXX03); |
| EXPECT_TRUE(ToD); |
| EXPECT_TRUE(MatchVerifier<FunctionDecl>().match( |
| ToD, functionDecl(hasName("f"), hasDescendant(declRefExpr())))); |
| } |
| |
| TEST_P(ImportFunctions, |
| DependentCallExprOfMemberFunctionTemplateWithExplicitTemplateArgs) { |
| Decl *FromTU = getTuDecl( |
| R"( |
| struct X { |
| template <typename T> |
| void foo(){} |
| }; |
| template <typename T> |
| void f() { |
| X x; |
| x.foo<T>(); |
| } |
| void g() { |
| f<int>(); |
| } |
| )", |
| Lang_CXX03); |
| auto *FromD = FirstDeclMatcher<FunctionDecl>().match( |
| FromTU, functionDecl(hasName("g"))); |
| auto *ToD = Import(FromD, Lang_CXX03); |
| EXPECT_TRUE(ToD); |
| Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); |
| EXPECT_TRUE(MatchVerifier<TranslationUnitDecl>().match( |
| ToTU, translationUnitDecl(hasDescendant( |
| functionDecl(hasName("f"), hasDescendant(declRefExpr())))))); |
| } |
| |
| struct ImportFunctionTemplates : ASTImporterOptionSpecificTestBase {}; |
| |
| TEST_P(ImportFunctionTemplates, ImportFunctionTemplateInRecordDeclTwice) { |
| auto Code = |
| R"( |
| class X { |
| template <class T> |
| void f(T t); |
| }; |
| )"; |
| Decl *FromTU1 = getTuDecl(Code, Lang_CXX03, "input1.cc"); |
| auto *FromD1 = FirstDeclMatcher<FunctionTemplateDecl>().match( |
| FromTU1, functionTemplateDecl(hasName("f"))); |
| auto *ToD1 = Import(FromD1, Lang_CXX03); |
| Decl *FromTU2 = getTuDecl(Code, Lang_CXX03, "input2.cc"); |
| auto *FromD2 = FirstDeclMatcher<FunctionTemplateDecl>().match( |
| FromTU2, functionTemplateDecl(hasName("f"))); |
| auto *ToD2 = Import(FromD2, Lang_CXX03); |
| EXPECT_EQ(ToD1, ToD2); |
| } |
| |
| TEST_P(ImportFunctionTemplates, |
| ImportFunctionTemplateWithDefInRecordDeclTwice) { |
| auto Code = |
| R"( |
| class X { |
| template <class T> |
| void f(T t); |
| }; |
| template <class T> |
| void X::f(T t) {}; |
| )"; |
| Decl *FromTU1 = getTuDecl(Code, Lang_CXX03, "input1.cc"); |
| auto *FromD1 = FirstDeclMatcher<FunctionTemplateDecl>().match( |
| FromTU1, functionTemplateDecl(hasName("f"))); |
| auto *ToD1 = Import(FromD1, Lang_CXX03); |
| Decl *FromTU2 = getTuDecl(Code, Lang_CXX03, "input2.cc"); |
| auto *FromD2 = FirstDeclMatcher<FunctionTemplateDecl>().match( |
| FromTU2, functionTemplateDecl(hasName("f"))); |
| auto *ToD2 = Import(FromD2, Lang_CXX03); |
| EXPECT_EQ(ToD1, ToD2); |
| } |
| |
| TEST_P(ImportFunctionTemplates, |
| ImportFunctionWhenThereIsAFunTemplateWithSameName) { |
| getToTuDecl( |
| R"( |
| template <typename T> |
| void foo(T) {} |
| void foo(); |
| )", |
| Lang_CXX03); |
| Decl *FromTU = getTuDecl("void foo();", Lang_CXX03); |
| auto *FromD = FirstDeclMatcher< |