ASTImporterFixtures.cpp 8.4 KB

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