1 //===- unittest/AST/ASTImporterFixtures.cpp - AST unit test support -------===//
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
7 //===----------------------------------------------------------------------===//
10 /// Implementation of fixture classes for testing the ASTImporter.
12 //===----------------------------------------------------------------------===//
14 #include "ASTImporterFixtures.h"
16 #include "clang/AST/ASTImporter.h"
17 #include "clang/AST/ASTImporterSharedState.h"
18 #include "clang/Frontend/ASTUnit.h"
19 #include "clang/Tooling/Tooling.h"
22 namespace ast_matchers
{
24 void createVirtualFileIfNeeded(ASTUnit
*ToAST
, StringRef FileName
,
25 std::unique_ptr
<llvm::MemoryBuffer
> &&Buffer
) {
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
));
35 void createVirtualFileIfNeeded(ASTUnit
*ToAST
, StringRef FileName
,
37 return createVirtualFileIfNeeded(ToAST
, FileName
,
38 llvm::MemoryBuffer::getMemBuffer(Code
));
41 ASTImporterTestBase::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();
51 // If the test doesn't need a specific ASTImporter, we just create a
52 // normal ASTImporter with it.
54 Creator
= [](ASTContext
&ToContext
, FileManager
&ToFileManager
,
55 ASTContext
&FromContext
, FileManager
&FromFileManager
,
57 const std::shared_ptr
<ASTImporterSharedState
> &SharedState
) {
58 return new ASTImporter(ToContext
, ToFileManager
, FromContext
,
59 FromFileManager
, MinimalImport
, SharedState
);
63 ASTImporterTestBase::TU::~TU() {}
65 void ASTImporterTestBase::TU::lazyInitImporter(
66 const std::shared_ptr
<ASTImporterSharedState
> &SharedState
,
70 Importer
.reset(Creator(ToAST
->getASTContext(), ToAST
->getFileManager(),
71 Unit
->getASTContext(), Unit
->getFileManager(), false,
73 Importer
->setODRHandling(ODRHandling
);
75 assert(&ToAST
->getASTContext() == &Importer
->getToContext());
76 createVirtualFileIfNeeded(ToAST
, FileName
, Code
);
79 Decl
*ASTImporterTestBase::TU::import(
80 const std::shared_ptr
<ASTImporterSharedState
> &SharedState
, ASTUnit
*ToAST
,
82 lazyInitImporter(SharedState
, ToAST
);
83 if (auto ImportedOrErr
= Importer
->Import(FromDecl
))
84 return *ImportedOrErr
;
86 llvm::consumeError(ImportedOrErr
.takeError());
91 llvm::Expected
<Decl
*> ASTImporterTestBase::TU::importOrError(
92 const std::shared_ptr
<ASTImporterSharedState
> &SharedState
, ASTUnit
*ToAST
,
94 lazyInitImporter(SharedState
, ToAST
);
95 return Importer
->Import(FromDecl
);
98 QualType
ASTImporterTestBase::TU::import(
99 const std::shared_ptr
<ASTImporterSharedState
> &SharedState
, ASTUnit
*ToAST
,
101 lazyInitImporter(SharedState
, ToAST
);
102 if (auto ImportedOrErr
= Importer
->Import(FromType
))
103 return *ImportedOrErr
;
105 llvm::consumeError(ImportedOrErr
.takeError());
110 void ASTImporterTestBase::lazyInitSharedState(TranslationUnitDecl
*ToTU
) {
113 SharedStatePtr
= std::make_shared
<ASTImporterSharedState
>(*ToTU
);
116 void ASTImporterTestBase::lazyInitToAST(TestLanguage ToLang
,
118 StringRef FileName
) {
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());
130 ASTImporterTestBase::TU
*ASTImporterTestBase::findFromTU(Decl
*From
) {
131 // Create a virtual file in the To Ctx which corresponds to the file from
132 // which we want to import the `From` Decl. Without this source locations
133 // will be invalid in the ToCtx.
134 auto It
= llvm::find_if(FromTUs
, [From
](const TU
&E
) {
135 return E
.TUDecl
== From
->getTranslationUnitDecl();
137 assert(It
!= FromTUs
.end());
141 std::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
);
147 FromTUs
.emplace_back(FromSrcCode
, InputFileName
, FromArgs
, Creator
,
149 TU
&FromTU
= FromTUs
.back();
152 lazyInitToAST(ToLang
, ToSrcCode
, OutputFileName
);
154 ASTContext
&FromCtx
= FromTU
.Unit
->getASTContext();
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
,
164 assert(FoundDecls
.size() == 1);
167 FromTU
.import(SharedStatePtr
, ToAST
.get(), FoundDecls
.front());
170 return std::make_tuple(*FoundDecls
.begin(), Imported
);
173 TranslationUnitDecl
*ASTImporterTestBase::getTuDecl(StringRef SrcCode
,
175 StringRef FileName
) {
176 assert(llvm::find_if(FromTUs
, [FileName
](const TU
&E
) {
177 return E
.FileName
== FileName
;
178 }) == FromTUs
.end());
180 std::vector
<std::string
> Args
= getCommandLineArgsForLanguage(Lang
);
181 FromTUs
.emplace_back(SrcCode
, FileName
, Args
, Creator
, ODRHandling
);
182 TU
&Tu
= FromTUs
.back();
187 TranslationUnitDecl
*ASTImporterTestBase::getToTuDecl(StringRef ToSrcCode
,
188 TestLanguage ToLang
) {
189 std::vector
<std::string
> ToArgs
= getCommandLineArgsForLanguage(ToLang
);
191 lazyInitToAST(ToLang
, ToSrcCode
, OutputFileName
);
192 return ToAST
->getASTContext().getTranslationUnitDecl();
195 Decl
*ASTImporterTestBase::Import(Decl
*From
, TestLanguage ToLang
) {
196 lazyInitToAST(ToLang
, "", OutputFileName
);
197 TU
*FromTU
= findFromTU(From
);
198 assert(SharedStatePtr
);
199 Decl
*To
= FromTU
->import(SharedStatePtr
, ToAST
.get(), From
);
203 llvm::Expected
<Decl
*> ASTImporterTestBase::importOrError(Decl
*From
,
204 TestLanguage ToLang
) {
205 lazyInitToAST(ToLang
, "", OutputFileName
);
206 TU
*FromTU
= findFromTU(From
);
207 assert(SharedStatePtr
);
208 llvm::Expected
<Decl
*> To
=
209 FromTU
->importOrError(SharedStatePtr
, ToAST
.get(), From
);
213 QualType
ASTImporterTestBase::ImportType(QualType FromType
, Decl
*TUDecl
,
214 TestLanguage ToLang
) {
215 lazyInitToAST(ToLang
, "", OutputFileName
);
216 TU
*FromTU
= findFromTU(TUDecl
);
217 assert(SharedStatePtr
);
218 return FromTU
->import(SharedStatePtr
, ToAST
.get(), FromType
);
221 ASTImporterTestBase::~ASTImporterTestBase() {
222 if (!::testing::Test::HasFailure())
225 for (auto &Tu
: FromTUs
) {
227 llvm::errs() << "FromAST:\n";
228 Tu
.Unit
->getASTContext().getTranslationUnitDecl()->dump();
229 llvm::errs() << "\n";
232 llvm::errs() << "ToAST:\n";
233 ToAST
->getASTContext().getTranslationUnitDecl()->dump();
237 } // end namespace ast_matchers
238 } // end namespace clang