1 //===- unittest/AST/ASTImporterFixtures.h - 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 /// Fixture classes for testing the ASTImporter.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_UNITTESTS_AST_IMPORTER_FIXTURES_H
15 #define LLVM_CLANG_UNITTESTS_AST_IMPORTER_FIXTURES_H
16 
17 #include "gmock/gmock.h"
18 
19 #include "clang/AST/ASTImporter.h"
20 #include "clang/Frontend/ASTUnit.h"
21 #include "clang/AST/ASTImporterSharedState.h"
22 
23 #include "DeclMatcher.h"
24 #include "Language.h"
25 
26 namespace clang {
27 
28 class ASTImporter;
29 class ASTImporterSharedState;
30 class ASTUnit;
31 
32 namespace ast_matchers {
33 
34 const StringRef DeclToImportID = "declToImport";
35 const StringRef DeclToVerifyID = "declToVerify";
36 
37 // Creates a virtual file and assigns that to the context of given AST. If the
38 // file already exists then the file will not be created again as a duplicate.
39 void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
40                                std::unique_ptr<llvm::MemoryBuffer> &&Buffer);
41 
42 void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
43                                StringRef Code);
44 
45 // Common base for the different families of ASTImporter tests that are
46 // parameterized on the compiler options which may result a different AST. E.g.
47 // -fms-compatibility or -fdelayed-template-parsing.
48 class CompilerOptionSpecificTest : public ::testing::Test {
49 protected:
50   // Return the extra arguments appended to runtime options at compilation.
getExtraArgs()51   virtual ArgVector getExtraArgs() const { return ArgVector(); }
52 
53   // Returns the argument vector used for a specific language option, this set
54   // can be tweaked by the test parameters.
getArgVectorForLanguage(Language Lang)55   ArgVector getArgVectorForLanguage(Language Lang) const {
56     ArgVector Args = getBasicRunOptionsForLanguage(Lang);
57     ArgVector ExtraArgs = getExtraArgs();
58     for (const auto &Arg : ExtraArgs) {
59       Args.push_back(Arg);
60     }
61     return Args;
62   }
63 };
64 
65 const auto DefaultTestValuesForRunOptions = ::testing::Values(
66     ArgVector(), ArgVector{"-fdelayed-template-parsing"},
67     ArgVector{"-fms-compatibility"},
68     ArgVector{"-fdelayed-template-parsing", "-fms-compatibility"});
69 
70 // This class provides generic methods to write tests which can check internal
71 // attributes of AST nodes like getPreviousDecl(), isVirtual(), etc. Also,
72 // this fixture makes it possible to import from several "From" contexts.
73 class ASTImporterTestBase : public CompilerOptionSpecificTest {
74 
75   const char *const InputFileName = "input.cc";
76   const char *const OutputFileName = "output.cc";
77 
78 public:
79   /// Allocates an ASTImporter (or one of its subclasses).
80   typedef std::function<ASTImporter *(
81       ASTContext &, FileManager &, ASTContext &, FileManager &, bool,
82       const std::shared_ptr<ASTImporterSharedState> &SharedState)>
83       ImporterConstructor;
84 
85   // The lambda that constructs the ASTImporter we use in this test.
86   ImporterConstructor Creator;
87 
88 private:
89   // Buffer for the To context, must live in the test scope.
90   std::string ToCode;
91 
92   // Represents a "From" translation unit and holds an importer object which we
93   // use to import from this translation unit.
94   struct TU {
95     // Buffer for the context, must live in the test scope.
96     std::string Code;
97     std::string FileName;
98     std::unique_ptr<ASTUnit> Unit;
99     TranslationUnitDecl *TUDecl = nullptr;
100     std::unique_ptr<ASTImporter> Importer;
101     ImporterConstructor Creator;
102 
103     TU(StringRef Code, StringRef FileName, ArgVector Args,
104        ImporterConstructor C = ImporterConstructor());
105     ~TU();
106 
107     void
108     lazyInitImporter(const std::shared_ptr<ASTImporterSharedState> &SharedState,
109                      ASTUnit *ToAST);
110     Decl *import(const std::shared_ptr<ASTImporterSharedState> &SharedState,
111                  ASTUnit *ToAST, Decl *FromDecl);
112     QualType import(const std::shared_ptr<ASTImporterSharedState> &SharedState,
113                     ASTUnit *ToAST, QualType FromType);
114   };
115 
116   // We may have several From contexts and related translation units. In each
117   // AST, the buffers for the source are handled via references and are set
118   // during the creation of the AST. These references must point to a valid
119   // buffer until the AST is alive. Thus, we must use a list in order to avoid
120   // moving of the stored objects because that would mean breaking the
121   // references in the AST. By using a vector a move could happen when the
122   // vector is expanding, with the list we won't have these issues.
123   std::list<TU> FromTUs;
124 
125   // Initialize the shared state if not initialized already.
126   void lazyInitSharedState(TranslationUnitDecl *ToTU);
127 
128   void lazyInitToAST(Language ToLang, StringRef ToSrcCode, StringRef FileName);
129 
130 protected:
131   std::shared_ptr<ASTImporterSharedState> SharedStatePtr;
132 
133 public:
134   // We may have several From context but only one To context.
135   std::unique_ptr<ASTUnit> ToAST;
136 
137   // Returns with the TU associated with the given Decl.
138   TU *findFromTU(Decl *From);
139 
140   // Creates an AST both for the From and To source code and imports the Decl
141   // of the identifier into the To context.
142   // Must not be called more than once within the same test.
143   std::tuple<Decl *, Decl *>
144   getImportedDecl(StringRef FromSrcCode, Language FromLang, StringRef ToSrcCode,
145                   Language ToLang, StringRef Identifier = DeclToImportID);
146 
147   // Creates a TU decl for the given source code which can be used as a From
148   // context.  May be called several times in a given test (with different file
149   // name).
150   TranslationUnitDecl *getTuDecl(StringRef SrcCode, Language Lang,
151                                  StringRef FileName = "input.cc");
152 
153   // Creates the To context with the given source code and returns the TU decl.
154   TranslationUnitDecl *getToTuDecl(StringRef ToSrcCode, Language ToLang);
155 
156   // Import the given Decl into the ToCtx.
157   // May be called several times in a given test.
158   // The different instances of the param From may have different ASTContext.
159   Decl *Import(Decl *From, Language ToLang);
160 
Import(DeclT * From,Language Lang)161   template <class DeclT> DeclT *Import(DeclT *From, Language Lang) {
162     return cast_or_null<DeclT>(Import(cast<Decl>(From), Lang));
163   }
164 
165   QualType ImportType(QualType FromType, Decl *TUDecl, Language ToLang);
166 
167   ~ASTImporterTestBase();
168 };
169 
170 class ASTImporterOptionSpecificTestBase
171     : public ASTImporterTestBase,
172       public ::testing::WithParamInterface<ArgVector> {
173 protected:
getExtraArgs()174   ArgVector getExtraArgs() const override { return GetParam(); }
175 };
176 
177 } // end namespace ast_matchers
178 } // end namespace clang
179 
180 #endif
181