brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.6 KiB · e4e5a07 Raw
238 lines · cpp
1//===- unittest/AST/ASTImporterFixtures.cpp - AST unit test support -------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9/// \file10/// Implementation of fixture classes for testing the ASTImporter.11//12//===----------------------------------------------------------------------===//13 14#include "ASTImporterFixtures.h"15 16#include "clang/AST/ASTImporter.h"17#include "clang/AST/ASTImporterSharedState.h"18#include "clang/Frontend/ASTUnit.h"19#include "clang/Tooling/Tooling.h"20 21namespace clang {22namespace ast_matchers {23 24void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,25                               std::unique_ptr<llvm::MemoryBuffer> &&Buffer) {26  assert(ToAST);27  ASTContext &ToCtx = ToAST->getASTContext();28  auto *OFS = static_cast<llvm::vfs::OverlayFileSystem *>(29      &ToCtx.getSourceManager().getFileManager().getVirtualFileSystem());30  auto *MFS = static_cast<llvm::vfs::InMemoryFileSystem *>(31      OFS->overlays_begin()->get());32  MFS->addFile(FileName, 0, std::move(Buffer));33}34 35void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,36                               StringRef Code) {37  return createVirtualFileIfNeeded(ToAST, FileName,38                                   llvm::MemoryBuffer::getMemBuffer(Code));39}40 41ASTImporterTestBase::TU::TU(StringRef Code, StringRef FileName,42                            std::vector<std::string> Args,43                            ImporterConstructor C,44                            ASTImporter::ODRHandlingType ODRHandling)45    : Code(std::string(Code)), FileName(std::string(FileName)),46      Unit(tooling::buildASTFromCodeWithArgs(this->Code, Args, this->FileName)),47      TUDecl(Unit->getASTContext().getTranslationUnitDecl()), Creator(C),48      ODRHandling(ODRHandling) {49  Unit->enableSourceFileDiagnostics();50 51  // If the test doesn't need a specific ASTImporter, we just create a52  // normal ASTImporter with it.53  if (!Creator)54    Creator = [](ASTContext &ToContext, FileManager &ToFileManager,55                 ASTContext &FromContext, FileManager &FromFileManager,56                 bool MinimalImport,57                 const std::shared_ptr<ASTImporterSharedState> &SharedState) {58      return new ASTImporter(ToContext, ToFileManager, FromContext,59                             FromFileManager, MinimalImport, SharedState);60    };61}62 63ASTImporterTestBase::TU::~TU() {}64 65void ASTImporterTestBase::TU::lazyInitImporter(66    const std::shared_ptr<ASTImporterSharedState> &SharedState,67    ASTUnit *ToAST) {68  assert(ToAST);69  if (!Importer) {70    Importer.reset(Creator(ToAST->getASTContext(), ToAST->getFileManager(),71                           Unit->getASTContext(), Unit->getFileManager(), false,72                           SharedState));73    Importer->setODRHandling(ODRHandling);74  }75  assert(&ToAST->getASTContext() == &Importer->getToContext());76  createVirtualFileIfNeeded(ToAST, FileName, Code);77}78 79Decl *ASTImporterTestBase::TU::import(80    const std::shared_ptr<ASTImporterSharedState> &SharedState, ASTUnit *ToAST,81    Decl *FromDecl) {82  lazyInitImporter(SharedState, ToAST);83  if (auto ImportedOrErr = Importer->Import(FromDecl))84    return *ImportedOrErr;85  else {86    llvm::consumeError(ImportedOrErr.takeError());87    return nullptr;88  }89}90 91llvm::Expected<Decl *> ASTImporterTestBase::TU::importOrError(92    const std::shared_ptr<ASTImporterSharedState> &SharedState, ASTUnit *ToAST,93    Decl *FromDecl) {94  lazyInitImporter(SharedState, ToAST);95  return Importer->Import(FromDecl);96}97 98QualType ASTImporterTestBase::TU::import(99    const std::shared_ptr<ASTImporterSharedState> &SharedState, ASTUnit *ToAST,100    QualType FromType) {101  lazyInitImporter(SharedState, ToAST);102  if (auto ImportedOrErr = Importer->Import(FromType))103    return *ImportedOrErr;104  else {105    llvm::consumeError(ImportedOrErr.takeError());106    return QualType{};107  }108}109 110void ASTImporterTestBase::lazyInitSharedState(TranslationUnitDecl *ToTU) {111  assert(ToTU);112  if (!SharedStatePtr)113    SharedStatePtr = std::make_shared<ASTImporterSharedState>(*ToTU);114}115 116void ASTImporterTestBase::lazyInitToAST(TestLanguage ToLang,117                                        StringRef ToSrcCode,118                                        StringRef FileName) {119  if (ToAST)120    return;121  std::vector<std::string> ToArgs = getCommandLineArgsForLanguage(ToLang);122  // Source code must be a valid live buffer through the tests lifetime.123  ToCode = std::string(ToSrcCode);124  // Build the AST from an empty file.125  ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, FileName);126  ToAST->enableSourceFileDiagnostics();127  lazyInitSharedState(ToAST->getASTContext().getTranslationUnitDecl());128}129 130ASTImporterTestBase::TU *ASTImporterTestBase::findFromTU(Decl *From) {131  // Create a virtual file in the To Ctx which corresponds to the file from132  // which we want to import the `From` Decl. Without this source locations133  // will be invalid in the ToCtx.134  auto It = llvm::find_if(FromTUs, [From](const TU &E) {135    return E.TUDecl == From->getTranslationUnitDecl();136  });137  assert(It != FromTUs.end());138  return &*It;139}140 141std::tuple<Decl *, Decl *> ASTImporterTestBase::getImportedDecl(142    StringRef FromSrcCode, TestLanguage FromLang, StringRef ToSrcCode,143    TestLanguage ToLang, StringRef Identifier) {144  std::vector<std::string> FromArgs = getCommandLineArgsForLanguage(FromLang);145  std::vector<std::string> ToArgs = getCommandLineArgsForLanguage(ToLang);146 147  FromTUs.emplace_back(FromSrcCode, InputFileName, FromArgs, Creator,148                       ODRHandling);149  TU &FromTU = FromTUs.back();150 151  assert(!ToAST);152  lazyInitToAST(ToLang, ToSrcCode, OutputFileName);153 154  ASTContext &FromCtx = FromTU.Unit->getASTContext();155 156  IdentifierInfo *ImportedII = &FromCtx.Idents.get(Identifier);157  assert(ImportedII && "Declaration with the given identifier "158                       "should be specified in test!");159  DeclarationName ImportDeclName(ImportedII);160  SmallVector<NamedDecl *, 1> FoundDecls;161  FromCtx.getTranslationUnitDecl()->localUncachedLookup(ImportDeclName,162                                                        FoundDecls);163 164  assert(FoundDecls.size() == 1);165 166  Decl *Imported =167      FromTU.import(SharedStatePtr, ToAST.get(), FoundDecls.front());168 169  assert(Imported);170  return std::make_tuple(*FoundDecls.begin(), Imported);171}172 173TranslationUnitDecl *ASTImporterTestBase::getTuDecl(StringRef SrcCode,174                                                    TestLanguage Lang,175                                                    StringRef FileName) {176  assert(llvm::none_of(177      FromTUs, [FileName](const TU &E) { return E.FileName == FileName; }));178 179  std::vector<std::string> Args = getCommandLineArgsForLanguage(Lang);180  FromTUs.emplace_back(SrcCode, FileName, Args, Creator, ODRHandling);181  TU &Tu = FromTUs.back();182 183  return Tu.TUDecl;184}185 186TranslationUnitDecl *ASTImporterTestBase::getToTuDecl(StringRef ToSrcCode,187                                                      TestLanguage ToLang) {188  std::vector<std::string> ToArgs = getCommandLineArgsForLanguage(ToLang);189  assert(!ToAST);190  lazyInitToAST(ToLang, ToSrcCode, OutputFileName);191  return ToAST->getASTContext().getTranslationUnitDecl();192}193 194Decl *ASTImporterTestBase::Import(Decl *From, TestLanguage ToLang) {195  lazyInitToAST(ToLang, "", OutputFileName);196  TU *FromTU = findFromTU(From);197  assert(SharedStatePtr);198  Decl *To = FromTU->import(SharedStatePtr, ToAST.get(), From);199  return To;200}201 202llvm::Expected<Decl *> ASTImporterTestBase::importOrError(Decl *From,203                                                          TestLanguage ToLang) {204  lazyInitToAST(ToLang, "", OutputFileName);205  TU *FromTU = findFromTU(From);206  assert(SharedStatePtr);207  llvm::Expected<Decl *> To =208      FromTU->importOrError(SharedStatePtr, ToAST.get(), From);209  return To;210}211 212QualType ASTImporterTestBase::ImportType(QualType FromType, Decl *TUDecl,213                                         TestLanguage ToLang) {214  lazyInitToAST(ToLang, "", OutputFileName);215  TU *FromTU = findFromTU(TUDecl);216  assert(SharedStatePtr);217  return FromTU->import(SharedStatePtr, ToAST.get(), FromType);218}219 220ASTImporterTestBase::~ASTImporterTestBase() {221  if (!::testing::Test::HasFailure())222    return;223 224  for (auto &Tu : FromTUs) {225    assert(Tu.Unit);226    llvm::errs() << "FromAST:\n";227    Tu.Unit->getASTContext().getTranslationUnitDecl()->dump();228    llvm::errs() << "\n";229  }230  if (ToAST) {231    llvm::errs() << "ToAST:\n";232    ToAST->getASTContext().getTranslationUnitDecl()->dump();233  }234}235 236} // end namespace ast_matchers237} // end namespace clang238