diff options
Diffstat (limited to 'clang/unittests/AST/ASTImporterTest.cpp')
-rw-r--r-- | clang/unittests/AST/ASTImporterTest.cpp | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 63bcc609f06..41a041f101e 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -4620,6 +4620,127 @@ TEST_P(ImportFriendFunctionTemplates, LookupShouldFindPreviousFriend) { EXPECT_EQ(Imported->getPreviousDecl(), Friend); } +struct ASTImporterWithFakeErrors : ASTImporter { + using ASTImporter::ASTImporter; + bool returnWithErrorInTest() override { return true; } +}; + +struct ErrorHandlingTest : ASTImporterOptionSpecificTestBase { + ErrorHandlingTest() { + Creator = [](ASTContext &ToContext, FileManager &ToFileManager, + ASTContext &FromContext, FileManager &FromFileManager, + bool MinimalImport, ASTImporterLookupTable *LookupTable) { + return new ASTImporterWithFakeErrors(ToContext, ToFileManager, + FromContext, FromFileManager, + MinimalImport, LookupTable); + }; + } + // In this test we purposely report an error (UnsupportedConstruct) when + // importing the below stmt. + static constexpr auto* ErroneousStmt = R"( asm(""); )"; +}; + +// Check a case when no new AST node is created in the AST before encountering +// the error. +TEST_P(ErrorHandlingTest, ErrorHappensBeforeCreatingANewNode) { + TranslationUnitDecl *ToTU = getToTuDecl( + R"( + template <typename T> + class X {}; + template <> + class X<int> { int a; }; + )", + Lang_CXX); + TranslationUnitDecl *FromTU = getTuDecl( + R"( + template <typename T> + class X {}; + template <> + class X<int> { double b; }; + )", + Lang_CXX); + auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match( + FromTU, classTemplateSpecializationDecl(hasName("X"))); + ClassTemplateSpecializationDecl *ImportedSpec = Import(FromSpec, Lang_CXX); + EXPECT_FALSE(ImportedSpec); + + // The original Decl is kept, no new decl is created. + EXPECT_EQ(DeclCounter<ClassTemplateSpecializationDecl>().match( + ToTU, classTemplateSpecializationDecl(hasName("X"))), + 1u); + + // But an error is set to the counterpart in the "from" context. + ASTImporter *Importer = findFromTU(FromSpec)->Importer.get(); + Optional<ImportError> OptErr = Importer->getImportDeclErrorIfAny(FromSpec); + ASSERT_TRUE(OptErr); + EXPECT_EQ(OptErr->Error, ImportError::NameConflict); +} + +// Check a case when a new AST node is created but not linked to the AST before +// encountering the error. +TEST_P(ErrorHandlingTest, + ErrorHappensAfterCreatingTheNodeButBeforeLinkingThatToTheAST) { + TranslationUnitDecl *FromTU = getTuDecl( + std::string("void foo() { ") + ErroneousStmt + " }", + Lang_CXX); + auto *FromFoo = FirstDeclMatcher<FunctionDecl>().match( + FromTU, functionDecl(hasName("foo"))); + + FunctionDecl *ImportedFoo = Import(FromFoo, Lang_CXX); + EXPECT_FALSE(ImportedFoo); + + TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); + // Created, but not linked. + EXPECT_EQ( + DeclCounter<FunctionDecl>().match(ToTU, functionDecl(hasName("foo"))), + 0u); + + ASTImporter *Importer = findFromTU(FromFoo)->Importer.get(); + Optional<ImportError> OptErr = Importer->getImportDeclErrorIfAny(FromFoo); + ASSERT_TRUE(OptErr); + EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct); +} + +// Check a case when a new AST node is created and linked to the AST before +// encountering the error. The error is set for the counterpart of the nodes in +// the "from" context. +TEST_P(ErrorHandlingTest, ErrorHappensAfterNodeIsCreatedAndLinked) { + TranslationUnitDecl *FromTU = getTuDecl( + std::string(R"( + void f(); + void f() { )") + ErroneousStmt + R"( } + )", + Lang_CXX); + auto *FromProto = FirstDeclMatcher<FunctionDecl>().match( + FromTU, functionDecl(hasName("f"))); + auto *FromDef = + LastDeclMatcher<FunctionDecl>().match(FromTU, functionDecl(hasName("f"))); + FunctionDecl *ImportedProto = Import(FromProto, Lang_CXX); + EXPECT_FALSE(ImportedProto); // Could not import. + // However, we created two nodes in the AST. 1) the fwd decl 2) the + // definition. The definition is not added to its DC, but the fwd decl is + // there. + TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); + EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, functionDecl(hasName("f"))), + 1u); + // Match the fwd decl. + auto *ToProto = + FirstDeclMatcher<FunctionDecl>().match(ToTU, functionDecl(hasName("f"))); + EXPECT_TRUE(ToProto); + // An error is set to the counterpart in the "from" context both for the fwd + // decl and the definition. + ASTImporter *Importer = findFromTU(FromProto)->Importer.get(); + Optional<ImportError> OptErr = Importer->getImportDeclErrorIfAny(FromProto); + ASSERT_TRUE(OptErr); + EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct); + OptErr = Importer->getImportDeclErrorIfAny(FromDef); + ASSERT_TRUE(OptErr); + EXPECT_EQ(OptErr->Error, ImportError::UnsupportedConstruct); +} + +INSTANTIATE_TEST_CASE_P(ParameterizedTests, ErrorHandlingTest, + DefaultTestValuesForRunOptions, ); + INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest, DefaultTestValuesForRunOptions, ); |