123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- //===- unittest/AST/ASTImporterFixtures.cpp - 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
- /// Implementation of fixture classes for testing the ASTImporter.
- //
- //===----------------------------------------------------------------------===//
- #include "ASTImporterFixtures.h"
- #include "clang/AST/ASTImporter.h"
- #include "clang/AST/ASTImporterSharedState.h"
- #include "clang/Frontend/ASTUnit.h"
- #include "clang/Tooling/Tooling.h"
- namespace clang {
- namespace ast_matchers {
- void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
- std::unique_ptr<llvm::MemoryBuffer> &&Buffer) {
- assert(ToAST);
- ASTContext &ToCtx = ToAST->getASTContext();
- auto *OFS = static_cast<llvm::vfs::OverlayFileSystem *>(
- &ToCtx.getSourceManager().getFileManager().getVirtualFileSystem());
- auto *MFS = static_cast<llvm::vfs::InMemoryFileSystem *>(
- OFS->overlays_begin()->get());
- MFS->addFile(FileName, 0, std::move(Buffer));
- }
- void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
- StringRef Code) {
- return createVirtualFileIfNeeded(ToAST, FileName,
- llvm::MemoryBuffer::getMemBuffer(Code));
- }
- ASTImporterTestBase::TU::TU(StringRef Code, StringRef FileName, ArgVector Args,
- ImporterConstructor C,
- ASTImporter::ODRHandlingType ODRHandling)
- : Code(Code), FileName(FileName),
- Unit(tooling::buildASTFromCodeWithArgs(this->Code, Args, this->FileName)),
- TUDecl(Unit->getASTContext().getTranslationUnitDecl()), Creator(C),
- ODRHandling(ODRHandling) {
- Unit->enableSourceFileDiagnostics();
- // If the test doesn't need a specific ASTImporter, we just create a
- // normal ASTImporter with it.
- if (!Creator)
- Creator = [](ASTContext &ToContext, FileManager &ToFileManager,
- ASTContext &FromContext, FileManager &FromFileManager,
- bool MinimalImport,
- const std::shared_ptr<ASTImporterSharedState> &SharedState) {
- return new ASTImporter(ToContext, ToFileManager, FromContext,
- FromFileManager, MinimalImport, SharedState);
- };
- }
- ASTImporterTestBase::TU::~TU() {}
- void ASTImporterTestBase::TU::lazyInitImporter(
- const std::shared_ptr<ASTImporterSharedState> &SharedState,
- ASTUnit *ToAST) {
- assert(ToAST);
- if (!Importer) {
- Importer.reset(Creator(ToAST->getASTContext(), ToAST->getFileManager(),
- Unit->getASTContext(), Unit->getFileManager(), false,
- SharedState));
- Importer->setODRHandling(ODRHandling);
- }
- assert(&ToAST->getASTContext() == &Importer->getToContext());
- createVirtualFileIfNeeded(ToAST, FileName, Code);
- }
- Decl *ASTImporterTestBase::TU::import(
- const std::shared_ptr<ASTImporterSharedState> &SharedState, ASTUnit *ToAST,
- Decl *FromDecl) {
- lazyInitImporter(SharedState, ToAST);
- if (auto ImportedOrErr = Importer->Import(FromDecl))
- return *ImportedOrErr;
- else {
- llvm::consumeError(ImportedOrErr.takeError());
- return nullptr;
- }
- }
- llvm::Expected<Decl *> ASTImporterTestBase::TU::importOrError(
- const std::shared_ptr<ASTImporterSharedState> &SharedState, ASTUnit *ToAST,
- Decl *FromDecl) {
- lazyInitImporter(SharedState, ToAST);
- return Importer->Import(FromDecl);
- }
- QualType ASTImporterTestBase::TU::import(
- const std::shared_ptr<ASTImporterSharedState> &SharedState, ASTUnit *ToAST,
- QualType FromType) {
- lazyInitImporter(SharedState, ToAST);
- if (auto ImportedOrErr = Importer->Import(FromType))
- return *ImportedOrErr;
- else {
- llvm::consumeError(ImportedOrErr.takeError());
- return QualType{};
- }
- }
- void ASTImporterTestBase::lazyInitSharedState(TranslationUnitDecl *ToTU) {
- assert(ToTU);
- if (!SharedStatePtr)
- SharedStatePtr = std::make_shared<ASTImporterSharedState>(*ToTU);
- }
- void ASTImporterTestBase::lazyInitToAST(Language ToLang, StringRef ToSrcCode,
- StringRef FileName) {
- if (ToAST)
- return;
- ArgVector ToArgs = getArgVectorForLanguage(ToLang);
- // Source code must be a valid live buffer through the tests lifetime.
- ToCode = ToSrcCode;
- // Build the AST from an empty file.
- ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, FileName);
- ToAST->enableSourceFileDiagnostics();
- lazyInitSharedState(ToAST->getASTContext().getTranslationUnitDecl());
- }
- ASTImporterTestBase::TU *ASTImporterTestBase::findFromTU(Decl *From) {
- // Create a virtual file in the To Ctx which corresponds to the file from
- // which we want to import the `From` Decl. Without this source locations
- // will be invalid in the ToCtx.
- auto It = llvm::find_if(FromTUs, [From](const TU &E) {
- return E.TUDecl == From->getTranslationUnitDecl();
- });
- assert(It != FromTUs.end());
- return &*It;
- }
- std::tuple<Decl *, Decl *>
- ASTImporterTestBase::getImportedDecl(StringRef FromSrcCode, Language FromLang,
- StringRef ToSrcCode, Language ToLang,
- StringRef Identifier) {
- ArgVector FromArgs = getArgVectorForLanguage(FromLang),
- ToArgs = getArgVectorForLanguage(ToLang);
- FromTUs.emplace_back(FromSrcCode, InputFileName, FromArgs, Creator,
- ODRHandling);
- TU &FromTU = FromTUs.back();
- assert(!ToAST);
- lazyInitToAST(ToLang, ToSrcCode, OutputFileName);
- ASTContext &FromCtx = FromTU.Unit->getASTContext();
- IdentifierInfo *ImportedII = &FromCtx.Idents.get(Identifier);
- assert(ImportedII && "Declaration with the given identifier "
- "should be specified in test!");
- DeclarationName ImportDeclName(ImportedII);
- SmallVector<NamedDecl *, 1> FoundDecls;
- FromCtx.getTranslationUnitDecl()->localUncachedLookup(ImportDeclName,
- FoundDecls);
- assert(FoundDecls.size() == 1);
- Decl *Imported =
- FromTU.import(SharedStatePtr, ToAST.get(), FoundDecls.front());
- assert(Imported);
- return std::make_tuple(*FoundDecls.begin(), Imported);
- }
- TranslationUnitDecl *ASTImporterTestBase::getTuDecl(StringRef SrcCode,
- Language Lang,
- StringRef FileName) {
- assert(llvm::find_if(FromTUs, [FileName](const TU &E) {
- return E.FileName == FileName;
- }) == FromTUs.end());
- ArgVector Args = getArgVectorForLanguage(Lang);
- FromTUs.emplace_back(SrcCode, FileName, Args, Creator, ODRHandling);
- TU &Tu = FromTUs.back();
- return Tu.TUDecl;
- }
- TranslationUnitDecl *ASTImporterTestBase::getToTuDecl(StringRef ToSrcCode,
- Language ToLang) {
- ArgVector ToArgs = getArgVectorForLanguage(ToLang);
- assert(!ToAST);
- lazyInitToAST(ToLang, ToSrcCode, OutputFileName);
- return ToAST->getASTContext().getTranslationUnitDecl();
- }
- Decl *ASTImporterTestBase::Import(Decl *From, Language ToLang) {
- lazyInitToAST(ToLang, "", OutputFileName);
- TU *FromTU = findFromTU(From);
- assert(SharedStatePtr);
- Decl *To = FromTU->import(SharedStatePtr, ToAST.get(), From);
- return To;
- }
- llvm::Expected<Decl *> ASTImporterTestBase::importOrError(Decl *From,
- Language ToLang) {
- lazyInitToAST(ToLang, "", OutputFileName);
- TU *FromTU = findFromTU(From);
- assert(SharedStatePtr);
- llvm::Expected<Decl *> To =
- FromTU->importOrError(SharedStatePtr, ToAST.get(), From);
- return To;
- }
- QualType ASTImporterTestBase::ImportType(QualType FromType, Decl *TUDecl,
- Language ToLang) {
- lazyInitToAST(ToLang, "", OutputFileName);
- TU *FromTU = findFromTU(TUDecl);
- assert(SharedStatePtr);
- return FromTU->import(SharedStatePtr, ToAST.get(), FromType);
- }
- ASTImporterTestBase::~ASTImporterTestBase() {
- if (!::testing::Test::HasFailure())
- return;
- for (auto &Tu : FromTUs) {
- assert(Tu.Unit);
- llvm::errs() << "FromAST:\n";
- Tu.Unit->getASTContext().getTranslationUnitDecl()->dump();
- llvm::errs() << "\n";
- }
- if (ToAST) {
- llvm::errs() << "ToAST:\n";
- ToAST->getASTContext().getTranslationUnitDecl()->dump();
- }
- }
- } // end namespace ast_matchers
- } // end namespace clang
|