blob: a4c823008d96619c63927e6191f607c80186af21 [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"
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000022#include "gtest/gtest.h"
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000023#include "llvm/ADT/StringMap.h"
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000024
25namespace clang {
26namespace ast_matchers {
27
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000028using internal::Matcher;
29using internal::BindableMatcher;
30using llvm::StringMap;
31
Aleksei Sidorine45ab562017-12-21 17:41:06 +000032typedef std::vector<std::string> ArgVector;
33typedef std::vector<ArgVector> RunOptions;
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000034
Aleksei Sidorine45ab562017-12-21 17:41:06 +000035static bool isCXX(Language Lang) {
36 return Lang == Lang_CXX || Lang == Lang_CXX11;
37}
38
Peter Szecsidedda6f2018-03-30 22:03:29 +000039static ArgVector getBasicRunOptionsForLanguage(Language Lang) {
Aleksei Sidorine45ab562017-12-21 17:41:06 +000040 ArgVector BasicArgs;
41 // Test with basic arguments.
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000042 switch (Lang) {
43 case Lang_C:
Aleksei Sidorine45ab562017-12-21 17:41:06 +000044 BasicArgs = {"-x", "c", "-std=c99"};
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000045 break;
46 case Lang_C89:
Aleksei Sidorine45ab562017-12-21 17:41:06 +000047 BasicArgs = {"-x", "c", "-std=c89"};
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000048 break;
49 case Lang_CXX:
Gabor Horvathd2c562d2018-01-27 16:38:56 +000050 BasicArgs = {"-std=c++98", "-frtti"};
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000051 break;
52 case Lang_CXX11:
Gabor Horvathd2c562d2018-01-27 16:38:56 +000053 BasicArgs = {"-std=c++11", "-frtti"};
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000054 break;
55 case Lang_OpenCL:
56 case Lang_OBJCXX:
Aleksei Sidorine45ab562017-12-21 17:41:06 +000057 llvm_unreachable("Not implemented yet!");
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000058 }
Peter Szecsidedda6f2018-03-30 22:03:29 +000059 return BasicArgs;
60}
61
62static RunOptions getRunOptionsForLanguage(Language Lang) {
63 ArgVector BasicArgs = getBasicRunOptionsForLanguage(Lang);
Aleksei Sidorine45ab562017-12-21 17:41:06 +000064
65 // For C++, test with "-fdelayed-template-parsing" enabled to handle MSVC
66 // default behaviour.
67 if (isCXX(Lang)) {
68 ArgVector ArgsForDelayedTemplateParse = BasicArgs;
69 ArgsForDelayedTemplateParse.emplace_back("-fdelayed-template-parsing");
70 return {BasicArgs, ArgsForDelayedTemplateParse};
71 }
72
73 return {BasicArgs};
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000074}
75
Peter Szecsidedda6f2018-03-30 22:03:29 +000076// Creates a virtual file and assigns that to the context of given AST. If the
77// file already exists then the file will not be created again as a duplicate.
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000078static void
79createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
80 std::unique_ptr<llvm::MemoryBuffer> &&Buffer) {
Peter Szecsidedda6f2018-03-30 22:03:29 +000081 assert(ToAST);
82 ASTContext &ToCtx = ToAST->getASTContext();
83 auto *OFS = static_cast<vfs::OverlayFileSystem *>(
84 ToCtx.getSourceManager().getFileManager().getVirtualFileSystem().get());
85 auto *MFS =
86 static_cast<vfs::InMemoryFileSystem *>(OFS->overlays_begin()->get());
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000087 MFS->addFile(FileName, 0, std::move(Buffer));
Peter Szecsidedda6f2018-03-30 22:03:29 +000088}
89
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000090static void createVirtualFileIfNeeded(ASTUnit *ToAST, StringRef FileName,
91 StringRef Code) {
92 return createVirtualFileIfNeeded(ToAST, FileName,
93 llvm::MemoryBuffer::getMemBuffer(Code));
94}
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +000095
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +000096template <typename NodeType>
97NodeType importNode(ASTUnit *From, ASTUnit *To, ASTImporter &Importer,
98 NodeType Node) {
99 ASTContext &ToCtx = To->getASTContext();
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000100
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +0000101 // Add 'From' file to virtual file system so importer can 'find' it
102 // while importing SourceLocations. It is safe to add same file multiple
103 // times - it just isn't replaced.
104 StringRef FromFileName = From->getMainFileName();
105 createVirtualFileIfNeeded(To, FromFileName,
106 From->getBufferForFile(FromFileName));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000107
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +0000108 auto Imported = Importer.Import(Node);
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000109
110 // This should dump source locations and assert if some source locations
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000111 // were not imported.
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000112 SmallString<1024> ImportChecker;
113 llvm::raw_svector_ostream ToNothing(ImportChecker);
114 ToCtx.getTranslationUnitDecl()->print(ToNothing);
115
Gabor Horvath480892b2017-10-18 09:25:18 +0000116 // This traverses the AST to catch certain bugs like poorly or not
117 // implemented subtrees.
118 Imported->dump(ToNothing);
119
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +0000120 return Imported;
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000121}
122
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +0000123const StringRef DeclToImportID = "declToImport";
124const StringRef DeclToVerifyID = "declToVerify";
125
126template <typename NodeType>
127testing::AssertionResult
128testImport(const std::string &FromCode, const ArgVector &FromArgs,
129 const std::string &ToCode, const ArgVector &ToArgs,
130 MatchVerifier<NodeType> &Verifier,
131 const BindableMatcher<NodeType> &SearchMatcher,
132 const BindableMatcher<NodeType> &VerificationMatcher) {
133 const char *const InputFileName = "input.cc";
134 const char *const OutputFileName = "output.cc";
135
136 std::unique_ptr<ASTUnit>
137 FromAST = tooling::buildASTFromCodeWithArgs(
138 FromCode, FromArgs, InputFileName),
139 ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, OutputFileName);
140
141 ASTContext &FromCtx = FromAST->getASTContext(),
142 &ToCtx = ToAST->getASTContext();
143
144 ASTImporter Importer(ToCtx, ToAST->getFileManager(),
145 FromCtx, FromAST->getFileManager(), false);
146
147 auto FoundNodes = match(SearchMatcher, FromCtx);
148 if (FoundNodes.size() != 1)
149 return testing::AssertionFailure()
150 << "Multiple potential nodes were found!";
151
152 auto ToImport = selectFirst<NodeType>(DeclToImportID, FoundNodes);
153 if (!ToImport)
154 return testing::AssertionFailure() << "Node type mismatch!";
155
156 // Sanity check: the node being imported should match in the same way as
157 // the result node.
158 BindableMatcher<NodeType> WrapperMatcher(VerificationMatcher);
159 EXPECT_TRUE(Verifier.match(ToImport, WrapperMatcher));
160
161 auto Imported = importNode(FromAST.get(), ToAST.get(), Importer, ToImport);
162 if (!Imported)
163 return testing::AssertionFailure() << "Import failed, nullptr returned!";
164
165 return Verifier.match(Imported, WrapperMatcher);
166}
167
168template <typename NodeType>
169testing::AssertionResult
170testImport(const std::string &FromCode, const ArgVector &FromArgs,
171 const std::string &ToCode, const ArgVector &ToArgs,
172 MatchVerifier<NodeType> &Verifier,
173 const BindableMatcher<NodeType> &VerificationMatcher) {
174 return testImport(
175 FromCode, FromArgs, ToCode, ToArgs, Verifier,
176 translationUnitDecl(
177 has(namedDecl(hasName(DeclToImportID)).bind(DeclToImportID))),
178 VerificationMatcher);
179}
180
181/// Test how AST node named "declToImport" located in the translation unit
182/// of "FromCode" virtual file is imported to "ToCode" virtual file.
183/// The verification is done by running AMatcher over the imported node.
184template <typename NodeType, typename MatcherType>
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000185void testImport(const std::string &FromCode, Language FromLang,
186 const std::string &ToCode, Language ToLang,
187 MatchVerifier<NodeType> &Verifier,
188 const MatcherType &AMatcher) {
189 auto RunOptsFrom = getRunOptionsForLanguage(FromLang);
190 auto RunOptsTo = getRunOptionsForLanguage(ToLang);
191 for (const auto &FromArgs : RunOptsFrom)
192 for (const auto &ToArgs : RunOptsTo)
193 EXPECT_TRUE(testImport(FromCode, FromArgs, ToCode, ToArgs,
194 Verifier, AMatcher));
195}
196
Peter Szecsidedda6f2018-03-30 22:03:29 +0000197// This class provides generic methods to write tests which can check internal
198// attributes of AST nodes like getPreviousDecl(), isVirtual(), etc. Also,
199// this fixture makes it possible to import from several "From" contexts.
200class ASTImporterTestBase : public ::testing::TestWithParam<ArgVector> {
201
202 const char *const InputFileName = "input.cc";
203 const char *const OutputFileName = "output.cc";
204
205 // Buffer for the To context, must live in the test scope.
206 std::string ToCode;
207
208 struct TU {
209 // Buffer for the context, must live in the test scope.
Aleksei Sidorin54d6af52018-05-14 16:12:31 +0000210 std::string Code;
211 std::string FileName;
Peter Szecsidedda6f2018-03-30 22:03:29 +0000212 std::unique_ptr<ASTUnit> Unit;
213 TranslationUnitDecl *TUDecl = nullptr;
214 TU(StringRef Code, StringRef FileName, ArgVector Args)
215 : Code(Code), FileName(FileName),
216 Unit(tooling::buildASTFromCodeWithArgs(this->Code, Args,
217 this->FileName)),
218 TUDecl(Unit->getASTContext().getTranslationUnitDecl()) {}
219 };
220
221 // We may have several From contexts and related translation units. In each
222 // AST, the buffers for the source are handled via references and are set
223 // during the creation of the AST. These references must point to a valid
224 // buffer until the AST is alive. Thus, we must use a list in order to avoid
225 // moving of the stored objects because that would mean breaking the
226 // references in the AST. By using a vector a move could happen when the
227 // vector is expanding, with the list we won't have these issues.
228 std::list<TU> FromTUs;
229
230public:
231 // We may have several From context but only one To context.
232 std::unique_ptr<ASTUnit> ToAST;
233
234 // Returns the argument vector used for a specific language, this set
235 // can be tweaked by the test parameters.
236 ArgVector getArgVectorForLanguage(Language Lang) {
237 ArgVector Args = getBasicRunOptionsForLanguage(Lang);
238 ArgVector ExtraArgs = GetParam();
239 for (const auto& Arg : ExtraArgs) {
240 Args.push_back(Arg);
241 }
242 return Args;
243 }
244
245 // Creates an AST both for the From and To source code and imports the Decl
246 // of the identifier into the To context.
247 // Must not be called more than once within the same test.
248 std::tuple<Decl *, Decl *>
249 getImportedDecl(StringRef FromSrcCode, Language FromLang, StringRef ToSrcCode,
250 Language ToLang, StringRef Identifier = DeclToImportID) {
251 ArgVector FromArgs = getArgVectorForLanguage(FromLang),
252 ToArgs = getArgVectorForLanguage(ToLang);
253
254 FromTUs.emplace_back(FromSrcCode, InputFileName, FromArgs);
255 TU &FromTU = FromTUs.back();
256
257 ToCode = ToSrcCode;
258 assert(!ToAST);
259 ToAST = tooling::buildASTFromCodeWithArgs(ToCode, ToArgs, OutputFileName);
260
261 ASTContext &FromCtx = FromTU.Unit->getASTContext(),
262 &ToCtx = ToAST->getASTContext();
263
264 createVirtualFileIfNeeded(ToAST.get(), InputFileName, FromTU.Code);
265
266 ASTImporter Importer(ToCtx, ToAST->getFileManager(), FromCtx,
267 FromTU.Unit->getFileManager(), false);
268
269 IdentifierInfo *ImportedII = &FromCtx.Idents.get(Identifier);
270 assert(ImportedII && "Declaration with the given identifier "
271 "should be specified in test!");
272 DeclarationName ImportDeclName(ImportedII);
273 SmallVector<NamedDecl *, 4> FoundDecls;
274 FromCtx.getTranslationUnitDecl()->localUncachedLookup(ImportDeclName,
275 FoundDecls);
276
277 assert(FoundDecls.size() == 1);
278
279 Decl *Imported = Importer.Import(FoundDecls.front());
280 assert(Imported);
281 return std::make_tuple(*FoundDecls.begin(), Imported);
282 }
283
284 // Creates a TU decl for the given source code.
285 // May be called several times in a given test.
286 TranslationUnitDecl *getTuDecl(StringRef SrcCode, Language Lang,
287 StringRef FileName = "input.cc") {
288 assert(
289 std::find_if(FromTUs.begin(), FromTUs.end(), [FileName](const TU &E) {
290 return E.FileName == FileName;
291 }) == FromTUs.end());
292
293 ArgVector Args = getArgVectorForLanguage(Lang);
294 FromTUs.emplace_back(SrcCode, FileName, Args);
295 TU &Tu = FromTUs.back();
296
297 return Tu.TUDecl;
298 }
299
300 // Import the given Decl into the ToCtx.
301 // May be called several times in a given test.
302 // The different instances of the param From may have different ASTContext.
303 Decl *Import(Decl *From, Language ToLang) {
304 if (!ToAST) {
305 ArgVector ToArgs = getArgVectorForLanguage(ToLang);
306 // Build the AST from an empty file.
307 ToAST =
308 tooling::buildASTFromCodeWithArgs(/*Code=*/"", ToArgs, "empty.cc");
309 }
310
311 // Create a virtual file in the To Ctx which corresponds to the file from
312 // which we want to import the `From` Decl. Without this source locations
313 // will be invalid in the ToCtx.
314 auto It = std::find_if(FromTUs.begin(), FromTUs.end(), [From](const TU &E) {
315 return E.TUDecl == From->getTranslationUnitDecl();
316 });
317 assert(It != FromTUs.end());
318 createVirtualFileIfNeeded(ToAST.get(), It->FileName, It->Code);
319
320 ASTContext &FromCtx = From->getASTContext(),
321 &ToCtx = ToAST->getASTContext();
322 ASTImporter Importer(ToCtx, ToAST->getFileManager(), FromCtx,
323 FromCtx.getSourceManager().getFileManager(), false);
324 return Importer.Import(From);
325 }
326
327 ~ASTImporterTestBase() {
328 if (!::testing::Test::HasFailure()) return;
329
330 for (auto &Tu : FromTUs) {
331 assert(Tu.Unit);
332 llvm::errs() << "FromAST:\n";
333 Tu.Unit->getASTContext().getTranslationUnitDecl()->dump();
334 llvm::errs() << "\n";
335 }
336 if (ToAST) {
337 llvm::errs() << "ToAST:\n";
338 ToAST->getASTContext().getTranslationUnitDecl()->dump();
339 }
340 }
341};
342
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +0000343
344struct ImportAction {
345 StringRef FromFilename;
346 StringRef ToFilename;
347 // FIXME: Generalize this to support other node kinds.
348 BindableMatcher<Decl> ImportPredicate;
349
350 ImportAction(StringRef FromFilename, StringRef ToFilename,
351 DeclarationMatcher ImportPredicate)
352 : FromFilename(FromFilename), ToFilename(ToFilename),
353 ImportPredicate(ImportPredicate) {}
354
355 ImportAction(StringRef FromFilename, StringRef ToFilename,
356 const std::string &DeclName)
357 : FromFilename(FromFilename), ToFilename(ToFilename),
358 ImportPredicate(namedDecl(hasName(DeclName))) {}
359};
360
361using SingleASTUnitForAllOpts = std::vector<std::unique_ptr<ASTUnit>>;
362using AllASTUnitsForAllOpts = StringMap<SingleASTUnitForAllOpts>;
363
364struct CodeEntry {
365 std::string CodeSample;
366 Language Lang;
367
368 /// Builds N copies of ASTUnits for each potential compile options set
369 /// for further import actions. N is equal to size of this option set.
370 SingleASTUnitForAllOpts createASTUnits(StringRef FileName) const {
371 auto RunOpts = getRunOptionsForLanguage(Lang);
372 size_t NumOpts = RunOpts.size();
373 SingleASTUnitForAllOpts ResultASTs(NumOpts);
374 for (size_t CompileOpt = 0; CompileOpt < NumOpts; ++CompileOpt) {
375 auto AST = tooling::buildASTFromCodeWithArgs(
376 CodeSample, RunOpts[CompileOpt], FileName);
377 EXPECT_TRUE(AST.get());
378 ResultASTs[CompileOpt] = std::move(AST);
379 }
380 return ResultASTs;
Peter Szecsidedda6f2018-03-30 22:03:29 +0000381 }
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +0000382};
383
384using CodeFiles = StringMap<CodeEntry>;
385
386/// Test an arbitrary sequence of imports for a set of given in-memory files.
387/// The verification is done by running VerificationMatcher against a specified
388/// AST node inside of one of given files.
389/// \param CodeSamples Map whose key is the file name and the value is the file
390/// content.
391/// \param ImportActions Sequence of imports. Each import in sequence
392/// specifies "from file" and "to file" and a matcher that is used for
393/// searching a declaration for import in "from file".
394/// \param FileForFinalCheck Name of virtual file for which the final check is
395/// applied.
396/// \param FinalSelectPredicate Matcher that specifies the AST node in the
397/// FileForFinalCheck for which the verification will be done.
398/// \param VerificationMatcher Matcher that will be used for verification after
399/// all imports in sequence are done.
400void testImportSequence(const CodeFiles &CodeSamples,
401 const std::vector<ImportAction> &ImportActions,
402 StringRef FileForFinalCheck,
403 BindableMatcher<Decl> FinalSelectPredicate,
404 BindableMatcher<Decl> VerificationMatcher) {
405 AllASTUnitsForAllOpts AllASTUnits;
406 using ImporterKey = std::pair<const ASTUnit *, const ASTUnit *>;
407 llvm::DenseMap<ImporterKey, std::unique_ptr<ASTImporter>> Importers;
408
409 auto GenASTsIfNeeded = [&AllASTUnits, &CodeSamples](StringRef Filename) {
410 if (!AllASTUnits.count(Filename)) {
411 auto Found = CodeSamples.find(Filename);
412 assert(Found != CodeSamples.end() && "Wrong file for import!");
413 AllASTUnits[Filename] = Found->getValue().createASTUnits(Filename);
414 }
415 };
416
417 size_t NumCompileOpts = 0;
418 for (const ImportAction &Action : ImportActions) {
419 StringRef FromFile = Action.FromFilename, ToFile = Action.ToFilename;
420 GenASTsIfNeeded(FromFile);
421 GenASTsIfNeeded(ToFile);
422 NumCompileOpts = AllASTUnits[FromFile].size();
423
424 for (size_t CompileOpt = 0; CompileOpt < NumCompileOpts; ++CompileOpt) {
425 ASTUnit *From = AllASTUnits[FromFile][CompileOpt].get();
426 ASTUnit *To = AllASTUnits[ToFile][CompileOpt].get();
427
428 // Create a new importer if needed.
429 std::unique_ptr<ASTImporter> &ImporterRef = Importers[{From, To}];
430 if (!ImporterRef)
431 ImporterRef.reset(new ASTImporter(
432 To->getASTContext(), To->getFileManager(), From->getASTContext(),
433 From->getFileManager(), false));
434
435 // Find the declaration and import it.
436 auto FoundDecl = match(Action.ImportPredicate.bind(DeclToImportID),
437 From->getASTContext());
438 EXPECT_TRUE(FoundDecl.size() == 1);
439 const Decl *ToImport = selectFirst<Decl>(DeclToImportID, FoundDecl);
440 auto Imported = importNode(From, To, *ImporterRef, ToImport);
441 EXPECT_TRUE(Imported);
442 }
443 }
444
445 // NOTE: We don't do cross-option import check here due to fast growth of
446 // potential option sets.
447 for (size_t CompileOpt = 0; CompileOpt < NumCompileOpts; ++CompileOpt) {
448 // Find the declaration and import it.
449 auto FoundDecl =
450 match(FinalSelectPredicate.bind(DeclToVerifyID),
451 AllASTUnits[FileForFinalCheck][CompileOpt]->getASTContext());
452 EXPECT_TRUE(FoundDecl.size() == 1);
453 const Decl *ToVerify = selectFirst<Decl>(DeclToVerifyID, FoundDecl);
454 MatchVerifier<Decl> Verifier;
455 EXPECT_TRUE(Verifier.match(ToVerify,
456 BindableMatcher<Decl>(VerificationMatcher)));
457 }
Peter Szecsidedda6f2018-03-30 22:03:29 +0000458}
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000459
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000460TEST(ImportExpr, ImportStringLiteral) {
461 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000462 testImport("void declToImport() { \"foo\"; }",
463 Lang_CXX, "", Lang_CXX, Verifier,
464 functionDecl(
465 hasBody(
466 compoundStmt(
467 has(
468 stringLiteral(
469 hasType(
470 asString("const char [4]"))))))));
471 testImport("void declToImport() { L\"foo\"; }",
472 Lang_CXX, "", Lang_CXX, Verifier,
473 functionDecl(
474 hasBody(
475 compoundStmt(
476 has(
477 stringLiteral(
478 hasType(
479 asString("const wchar_t [4]"))))))));
480 testImport("void declToImport() { \"foo\" \"bar\"; }",
481 Lang_CXX, "", Lang_CXX, Verifier,
482 functionDecl(
483 hasBody(
484 compoundStmt(
485 has(
486 stringLiteral(
487 hasType(
488 asString("const char [7]"))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000489}
490
491TEST(ImportExpr, ImportGNUNullExpr) {
492 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000493 testImport("void declToImport() { __null; }",
494 Lang_CXX, "", Lang_CXX, Verifier,
495 functionDecl(
496 hasBody(
497 compoundStmt(
498 has(
499 gnuNullExpr(
500 hasType(isInteger())))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000501}
502
503TEST(ImportExpr, ImportCXXNullPtrLiteralExpr) {
504 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000505 testImport("void declToImport() { nullptr; }",
506 Lang_CXX11, "", Lang_CXX11, Verifier,
507 functionDecl(
508 hasBody(
509 compoundStmt(
510 has(
511 cxxNullPtrLiteralExpr())))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000512}
513
514
515TEST(ImportExpr, ImportFloatinglLiteralExpr) {
516 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000517 testImport("void declToImport() { 1.0; }",
518 Lang_C, "", Lang_C, Verifier,
519 functionDecl(
520 hasBody(
521 compoundStmt(
522 has(
523 floatLiteral(
524 equals(1.0),
525 hasType(asString("double"))))))));
526 testImport("void declToImport() { 1.0e-5f; }",
527 Lang_C, "", Lang_C, Verifier,
528 functionDecl(
529 hasBody(
530 compoundStmt(
531 has(
532 floatLiteral(
533 equals(1.0e-5f),
534 hasType(asString("float"))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000535}
536
537TEST(ImportExpr, ImportCompoundLiteralExpr) {
538 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000539 testImport("void declToImport() {"
540 " struct s { int x; long y; unsigned z; }; "
541 " (struct s){ 42, 0L, 1U }; }",
542 Lang_CXX, "", Lang_CXX, Verifier,
543 functionDecl(
544 hasBody(
545 compoundStmt(
546 has(
547 compoundLiteralExpr(
548 hasType(asString("struct s")),
549 has(initListExpr(
550 hasType(asString("struct s")),
551 has(integerLiteral(
552 equals(42), hasType(asString("int")))),
553 has(integerLiteral(
554 equals(0), hasType(asString("long")))),
555 has(integerLiteral(
556 equals(1),
557 hasType(asString("unsigned int"))))
558 ))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000559}
560
561TEST(ImportExpr, ImportCXXThisExpr) {
562 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000563 testImport("class declToImport { void f() { this; } };",
564 Lang_CXX, "", Lang_CXX, Verifier,
565 cxxRecordDecl(
566 hasMethod(
567 hasBody(
568 compoundStmt(
569 has(
570 cxxThisExpr(
571 hasType(
572 asString("class declToImport *")))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000573}
574
575TEST(ImportExpr, ImportAtomicExpr) {
576 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000577 testImport("void declToImport() { int *ptr; __atomic_load_n(ptr, 1); }",
578 Lang_C, "", Lang_C, Verifier,
579 functionDecl(hasBody(compoundStmt(has(atomicExpr(
580 has(ignoringParenImpCasts(
581 declRefExpr(hasDeclaration(varDecl(hasName("ptr"))),
582 hasType(asString("int *"))))),
583 has(integerLiteral(equals(1), hasType(asString("int"))))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000584}
585
586TEST(ImportExpr, ImportLabelDeclAndAddrLabelExpr) {
587 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000588 testImport(
589 "void declToImport() { loop: goto loop; &&loop; }", Lang_C, "", Lang_C,
590 Verifier,
591 functionDecl(hasBody(compoundStmt(
592 has(labelStmt(hasDeclaration(labelDecl(hasName("loop"))))),
593 has(addrLabelExpr(hasDeclaration(labelDecl(hasName("loop")))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000594}
595
596AST_MATCHER_P(TemplateDecl, hasTemplateDecl,
597 internal::Matcher<NamedDecl>, InnerMatcher) {
598 const NamedDecl *Template = Node.getTemplatedDecl();
599 return Template && InnerMatcher.matches(*Template, Finder, Builder);
600}
601
602TEST(ImportExpr, ImportParenListExpr) {
603 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000604 testImport(
Manuel Klimek696e5052017-08-02 13:04:44 +0000605 "template<typename T> class dummy { void f() { dummy X(*this); } };"
606 "typedef dummy<int> declToImport;"
607 "template class dummy<int>;",
608 Lang_CXX, "", Lang_CXX, Verifier,
609 typedefDecl(hasType(templateSpecializationType(
610 hasDeclaration(classTemplateSpecializationDecl(hasSpecializedTemplate(
611 classTemplateDecl(hasTemplateDecl(cxxRecordDecl(hasMethod(allOf(
612 hasName("f"),
613 hasBody(compoundStmt(has(declStmt(hasSingleDecl(
614 varDecl(hasInitializer(parenListExpr(has(unaryOperator(
615 hasOperatorName("*"),
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000616 hasUnaryOperand(cxxThisExpr())))))))))))))))))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000617}
618
Gabor Horvath480892b2017-10-18 09:25:18 +0000619TEST(ImportExpr, ImportSwitch) {
620 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000621 testImport("void declToImport() { int b; switch (b) { case 1: break; } }",
622 Lang_C, "", Lang_C, Verifier,
623 functionDecl(hasBody(compoundStmt(
624 has(switchStmt(has(compoundStmt(has(caseStmt())))))))));
Gabor Horvath480892b2017-10-18 09:25:18 +0000625}
626
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000627TEST(ImportExpr, ImportStmtExpr) {
628 MatchVerifier<Decl> Verifier;
629 // NOTE: has() ignores implicit casts, using hasDescendant() to match it
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000630 testImport(
631 "void declToImport() { int b; int a = b ?: 1; int C = ({int X=4; X;}); }",
632 Lang_C, "", Lang_C, Verifier,
633 functionDecl(
634 hasBody(
635 compoundStmt(
636 has(
637 declStmt(
638 hasSingleDecl(
639 varDecl(
640 hasName("C"),
641 hasType(asString("int")),
642 hasInitializer(
643 stmtExpr(
644 hasAnySubstatement(
645 declStmt(
646 hasSingleDecl(
647 varDecl(
648 hasName("X"),
649 hasType(asString("int")),
650 hasInitializer(
651 integerLiteral(equals(4))))))),
652 hasDescendant(
653 implicitCastExpr()
654 )))))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000655}
656
657TEST(ImportExpr, ImportConditionalOperator) {
658 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000659 testImport(
660 "void declToImport() { true ? 1 : -5; }",
661 Lang_CXX, "", Lang_CXX, Verifier,
662 functionDecl(
663 hasBody(
664 compoundStmt(
665 has(
666 conditionalOperator(
667 hasCondition(cxxBoolLiteral(equals(true))),
668 hasTrueExpression(integerLiteral(equals(1))),
669 hasFalseExpression(
670 unaryOperator(hasUnaryOperand(integerLiteral(equals(5))))
671 )))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000672}
673
674TEST(ImportExpr, ImportBinaryConditionalOperator) {
675 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000676 testImport(
677 "void declToImport() { 1 ?: -5; }", Lang_CXX, "", Lang_CXX, Verifier,
678 functionDecl(
679 hasBody(
680 compoundStmt(
681 has(
682 binaryConditionalOperator(
683 hasCondition(
684 implicitCastExpr(
685 hasSourceExpression(
686 opaqueValueExpr(
687 hasSourceExpression(integerLiteral(equals(1))))),
688 hasType(booleanType()))),
689 hasTrueExpression(
690 opaqueValueExpr(hasSourceExpression(
691 integerLiteral(equals(1))))),
692 hasFalseExpression(
693 unaryOperator(hasOperatorName("-"),
694 hasUnaryOperand(integerLiteral(equals(5)))))
695 ))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000696}
697
698TEST(ImportExpr, ImportDesignatedInitExpr) {
699 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000700 testImport("void declToImport() {"
701 " struct point { double x; double y; };"
702 " struct point ptarray[10] = "
703 "{ [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; }",
704 Lang_C, "", Lang_C, Verifier,
705 functionDecl(
706 hasBody(
707 compoundStmt(
708 has(
709 declStmt(
710 hasSingleDecl(
711 varDecl(
712 hasInitializer(
713 initListExpr(
714 hasSyntacticForm(
715 initListExpr(
716 has(
717 designatedInitExpr(
718 designatorCountIs(2),
719 has(floatLiteral(
720 equals(1.0))),
721 has(integerLiteral(
722 equals(2))))),
723 has(
724 designatedInitExpr(
725 designatorCountIs(2),
726 has(floatLiteral(
727 equals(2.0))),
728 has(integerLiteral(
729 equals(2))))),
730 has(
731 designatedInitExpr(
732 designatorCountIs(2),
733 has(floatLiteral(
734 equals(1.0))),
735 has(integerLiteral(
736 equals(0)))))
737 ))))))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000738}
739
740
741TEST(ImportExpr, ImportPredefinedExpr) {
742 MatchVerifier<Decl> Verifier;
743 // __func__ expands as StringLiteral("declToImport")
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000744 testImport("void declToImport() { __func__; }",
745 Lang_CXX, "", Lang_CXX, Verifier,
746 functionDecl(
747 hasBody(
748 compoundStmt(
749 has(
750 predefinedExpr(
751 hasType(
752 asString("const char [13]")),
753 has(
754 stringLiteral(
755 hasType(
756 asString("const char [13]"))))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000757}
758
759TEST(ImportExpr, ImportInitListExpr) {
760 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000761 testImport(
762 "void declToImport() {"
763 " struct point { double x; double y; };"
764 " point ptarray[10] = { [2].y = 1.0, [2].x = 2.0,"
765 " [0].x = 1.0 }; }",
766 Lang_CXX, "", Lang_CXX, Verifier,
767 functionDecl(
768 hasBody(
769 compoundStmt(
770 has(
771 declStmt(
772 hasSingleDecl(
773 varDecl(
774 hasInitializer(
775 initListExpr(
776 has(
777 cxxConstructExpr(
778 requiresZeroInitialization())),
779 has(
780 initListExpr(
781 hasType(asString("struct point")),
782 has(floatLiteral(equals(1.0))),
783 has(implicitValueInitExpr(
784 hasType(asString("double")))))),
785 has(
786 initListExpr(
787 hasType(asString("struct point")),
788 has(floatLiteral(equals(2.0))),
789 has(floatLiteral(equals(1.0)))))
790 ))))))))));
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +0000791}
792
793
Aleksei Sidorina693b372016-09-28 10:16:56 +0000794const internal::VariadicDynCastAllOfMatcher<Expr, VAArgExpr> vaArgExpr;
795
796TEST(ImportExpr, ImportVAArgExpr) {
797 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000798 testImport("void declToImport(__builtin_va_list list, ...) {"
799 " (void)__builtin_va_arg(list, int); }",
800 Lang_CXX, "", Lang_CXX, Verifier,
801 functionDecl(
802 hasBody(
803 compoundStmt(
804 has(
805 cStyleCastExpr(
806 hasSourceExpression(
807 vaArgExpr())))))));
Aleksei Sidorina693b372016-09-28 10:16:56 +0000808}
809
Gabor Horvathc78d99a2018-01-27 16:11:45 +0000810TEST(ImportExpr, CXXTemporaryObjectExpr) {
811 MatchVerifier<Decl> Verifier;
812 testImport("struct C {};"
813 "void declToImport() { C c = C(); }",
814 Lang_CXX, "", Lang_CXX, Verifier,
815 functionDecl(hasBody(compoundStmt(has(
816 declStmt(has(varDecl(has(exprWithCleanups(has(cxxConstructExpr(
817 has(materializeTemporaryExpr(has(implicitCastExpr(
818 has(cxxTemporaryObjectExpr())))))))))))))))));
819}
Aleksei Sidorina693b372016-09-28 10:16:56 +0000820
Gabor Horvath0866c2f2016-11-23 15:24:23 +0000821TEST(ImportType, ImportAtomicType) {
822 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000823 testImport("void declToImport() { typedef _Atomic(int) a_int; }",
824 Lang_CXX11, "", Lang_CXX11, Verifier,
825 functionDecl(
826 hasBody(
827 compoundStmt(
828 has(
829 declStmt(
830 has(
831 typedefDecl(
832 has(atomicType())))))))));
Gabor Horvath0866c2f2016-11-23 15:24:23 +0000833}
834
Aleksei Sidorin7f758b62017-12-27 17:04:42 +0000835TEST(ImportDecl, ImportFunctionTemplateDecl) {
836 MatchVerifier<Decl> Verifier;
837 testImport("template <typename T> void declToImport() { };", Lang_CXX, "",
838 Lang_CXX, Verifier, functionTemplateDecl());
839}
840
841const internal::VariadicDynCastAllOfMatcher<Expr, CXXDependentScopeMemberExpr>
842 cxxDependentScopeMemberExpr;
843
844TEST(ImportExpr, ImportCXXDependentScopeMemberExpr) {
845 MatchVerifier<Decl> Verifier;
846 testImport("template <typename T> struct C { T t; };"
847 "template <typename T> void declToImport() {"
848 " C<T> d;"
849 " d.t;"
850 "}"
851 "void instantiate() { declToImport<int>(); }",
852 Lang_CXX, "", Lang_CXX, Verifier,
853 functionTemplateDecl(has(functionDecl(
854 has(compoundStmt(has(cxxDependentScopeMemberExpr())))))));
855 testImport("template <typename T> struct C { T t; };"
856 "template <typename T> void declToImport() {"
857 " C<T> d;"
858 " (&d)->t;"
859 "}"
860 "void instantiate() { declToImport<int>(); }",
861 Lang_CXX, "", Lang_CXX, Verifier,
862 functionTemplateDecl(has(functionDecl(
863 has(compoundStmt(has(cxxDependentScopeMemberExpr())))))));
864}
Gabor Horvath0866c2f2016-11-23 15:24:23 +0000865
Gabor Horvath7a91c082017-11-14 11:30:38 +0000866TEST(ImportType, ImportTypeAliasTemplate) {
867 MatchVerifier<Decl> Verifier;
Aleksei Sidorin4c05f142018-02-14 11:18:00 +0000868 testImport(
869 "template <int K>"
870 "struct dummy { static const int i = K; };"
871 "template <int K> using dummy2 = dummy<K>;"
872 "int declToImport() { return dummy2<3>::i; }",
873 Lang_CXX11, "", Lang_CXX11, Verifier,
874 functionDecl(
875 hasBody(compoundStmt(
876 has(returnStmt(has(implicitCastExpr(has(declRefExpr()))))))),
877 unless(hasAncestor(translationUnitDecl(has(typeAliasDecl()))))));
878}
879
880const internal::VariadicDynCastAllOfMatcher<Decl, VarTemplateSpecializationDecl>
881 varTemplateSpecializationDecl;
882
883TEST(ImportDecl, ImportVarTemplate) {
884 MatchVerifier<Decl> Verifier;
885 testImport(
886 "template <typename T>"
887 "T pi = T(3.1415926535897932385L);"
888 "void declToImport() { pi<int>; }",
889 Lang_CXX11, "", Lang_CXX11, Verifier,
890 functionDecl(
891 hasBody(has(declRefExpr(to(varTemplateSpecializationDecl())))),
892 unless(hasAncestor(translationUnitDecl(has(varDecl(
893 hasName("pi"), unless(varTemplateSpecializationDecl()))))))));
Gabor Horvath7a91c082017-11-14 11:30:38 +0000894}
895
Gabor Horvath7a91c082017-11-14 11:30:38 +0000896TEST(ImportType, ImportPackExpansion) {
897 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000898 testImport("template <typename... Args>"
899 "struct dummy {"
900 " dummy(Args... args) {}"
901 " static const int i = 4;"
902 "};"
903 "int declToImport() { return dummy<int>::i; }",
904 Lang_CXX11, "", Lang_CXX11, Verifier,
905 functionDecl(
906 hasBody(
907 compoundStmt(
908 has(
909 returnStmt(
910 has(
911 implicitCastExpr(
912 has(
913 declRefExpr())))))))));
Gabor Horvath7a91c082017-11-14 11:30:38 +0000914}
915
Gabor Horvathc78d99a2018-01-27 16:11:45 +0000916const internal::VariadicDynCastAllOfMatcher<Type,
917 DependentTemplateSpecializationType>
918 dependentTemplateSpecializationType;
919
920TEST(ImportType, ImportDependentTemplateSpecialization) {
921 MatchVerifier<Decl> Verifier;
922 testImport("template<typename T>"
923 "struct A;"
924 "template<typename T>"
925 "struct declToImport {"
926 " typename A<T>::template B<T> a;"
927 "};",
928 Lang_CXX, "", Lang_CXX, Verifier,
929 classTemplateDecl(has(cxxRecordDecl(has(
930 fieldDecl(hasType(dependentTemplateSpecializationType())))))));
931}
932
933const internal::VariadicDynCastAllOfMatcher<Stmt, SizeOfPackExpr>
934 sizeOfPackExpr;
935
936TEST(ImportExpr, ImportSizeOfPackExpr) {
937 MatchVerifier<Decl> Verifier;
938 testImport("template <typename... Ts>"
939 "void declToImport() {"
940 " const int i = sizeof...(Ts);"
941 "};"
942 "void g() { declToImport<int>(); }",
943 Lang_CXX11, "", Lang_CXX11, Verifier,
944 functionTemplateDecl(has(functionDecl(
945 hasBody(compoundStmt(has(declStmt(has(varDecl(hasInitializer(
946 implicitCastExpr(has(sizeOfPackExpr())))))))))))));
947 testImport(
948 "template <typename... Ts>"
949 "using X = int[sizeof...(Ts)];"
950 "template <typename... Us>"
951 "struct Y {"
952 " X<Us..., int, double, int, Us...> f;"
953 "};"
954 "Y<float, int> declToImport;",
955 Lang_CXX11, "", Lang_CXX11, Verifier,
956 varDecl(hasType(classTemplateSpecializationDecl(has(fieldDecl(hasType(
957 hasUnqualifiedDesugaredType(constantArrayType(hasSize(7))))))))));
958}
959
Aleksei Sidorinb05f37a2017-11-26 17:04:06 +0000960/// \brief Matches __builtin_types_compatible_p:
961/// GNU extension to check equivalent types
962/// Given
963/// \code
964/// __builtin_types_compatible_p(int, int)
965/// \endcode
966// will generate TypeTraitExpr <...> 'int'
967const internal::VariadicDynCastAllOfMatcher<Stmt, TypeTraitExpr> typeTraitExpr;
968
969TEST(ImportExpr, ImportTypeTraitExpr) {
970 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +0000971 testImport("void declToImport() { "
972 " __builtin_types_compatible_p(int, int);"
973 "}",
974 Lang_C, "", Lang_C, Verifier,
975 functionDecl(
976 hasBody(
977 compoundStmt(
978 has(
979 typeTraitExpr(hasType(asString("int"))))))));
Aleksei Sidorinb05f37a2017-11-26 17:04:06 +0000980}
981
Gabor Horvathc78d99a2018-01-27 16:11:45 +0000982const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTypeidExpr> cxxTypeidExpr;
983
984TEST(ImportExpr, ImportCXXTypeidExpr) {
985 MatchVerifier<Decl> Verifier;
986 testImport(
987 "namespace std { class type_info {}; }"
988 "void declToImport() {"
989 " int x;"
990 " auto a = typeid(int); auto b = typeid(x);"
991 "}",
992 Lang_CXX11, "", Lang_CXX11, Verifier,
993 functionDecl(
994 hasDescendant(varDecl(
995 hasName("a"), hasInitializer(hasDescendant(cxxTypeidExpr())))),
996 hasDescendant(varDecl(
997 hasName("b"), hasInitializer(hasDescendant(cxxTypeidExpr()))))));
998}
999
Aleksei Sidorinb05f37a2017-11-26 17:04:06 +00001000TEST(ImportExpr, ImportTypeTraitExprValDep) {
1001 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +00001002 testImport("template<typename T> struct declToImport {"
1003 " void m() { __is_pod(T); }"
1004 "};"
1005 "void f() { declToImport<int>().m(); }",
1006 Lang_CXX11, "", Lang_CXX11, Verifier,
1007 classTemplateDecl(
1008 has(
1009 cxxRecordDecl(
1010 has(
1011 functionDecl(
1012 hasBody(
1013 compoundStmt(
Aleksei Sidorinb05f37a2017-11-26 17:04:06 +00001014 has(
Aleksei Sidorine45ab562017-12-21 17:41:06 +00001015 typeTraitExpr(
1016 hasType(booleanType())
1017 ))))))))));
Aleksei Sidorinb05f37a2017-11-26 17:04:06 +00001018}
Gabor Horvath7a91c082017-11-14 11:30:38 +00001019
Aleksei Sidorin60ccb7d2017-11-27 10:30:00 +00001020const internal::VariadicDynCastAllOfMatcher<Expr, CXXPseudoDestructorExpr>
1021 cxxPseudoDestructorExpr;
1022
1023TEST(ImportExpr, ImportCXXPseudoDestructorExpr) {
1024 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +00001025 testImport("typedef int T;"
1026 "void declToImport(int *p) {"
1027 " T t;"
1028 " p->T::~T();"
1029 "}",
1030 Lang_CXX, "", Lang_CXX, Verifier,
1031 functionDecl(has(compoundStmt(has(
1032 callExpr(has(cxxPseudoDestructorExpr())))))));
Aleksei Sidorin60ccb7d2017-11-27 10:30:00 +00001033}
1034
Aleksei Sidorin9d8ba2e2017-12-03 16:04:07 +00001035TEST(ImportDecl, ImportUsingDecl) {
1036 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +00001037 testImport("namespace foo { int bar; }"
Aleksei Sidorin8fc85102018-01-26 11:36:54 +00001038 "void declToImport() { using foo::bar; }",
Aleksei Sidorine45ab562017-12-21 17:41:06 +00001039 Lang_CXX, "", Lang_CXX, Verifier,
1040 functionDecl(
1041 has(
1042 compoundStmt(
1043 has(
1044 declStmt(
1045 has(
1046 usingDecl())))))));
Aleksei Sidorin9d8ba2e2017-12-03 16:04:07 +00001047}
1048
1049/// \brief Matches shadow declarations introduced into a scope by a
1050/// (resolved) using declaration.
1051///
1052/// Given
1053/// \code
1054/// namespace n { int f; }
1055/// namespace declToImport { using n::f; }
1056/// \endcode
1057/// usingShadowDecl()
1058/// matches \code f \endcode
1059const internal::VariadicDynCastAllOfMatcher<Decl,
1060 UsingShadowDecl> usingShadowDecl;
1061
1062TEST(ImportDecl, ImportUsingShadowDecl) {
1063 MatchVerifier<Decl> Verifier;
Aleksei Sidorine45ab562017-12-21 17:41:06 +00001064 testImport("namespace foo { int bar; }"
1065 "namespace declToImport { using foo::bar; }",
1066 Lang_CXX, "", Lang_CXX, Verifier,
1067 namespaceDecl(has(usingShadowDecl())));
Aleksei Sidorin9d8ba2e2017-12-03 16:04:07 +00001068}
1069
Aleksei Sidorine267a0f2018-01-09 16:40:40 +00001070TEST(ImportExpr, ImportUnresolvedLookupExpr) {
1071 MatchVerifier<Decl> Verifier;
1072 testImport("template<typename T> int foo();"
1073 "template <typename T> void declToImport() {"
1074 " ::foo<T>;"
1075 " ::template foo<T>;"
1076 "}"
1077 "void instantiate() { declToImport<int>(); }",
1078 Lang_CXX, "", Lang_CXX, Verifier,
Aleksei Sidorin8fc85102018-01-26 11:36:54 +00001079 functionTemplateDecl(has(functionDecl(
1080 has(compoundStmt(has(unresolvedLookupExpr())))))));
Aleksei Sidorine267a0f2018-01-09 16:40:40 +00001081}
1082
1083TEST(ImportExpr, ImportCXXUnresolvedConstructExpr) {
1084 MatchVerifier<Decl> Verifier;
Aleksei Sidorin8fc85102018-01-26 11:36:54 +00001085 testImport("template <typename T> struct C { T t; };"
Aleksei Sidorine267a0f2018-01-09 16:40:40 +00001086 "template <typename T> void declToImport() {"
1087 " C<T> d;"
1088 " d.t = T();"
1089 "}"
1090 "void instantiate() { declToImport<int>(); }",
1091 Lang_CXX, "", Lang_CXX, Verifier,
1092 functionTemplateDecl(has(functionDecl(has(compoundStmt(has(
1093 binaryOperator(has(cxxUnresolvedConstructExpr())))))))));
Aleksei Sidorin8fc85102018-01-26 11:36:54 +00001094 testImport("template <typename T> struct C { T t; };"
Aleksei Sidorine267a0f2018-01-09 16:40:40 +00001095 "template <typename T> void declToImport() {"
1096 " C<T> d;"
1097 " (&d)->t = T();"
1098 "}"
1099 "void instantiate() { declToImport<int>(); }",
1100 Lang_CXX, "", Lang_CXX, Verifier,
1101 functionTemplateDecl(has(functionDecl(has(compoundStmt(has(
1102 binaryOperator(has(cxxUnresolvedConstructExpr())))))))));
1103}
1104
Aleksei Sidorin8fc85102018-01-26 11:36:54 +00001105/// Check that function "declToImport()" (which is the templated function
1106/// for corresponding FunctionTemplateDecl) is not added into DeclContext.
1107/// Same for class template declarations.
1108TEST(ImportDecl, ImportTemplatedDeclForTemplate) {
1109 MatchVerifier<Decl> Verifier;
1110 testImport("template <typename T> void declToImport() { T a = 1; }"
1111 "void instantiate() { declToImport<int>(); }",
1112 Lang_CXX, "", Lang_CXX, Verifier,
1113 functionTemplateDecl(hasAncestor(translationUnitDecl(
1114 unless(has(functionDecl(hasName("declToImport"))))))));
1115 testImport("template <typename T> struct declToImport { T t; };"
1116 "void instantiate() { declToImport<int>(); }",
1117 Lang_CXX, "", Lang_CXX, Verifier,
1118 classTemplateDecl(hasAncestor(translationUnitDecl(
1119 unless(has(cxxRecordDecl(hasName("declToImport"))))))));
1120}
1121
Gabor Horvathc78d99a2018-01-27 16:11:45 +00001122TEST(ImportExpr, CXXOperatorCallExpr) {
1123 MatchVerifier<Decl> Verifier;
1124 testImport("class declToImport {"
1125 " void f() { *this = declToImport(); }"
1126 "};",
1127 Lang_CXX, "", Lang_CXX, Verifier,
1128 cxxRecordDecl(has(cxxMethodDecl(hasBody(compoundStmt(
1129 has(exprWithCleanups(has(cxxOperatorCallExpr())))))))));
1130}
1131
1132TEST(ImportExpr, DependentSizedArrayType) {
1133 MatchVerifier<Decl> Verifier;
1134 testImport("template<typename T, int Size> class declToImport {"
1135 " T data[Size];"
1136 "};",
1137 Lang_CXX, "", Lang_CXX, Verifier,
1138 classTemplateDecl(has(cxxRecordDecl(
1139 has(fieldDecl(hasType(dependentSizedArrayType())))))));
1140}
1141
Peter Szecsidedda6f2018-03-30 22:03:29 +00001142TEST_P(ASTImporterTestBase, DISABLED_ImportFunctionWithBackReferringParameter) {
1143 Decl *From, *To;
1144 std::tie(From, To) = getImportedDecl(
1145 R"(
1146 template <typename T> struct X {};
1147
1148 void declToImport(int y, X<int> &x) {}
1149
1150 template <> struct X<int> {
1151 void g() {
1152 X<int> x;
1153 declToImport(0, x);
1154 }
1155 };
1156 )",
1157 Lang_CXX, "", Lang_CXX);
1158
1159 MatchVerifier<Decl> Verifier;
1160 auto Matcher = functionDecl(hasName("declToImport"),
1161 parameterCountIs(2),
1162 hasParameter(0, hasName("y")),
1163 hasParameter(1, hasName("x")),
1164 hasParameter(1, hasType(asString("X<int> &"))));
1165 ASSERT_TRUE(Verifier.match(From, Matcher));
1166 EXPECT_TRUE(Verifier.match(To, Matcher));
1167}
1168
1169TEST_P(ASTImporterTestBase,
1170 TUshouldNotContainTemplatedDeclOfFunctionTemplates) {
1171 Decl *From, *To;
1172 std::tie(From, To) =
1173 getImportedDecl("template <typename T> void declToImport() { T a = 1; }"
1174 "void instantiate() { declToImport<int>(); }",
1175 Lang_CXX, "", Lang_CXX);
1176
1177 auto Check = [](Decl *D) -> bool {
1178 auto TU = D->getTranslationUnitDecl();
1179 for (auto Child : TU->decls()) {
1180 if (auto *FD = dyn_cast<FunctionDecl>(Child)) {
1181 if (FD->getNameAsString() == "declToImport") {
1182 GTEST_NONFATAL_FAILURE_(
1183 "TU should not contain any FunctionDecl with name declToImport");
1184 return false;
1185 }
1186 }
1187 }
1188 return true;
1189 };
1190
1191 ASSERT_TRUE(Check(From));
1192 EXPECT_TRUE(Check(To));
1193}
1194
1195TEST_P(ASTImporterTestBase, TUshouldNotContainTemplatedDeclOfClassTemplates) {
1196 Decl *From, *To;
1197 std::tie(From, To) =
1198 getImportedDecl("template <typename T> struct declToImport { T t; };"
1199 "void instantiate() { declToImport<int>(); }",
1200 Lang_CXX, "", Lang_CXX);
1201
1202 auto Check = [](Decl *D) -> bool {
1203 auto TU = D->getTranslationUnitDecl();
1204 for (auto Child : TU->decls()) {
1205 if (auto *RD = dyn_cast<CXXRecordDecl>(Child)) {
1206 if (RD->getNameAsString() == "declToImport") {
1207 GTEST_NONFATAL_FAILURE_(
1208 "TU should not contain any CXXRecordDecl with name declToImport");
1209 return false;
1210 }
1211 }
1212 }
1213 return true;
1214 };
1215
1216 ASSERT_TRUE(Check(From));
1217 EXPECT_TRUE(Check(To));
1218}
1219
1220TEST_P(ASTImporterTestBase, TUshouldNotContainTemplatedDeclOfTypeAlias) {
1221 Decl *From, *To;
1222 std::tie(From, To) =
1223 getImportedDecl(
1224 "template <typename T> struct X {};"
1225 "template <typename T> using declToImport = X<T>;"
1226 "void instantiate() { declToImport<int> a; }",
1227 Lang_CXX11, "", Lang_CXX11);
1228
1229 auto Check = [](Decl *D) -> bool {
1230 auto TU = D->getTranslationUnitDecl();
1231 for (auto Child : TU->decls()) {
1232 if (auto *AD = dyn_cast<TypeAliasDecl>(Child)) {
1233 if (AD->getNameAsString() == "declToImport") {
1234 GTEST_NONFATAL_FAILURE_(
1235 "TU should not contain any TypeAliasDecl with name declToImport");
1236 return false;
1237 }
1238 }
1239 }
1240 return true;
1241 };
1242
1243 ASSERT_TRUE(Check(From));
1244 EXPECT_TRUE(Check(To));
1245}
1246
1247TEST_P(
1248 ASTImporterTestBase,
1249 DISABLED_TUshouldNotContainClassTemplateSpecializationOfImplicitInstantiation) {
1250
1251 Decl *From, *To;
1252 std::tie(From, To) = getImportedDecl(
1253 R"(
1254 template<class T>
1255 class Base {};
1256 class declToImport : public Base<declToImport> {};
1257 )",
1258 Lang_CXX, "", Lang_CXX);
1259
1260 // Check that the ClassTemplateSpecializationDecl is NOT the child of the TU.
1261 auto Pattern =
1262 translationUnitDecl(unless(has(classTemplateSpecializationDecl())));
1263 ASSERT_TRUE(
1264 MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern));
1265 EXPECT_TRUE(
1266 MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
1267
1268 // Check that the ClassTemplateSpecializationDecl is the child of the
1269 // ClassTemplateDecl.
1270 Pattern = translationUnitDecl(has(classTemplateDecl(
1271 hasName("Base"), has(classTemplateSpecializationDecl()))));
1272 ASSERT_TRUE(
1273 MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern));
1274 EXPECT_TRUE(
1275 MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
1276}
1277
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +00001278AST_MATCHER_P(RecordDecl, hasFieldOrder, std::vector<StringRef>, Order) {
1279 size_t Index = 0;
1280 for (FieldDecl *Field : Node.fields()) {
1281 if (Index == Order.size())
1282 return false;
1283 if (Field->getName() != Order[Index])
1284 return false;
1285 ++Index;
1286 }
1287 return Index == Order.size();
1288}
1289
Peter Szecsidedda6f2018-03-30 22:03:29 +00001290TEST_P(ASTImporterTestBase,
1291 TUshouldContainClassTemplateSpecializationOfExplicitInstantiation) {
1292 Decl *From, *To;
1293 std::tie(From, To) = getImportedDecl(
1294 R"(
1295 namespace NS {
1296 template<class T>
1297 class X {};
1298 template class X<int>;
1299 }
1300 )",
1301 Lang_CXX, "", Lang_CXX, "NS");
1302
1303 // Check that the ClassTemplateSpecializationDecl is NOT the child of the
1304 // ClassTemplateDecl.
1305 auto Pattern = namespaceDecl(has(classTemplateDecl(
1306 hasName("X"), unless(has(classTemplateSpecializationDecl())))));
1307 ASSERT_TRUE(MatchVerifier<Decl>{}.match(From, Pattern));
1308 EXPECT_TRUE(MatchVerifier<Decl>{}.match(To, Pattern));
1309
1310 // Check that the ClassTemplateSpecializationDecl is the child of the
1311 // NamespaceDecl.
1312 Pattern = namespaceDecl(has(classTemplateSpecializationDecl(hasName("X"))));
1313 ASSERT_TRUE(MatchVerifier<Decl>{}.match(From, Pattern));
1314 EXPECT_TRUE(MatchVerifier<Decl>{}.match(To, Pattern));
1315}
1316
1317TEST_P(ASTImporterTestBase, CXXRecordDeclFieldsShouldBeInCorrectOrder) {
1318 Decl *From, *To;
1319 std::tie(From, To) =
1320 getImportedDecl(
1321 "struct declToImport { int a; int b; };",
1322 Lang_CXX11, "", Lang_CXX11);
1323
1324 MatchVerifier<Decl> Verifier;
1325 ASSERT_TRUE(Verifier.match(From, cxxRecordDecl(hasFieldOrder({"a", "b"}))));
1326 EXPECT_TRUE(Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b"}))));
1327}
1328
1329TEST_P(ASTImporterTestBase,
1330 DISABLED_CXXRecordDeclFieldOrderShouldNotDependOnImportOrder) {
1331 Decl *From, *To;
1332 std::tie(From, To) = getImportedDecl(
1333 // The original recursive algorithm of ASTImporter first imports 'c' then
1334 // 'b' and lastly 'a'. Therefore we must restore the order somehow.
1335 R"s(
1336 struct declToImport {
1337 int a = c + b;
1338 int b = 1;
1339 int c = 2;
1340 };
1341 )s",
1342 Lang_CXX11, "", Lang_CXX11);
1343
1344 MatchVerifier<Decl> Verifier;
1345 ASSERT_TRUE(
1346 Verifier.match(From, cxxRecordDecl(hasFieldOrder({"a", "b", "c"}))));
1347 EXPECT_TRUE(
1348 Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b", "c"}))));
1349}
1350
Gabor Martonde8bf262018-05-17 09:46:07 +00001351TEST_P(ASTImporterTestBase, ShouldImportImplicitCXXRecordDecl) {
Peter Szecsidedda6f2018-03-30 22:03:29 +00001352 Decl *From, *To;
1353 std::tie(From, To) = getImportedDecl(
1354 R"(
1355 template <typename U>
1356 struct declToImport {
1357 };
1358 )",
1359 Lang_CXX, "", Lang_CXX);
1360
1361 MatchVerifier<Decl> Verifier;
1362 // Match the implicit Decl.
1363 auto Matcher = classTemplateDecl(has(cxxRecordDecl(has(cxxRecordDecl()))));
1364 ASSERT_TRUE(Verifier.match(From, Matcher));
1365 EXPECT_TRUE(Verifier.match(To, Matcher));
1366}
1367
1368TEST_P(
1369 ASTImporterTestBase,
1370 DISABLED_ShouldImportImplicitCXXRecordDeclOfClassTemplateSpecializationDecl) {
1371 Decl *From, *To;
1372 std::tie(From, To) = getImportedDecl(
1373 R"(
1374 template<class T>
1375 class Base {};
1376 class declToImport : public Base<declToImport> {};
1377 )",
1378 Lang_CXX, "", Lang_CXX);
1379
1380 auto hasImplicitClass = has(cxxRecordDecl());
1381 auto Pattern = translationUnitDecl(has(classTemplateDecl(
1382 hasName("Base"),
1383 has(classTemplateSpecializationDecl(hasImplicitClass)))));
1384 ASSERT_TRUE(
1385 MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern));
1386 EXPECT_TRUE(
1387 MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
1388}
1389
1390TEST_P(ASTImporterTestBase, IDNSOrdinary) {
1391 Decl *From, *To;
1392 std::tie(From, To) =
1393 getImportedDecl("void declToImport() {}", Lang_CXX, "", Lang_CXX);
1394
1395 MatchVerifier<Decl> Verifier;
1396 auto Matcher = functionDecl();
1397 ASSERT_TRUE(Verifier.match(From, Matcher));
1398 EXPECT_TRUE(Verifier.match(To, Matcher));
1399 EXPECT_EQ(From->getIdentifierNamespace(), To->getIdentifierNamespace());
1400}
1401
1402TEST_P(ASTImporterTestBase, DISABLED_IDNSOfNonmemberOperator) {
1403 Decl *FromTU = getTuDecl(
1404 R"(
1405 struct X {};
1406 void operator<<(int, X);
1407 )",
1408 Lang_CXX);
1409 Decl *From = LastDeclMatcher<Decl>{}.match(FromTU, functionDecl());
1410 const Decl *To = Import(From, Lang_CXX);
1411 EXPECT_EQ(From->getIdentifierNamespace(), To->getIdentifierNamespace());
1412}
1413
1414TEST_P(ASTImporterTestBase,
1415 ShouldImportMembersOfClassTemplateSpecializationDecl) {
1416 Decl *From, *To;
1417 std::tie(From, To) = getImportedDecl(
1418 R"(
1419 template<class T>
1420 class Base { int a; };
1421 class declToImport : Base<declToImport> {};
1422 )",
1423 Lang_CXX, "", Lang_CXX);
1424
1425 auto Pattern = translationUnitDecl(has(classTemplateDecl(
1426 hasName("Base"),
1427 has(classTemplateSpecializationDecl(has(fieldDecl(hasName("a"))))))));
1428 ASSERT_TRUE(
1429 MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern));
1430 EXPECT_TRUE(
1431 MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
1432}
1433
Aleksei Sidorin761c2242018-05-15 11:09:07 +00001434TEST_P(ASTImporterTestBase, ImportDefinitionOfClassTemplateAfterFwdDecl) {
1435 {
1436 Decl *FromTU = getTuDecl(
1437 R"(
1438 template <typename T>
1439 struct B;
1440 )",
1441 Lang_CXX, "input0.cc");
1442 auto *FromD = FirstDeclMatcher<ClassTemplateDecl>().match(
1443 FromTU, classTemplateDecl(hasName("B")));
1444
1445 Import(FromD, Lang_CXX);
1446 }
1447
1448 {
1449 Decl *FromTU = getTuDecl(
1450 R"(
1451 template <typename T>
1452 struct B {
1453 void f();
1454 };
1455 )",
1456 Lang_CXX, "input1.cc");
1457 FunctionDecl *FromD = FirstDeclMatcher<FunctionDecl>().match(
1458 FromTU, functionDecl(hasName("f")));
1459 Import(FromD, Lang_CXX);
1460 auto *FromCTD = FirstDeclMatcher<ClassTemplateDecl>().match(
1461 FromTU, classTemplateDecl(hasName("B")));
1462 auto *ToCTD = cast<ClassTemplateDecl>(Import(FromCTD, Lang_CXX));
1463 EXPECT_TRUE(ToCTD->isThisDeclarationADefinition());
1464 }
1465}
1466
Peter Szecsidedda6f2018-03-30 22:03:29 +00001467INSTANTIATE_TEST_CASE_P(
1468 ParameterizedTests, ASTImporterTestBase,
1469 ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
1470
1471struct ImportFunctions : ASTImporterTestBase {};
1472
1473TEST_P(ImportFunctions,
1474 PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition) {
1475 Decl *FromTU = getTuDecl("void f();", Lang_CXX);
1476 auto Pattern = functionDecl(hasName("f"));
1477 FunctionDecl *FromD =
1478 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1479
1480 Decl *ImportedD = Import(FromD, Lang_CXX);
1481 Decl *ToTU = ImportedD->getTranslationUnitDecl();
1482
1483 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1484 EXPECT_TRUE(!cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1485}
1486
1487TEST_P(ImportFunctions,
1488 PrototypeShouldBeImportedAsDefintionWhenThereIsADefinition) {
1489 Decl *FromTU = getTuDecl("void f(); void f() {}", Lang_CXX);
1490 auto Pattern = functionDecl(hasName("f"));
1491 FunctionDecl *FromD = // Prototype
1492 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1493
1494 Decl *ImportedD = Import(FromD, Lang_CXX);
1495 Decl *ToTU = ImportedD->getTranslationUnitDecl();
1496
1497 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1498 EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1499}
1500
1501TEST_P(ImportFunctions,
1502 DefinitionShouldBeImportedAsDefintionWhenThereIsAPrototype) {
1503 Decl *FromTU = getTuDecl("void f(); void f() {}", Lang_CXX);
1504 auto Pattern = functionDecl(hasName("f"));
1505 FunctionDecl *FromD = // Definition
1506 LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1507
1508 Decl *ImportedD = Import(FromD, Lang_CXX);
1509 Decl *ToTU = ImportedD->getTranslationUnitDecl();
1510
1511 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1512 EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1513}
1514
1515TEST_P(ImportFunctions, DefinitionShouldBeImportedAsADefinition) {
1516 Decl *FromTU = getTuDecl("void f() {}", Lang_CXX);
1517 auto Pattern = functionDecl(hasName("f"));
1518 FunctionDecl *FromD =
1519 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1520
1521 Decl *ImportedD = Import(FromD, Lang_CXX);
1522 Decl *ToTU = ImportedD->getTranslationUnitDecl();
1523
1524 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1525 EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1526}
1527
1528TEST_P(ImportFunctions, DISABLED_ImportPrototypeOfRecursiveFunction) {
1529 Decl *FromTU = getTuDecl("void f(); void f() { f(); }", Lang_CXX);
1530 auto Pattern = functionDecl(hasName("f"));
1531 FunctionDecl *PrototypeFD =
1532 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1533
1534 Decl *ImportedD = Import(PrototypeFD, Lang_CXX);
1535 Decl *ToTU = ImportedD->getTranslationUnitDecl();
1536
1537 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1538 EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1539}
1540
1541TEST_P(ImportFunctions, ImportDefinitionOfRecursiveFunction) {
1542 Decl *FromTU = getTuDecl("void f(); void f() { f(); }", Lang_CXX);
1543 auto Pattern = functionDecl(hasName("f"));
1544 FunctionDecl *DefinitionFD =
1545 LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1546
1547 Decl *ImportedD = Import(DefinitionFD, Lang_CXX);
1548 Decl *ToTU = ImportedD->getTranslationUnitDecl();
1549
1550 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1551 EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1552}
1553
1554TEST_P(ImportFunctions, ImportPrototypes) {
1555 auto Pattern = functionDecl(hasName("f"));
1556
1557 Decl *ImportedD;
1558 {
1559 Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input0.cc");
1560 FunctionDecl *FromD =
1561 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1562
1563 ImportedD = Import(FromD, Lang_CXX);
1564 }
1565 Decl *ImportedD1;
1566 {
1567 Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input1.cc");
1568 FunctionDecl *FromD =
1569 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1570 ImportedD1 = Import(FromD, Lang_CXX);
1571 }
1572
1573 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
1574 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1575 EXPECT_EQ(ImportedD, ImportedD1);
1576 EXPECT_TRUE(!cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1577}
1578
1579TEST_P(ImportFunctions, ImportDefinitionThenPrototype) {
1580 auto Pattern = functionDecl(hasName("f"));
1581
1582 Decl *ImportedD;
1583 {
1584 Decl *FromTU = getTuDecl("void f(){}", Lang_CXX, "input0.cc");
1585 FunctionDecl *FromD =
1586 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1587
1588 ImportedD = Import(FromD, Lang_CXX);
1589 }
1590 Decl *ImportedD1;
1591 {
1592 Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input1.cc");
1593 FunctionDecl *FromD =
1594 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1595 ImportedD1 = Import(FromD, Lang_CXX);
1596 }
1597
1598 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
1599 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
1600 EXPECT_EQ(ImportedD, ImportedD1);
1601 EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
1602}
1603
1604TEST_P(ImportFunctions, ImportPrototypeThenDefinition) {
1605 auto Pattern = functionDecl(hasName("f"));
1606
1607 {
1608 Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input0.cc");
1609 FunctionDecl *FromD =
1610 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1611
1612 Import(FromD, Lang_CXX);
1613 }
1614 {
1615 Decl *FromTU = getTuDecl("void f(){}", Lang_CXX, "input1.cc");
1616 FunctionDecl *FromD =
1617 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1618 Import(FromD, Lang_CXX);
1619 }
1620
1621 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
1622 ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
1623 FunctionDecl *ProtoD = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
1624 EXPECT_TRUE(!ProtoD->doesThisDeclarationHaveABody());
1625 FunctionDecl *DefinitionD =
1626 LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
1627 EXPECT_TRUE(DefinitionD->doesThisDeclarationHaveABody());
1628 EXPECT_EQ(DefinitionD->getPreviousDecl(), ProtoD);
1629}
1630
1631TEST_P(ImportFunctions, DISABLED_ImportPrototypeThenProtoAndDefinition) {
1632 auto Pattern = functionDecl(hasName("f"));
1633
1634 {
1635 Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input0.cc");
1636 FunctionDecl *FromD =
1637 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1638
1639 Import(FromD, Lang_CXX);
1640 }
1641 {
1642 Decl *FromTU = getTuDecl("void f(); void f(){}", Lang_CXX, "input1.cc");
1643 FunctionDecl *FromD =
1644 FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
1645 Import(FromD, Lang_CXX);
1646 }
1647
1648 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
1649 ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
1650 FunctionDecl *ProtoD = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
1651 EXPECT_TRUE(!ProtoD->doesThisDeclarationHaveABody());
1652 FunctionDecl *DefinitionD =
1653 LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
1654 EXPECT_TRUE(DefinitionD->doesThisDeclarationHaveABody());
1655 EXPECT_EQ(DefinitionD->getPreviousDecl(), ProtoD);
1656}
1657
1658TEST_P(ImportFunctions, OverriddenMethodsShouldBeImported) {
1659 auto Code =
1660 R"(
1661 struct B { virtual void f(); };
1662 void B::f() {}
1663 struct D : B { void f(); };
1664 )";
1665 auto Pattern =
1666 cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("D"))));
1667 Decl *FromTU = getTuDecl(Code, Lang_CXX);
1668 CXXMethodDecl *Proto =
1669 FirstDeclMatcher<CXXMethodDecl>().match(FromTU, Pattern);
1670
1671 ASSERT_EQ(Proto->size_overridden_methods(), 1u);
1672 CXXMethodDecl *To = cast<CXXMethodDecl>(Import(Proto, Lang_CXX));
1673 EXPECT_EQ(To->size_overridden_methods(), 1u);
1674}
1675
1676TEST_P(ImportFunctions, VirtualFlagShouldBePreservedWhenImportingPrototype) {
1677 auto Code =
1678 R"(
1679 struct B { virtual void f(); };
1680 void B::f() {}
1681 )";
1682 auto Pattern =
1683 cxxMethodDecl(hasName("f"), hasParent(cxxRecordDecl(hasName("B"))));
1684 Decl *FromTU = getTuDecl(Code, Lang_CXX);
1685 CXXMethodDecl *Proto =
1686 FirstDeclMatcher<CXXMethodDecl>().match(FromTU, Pattern);
1687 CXXMethodDecl *Def = LastDeclMatcher<CXXMethodDecl>().match(FromTU, Pattern);
1688
1689 ASSERT_TRUE(Proto->isVirtual());
1690 ASSERT_TRUE(Def->isVirtual());
1691 CXXMethodDecl *To = cast<CXXMethodDecl>(Import(Proto, Lang_CXX));
1692 EXPECT_TRUE(To->isVirtual());
1693}
1694
1695INSTANTIATE_TEST_CASE_P(
1696 ParameterizedTests, ImportFunctions,
1697 ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
1698
Aleksei Sidorin04fbffc2018-04-24 10:11:53 +00001699AST_MATCHER_P(TagDecl, hasTypedefForAnonDecl, Matcher<TypedefNameDecl>,
1700 InnerMatcher) {
1701 if (auto *Typedef = Node.getTypedefNameForAnonDecl())
1702 return InnerMatcher.matches(*Typedef, Finder, Builder);
1703 return false;
1704}
1705
1706TEST(ImportDecl, ImportEnumSequential) {
1707 CodeFiles Samples{{"main.c",
1708 {"void foo();"
1709 "void moo();"
1710 "int main() { foo(); moo(); }",
1711 Lang_C}},
1712
1713 {"foo.c",
1714 {"typedef enum { THING_VALUE } thing_t;"
1715 "void conflict(thing_t type);"
1716 "void foo() { (void)THING_VALUE; }"
1717 "void conflict(thing_t type) {}",
1718 Lang_C}},
1719
1720 {"moo.c",
1721 {"typedef enum { THING_VALUE } thing_t;"
1722 "void conflict(thing_t type);"
1723 "void moo() { conflict(THING_VALUE); }",
1724 Lang_C}}};
1725
1726 auto VerificationMatcher =
1727 enumDecl(has(enumConstantDecl(hasName("THING_VALUE"))),
1728 hasTypedefForAnonDecl(hasName("thing_t")));
1729
1730 ImportAction ImportFoo{"foo.c", "main.c", functionDecl(hasName("foo"))},
1731 ImportMoo{"moo.c", "main.c", functionDecl(hasName("moo"))};
1732
1733 testImportSequence(
1734 Samples, {ImportFoo, ImportMoo}, // "foo", them "moo".
1735 // Just check that there is only one enum decl in the result AST.
1736 "main.c", enumDecl(), VerificationMatcher);
1737
1738 // For different import order, result should be the same.
1739 testImportSequence(
1740 Samples, {ImportMoo, ImportFoo}, // "moo", them "foo".
1741 // Check that there is only one enum decl in the result AST.
1742 "main.c", enumDecl(), VerificationMatcher);
1743}
1744
Peter Szecsice7f3182018-05-07 12:08:27 +00001745const internal::VariadicDynCastAllOfMatcher<Expr, DependentScopeDeclRefExpr>
1746 dependentScopeDeclRefExpr;
1747
1748TEST(ImportExpr, DependentScopeDeclRefExpr) {
1749 MatchVerifier<Decl> Verifier;
1750 testImport("template <typename T> struct S { static T foo; };"
1751 "template <typename T> void declToImport() {"
1752 " (void) S<T>::foo;"
1753 "}"
1754 "void instantiate() { declToImport<int>(); }",
1755 Lang_CXX11, "", Lang_CXX11, Verifier,
1756 functionTemplateDecl(has(functionDecl(has(compoundStmt(
1757 has(cStyleCastExpr(has(dependentScopeDeclRefExpr())))))))));
1758
1759 testImport("template <typename T> struct S {"
1760 "template<typename S> static void foo(){};"
1761 "};"
1762 "template <typename T> void declToImport() {"
1763 " S<T>::template foo<T>();"
1764 "}"
1765 "void instantiate() { declToImport<int>(); }",
1766 Lang_CXX11, "", Lang_CXX11, Verifier,
1767 functionTemplateDecl(has(functionDecl(has(compoundStmt(
1768 has(callExpr(has(dependentScopeDeclRefExpr())))))))));
1769}
1770
1771const internal::VariadicDynCastAllOfMatcher<Type, DependentNameType>
1772 dependentNameType;
1773
1774TEST(ImportExpr, DependentNameType) {
1775 MatchVerifier<Decl> Verifier;
1776 testImport("template <typename T> struct declToImport {"
1777 " typedef typename T::type dependent_name;"
1778 "};",
1779 Lang_CXX11, "", Lang_CXX11, Verifier,
1780 classTemplateDecl(has(
1781 cxxRecordDecl(has(typedefDecl(has(dependentNameType())))))));
1782}
1783
1784const internal::VariadicDynCastAllOfMatcher<Expr, UnresolvedMemberExpr>
1785 unresolvedMemberExpr;
1786
1787TEST(ImportExpr, UnresolvedMemberExpr) {
1788 MatchVerifier<Decl> Verifier;
1789 testImport("struct S { template <typename T> void mem(); };"
1790 "template <typename U> void declToImport() {"
1791 " S s;"
1792 " s.mem<U>();"
1793 "}"
1794 "void instantiate() { declToImport<int>(); }",
1795 Lang_CXX11, "", Lang_CXX11, Verifier,
1796 functionTemplateDecl(has(functionDecl(has(
1797 compoundStmt(has(callExpr(has(unresolvedMemberExpr())))))))));
1798}
1799
Artem Dergachev4e7c6fd2016-04-14 11:51:27 +00001800} // end namespace ast_matchers
1801} // end namespace clang