//===- unittest/AST/ASTImporterFixtures.h - AST unit test support ---------===// // // 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 // //===----------------------------------------------------------------------===// // /// \file /// Fixture classes for testing the ASTImporter. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_UNITTESTS_AST_IMPORTER_FIXTURES_H #define LLVM_CLANG_UNITTESTS_AST_IMPORTER_FIXTURES_H #include "gmock/gmock.h" #include "clang/AST/ASTImporter.h" #include "clang/Frontend/ASTUnit.h" #include "clang/AST/ASTImporterSharedState.h" #include "DeclMatcher.h" #include "Language.h" namespace clang { class ASTImporter; class ASTImporterSharedState; class ASTUnit; namespace ast_matchers { const StringRef DeclToImportID = "declToImport"; const StringRef DeclToVerifyID = "declToVerify"; // Creates a virtual file and assigns that to the context of given AST. If the // file already exists then the file will not be created again as a duplicate. void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName, std::unique_ptr &&Buffer); void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName, StringRef Code); // Common base for the different families of ASTImporter tests that are // parameterized on the compiler options which may result a different AST. E.g. // -fms-compatibility or -fdelayed-template-parsing. class CompilerOptionSpecificTest : public ::testing::Test { protected: // Return the extra arguments appended to runtime options at compilation. virtual ArgVector getExtraArgs() const { return ArgVector(); } // Returns the argument vector used for a specific language option, this set // can be tweaked by the test parameters. ArgVector getArgVectorForLanguage(Language Lang) const { ArgVector Args = getBasicRunOptionsForLanguage(Lang); ArgVector ExtraArgs = getExtraArgs(); for (const auto &Arg : ExtraArgs) { Args.push_back(Arg); } return Args; } }; const auto DefaultTestValuesForRunOptions = ::testing::Values( ArgVector(), ArgVector{"-fdelayed-template-parsing"}, ArgVector{"-fms-compatibility"}, ArgVector{"-fdelayed-template-parsing", "-fms-compatibility"}); // This class provides generic methods to write tests which can check internal // attributes of AST nodes like getPreviousDecl(), isVirtual(), etc. Also, // this fixture makes it possible to import from several "From" contexts. class ASTImporterTestBase : public CompilerOptionSpecificTest { const char *const InputFileName = "input.cc"; const char *const OutputFileName = "output.cc"; public: /// Allocates an ASTImporter (or one of its subclasses). typedef std::function &SharedState)> ImporterConstructor; // The lambda that constructs the ASTImporter we use in this test. ImporterConstructor Creator; private: // Buffer for the To context, must live in the test scope. std::string ToCode; // Represents a "From" translation unit and holds an importer object which we // use to import from this translation unit. struct TU { // Buffer for the context, must live in the test scope. std::string Code; std::string FileName; std::unique_ptr Unit; TranslationUnitDecl *TUDecl = nullptr; std::unique_ptr Importer; ImporterConstructor Creator; TU(StringRef Code, StringRef FileName, ArgVector Args, ImporterConstructor C = ImporterConstructor()); ~TU(); void lazyInitImporter(const std::shared_ptr &SharedState, ASTUnit *ToAST); Decl *import(const std::shared_ptr &SharedState, ASTUnit *ToAST, Decl *FromDecl); QualType import(const std::shared_ptr &SharedState, ASTUnit *ToAST, QualType FromType); }; // We may have several From contexts and related translation units. In each // AST, the buffers for the source are handled via references and are set // during the creation of the AST. These references must point to a valid // buffer until the AST is alive. Thus, we must use a list in order to avoid // moving of the stored objects because that would mean breaking the // references in the AST. By using a vector a move could happen when the // vector is expanding, with the list we won't have these issues. std::list FromTUs; // Initialize the shared state if not initialized already. void lazyInitSharedState(TranslationUnitDecl *ToTU); void lazyInitToAST(Language ToLang, StringRef ToSrcCode, StringRef FileName); protected: std::shared_ptr SharedStatePtr; public: // We may have several From context but only one To context. std::unique_ptr ToAST; // Returns with the TU associated with the given Decl. TU *findFromTU(Decl *From); // Creates an AST both for the From and To source code and imports the Decl // of the identifier into the To context. // Must not be called more than once within the same test. std::tuple getImportedDecl(StringRef FromSrcCode, Language FromLang, StringRef ToSrcCode, Language ToLang, StringRef Identifier = DeclToImportID); // Creates a TU decl for the given source code which can be used as a From // context. May be called several times in a given test (with different file // name). TranslationUnitDecl *getTuDecl(StringRef SrcCode, Language Lang, StringRef FileName = "input.cc"); // Creates the To context with the given source code and returns the TU decl. TranslationUnitDecl *getToTuDecl(StringRef ToSrcCode, Language ToLang); // Import the given Decl into the ToCtx. // May be called several times in a given test. // The different instances of the param From may have different ASTContext. Decl *Import(Decl *From, Language ToLang); template DeclT *Import(DeclT *From, Language Lang) { return cast_or_null(Import(cast(From), Lang)); } QualType ImportType(QualType FromType, Decl *TUDecl, Language ToLang); ~ASTImporterTestBase(); }; class ASTImporterOptionSpecificTestBase : public ASTImporterTestBase, public ::testing::WithParamInterface { protected: ArgVector getExtraArgs() const override { return GetParam(); } }; } // end namespace ast_matchers } // end namespace clang #endif