blob: c95e8fdaf80ab2baa7318f156f02857f04f1e9ec [file] [log] [blame]
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +00001//===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Tests for the correct import of AST nodes from one AST context to another.
11//
12//===----------------------------------------------------------------------===//
13
Aleksei Sidorin8fc85102018-01-26 11:36:54 +000014#include "MatchVerifier.h"
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000015#include "clang/AST/ASTContext.h"
16#include "clang/AST/ASTImporter.h"
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000017#include "clang/ASTMatchers/ASTMatchFinder.h"
18#include "clang/ASTMatchers/ASTMatchers.h"
19#include "clang/Tooling/Tooling.h"
Peter Szecsidedda6f2018-03-30 22:03:29 +000020
21#include "DeclMatcher.h"
Gabor Marton1f667532018-05-24 08:41:07 +000022#include "Language.h"
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000023#include "gtest/gtest.h"
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000024#include "llvm/ADT/StringMap.h"
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000025
26namespace clang {
27namespace ast_matchers {
28
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000029using internal::Matcher;
30using internal::BindableMatcher;
31using llvm::StringMap;
32
Peter Szecsidedda6f2018-03-30 22:03:29 +000033// Creates a virtual file and assigns that to the context of given AST. If the
34// file already exists then the file will not be created again as a duplicate.
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000035static void
36createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
37 std::unique_ptr<llvm::MemoryBuffer> &&Buffer) {
Peter Szecsidedda6f2018-03-30 22:03:29 +000038 assert(ToAST);
39 ASTContext &ToCtx = ToAST->getASTContext();
40 auto *OFS = static_cast<vfs::OverlayFileSystem *>(
41 ToCtx.getSourceManager().getFileManager().getVirtualFileSystem().get());
42 auto *MFS =
43 static_cast<vfs::InMemoryFileSystem *>(OFS->overlays_begin()->get());
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000044 MFS->addFile(FileName, 0, std::move(Buffer));
Peter Szecsidedda6f2018-03-30 22:03:29 +000045}
46
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000047static void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
48 StringRef Code) {
49 return createVirtualFileIfNeeded(ToAST, FileName,
50 llvm::MemoryBuffer::getMemBuffer(Code));
51}
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000052
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000053template <typename NodeType>
54NodeType importNode(ASTUnit *From, ASTUnit *To, ASTImporter &Importer,
55 NodeType Node) {
56 ASTContext &ToCtx = To->getASTContext();
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000057
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000058 // Add 'From' file to virtual file system so importer can 'find' it
59 // while importing SourceLocations. It is safe to add same file multiple
60 // times - it just isn't replaced.
61 StringRef FromFileName = From->getMainFileName();
62 createVirtualFileIfNeeded(To, FromFileName,
63 From->getBufferForFile(FromFileName));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000064
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000065 auto Imported = Importer.Import(Node);
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000066
67 // This should dump source locations and assert if some source locations
Aleksei Sidorine45ab562017-12-21 17:41:06 +000068 // were not imported.
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000069 SmallString<1024> ImportChecker;
70 llvm::raw_svector_ostream ToNothing(ImportChecker);
71 ToCtx.getTranslationUnitDecl()->print(ToNothing);
72
Gabor Horvath480892b2017-10-18 09:25:18 +000073 // This traverses the AST to catch certain bugs like poorly or not
74 // implemented subtrees.
75 Imported->dump(ToNothing);
76
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000077 return Imported;
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000078}
79
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000080const StringRef DeclToImportID = "declToImport";
81const StringRef DeclToVerifyID = "declToVerify";
82
83template <typename NodeType>
84testing::AssertionResult
85testImport(const std::string &FromCode, const ArgVector &FromArgs,
86 const std::string &ToCode, const ArgVector &ToArgs,
87 MatchVerifier<NodeType> &Verifier,
88 const BindableMatcher<NodeType> &SearchMatcher,
89 const BindableMatcher<NodeType> &VerificationMatcher) {
90 const char *const InputFileName = "input.cc";
91 const char *const OutputFileName = "output.cc";
92
93 std::unique_ptr<ASTUnit>
94 FromAST = tooling::buildASTFromCodeWithArgs(
95 FromCode, FromArgs, InputFileName),
96 ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, OutputFileName);
97
98 ASTContext &FromCtx = FromAST->getASTContext(),
99 &ToCtx = ToAST->getASTContext();
100
101 ASTImporter Importer(ToCtx, ToAST->getFileManager(),
102 FromCtx, FromAST->getFileManager(), false);
103
104 auto FoundNodes = match(SearchMatcher, FromCtx);
105 if (FoundNodes.size() != 1)
106 return testing::AssertionFailure()
107 << "Multiple potential nodes were found!";
108
109 auto ToImport = selectFirst<NodeType>(DeclToImportID, FoundNodes);
110 if (!ToImport)
111 return testing::AssertionFailure() << "Node type mismatch!";
112
113 // Sanity check: the node being imported should match in the same way as
114 // the result node.
115 BindableMatcher<NodeType> WrapperMatcher(VerificationMatcher);
116 EXPECT_TRUE(Verifier.match(ToImport, WrapperMatcher));
117
118 auto Imported = importNode(FromAST.get(), ToAST.get(), Importer, ToImport);
119 if (!Imported)
120 return testing::AssertionFailure() << "Import failed, nullptr returned!";
121
122 return Verifier.match(Imported, WrapperMatcher);
123}
124
125template <typename NodeType>
126testing::AssertionResult
127testImport(const std::string &FromCode, const ArgVector &FromArgs,
128 const std::string &ToCode, const ArgVector &ToArgs,
129 MatchVerifier<NodeType> &Verifier,
130 const BindableMatcher<NodeType> &VerificationMatcher) {
131 return testImport(
132 FromCode, FromArgs, ToCode, ToArgs, Verifier,
133 translationUnitDecl(
134 has(namedDecl(hasName(DeclToImportID)).bind(DeclToImportID))),
135 VerificationMatcher);
136}
137
138/// Test how AST node named "declToImport" located in the translation unit
139/// of "FromCode" virtual file is imported to "ToCode" virtual file.
140/// The verification is done by running AMatcher over the imported node.
141template <typename NodeType, typename MatcherType>
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000142void testImport(const std::string &FromCode, Language FromLang,
143 const std::string &ToCode, Language ToLang,
144 MatchVerifier<NodeType> &Verifier,
145 const MatcherType &AMatcher) {
146 auto RunOptsFrom = getRunOptionsForLanguage(FromLang);
147 auto RunOptsTo = getRunOptionsForLanguage(ToLang);
148 for (const auto &FromArgs : RunOptsFrom)
149 for (const auto &ToArgs : RunOptsTo)
150 EXPECT_TRUE(testImport(FromCode, FromArgs, ToCode, ToArgs,
151 Verifier, AMatcher));
152}
153
Peter Szecsidedda6f2018-03-30 22:03:29 +0000154// This class provides generic methods to write tests which can check internal
155// attributes of AST nodes like getPreviousDecl(), isVirtual(), etc. Also,
156// this fixture makes it possible to import from several "From" contexts.
157class ASTImporterTestBase : public ::testing::TestWithParam<ArgVector> {
158
159 const char *const InputFileName = "input.cc";
160 const char *const OutputFileName = "output.cc";
161
162 // Buffer for the To context, must live in the test scope.
163 std::string ToCode;
164
165 struct TU {
166 // Buffer for the context, must live in the test scope.
Aleksei Sidorin54d6af52018-05-14 16:12:31 +0000167 std::string Code;
168 std::string FileName;
Peter Szecsidedda6f2018-03-30 22:03:29 +0000169 std::unique_ptr<ASTUnit> Unit;
170 TranslationUnitDecl *TUDecl = nullptr;
171 TU(StringRef Code, StringRef FileName, ArgVector Args)
172 : Code(Code), FileName(FileName),
173 Unit(tooling::buildASTFromCodeWithArgs(this->Code, Args,
174 this->FileName)),
175 TUDecl(Unit->getASTContext().getTranslationUnitDecl()) {}
176 };
177
178 // We may have several From contexts and related translation units. In each
179 // AST, the buffers for the source are handled via references and are set
180 // during the creation of the AST. These references must point to a valid
181 // buffer until the AST is alive. Thus, we must use a list in order to avoid
182 // moving of the stored objects because that would mean breaking the
183 // references in the AST. By using a vector a move could happen when the
184 // vector is expanding, with the list we won't have these issues.
185 std::list<TU> FromTUs;
186
187public:
188 // We may have several From context but only one To context.
189 std::unique_ptr<ASTUnit> ToAST;
190
191 // Returns the argument vector used for a specific language, this set
192 // can be tweaked by the test parameters.
193 ArgVector getArgVectorForLanguage(Language Lang) {
194 ArgVector Args = getBasicRunOptionsForLanguage(Lang);
195 ArgVector ExtraArgs = GetParam();
196 for (const auto& Arg : ExtraArgs) {
197 Args.push_back(Arg);
198 }
199 return Args;
200 }
201
202 // Creates an AST both for the From and To source code and imports the Decl
203 // of the identifier into the To context.
204 // Must not be called more than once within the same test.
205 std::tuple<Decl *, Decl *>
206 getImportedDecl(StringRef FromSrcCode, Language FromLang, StringRef ToSrcCode,
207 Language ToLang, StringRef Identifier = DeclToImportID) {
208 ArgVector FromArgs = getArgVectorForLanguage(FromLang),
209 ToArgs = getArgVectorForLanguage(ToLang);
210
211 FromTUs.emplace_back(FromSrcCode, InputFileName, FromArgs);
212 TU &FromTU = FromTUs.back();
213
214 ToCode = ToSrcCode;
215 assert(!ToAST);
216 ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, OutputFileName);
217
218 ASTContext &FromCtx = FromTU.Unit->getASTContext(),
219 &ToCtx = ToAST->getASTContext();
220
221 createVirtualFileIfNeeded(ToAST.get(), InputFileName, FromTU.Code);
222
223 ASTImporter Importer(ToCtx, ToAST->getFileManager(), FromCtx,
224 FromTU.Unit->getFileManager(), false);
225
226 IdentifierInfo *ImportedII = &FromCtx.Idents.get(Identifier);
227 assert(ImportedII && "Declaration with the given identifier "
228 "should be specified in test!");
229 DeclarationName ImportDeclName(ImportedII);
230 SmallVector<NamedDecl *, 4> FoundDecls;
231 FromCtx.getTranslationUnitDecl()->localUncachedLookup(ImportDeclName,
232 FoundDecls);
233
234 assert(FoundDecls.size() == 1);
235
236 Decl *Imported = Importer.Import(FoundDecls.front());
237 assert(Imported);
238 return std::make_tuple(*FoundDecls.begin(), Imported);
239 }
240
Gabor Marton9581c332018-05-23 13:53:36 +0000241 // Creates a TU decl for the given source code which can be used as a From
242 // context. May be called several times in a given test (with different file
243 // name).
Peter Szecsidedda6f2018-03-30 22:03:29 +0000244 TranslationUnitDecl *getTuDecl(StringRef SrcCode, Language Lang,
245 StringRef FileName = "input.cc") {
246 assert(
247 std::find_if(FromTUs.begin(), FromTUs.end(), [FileName](const TU &E) {
248 return E.FileName == FileName;
249 }) == FromTUs.end());
250
251 ArgVector Args = getArgVectorForLanguage(Lang);
252 FromTUs.emplace_back(SrcCode, FileName, Args);
253 TU &Tu = FromTUs.back();
254
255 return Tu.TUDecl;
256 }
257
Gabor Marton9581c332018-05-23 13:53:36 +0000258 // Creates the To context with the given source code and returns the TU decl.
259 TranslationUnitDecl *getToTuDecl(StringRef ToSrcCode, Language ToLang) {
260 ArgVector ToArgs = getArgVectorForLanguage(ToLang);
261 ToCode = ToSrcCode;
262 assert(!ToAST);
263 ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, OutputFileName);
264
265 return ToAST->getASTContext().getTranslationUnitDecl();
266 }
267
Peter Szecsidedda6f2018-03-30 22:03:29 +0000268 // Import the given Decl into the ToCtx.
269 // May be called several times in a given test.
270 // The different instances of the param From may have different ASTContext.
271 Decl *Import(Decl *From, Language ToLang) {
272 if (!ToAST) {
273 ArgVector ToArgs = getArgVectorForLanguage(ToLang);
274 // Build the AST from an empty file.
275 ToAST =
276 tooling::buildASTFromCodeWithArgs(/*Code=*/"", ToArgs, "empty.cc");
277 }
278
279 // Create a virtual file in the To Ctx which corresponds to the file from
280 // which we want to import the `From` Decl. Without this source locations
281 // will be invalid in the ToCtx.
282 auto It = std::find_if(FromTUs.begin(), FromTUs.end(), [From](const TU &E) {
283 return E.TUDecl == From->getTranslationUnitDecl();
284 });
285 assert(It != FromTUs.end());
286 createVirtualFileIfNeeded(ToAST.get(), It->FileName, It->Code);
287
288 ASTContext &FromCtx = From->getASTContext(),
289 &ToCtx = ToAST->getASTContext();
290 ASTImporter Importer(ToCtx, ToAST->getFileManager(), FromCtx,
291 FromCtx.getSourceManager().getFileManager(), false);
292 return Importer.Import(From);
293 }
294
295 ~ASTImporterTestBase() {
296 if (!::testing::Test::HasFailure()) return;
297
298 for (auto &Tu : FromTUs) {
299 assert(Tu.Unit);
300 llvm::errs() << "FromAST:\n";
301 Tu.Unit->getASTContext().getTranslationUnitDecl()->dump();
302 llvm::errs() << "\n";
303 }
304 if (ToAST) {
305 llvm::errs() << "ToAST:\n";
306 ToAST->getASTContext().getTranslationUnitDecl()->dump();
307 }
308 }
309};
310
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +0000311
312struct ImportAction {
313 StringRef FromFilename;
314 StringRef ToFilename;
315 // FIXME: Generalize this to support other node kinds.
316 BindableMatcher<Decl> ImportPredicate;
317
318 ImportAction(StringRef FromFilename, StringRef ToFilename,
319 DeclarationMatcher ImportPredicate)
320 : FromFilename(FromFilename), ToFilename(ToFilename),
321 ImportPredicate(ImportPredicate) {}
322
323 ImportAction(StringRef FromFilename, StringRef ToFilename,
324 const std::string &DeclName)
325 : FromFilename(FromFilename), ToFilename(ToFilename),
326 ImportPredicate(namedDecl(hasName(DeclName))) {}
327};
328
329using SingleASTUnitForAllOpts = std::vector<std::unique_ptr<ASTUnit>>;
330using AllASTUnitsForAllOpts = StringMap<SingleASTUnitForAllOpts>;
331
332struct CodeEntry {
333 std::string CodeSample;
334 Language Lang;
335
336 /// Builds N copies of ASTUnits for each potential compile options set
337 /// for further import actions. N is equal to size of this option set.
338 SingleASTUnitForAllOpts createASTUnits(StringRef FileName) const {
339 auto RunOpts = getRunOptionsForLanguage(Lang);
340 size_t NumOpts = RunOpts.size();
341 SingleASTUnitForAllOpts ResultASTs(NumOpts);
342 for (size_t CompileOpt = 0; CompileOpt < NumOpts; ++CompileOpt) {
343 auto AST = tooling::buildASTFromCodeWithArgs(
344 CodeSample, RunOpts[CompileOpt], FileName);
345 EXPECT_TRUE(AST.get());
346 ResultASTs[CompileOpt] = std::move(AST);
347 }
348 return ResultASTs;
Peter Szecsidedda6f2018-03-30 22:03:29 +0000349 }
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +0000350};
351
352using CodeFiles = StringMap<CodeEntry>;
353
354/// Test an arbitrary sequence of imports for a set of given in-memory files.
355/// The verification is done by running VerificationMatcher against a specified
356/// AST node inside of one of given files.
357/// \param CodeSamples Map whose key is the file name and the value is the file
358/// content.
359/// \param ImportActions Sequence of imports. Each import in sequence
360/// specifies "from file" and "to file" and a matcher that is used for
361/// searching a declaration for import in "from file".
362/// \param FileForFinalCheck Name of virtual file for which the final check is
363/// applied.
364/// \param FinalSelectPredicate Matcher that specifies the AST node in the
365/// FileForFinalCheck for which the verification will be done.
366/// \param VerificationMatcher Matcher that will be used for verification after
367/// all imports in sequence are done.
368void testImportSequence(const CodeFiles &CodeSamples,
369 const std::vector<ImportAction> &ImportActions,
370 StringRef FileForFinalCheck,
371 BindableMatcher<Decl> FinalSelectPredicate,
372 BindableMatcher<Decl> VerificationMatcher) {
373 AllASTUnitsForAllOpts AllASTUnits;
374 using ImporterKey = std::pair<const ASTUnit *, const ASTUnit *>;
375 llvm::DenseMap<ImporterKey, std::unique_ptr<ASTImporter>> Importers;
376
377 auto GenASTsIfNeeded = [&AllASTUnits, &CodeSamples](StringRef Filename) {
378 if (!AllASTUnits.count(Filename)) {
379 auto Found = CodeSamples.find(Filename);
380 assert(Found != CodeSamples.end() && "Wrong file for import!");
381 AllASTUnits[Filename] = Found->getValue().createASTUnits(Filename);
382 }
383 };
384
385 size_t NumCompileOpts = 0;
386 for (const ImportAction &Action : ImportActions) {
387 StringRef FromFile = Action.FromFilename, ToFile = Action.ToFilename;
388 GenASTsIfNeeded(FromFile);
389 GenASTsIfNeeded(ToFile);
390 NumCompileOpts = AllASTUnits[FromFile].size();
391
392 for (size_t CompileOpt = 0; CompileOpt < NumCompileOpts; ++CompileOpt) {
393 ASTUnit *From = AllASTUnits[FromFile][CompileOpt].get();
394 ASTUnit *To = AllASTUnits[ToFile][CompileOpt].get();
395
396 // Create a new importer if needed.
397 std::unique_ptr<ASTImporter> &ImporterRef = Importers[{From, To}];
398 if (!ImporterRef)
399 ImporterRef.reset(new ASTImporter(
400 To->getASTContext(), To->getFileManager(), From->getASTContext(),
401 From->getFileManager(), false));
402
403 // Find the declaration and import it.
404 auto FoundDecl = match(Action.ImportPredicate.bind(DeclToImportID),
405 From->getASTContext());
406 EXPECT_TRUE(FoundDecl.size() == 1);
407 const Decl *ToImport = selectFirst<Decl>(DeclToImportID, FoundDecl);
408 auto Imported = importNode(From, To, *ImporterRef, ToImport);
409 EXPECT_TRUE(Imported);
410 }
411 }
412
413 // NOTE: We don't do cross-option import check here due to fast growth of
414 // potential option sets.
415 for (size_t CompileOpt = 0; CompileOpt < NumCompileOpts; ++CompileOpt) {
416 // Find the declaration and import it.
417 auto FoundDecl =
418 match(FinalSelectPredicate.bind(DeclToVerifyID),
419 AllASTUnits[FileForFinalCheck][CompileOpt]->getASTContext());
420 EXPECT_TRUE(FoundDecl.size() == 1);
421 const Decl *ToVerify = selectFirst<Decl>(DeclToVerifyID, FoundDecl);
422 MatchVerifier<Decl> Verifier;
423 EXPECT_TRUE(Verifier.match(ToVerify,
424 BindableMatcher<Decl>(VerificationMatcher)));
425 }
Peter Szecsidedda6f2018-03-30 22:03:29 +0000426}
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000427
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000428TEST(ImportExpr, ImportStringLiteral) {
429 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000430 testImport("void declToImport() { \"foo\"; }",
431 Lang_CXX, "", Lang_CXX, Verifier,
432 functionDecl(
433 hasBody(
434 compoundStmt(
435 has(
436 stringLiteral(
437 hasType(
438 asString("const char [4]"))))))));
439 testImport("void declToImport() { L\"foo\"; }",
440 Lang_CXX, "", Lang_CXX, Verifier,
441 functionDecl(
442 hasBody(
443 compoundStmt(
444 has(
445 stringLiteral(
446 hasType(
447 asString("const wchar_t [4]"))))))));
448 testImport("void declToImport() { \"foo\" \"bar\"; }",
449 Lang_CXX, "", Lang_CXX, Verifier,
450 functionDecl(
451 hasBody(
452 compoundStmt(
453 has(
454 stringLiteral(
455 hasType(
456 asString("const char [7]"))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000457}
458
459TEST(ImportExpr, ImportGNUNullExpr) {
460 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000461 testImport("void declToImport() { __null; }",
462 Lang_CXX, "", Lang_CXX, Verifier,
463 functionDecl(
464 hasBody(
465 compoundStmt(
466 has(
467 gnuNullExpr(
468 hasType(isInteger())))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000469}
470
471TEST(ImportExpr, ImportCXXNullPtrLiteralExpr) {
472 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000473 testImport("void declToImport() { nullptr; }",
474 Lang_CXX11, "", Lang_CXX11, Verifier,
475 functionDecl(
476 hasBody(
477 compoundStmt(
478 has(
479 cxxNullPtrLiteralExpr())))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000480}
481
482
483TEST(ImportExpr, ImportFloatinglLiteralExpr) {
484 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000485 testImport("void declToImport() { 1.0; }",
486 Lang_C, "", Lang_C, Verifier,
487 functionDecl(
488 hasBody(
489 compoundStmt(
490 has(
491 floatLiteral(
492 equals(1.0),
493 hasType(asString("double"))))))));
494 testImport("void declToImport() { 1.0e-5f; }",
495 Lang_C, "", Lang_C, Verifier,
496 functionDecl(
497 hasBody(
498 compoundStmt(
499 has(
500 floatLiteral(
501 equals(1.0e-5f),
502 hasType(asString("float"))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000503}
504
505TEST(ImportExpr, ImportCompoundLiteralExpr) {
506 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000507 testImport("void declToImport() {"
508 " struct s { int x; long y; unsigned z; }; "
509 " (struct s){ 42, 0L, 1U }; }",
510 Lang_CXX, "", Lang_CXX, Verifier,
511 functionDecl(
512 hasBody(
513 compoundStmt(
514 has(
515 compoundLiteralExpr(
516 hasType(asString("struct s")),
517 has(initListExpr(
518 hasType(asString("struct s")),
519 has(integerLiteral(
520 equals(42), hasType(asString("int")))),
521 has(integerLiteral(
522 equals(0), hasType(asString("long")))),
523 has(integerLiteral(
524 equals(1),
525 hasType(asString("unsigned int"))))
526 ))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000527}
528
529TEST(ImportExpr, ImportCXXThisExpr) {
530 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000531 testImport("class declToImport { void f() { this; } };",
532 Lang_CXX, "", Lang_CXX, Verifier,
533 cxxRecordDecl(
534 hasMethod(
535 hasBody(
536 compoundStmt(
537 has(
538 cxxThisExpr(
539 hasType(
540 asString("class declToImport *")))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000541}
542
543TEST(ImportExpr, ImportAtomicExpr) {
544 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000545 testImport("void declToImport() { int *ptr; __atomic_load_n(ptr, 1); }",
546 Lang_C, "", Lang_C, Verifier,
547 functionDecl(hasBody(compoundStmt(has(atomicExpr(
548 has(ignoringParenImpCasts(
549 declRefExpr(hasDeclaration(varDecl(hasName("ptr"))),
550 hasType(asString("int *"))))),
551 has(integerLiteral(equals(1), hasType(asString("int"))))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000552}
553
554TEST(ImportExpr, ImportLabelDeclAndAddrLabelExpr) {
555 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000556 testImport(
557 "void declToImport() { loop: goto loop; &&loop; }", Lang_C, "", Lang_C,
558 Verifier,
559 functionDecl(hasBody(compoundStmt(
560 has(labelStmt(hasDeclaration(labelDecl(hasName("loop"))))),
561 has(addrLabelExpr(hasDeclaration(labelDecl(hasName("loop")))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000562}
563
564AST_MATCHER_P(TemplateDecl, hasTemplateDecl,
565 internal::Matcher<NamedDecl>, InnerMatcher) {
566 const NamedDecl *Template = Node.getTemplatedDecl();
567 return Template && InnerMatcher.matches(*Template, Finder, Builder);
568}
569
570TEST(ImportExpr, ImportParenListExpr) {
571 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000572 testImport(
Manuel Klimek696e5052017-08-02 13:04:44 +0000573 "template<typename T> class dummy { void f() { dummy X(*this); } };"
574 "typedef dummy<int> declToImport;"
575 "template class dummy<int>;",
576 Lang_CXX, "", Lang_CXX, Verifier,
577 typedefDecl(hasType(templateSpecializationType(
578 hasDeclaration(classTemplateSpecializationDecl(hasSpecializedTemplate(
579 classTemplateDecl(hasTemplateDecl(cxxRecordDecl(hasMethod(allOf(
580 hasName("f"),
581 hasBody(compoundStmt(has(declStmt(hasSingleDecl(
582 varDecl(hasInitializer(parenListExpr(has(unaryOperator(
583 hasOperatorName("*"),
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000584 hasUnaryOperand(cxxThisExpr())))))))))))))))))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000585}
586
Gabor Horvath480892b2017-10-18 09:25:18 +0000587TEST(ImportExpr, ImportSwitch) {
588 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000589 testImport("void declToImport() { int b; switch (b) { case 1: break; } }",
590 Lang_C, "", Lang_C, Verifier,
591 functionDecl(hasBody(compoundStmt(
592 has(switchStmt(has(compoundStmt(has(caseStmt())))))))));
Gabor Horvath480892b2017-10-18 09:25:18 +0000593}
594
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000595TEST(ImportExpr, ImportStmtExpr) {
596 MatchVerifier<Decl> Verifier;
597 // NOTE: has() ignores implicit casts, using hasDescendant() to match it
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000598 testImport(
599 "void declToImport() { int b; int a = b ?: 1; int C = ({int X=4; X;}); }",
600 Lang_C, "", Lang_C, Verifier,
601 functionDecl(
602 hasBody(
603 compoundStmt(
604 has(
605 declStmt(
606 hasSingleDecl(
607 varDecl(
608 hasName("C"),
609 hasType(asString("int")),
610 hasInitializer(
611 stmtExpr(
612 hasAnySubstatement(
613 declStmt(
614 hasSingleDecl(
615 varDecl(
616 hasName("X"),
617 hasType(asString("int")),
618 hasInitializer(
619 integerLiteral(equals(4))))))),
620 hasDescendant(
621 implicitCastExpr()
622 )))))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000623}
624
625TEST(ImportExpr, ImportConditionalOperator) {
626 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000627 testImport(
628 "void declToImport() { true ? 1 : -5; }",
629 Lang_CXX, "", Lang_CXX, Verifier,
630 functionDecl(
631 hasBody(
632 compoundStmt(
633 has(
634 conditionalOperator(
635 hasCondition(cxxBoolLiteral(equals(true))),
636 hasTrueExpression(integerLiteral(equals(1))),
637 hasFalseExpression(
638 unaryOperator(hasUnaryOperand(integerLiteral(equals(5))))
639 )))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000640}
641
642TEST(ImportExpr, ImportBinaryConditionalOperator) {
643 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000644 testImport(
645 "void declToImport() { 1 ?: -5; }", Lang_CXX, "", Lang_CXX, Verifier,
646 functionDecl(
647 hasBody(
648 compoundStmt(
649 has(
650 binaryConditionalOperator(
651 hasCondition(
652 implicitCastExpr(
653 hasSourceExpression(
654 opaqueValueExpr(
655 hasSourceExpression(integerLiteral(equals(1))))),
656 hasType(booleanType()))),
657 hasTrueExpression(
658 opaqueValueExpr(hasSourceExpression(
659 integerLiteral(equals(1))))),
660 hasFalseExpression(
661 unaryOperator(hasOperatorName("-"),
662 hasUnaryOperand(integerLiteral(equals(5)))))
663 ))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000664}
665
666TEST(ImportExpr, ImportDesignatedInitExpr) {
667 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000668 testImport("void declToImport() {"
669 " struct point { double x; double y; };"
670 " struct point ptarray[10] = "
671 "{ [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; }",
672 Lang_C, "", Lang_C, Verifier,
673 functionDecl(
674 hasBody(
675 compoundStmt(
676 has(
677 declStmt(
678 hasSingleDecl(
679 varDecl(
680 hasInitializer(
681 initListExpr(
682 hasSyntacticForm(
683 initListExpr(
684 has(
685 designatedInitExpr(
686 designatorCountIs(2),
687 has(floatLiteral(
688 equals(1.0))),
689 has(integerLiteral(
690 equals(2))))),
691 has(
692 designatedInitExpr(
693 designatorCountIs(2),
694 has(floatLiteral(
695 equals(2.0))),
696 has(integerLiteral(
697 equals(2))))),
698 has(
699 designatedInitExpr(
700 designatorCountIs(2),
701 has(floatLiteral(
702 equals(1.0))),
703 has(integerLiteral(
704 equals(0)))))
705 ))))))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000706}
707
708
709TEST(ImportExpr, ImportPredefinedExpr) {
710 MatchVerifier<Decl> Verifier;
711 // __func__ expands as StringLiteral("declToImport")
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000712 testImport("void declToImport() { __func__; }",
713 Lang_CXX, "", Lang_CXX, Verifier,
714 functionDecl(
715 hasBody(
716 compoundStmt(
717 has(
718 predefinedExpr(
719 hasType(
720 asString("const char [13]")),
721 has(
722 stringLiteral(
723 hasType(
724 asString("const char [13]"))))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000725}
726
727TEST(ImportExpr, ImportInitListExpr) {
728 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000729 testImport(
730 "void declToImport() {"
731 " struct point { double x; double y; };"
732 " point ptarray[10] = { [2].y = 1.0, [2].x = 2.0,"
733 " [0].x = 1.0 }; }",
734 Lang_CXX, "", Lang_CXX, Verifier,
735 functionDecl(
736 hasBody(
737 compoundStmt(
738 has(
739 declStmt(
740 hasSingleDecl(
741 varDecl(
742 hasInitializer(
743 initListExpr(
744 has(
745 cxxConstructExpr(
746 requiresZeroInitialization())),
747 has(
748 initListExpr(
749 hasType(asString("struct point")),
750 has(floatLiteral(equals(1.0))),
751 has(implicitValueInitExpr(
752 hasType(asString("double")))))),
753 has(
754 initListExpr(
755 hasType(asString("struct point")),
756 has(floatLiteral(equals(2.0))),
757 has(floatLiteral(equals(1.0)))))
758 ))))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000759}
760
761
Aleksei Sidorina693b372016-09-28 10:16:56 +0000762const internal::VariadicDynCastAllOfMatcher<Expr, VAArgExpr> vaArgExpr;
763
764TEST(ImportExpr, ImportVAArgExpr) {
765 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000766 testImport("void declToImport(__builtin_va_list list, ...) {"
767 " (void)__builtin_va_arg(list, int); }",
768 Lang_CXX, "", Lang_CXX, Verifier,
769 functionDecl(
770 hasBody(
771 compoundStmt(
772 has(
773 cStyleCastExpr(
774 hasSourceExpression(
775 vaArgExpr())))))));
Aleksei Sidorina693b372016-09-28 10:16:56 +0000776}
777
Gabor Horvathc78d99a2018-01-27 16:11:45 +0000778TEST(ImportExpr, CXXTemporaryObjectExpr) {
779 MatchVerifier<Decl> Verifier;
780 testImport("struct C {};"
781 "void declToImport() { C c = C(); }",
782 Lang_CXX, "", Lang_CXX, Verifier,
783 functionDecl(hasBody(compoundStmt(has(
784 declStmt(has(varDecl(has(exprWithCleanups(has(cxxConstructExpr(
785 has(materializeTemporaryExpr(has(implicitCastExpr(
786 has(cxxTemporaryObjectExpr())))))))))))))))));
787}
Aleksei Sidorina693b372016-09-28 10:16:56 +0000788
Gabor Horvath0866c2f2016-11-23 15:24:23 +0000789TEST(ImportType, ImportAtomicType) {
790 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000791 testImport("void declToImport() { typedef _Atomic(int) a_int; }",
792 Lang_CXX11, "", Lang_CXX11, Verifier,
793 functionDecl(
794 hasBody(
795 compoundStmt(
796 has(
797 declStmt(
798 has(
799 typedefDecl(
800 has(atomicType())))))))));
Gabor Horvath0866c2f2016-11-23 15:24:23 +0000801}
802
Aleksei Sidorin7f758b62017-12-27 17:04:42 +0000803TEST(ImportDecl, ImportFunctionTemplateDecl) {
804 MatchVerifier<Decl> Verifier;
805 testImport("template <typename T> void declToImport() { };", Lang_CXX, "",
806 Lang_CXX, Verifier, functionTemplateDecl());
807}
808
809const internal::VariadicDynCastAllOfMatcher<Expr, CXXDependentScopeMemberExpr>
810 cxxDependentScopeMemberExpr;
811
812TEST(ImportExpr, ImportCXXDependentScopeMemberExpr) {
813 MatchVerifier<Decl> Verifier;
814 testImport("template <typename T> struct C { T t; };"
815 "template <typename T> void declToImport() {"
816 " C<T> d;"
817 " d.t;"
818 "}"
819 "void instantiate() { declToImport<int>(); }",
820 Lang_CXX, "", Lang_CXX, Verifier,
821 functionTemplateDecl(has(functionDecl(
822 has(compoundStmt(has(cxxDependentScopeMemberExpr())))))));
823 testImport("template <typename T> struct C { T t; };"
824 "template <typename T> void declToImport() {"
825 " C<T> d;"
826 " (&d)->t;"
827 "}"
828 "void instantiate() { declToImport<int>(); }",
829 Lang_CXX, "", Lang_CXX, Verifier,
830 functionTemplateDecl(has(functionDecl(
831 has(compoundStmt(has(cxxDependentScopeMemberExpr())))))));
832}
Gabor Horvath0866c2f2016-11-23 15:24:23 +0000833
Gabor Horvath7a91c082017-11-14 11:30:38 +0000834TEST(ImportType, ImportTypeAliasTemplate) {
835 MatchVerifier<Decl> Verifier;
Aleksei Sidorin4c05f142018-02-14 11:18:00 +0000836 testImport(
837 "template <int K>"
838 "struct dummy { static const int i = K; };"
839 "template <int K> using dummy2 = dummy<K>;"
840 "int declToImport() { return dummy2<3>::i; }",
841 Lang_CXX11, "", Lang_CXX11, Verifier,
842 functionDecl(
843 hasBody(compoundStmt(
844 has(returnStmt(has(implicitCastExpr(has(declRefExpr()))))))),
845 unless(hasAncestor(translationUnitDecl(has(typeAliasDecl()))))));
846}
847
848const internal::VariadicDynCastAllOfMatcher<Decl, VarTemplateSpecializationDecl>
849 varTemplateSpecializationDecl;
850
851TEST(ImportDecl, ImportVarTemplate) {
852 MatchVerifier<Decl> Verifier;
853 testImport(
854 "template <typename T>"
855 "T pi = T(3.1415926535897932385L);"
856 "void declToImport() { pi<int>; }",
857 Lang_CXX11, "", Lang_CXX11, Verifier,
858 functionDecl(
859 hasBody(has(declRefExpr(to(varTemplateSpecializationDecl())))),
860 unless(hasAncestor(translationUnitDecl(has(varDecl(
861 hasName("pi"), unless(varTemplateSpecializationDecl()))))))));
Gabor Horvath7a91c082017-11-14 11:30:38 +0000862}
863
Gabor Horvath7a91c082017-11-14 11:30:38 +0000864TEST(ImportType, ImportPackExpansion) {
865 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000866 testImport("template <typename... Args>"
867 "struct dummy {"
868 " dummy(Args... args) {}"
869 " static const int i = 4;"
870 "};"
871 "int declToImport() { return dummy<int>::i; }",
872 Lang_CXX11, "", Lang_CXX11, Verifier,
873 functionDecl(
874 hasBody(
875 compoundStmt(
876 has(
877 returnStmt(
878 has(
879 implicitCastExpr(
880 has(
881 declRefExpr())))))))));
Gabor Horvath7a91c082017-11-14 11:30:38 +0000882}
883
Gabor Horvathc78d99a2018-01-27 16:11:45 +0000884const internal::VariadicDynCastAllOfMatcher<Type,
885 DependentTemplateSpecializationType>
886 dependentTemplateSpecializationType;
887
888TEST(ImportType, ImportDependentTemplateSpecialization) {
889 MatchVerifier<Decl> Verifier;
890 testImport("template<typename T>"
891 "struct A;"
892 "template<typename T>"
893 "struct declToImport {"
894 " typename A<T>::template B<T> a;"
895 "};",
896 Lang_CXX, "", Lang_CXX, Verifier,
897 classTemplateDecl(has(cxxRecordDecl(has(
898 fieldDecl(hasType(dependentTemplateSpecializationType())))))));
899}
900
901const internal::VariadicDynCastAllOfMatcher<Stmt, SizeOfPackExpr>
902 sizeOfPackExpr;
903
904TEST(ImportExpr, ImportSizeOfPackExpr) {
905 MatchVerifier<Decl> Verifier;
906 testImport("template <typename... Ts>"
907 "void declToImport() {"
908 " const int i = sizeof...(Ts);"
909 "};"
910 "void g() { declToImport<int>(); }",
911 Lang_CXX11, "", Lang_CXX11, Verifier,
912 functionTemplateDecl(has(functionDecl(
913 hasBody(compoundStmt(has(declStmt(has(varDecl(hasInitializer(
914 implicitCastExpr(has(sizeOfPackExpr())))))))))))));
915 testImport(
916 "template <typename... Ts>"
917 "using X = int[sizeof...(Ts)];"
918 "template <typename... Us>"
919 "struct Y {"
920 " X<Us..., int, double, int, Us...> f;"
921 "};"
922 "Y<float, int> declToImport;",
923 Lang_CXX11, "", Lang_CXX11, Verifier,
924 varDecl(hasType(classTemplateSpecializationDecl(has(fieldDecl(hasType(
925 hasUnqualifiedDesugaredType(constantArrayType(hasSize(7))))))))));
926}
927
Aleksei Sidorinb05f37a2017-11-26 17:04:06 +0000928/// \brief Matches __builtin_types_compatible_p:
929/// GNU extension to check equivalent types
930/// Given
931/// \code
932/// __builtin_types_compatible_p(int, int)
933/// \endcode
934// will generate TypeTraitExpr <...> 'int'
935const internal::VariadicDynCastAllOfMatcher<Stmt, TypeTraitExpr> typeTraitExpr;
936
937TEST(ImportExpr, ImportTypeTraitExpr) {
938 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000939 testImport("void declToImport() { "
940 " __builtin_types_compatible_p(int, int);"
941 "}",
942 Lang_C, "", Lang_C, Verifier,
943 functionDecl(
944 hasBody(
945 compoundStmt(
946 has(
947 typeTraitExpr(hasType(asString("int"))))))));
Aleksei Sidorinb05f37a2017-11-26 17:04:06 +0000948}
949
Gabor Horvathc78d99a2018-01-27 16:11:45 +0000950const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTypeidExpr> cxxTypeidExpr;
951
952TEST(ImportExpr, ImportCXXTypeidExpr) {
953 MatchVerifier<Decl> Verifier;
954 testImport(
955 "namespace std { class type_info {}; }"
956 "void declToImport() {"
957 " int x;"
958 " auto a = typeid(int); auto b = typeid(x);"
959 "}",
960 Lang_CXX11, "", Lang_CXX11, Verifier,
961 functionDecl(
962 hasDescendant(varDecl(
963 hasName("a"), hasInitializer(hasDescendant(cxxTypeidExpr())))),
964 hasDescendant(varDecl(
965 hasName("b"), hasInitializer(hasDescendant(cxxTypeidExpr()))))));
966}
967
Aleksei Sidorinb05f37a2017-11-26 17:04:06 +0000968TEST(ImportExpr, ImportTypeTraitExprValDep) {
969 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000970 testImport("template<typename T> struct declToImport {"
971 " void m() { __is_pod(T); }"
972 "};"
973 "void f() { declToImport<int>().m(); }",
974 Lang_CXX11, "", Lang_CXX11, Verifier,
975 classTemplateDecl(
976 has(
977 cxxRecordDecl(
978 has(
979 functionDecl(
980 hasBody(
981 compoundStmt(
Aleksei Sidorinb05f37a2017-11-26 17:04:06 +0000982 has(
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000983 typeTraitExpr(
984 hasType(booleanType())
985 ))))))))));
Aleksei Sidorinb05f37a2017-11-26 17:04:06 +0000986}
Gabor Horvath7a91c082017-11-14 11:30:38 +0000987
Aleksei Sidorin60ccb7d2017-11-27 10:30:00 +0000988const internal::VariadicDynCastAllOfMatcher<Expr, CXXPseudoDestructorExpr>
989 cxxPseudoDestructorExpr;
990
991TEST(ImportExpr, ImportCXXPseudoDestructorExpr) {
992 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000993 testImport("typedef int T;"
994 "void declToImport(int *p) {"
995 " T t;"
996 " p->T::~T();"
997 "}",
998 Lang_CXX, "", Lang_CXX, Verifier,
999 functionDecl(has(compoundStmt(has(
1000 callExpr(has(cxxPseudoDestructorExpr())))))));
Aleksei Sidorin60ccb7d2017-11-27 10:30:00 +00001001}
1002
Aleksei Sidorin9d8ba2e2017-12-03 16:04:07 +00001003TEST(ImportDecl, ImportUsingDecl) {
1004 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +00001005 testImport("namespace foo { int bar; }"
Aleksei Sidorin8fc85102018-01-26 11:36:54 +00001006 "void declToImport() { using foo::bar; }",
Aleksei Sidorine45ab562017-12-21 17:41:06 +00001007 Lang_CXX, "", Lang_CXX, Verifier,
1008 functionDecl(
1009 has(
1010 compoundStmt(
1011 has(
1012 declStmt(
1013 has(
1014 usingDecl())))))));
Aleksei Sidorin9d8ba2e2017-12-03 16:04:07 +00001015}
1016
1017/// \brief Matches shadow declarations introduced into a scope by a
1018/// (resolved) using declaration.
1019///
1020/// Given
1021/// \code
1022/// namespace n { int f; }
1023/// namespace declToImport { using n::f; }
1024/// \endcode
1025/// usingShadowDecl()
1026/// matches \code f \endcode
1027const internal::VariadicDynCastAllOfMatcher<Decl,
1028 UsingShadowDecl> usingShadowDecl;
1029
1030TEST(ImportDecl, ImportUsingShadowDecl) {
1031 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +00001032 testImport("namespace foo { int bar; }"
1033 "namespace declToImport { using foo::bar; }",
1034 Lang_CXX, "", Lang_CXX, Verifier,
1035 namespaceDecl(has(usingShadowDecl())));
Aleksei Sidorin9d8ba2e2017-12-03 16:04:07 +00001036}
1037
Aleksei Sidorine267a0f2018-01-09 16:40:40 +00001038TEST(ImportExpr, ImportUnresolvedLookupExpr) {
1039 MatchVerifier<Decl> Verifier;
1040 testImport("template<typename T> int foo();"
1041 "template <typename T> void declToImport() {"
1042 " ::foo<T>;"
1043 " ::template foo<T>;"
1044 "}"
1045 "void instantiate() { declToImport<int>(); }",
1046 Lang_CXX, "", Lang_CXX, Verifier,
Aleksei Sidorin8fc85102018-01-26 11:36:54 +00001047 functionTemplateDecl(has(functionDecl(
1048 has(compoundStmt(has(unresolvedLookupExpr())))))));
Aleksei Sidorine267a0f2018-01-09 16:40:40 +00001049}
1050
1051TEST(ImportExpr, ImportCXXUnresolvedConstructExpr) {
1052 MatchVerifier<Decl> Verifier;
Aleksei Sidorin8fc85102018-01-26 11:36:54 +00001053 testImport("template <typename T> struct C { T t; };"
Aleksei Sidorine267a0f2018-01-09 16:40:40 +00001054 "template <typename T> void declToImport() {"
1055 " C<T> d;"
1056 " d.t = T();"
1057 "}"
1058 "void instantiate() { declToImport<int>(); }",
1059 Lang_CXX, "", Lang_CXX, Verifier,
1060 functionTemplateDecl(has(functionDecl(has(compoundStmt(has(
1061 binaryOperator(has(cxxUnresolvedConstructExpr())))))))));
Aleksei Sidorin8fc85102018-01-26 11:36:54 +00001062 testImport("template <typename T> struct C { T t; };"
Aleksei Sidorine267a0f2018-01-09 16:40:40 +00001063 "template <typename T> void declToImport() {"
1064 " C<T> d;"
1065 " (&d)->t = T();"
1066 "}"
1067 "void instantiate() { declToImport<int>(); }",
1068 Lang_CXX, "", Lang_CXX, Verifier,
1069 functionTemplateDecl(has(functionDecl(has(compoundStmt(has(
1070 binaryOperator(has(cxxUnresolvedConstructExpr())))))))));
1071}
1072
Aleksei Sidorin8fc85102018-01-26 11:36:54 +00001073/// Check that function "declToImport()" (which is the templated function
1074/// for corresponding FunctionTemplateDecl) is not added into DeclContext.
1075/// Same for class template declarations.
1076TEST(ImportDecl, ImportTemplatedDeclForTemplate) {
1077 MatchVerifier<Decl> Verifier;
1078 testImport("template <typename T> void declToImport() { T a = 1; }"
1079 "void instantiate() { declToImport<int>(); }",
1080 Lang_CXX, "", Lang_CXX, Verifier,
1081 functionTemplateDecl(hasAncestor(translationUnitDecl(
1082 unless(has(functionDecl(hasName("declToImport"))))))));
1083 testImport("template <typename T> struct declToImport { T t; };"
1084 "void instantiate() { declToImport<int>(); }",
1085 Lang_CXX, "", Lang_CXX, Verifier,
1086 classTemplateDecl(hasAncestor(translationUnitDecl(
1087 unless(has(cxxRecordDecl(hasName("declToImport"))))))));
1088}
1089
Gabor Horvathc78d99a2018-01-27 16:11:45 +00001090TEST(ImportExpr, CXXOperatorCallExpr) {
1091 MatchVerifier<Decl> Verifier;
1092 testImport("class declToImport {"
1093 " void f() { *this = declToImport(); }"
1094 "};",
1095 Lang_CXX, "", Lang_CXX, Verifier,
1096 cxxRecordDecl(has(cxxMethodDecl(hasBody(compoundStmt(
1097 has(exprWithCleanups(has(cxxOperatorCallExpr())))))))));
1098}
1099
1100TEST(ImportExpr, DependentSizedArrayType) {
1101 MatchVerifier<Decl> Verifier;
1102 testImport("template<typename T, int Size> class declToImport {"
1103 " T data[Size];"
1104 "};",
1105 Lang_CXX, "", Lang_CXX, Verifier,
1106 classTemplateDecl(has(cxxRecordDecl(
1107 has(fieldDecl(hasType(dependentSizedArrayType())))))));
1108}
1109
Peter Szecsidedda6f2018-03-30 22:03:29 +00001110TEST_P(ASTImporterTestBase, DISABLED_ImportFunctionWithBackReferringParameter) {
1111 Decl *From, *To;
1112 std::tie(From, To) = getImportedDecl(
1113 R"(
1114 template <typename T> struct X {};
1115
1116 void declToImport(int y, X<int> &x) {}
1117
1118 template <> struct X<int> {
1119 void g() {
1120 X<int> x;
1121 declToImport(0, x);
1122 }
1123 };
1124 )",
1125 Lang_CXX, "", Lang_CXX);
1126
1127 MatchVerifier<Decl> Verifier;
1128 auto Matcher = functionDecl(hasName("declToImport"),
1129 parameterCountIs(2),
1130 hasParameter(0, hasName("y")),
1131 hasParameter(1, hasName("x")),
1132 hasParameter(1, hasType(asString("X<int> &"))));
1133 ASSERT_TRUE(Verifier.match(From, Matcher));
1134 EXPECT_TRUE(Verifier.match(To, Matcher));
1135}
1136
1137TEST_P(ASTImporterTestBase,
1138 TUshouldNotContainTemplatedDeclOfFunctionTemplates) {
1139 Decl *From, *To;
1140 std::tie(From, To) =
1141 getImportedDecl("template <typename T> void declToImport() { T a = 1; }"
1142 "void instantiate() { declToImport<int>(); }",
1143 Lang_CXX, "", Lang_CXX);
1144
1145 auto Check = [](Decl *D) -> bool {
1146 auto TU = D->getTranslationUnitDecl();
1147 for (auto Child : TU->decls()) {
1148 if (auto *FD = dyn_cast<FunctionDecl>(Child)) {
1149 if (FD->getNameAsString() == "declToImport") {
1150 GTEST_NONFATAL_FAILURE_(
1151 "TU should not contain any FunctionDecl with name declToImport");
1152 return false;
1153 }
1154 }
1155 }
1156 return true;
1157 };
1158
1159 ASSERT_TRUE(Check(From));
1160 EXPECT_TRUE(Check(To));
1161}
1162
1163TEST_P(ASTImporterTestBase, TUshouldNotContainTemplatedDeclOfClassTemplates) {
1164 Decl *From, *To;
1165 std::tie(From, To) =
1166 getImportedDecl("template <typename T> struct declToImport { T t; };"
1167 "void instantiate() { declToImport<int>(); }",
1168 Lang_CXX, "", Lang_CXX);
1169
1170 auto Check = [](Decl *D) -> bool {
1171 auto TU = D->getTranslationUnitDecl();
1172 for (auto Child : TU->decls()) {
1173 if (auto *RD = dyn_cast<CXXRecordDecl>(Child)) {
1174 if (RD->getNameAsString() == "declToImport") {
1175 GTEST_NONFATAL_FAILURE_(
1176 "TU should not contain any CXXRecordDecl with name declToImport");
1177 return false;
1178 }
1179 }
1180 }
1181 return true;
1182 };
1183
1184 ASSERT_TRUE(Check(From));
1185 EXPECT_TRUE(Check(To));
1186}
1187
1188TEST_P(ASTImporterTestBase, TUshouldNotContainTemplatedDeclOfTypeAlias) {
1189 Decl *From, *To;
1190 std::tie(From, To) =
1191 getImportedDecl(
1192 "template <typename T> struct X {};"
1193 "template <typename T> using declToImport = X<T>;"
1194 "void instantiate() { declToImport<int> a; }",
1195 Lang_CXX11, "", Lang_CXX11);
1196
1197 auto Check = [](Decl *D) -> bool {
1198 auto TU = D->getTranslationUnitDecl();
1199 for (auto Child : TU->decls()) {
1200 if (auto *AD = dyn_cast<TypeAliasDecl>(Child)) {
1201 if (AD->getNameAsString() == "declToImport") {
1202 GTEST_NONFATAL_FAILURE_(
1203 "TU should not contain any TypeAliasDecl with name declToImport");
1204 return false;
1205 }
1206 }
1207 }
1208 return true;
1209 };
1210
1211 ASSERT_TRUE(Check(From));
1212 EXPECT_TRUE(Check(To));
1213}
1214
1215TEST_P(
1216 ASTImporterTestBase,
1217 DISABLED_TUshouldNotContainClassTemplateSpecializationOfImplicitInstantiation) {
1218
1219 Decl *From, *To;
1220 std::tie(From, To) = getImportedDecl(
1221 R"(
1222 template<class T>
1223 class Base {};
1224 class declToImport : public Base<declToImport> {};
1225 )",
1226 Lang_CXX, "", Lang_CXX);
1227
1228 // Check that the ClassTemplateSpecializationDecl is NOT the child of the TU.
1229 auto Pattern =
1230 translationUnitDecl(unless(has(classTemplateSpecializationDecl())));
1231 ASSERT_TRUE(
1232 MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern));
1233 EXPECT_TRUE(
1234 MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
1235
1236 // Check that the ClassTemplateSpecializationDecl is the child of the
1237 // ClassTemplateDecl.
1238 Pattern = translationUnitDecl(has(classTemplateDecl(
1239 hasName("Base"), has(classTemplateSpecializationDecl()))));
1240 ASSERT_TRUE(
1241 MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern));
1242 EXPECT_TRUE(
1243 MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
1244}
1245
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +00001246AST_MATCHER_P(RecordDecl, hasFieldOrder, std::vector<StringRef>, Order) {
1247 size_t Index = 0;
1248 for (FieldDecl *Field : Node.fields()) {
1249 if (Index == Order.size())
1250 return false;
1251 if (Field->getName() != Order[Index])
1252 return false;
1253 ++Index;
1254 }
1255 return Index == Order.size();
1256}
1257
Peter Szecsidedda6f2018-03-30 22:03:29 +00001258TEST_P(ASTImporterTestBase,
1259 TUshouldContainClassTemplateSpecializationOfExplicitInstantiation) {
1260 Decl *From, *To;
1261 std::tie(From, To) = getImportedDecl(
1262 R"(
1263 namespace NS {
1264 template<class T>
1265 class X {};
1266 template class X<int>;
1267 }
1268 )",
1269 Lang_CXX, "", Lang_CXX, "NS");
1270
1271 // Check that the ClassTemplateSpecializationDecl is NOT the child of the
1272 // ClassTemplateDecl.
1273 auto Pattern = namespaceDecl(has(classTemplateDecl(
1274 hasName("X"), unless(has(classTemplateSpecializationDecl())))));
1275 ASSERT_TRUE(MatchVerifier<Decl>{}.match(From, Pattern));
1276 EXPECT_TRUE(MatchVerifier<Decl>{}.match(To, Pattern));
1277
1278 // Check that the ClassTemplateSpecializationDecl is the child of the
1279 // NamespaceDecl.
1280 Pattern = namespaceDecl(has(classTemplateSpecializationDecl(hasName("X"))));
1281 ASSERT_TRUE(MatchVerifier<Decl>{}.match(From, Pattern));
1282 EXPECT_TRUE(MatchVerifier<Decl>{}.match(To, Pattern));
1283}
1284
1285TEST_P(ASTImporterTestBase, CXXRecordDeclFieldsShouldBeInCorrectOrder) {
1286 Decl *From, *To;
1287 std::tie(From, To) =
1288 getImportedDecl(
1289 "struct declToImport { int a; int b; };",
1290 Lang_CXX11, "", Lang_CXX11);
1291
1292 MatchVerifier<Decl> Verifier;
1293 ASSERT_TRUE(Verifier.match(From, cxxRecordDecl(hasFieldOrder({"a", "b"}))));
1294 EXPECT_TRUE(Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b"}))));
1295}
1296
1297TEST_P(ASTImporterTestBase,
1298 DISABLED_CXXRecordDeclFieldOrderShouldNotDependOnImportOrder) {
1299 Decl *From, *To;
1300 std::tie(From, To) = getImportedDecl(
1301 // The original recursive algorithm of ASTImporter first imports 'c' then
1302 // 'b' and lastly 'a'. Therefore we must restore the order somehow.
1303 R"s(
1304 struct declToImport {
1305 int a = c + b;
1306 int b = 1;
1307 int c = 2;
1308 };
1309 )s",
1310 Lang_CXX11, "", Lang_CXX11);
1311
1312 MatchVerifier<Decl> Verifier;
1313 ASSERT_TRUE(
1314 Verifier.match(From, cxxRecordDecl(hasFieldOrder({"a", "b", "c"}))));
1315 EXPECT_TRUE(
1316 Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b", "c"}))));
1317}
1318
Gabor Martonde8bf262018-05-17 09:46:07 +00001319TEST_P(ASTImporterTestBase, ShouldImportImplicitCXXRecordDecl) {
Peter Szecsidedda6f2018-03-30 22:03:29 +00001320 Decl *From, *To;
1321 std::tie(From, To) = getImportedDecl(
1322 R"(
Gabor Martona3af5672018-05-23 14:24:02 +00001323 struct declToImport {
1324 };
1325 )",
1326 Lang_CXX, "", Lang_CXX);
1327
1328 MatchVerifier<Decl> Verifier;
1329 // Match the implicit Decl.
1330 auto Matcher = cxxRecordDecl(has(cxxRecordDecl()));
1331 ASSERT_TRUE(Verifier.match(From, Matcher));
1332 EXPECT_TRUE(Verifier.match(To, Matcher));
1333}
1334
1335TEST_P(ASTImporterTestBase, ShouldImportImplicitCXXRecordDeclOfClassTemplate) {
1336 Decl *From, *To;
1337 std::tie(From, To) = getImportedDecl(
1338 R"(
Peter Szecsidedda6f2018-03-30 22:03:29 +00001339 template <typename U>
1340 struct declToImport {
1341 };
1342 )",
1343 Lang_CXX, "", Lang_CXX);
1344
1345 MatchVerifier<Decl> Verifier;
1346 // Match the implicit Decl.
1347 auto Matcher = classTemplateDecl(has(cxxRecordDecl(has(cxxRecordDecl()))));
1348 ASSERT_TRUE(Verifier.match(From, Matcher));
1349 EXPECT_TRUE(Verifier.match(To, Matcher));
1350}
1351
1352TEST_P(
1353 ASTImporterTestBase,
Gabor Martona3af5672018-05-23 14:24:02 +00001354 ShouldImportImplicitCXXRecordDeclOfClassTemplateSpecializationDecl) {
Peter Szecsidedda6f2018-03-30 22:03:29 +00001355 Decl *From, *To;
1356 std::tie(From, To) = getImportedDecl(
1357 R"(
1358 template<class T>
1359 class Base {};
1360 class declToImport : public Base<declToImport> {};
1361 )",
1362 Lang_CXX, "", Lang_CXX);
1363
1364 auto hasImplicitClass = has(cxxRecordDecl());
1365 auto Pattern = translationUnitDecl(has(classTemplateDecl(
1366 hasName("Base"),
1367 has(classTemplateSpecializationDecl(hasImplicitClass)))));
1368 ASSERT_TRUE(
1369 MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern));
1370 EXPECT_TRUE(
1371 MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
1372}
1373
1374TEST_P(ASTImporterTestBase, IDNSOrdinary) {
1375 Decl *From, *To;
1376 std::tie(From, To) =
1377 getImportedDecl("void declToImport() {}", Lang_CXX, "", Lang_CXX);
1378
1379 MatchVerifier<Decl> Verifier;
1380 auto Matcher = functionDecl();
1381 ASSERT_TRUE(Verifier.match(From, Matcher));
1382 EXPECT_TRUE(Verifier.match(To, Matcher));
1383 EXPECT_EQ(From->getIdentifierNamespace(), To->getIdentifierNamespace());
1384}
1385
Gabor Marton2ae9da32018-05-18 15:46:18 +00001386TEST_P(ASTImporterTestBase, IDNSOfNonmemberOperator) {
Peter Szecsidedda6f2018-03-30 22:03:29 +00001387 Decl *FromTU = getTuDecl(
1388 R"(
1389 struct X {};
1390 void operator<<(int, X);
1391 )",
1392 Lang_CXX);
1393 Decl *From = LastDeclMatcher<Decl>{}.match(FromTU, functionDecl());
1394 const Decl *To = Import(From, Lang_CXX);
1395 EXPECT_EQ(From->getIdentifierNamespace(), To->getIdentifierNamespace());
1396}
1397
1398TEST_P(ASTImporterTestBase,
1399 ShouldImportMembersOfClassTemplateSpecializationDecl) {
1400 Decl *From, *To;
1401 std::tie(From, To) = getImportedDecl(
1402 R"(
1403 template<class T>
1404 class Base { int a; };
1405 class declToImport : Base<declToImport> {};
1406 )",
1407 Lang_CXX, "", Lang_CXX);
1408
1409 auto Pattern = translationUnitDecl(has(classTemplateDecl(
1410 hasName("Base"),
1411 has(classTemplateSpecializationDecl(has(fieldDecl(hasName("a"))))))));
1412 ASSERT_TRUE(
1413 MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern));
1414 EXPECT_TRUE(
1415 MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
1416}
1417
Aleksei Sidorin761c2242018-05-15 11:09:07 +00001418TEST_P(ASTImporterTestBase, ImportDefinitionOfClassTemplateAfterFwdDecl) {
1419 {
1420 Decl *FromTU = getTuDecl(
1421 R"(
1422 template <typename T>
1423 struct B;
1424 )",
1425 Lang_CXX, "input0.cc");
1426 auto *FromD = FirstDeclMatcher<ClassTemplateDecl>().match(
1427 FromTU, classTemplateDecl(hasName("B")));
1428
1429 Import(FromD, Lang_CXX);
1430 }
1431
1432 {
1433 Decl *FromTU = getTuDecl(
1434 R"(
1435 template <typename T>
1436 struct B {
1437 void f();
1438 };
1439 )",
1440 Lang_CXX, "input1.cc");
1441 FunctionDecl *FromD = FirstDeclMatcher<FunctionDecl>().match(
1442 FromTU, functionDecl(hasName("f")));
1443 Import(FromD, Lang_CXX);
1444 auto *FromCTD = FirstDeclMatcher<ClassTemplateDecl>().match(
1445 FromTU, classTemplateDecl(hasName("B")));
1446 auto *ToCTD = cast<ClassTemplateDecl>(Import(FromCTD, Lang_CXX));
1447 EXPECT_TRUE(ToCTD->isThisDeclarationADefinition());
1448 }
1449}
1450
Gabor Marton9581c332018-05-23 13:53:36 +00001451TEST_P(ASTImporterTestBase,
1452 ImportDefinitionOfClassTemplateIfThereIsAnExistingFwdDeclAndDefinition) {
1453 Decl *ToTU = getToTuDecl(
1454 R"(
1455 template <typename T>
1456 struct B {
1457 void f();
1458 };
1459
1460 template <typename T>
1461 struct B;
1462 )",
1463 Lang_CXX);
1464 ASSERT_EQ(1u, DeclCounterWithPredicate<ClassTemplateDecl>(
1465 [](const ClassTemplateDecl *T) {
1466 return T->isThisDeclarationADefinition();
1467 })
1468 .match(ToTU, classTemplateDecl()));
1469
1470 Decl *FromTU = getTuDecl(
1471 R"(
1472 template <typename T>
1473 struct B {
1474 void f();
1475 };
1476 )",
1477 Lang_CXX, "input1.cc");
1478 ClassTemplateDecl *FromD = FirstDeclMatcher<ClassTemplateDecl>().match(
1479 FromTU, classTemplateDecl(hasName("B")));
1480
1481 Import(FromD, Lang_CXX);
1482
1483 // We should have only one definition.
1484 EXPECT_EQ(1u, DeclCounterWithPredicate<ClassTemplateDecl>(
1485 [](const ClassTemplateDecl *T) {
1486 return T->isThisDeclarationADefinition();
1487 })
1488 .match(ToTU, classTemplateDecl()));
1489}
1490
1491TEST_P(ASTImporterTestBase,
1492 ImportDefinitionOfClassIfThereIsAnExistingFwdDeclAndDefinition) {
1493 Decl *ToTU = getToTuDecl(
1494 R"(
1495 struct B {
1496 void f();
1497 };
1498
1499 struct B;
1500 )",
1501 Lang_CXX);
1502 ASSERT_EQ(2u, DeclCounter<CXXRecordDecl>().match(
Hans Wennborgd0a8ad32018-05-24 10:49:38 +00001503 ToTU, cxxRecordDecl(unless(isImplicit()))));
Gabor Marton9581c332018-05-23 13:53:36 +00001504
1505 Decl *FromTU = getTuDecl(
1506 R"(
1507 struct B {
1508 void f();
1509 };
1510 )",
1511 Lang_CXX, "input1.cc");
1512 auto *FromD = FirstDeclMatcher<CXXRecordDecl>().match(
1513 FromTU, cxxRecordDecl(hasName("B")));
1514
1515 Import(FromD, Lang_CXX);
1516
1517 EXPECT_EQ(2u, DeclCounter<CXXRecordDecl>().match(
Hans Wennborgd0a8ad32018-05-24 10:49:38 +00001518 ToTU, cxxRecordDecl(unless(isImplicit()))));
Gabor Marton9581c332018-05-23 13:53:36 +00001519}
1520
1521TEST_P(
1522 ASTImporterTestBase,
1523 ImportDefinitionOfClassTemplateSpecIfThereIsAnExistingFwdDeclAndDefinition)
1524{
1525 Decl *ToTU = getToTuDecl(
1526 R"(
1527 template <typename T>
1528 struct B;
1529
1530 template <>
1531 struct B<int> {};
1532
1533 template <>
1534 struct B<int>;
1535 )",
1536 Lang_CXX);
1537 // We should have only one definition.
1538 ASSERT_EQ(1u, DeclCounterWithPredicate<ClassTemplateSpecializationDecl>(
1539 [](const ClassTemplateSpecializationDecl *T) {
1540 return T->isThisDeclarationADefinition();
1541 })
1542 .match(ToTU, classTemplateSpecializationDecl()));
1543
1544 Decl *FromTU = getTuDecl(
1545 R"(
1546 template <typename T>
1547 struct B;
1548
1549 template <>
1550 struct B<int> {};
1551 )",
1552 Lang_CXX, "input1.cc");
1553 auto *FromD = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
1554 FromTU, classTemplateSpecializationDecl(hasName("B")));
1555
1556 Import(FromD, Lang_CXX);
1557
1558 // We should have only one definition.
1559 EXPECT_EQ(1u, DeclCounterWithPredicate<ClassTemplateSpecializationDecl>(
1560 [](const ClassTemplateSpecializationDecl *T) {
1561 return T->isThisDeclarationADefinition();
1562 })
1563 .match(ToTU, classTemplateSpecializationDecl()));
1564}
1565
Peter Szecsidedda6f2018-03-30 22:03:29 +00001566INSTANTIATE_TEST_CASE_P(
1567 ParameterizedTests, ASTImporterTestBase,
1568 ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
1569
1570struct ImportFunctions : ASTImporterTestBase {};
1571
1572TEST_P(ImportFunctions,
1573 PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition) {
1574 Decl *FromTU = getTuDecl("void f();", Lang_CXX);
1575 auto Pattern = functionDecl(hasName("f"));
1576 FunctionDecl *FromD =
1577 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1578
1579 Decl *ImportedD = Import(FromD, Lang_CXX);
1580 Decl *ToTU = ImportedD->getTranslationUnitDecl();
1581
1582 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1583 EXPECT_TRUE(!cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1584}
1585
1586TEST_P(ImportFunctions,
1587 PrototypeShouldBeImportedAsDefintionWhenThereIsADefinition) {
1588 Decl *FromTU = getTuDecl("void f(); void f() {}", Lang_CXX);
1589 auto Pattern = functionDecl(hasName("f"));
1590 FunctionDecl *FromD = // Prototype
1591 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1592
1593 Decl *ImportedD = Import(FromD, Lang_CXX);
1594 Decl *ToTU = ImportedD->getTranslationUnitDecl();
1595
1596 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1597 EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1598}
1599
1600TEST_P(ImportFunctions,
1601 DefinitionShouldBeImportedAsDefintionWhenThereIsAPrototype) {
1602 Decl *FromTU = getTuDecl("void f(); void f() {}", Lang_CXX);
1603 auto Pattern = functionDecl(hasName("f"));
1604 FunctionDecl *FromD = // Definition
1605 LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1606
1607 Decl *ImportedD = Import(FromD, Lang_CXX);
1608 Decl *ToTU = ImportedD->getTranslationUnitDecl();
1609
1610 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1611 EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1612}
1613
1614TEST_P(ImportFunctions, DefinitionShouldBeImportedAsADefinition) {
1615 Decl *FromTU = getTuDecl("void f() {}", Lang_CXX);
1616 auto Pattern = functionDecl(hasName("f"));
1617 FunctionDecl *FromD =
1618 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1619
1620 Decl *ImportedD = Import(FromD, Lang_CXX);
1621 Decl *ToTU = ImportedD->getTranslationUnitDecl();
1622
1623 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1624 EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1625}
1626
1627TEST_P(ImportFunctions, DISABLED_ImportPrototypeOfRecursiveFunction) {
1628 Decl *FromTU = getTuDecl("void f(); void f() { f(); }", Lang_CXX);
1629 auto Pattern = functionDecl(hasName("f"));
1630 FunctionDecl *PrototypeFD =
1631 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1632
1633 Decl *ImportedD = Import(PrototypeFD, Lang_CXX);
1634 Decl *ToTU = ImportedD->getTranslationUnitDecl();
1635
1636 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1637 EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1638}
1639
1640TEST_P(ImportFunctions, ImportDefinitionOfRecursiveFunction) {
1641 Decl *FromTU = getTuDecl("void f(); void f() { f(); }", Lang_CXX);
1642 auto Pattern = functionDecl(hasName("f"));
1643 FunctionDecl *DefinitionFD =
1644 LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1645
1646 Decl *ImportedD = Import(DefinitionFD, Lang_CXX);
1647 Decl *ToTU = ImportedD->getTranslationUnitDecl();
1648
1649 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1650 EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1651}
1652
1653TEST_P(ImportFunctions, ImportPrototypes) {
1654 auto Pattern = functionDecl(hasName("f"));
1655
1656 Decl *ImportedD;
1657 {
1658 Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input0.cc");
1659 FunctionDecl *FromD =
1660 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1661
1662 ImportedD = Import(FromD, Lang_CXX);
1663 }
1664 Decl *ImportedD1;
1665 {
1666 Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input1.cc");
1667 FunctionDecl *FromD =
1668 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1669 ImportedD1 = Import(FromD, Lang_CXX);
1670 }
1671
1672 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
1673 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1674 EXPECT_EQ(ImportedD, ImportedD1);
1675 EXPECT_TRUE(!cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1676}
1677
1678TEST_P(ImportFunctions, ImportDefinitionThenPrototype) {
1679 auto Pattern = functionDecl(hasName("f"));
1680
1681 Decl *ImportedD;
1682 {
1683 Decl *FromTU = getTuDecl("void f(){}", Lang_CXX, "input0.cc");
1684 FunctionDecl *FromD =
1685 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1686
1687 ImportedD = Import(FromD, Lang_CXX);
1688 }
1689 Decl *ImportedD1;
1690 {
1691 Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input1.cc");
1692 FunctionDecl *FromD =
1693 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1694 ImportedD1 = Import(FromD, Lang_CXX);
1695 }
1696
1697 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
1698 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1699 EXPECT_EQ(ImportedD, ImportedD1);
1700 EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1701}
1702
1703TEST_P(ImportFunctions, ImportPrototypeThenDefinition) {
1704 auto Pattern = functionDecl(hasName("f"));
1705
1706 {
1707 Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input0.cc");
1708 FunctionDecl *FromD =
1709 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1710
1711 Import(FromD, Lang_CXX);
1712 }
1713 {
1714 Decl *FromTU = getTuDecl("void f(){}", Lang_CXX, "input1.cc");
1715 FunctionDecl *FromD =
1716 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1717 Import(FromD, Lang_CXX);
1718 }
1719
1720 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
1721 ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
1722 FunctionDecl *ProtoD = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
1723 EXPECT_TRUE(!ProtoD->doesThisDeclarationHaveABody());
1724 FunctionDecl *DefinitionD =
1725 LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
1726 EXPECT_TRUE(DefinitionD->doesThisDeclarationHaveABody());
1727 EXPECT_EQ(DefinitionD->getPreviousDecl(), ProtoD);
1728}
1729
1730TEST_P(ImportFunctions, DISABLED_ImportPrototypeThenProtoAndDefinition) {
1731 auto Pattern = functionDecl(hasName("f"));
1732
1733 {
1734 Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input0.cc");
1735 FunctionDecl *FromD =
1736 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1737
1738 Import(FromD, Lang_CXX);
1739 }
1740 {
1741 Decl *FromTU = getTuDecl("void f(); void f(){}", Lang_CXX, "input1.cc");
1742 FunctionDecl *FromD =
1743 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1744 Import(FromD, Lang_CXX);
1745 }
1746
1747 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
1748 ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
1749 FunctionDecl *ProtoD = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
1750 EXPECT_TRUE(!ProtoD->doesThisDeclarationHaveABody());
1751 FunctionDecl *DefinitionD =
1752 LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
1753 EXPECT_TRUE(DefinitionD->doesThisDeclarationHaveABody());
1754 EXPECT_EQ(DefinitionD->getPreviousDecl(), ProtoD);
1755}
1756
1757TEST_P(ImportFunctions, OverriddenMethodsShouldBeImported) {
1758 auto Code =
1759 R"(
1760 struct B { virtual void f(); };
1761 void B::f() {}
1762 struct D : B { void f(); };
1763 )";
1764 auto Pattern =
1765 cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D"))));
1766 Decl *FromTU = getTuDecl(Code, Lang_CXX);
1767 CXXMethodDecl *Proto =
1768 FirstDeclMatcher<CXXMethodDecl>().match(FromTU, Pattern);
1769
1770 ASSERT_EQ(Proto->size_overridden_methods(), 1u);
1771 CXXMethodDecl *To = cast<CXXMethodDecl>(Import(Proto, Lang_CXX));
1772 EXPECT_EQ(To->size_overridden_methods(), 1u);
1773}
1774
1775TEST_P(ImportFunctions, VirtualFlagShouldBePreservedWhenImportingPrototype) {
1776 auto Code =
1777 R"(
1778 struct B { virtual void f(); };
1779 void B::f() {}
1780 )";
1781 auto Pattern =
1782 cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B"))));
1783 Decl *FromTU = getTuDecl(Code, Lang_CXX);
1784 CXXMethodDecl *Proto =
1785 FirstDeclMatcher<CXXMethodDecl>().match(FromTU, Pattern);
1786 CXXMethodDecl *Def = LastDeclMatcher<CXXMethodDecl>().match(FromTU, Pattern);
1787
1788 ASSERT_TRUE(Proto->isVirtual());
1789 ASSERT_TRUE(Def->isVirtual());
1790 CXXMethodDecl *To = cast<CXXMethodDecl>(Import(Proto, Lang_CXX));
1791 EXPECT_TRUE(To->isVirtual());
1792}
1793
1794INSTANTIATE_TEST_CASE_P(
1795 ParameterizedTests, ImportFunctions,
1796 ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
1797
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +00001798AST_MATCHER_P(TagDecl, hasTypedefForAnonDecl, Matcher<TypedefNameDecl>,
1799 InnerMatcher) {
1800 if (auto *Typedef = Node.getTypedefNameForAnonDecl())
1801 return InnerMatcher.matches(*Typedef, Finder, Builder);
1802 return false;
1803}
1804
1805TEST(ImportDecl, ImportEnumSequential) {
1806 CodeFiles Samples{{"main.c",
1807 {"void foo();"
1808 "void moo();"
1809 "int main() { foo(); moo(); }",
1810 Lang_C}},
1811
1812 {"foo.c",
1813 {"typedef enum { THING_VALUE } thing_t;"
1814 "void conflict(thing_t type);"
1815 "void foo() { (void)THING_VALUE; }"
1816 "void conflict(thing_t type) {}",
1817 Lang_C}},
1818
1819 {"moo.c",
1820 {"typedef enum { THING_VALUE } thing_t;"
1821 "void conflict(thing_t type);"
1822 "void moo() { conflict(THING_VALUE); }",
1823 Lang_C}}};
1824
1825 auto VerificationMatcher =
1826 enumDecl(has(enumConstantDecl(hasName("THING_VALUE"))),
1827 hasTypedefForAnonDecl(hasName("thing_t")));
1828
1829 ImportAction ImportFoo{"foo.c", "main.c", functionDecl(hasName("foo"))},
1830 ImportMoo{"moo.c", "main.c", functionDecl(hasName("moo"))};
1831
1832 testImportSequence(
1833 Samples, {ImportFoo, ImportMoo}, // "foo", them "moo".
1834 // Just check that there is only one enum decl in the result AST.
1835 "main.c", enumDecl(), VerificationMatcher);
1836
1837 // For different import order, result should be the same.
1838 testImportSequence(
1839 Samples, {ImportMoo, ImportFoo}, // "moo", them "foo".
1840 // Check that there is only one enum decl in the result AST.
1841 "main.c", enumDecl(), VerificationMatcher);
1842}
1843
Peter Szecsice7f3182018-05-07 12:08:27 +00001844const internal::VariadicDynCastAllOfMatcher<Expr, DependentScopeDeclRefExpr>
1845 dependentScopeDeclRefExpr;
1846
1847TEST(ImportExpr, DependentScopeDeclRefExpr) {
1848 MatchVerifier<Decl> Verifier;
1849 testImport("template <typename T> struct S { static T foo; };"
1850 "template <typename T> void declToImport() {"
1851 " (void) S<T>::foo;"
1852 "}"
1853 "void instantiate() { declToImport<int>(); }",
1854 Lang_CXX11, "", Lang_CXX11, Verifier,
1855 functionTemplateDecl(has(functionDecl(has(compoundStmt(
1856 has(cStyleCastExpr(has(dependentScopeDeclRefExpr())))))))));
1857
1858 testImport("template <typename T> struct S {"
1859 "template<typename S> static void foo(){};"
1860 "};"
1861 "template <typename T> void declToImport() {"
1862 " S<T>::template foo<T>();"
1863 "}"
1864 "void instantiate() { declToImport<int>(); }",
1865 Lang_CXX11, "", Lang_CXX11, Verifier,
1866 functionTemplateDecl(has(functionDecl(has(compoundStmt(
1867 has(callExpr(has(dependentScopeDeclRefExpr())))))))));
1868}
1869
1870const internal::VariadicDynCastAllOfMatcher<Type, DependentNameType>
1871 dependentNameType;
1872
1873TEST(ImportExpr, DependentNameType) {
1874 MatchVerifier<Decl> Verifier;
1875 testImport("template <typename T> struct declToImport {"
1876 " typedef typename T::type dependent_name;"
1877 "};",
1878 Lang_CXX11, "", Lang_CXX11, Verifier,
1879 classTemplateDecl(has(
1880 cxxRecordDecl(has(typedefDecl(has(dependentNameType())))))));
1881}
1882
1883const internal::VariadicDynCastAllOfMatcher<Expr, UnresolvedMemberExpr>
1884 unresolvedMemberExpr;
1885
1886TEST(ImportExpr, UnresolvedMemberExpr) {
1887 MatchVerifier<Decl> Verifier;
1888 testImport("struct S { template <typename T> void mem(); };"
1889 "template <typename U> void declToImport() {"
1890 " S s;"
1891 " s.mem<U>();"
1892 "}"
1893 "void instantiate() { declToImport<int>(); }",
1894 Lang_CXX11, "", Lang_CXX11, Verifier,
1895 functionTemplateDecl(has(functionDecl(has(
1896 compoundStmt(has(callExpr(has(unresolvedMemberExpr())))))))));
1897}
1898
Gabor Marton61d862a2018-05-18 09:08:47 +00001899struct DeclContextTest : ASTImporterTestBase {};
1900
1901TEST_P(DeclContextTest, removeDeclOfClassTemplateSpecialization) {
1902 Decl *TU = getTuDecl(
1903 R"(
1904 namespace NS {
1905
1906 template <typename T>
1907 struct S {};
1908 template struct S<int>;
1909
1910 inline namespace INS {
1911 template <typename T>
1912 struct S {};
1913 template struct S<int>;
1914 }
1915
1916 }
1917 )", Lang_CXX11, "input0.cc");
1918 auto *NS = FirstDeclMatcher<NamespaceDecl>().match(
1919 TU, namespaceDecl());
1920 auto *Spec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
1921 TU, classTemplateSpecializationDecl());
1922 ASSERT_TRUE(NS->containsDecl(Spec));
1923
1924 NS->removeDecl(Spec);
1925 EXPECT_FALSE(NS->containsDecl(Spec));
1926}
1927
1928INSTANTIATE_TEST_CASE_P(
1929 ParameterizedTests, DeclContextTest,
1930 ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
1931
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +00001932} // end namespace ast_matchers
1933} // end namespace clang