1//===- unittest/AST/ASTImporterTest.cpp - AST node import test ------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Tests for the correct import of AST nodes from one AST context to another.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/AST/RecordLayout.h"
14#include "clang/ASTMatchers/ASTMatchers.h"
15#include "clang/Testing/CommandLineArgs.h"
16#include "llvm/Support/SmallVectorMemoryBuffer.h"
17
18#include "clang/AST/DeclContextInternals.h"
19#include "gtest/gtest.h"
20
21#include "ASTImporterFixtures.h"
22#include <optional>
23
24namespace clang {
25namespace ast_matchers {
26
27using internal::Matcher;
28
29static const RecordDecl *getRecordDeclOfFriend(FriendDecl *FD) {
30 QualType Ty = FD->getFriendType()->getType().getCanonicalType();
31 return cast<RecordType>(Val&: Ty)->getDecl();
32}
33
34struct ImportExpr : TestImportBase {};
35struct ImportType : TestImportBase {};
36struct ImportDecl : TestImportBase {};
37struct ImportFixedPointExpr : ImportExpr {};
38
39struct CanonicalRedeclChain : ASTImporterOptionSpecificTestBase {};
40
41TEST_P(CanonicalRedeclChain, ShouldBeConsequentWithMatchers) {
42 Decl *FromTU = getTuDecl(SrcCode: "void f();", Lang: Lang_CXX03);
43 auto Pattern = functionDecl(hasName(Name: "f"));
44 auto *D0 = FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
45
46 auto Redecls = getCanonicalForwardRedeclChain(D0);
47 ASSERT_EQ(Redecls.size(), 1u);
48 EXPECT_EQ(D0, Redecls[0]);
49}
50
51TEST_P(CanonicalRedeclChain, ShouldBeConsequentWithMatchers2) {
52 Decl *FromTU = getTuDecl(SrcCode: "void f(); void f(); void f();", Lang: Lang_CXX03);
53 auto Pattern = functionDecl(hasName(Name: "f"));
54 auto *D0 = FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
55 auto *D2 = LastDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
56 FunctionDecl *D1 = D2->getPreviousDecl();
57
58 auto Redecls = getCanonicalForwardRedeclChain(D0);
59 ASSERT_EQ(Redecls.size(), 3u);
60 EXPECT_EQ(D0, Redecls[0]);
61 EXPECT_EQ(D1, Redecls[1]);
62 EXPECT_EQ(D2, Redecls[2]);
63}
64
65TEST_P(CanonicalRedeclChain, ShouldBeSameForAllDeclInTheChain) {
66 Decl *FromTU = getTuDecl(SrcCode: "void f(); void f(); void f();", Lang: Lang_CXX03);
67 auto Pattern = functionDecl(hasName(Name: "f"));
68 auto *D0 = FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
69 auto *D2 = LastDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
70 FunctionDecl *D1 = D2->getPreviousDecl();
71
72 auto RedeclsD0 = getCanonicalForwardRedeclChain(D0);
73 auto RedeclsD1 = getCanonicalForwardRedeclChain(D1);
74 auto RedeclsD2 = getCanonicalForwardRedeclChain(D2);
75
76 EXPECT_THAT(RedeclsD0, ::testing::ContainerEq(RedeclsD1));
77 EXPECT_THAT(RedeclsD1, ::testing::ContainerEq(RedeclsD2));
78}
79
80namespace {
81struct RedirectingImporter : public ASTImporter {
82 using ASTImporter::ASTImporter;
83
84protected:
85 llvm::Expected<Decl *> ImportImpl(Decl *FromD) override {
86 auto *ND = dyn_cast<NamedDecl>(Val: FromD);
87 if (!ND || ND->getName() != "shouldNotBeImported")
88 return ASTImporter::ImportImpl(From: FromD);
89 for (Decl *D : getToContext().getTranslationUnitDecl()->decls()) {
90 if (auto *ND = dyn_cast<NamedDecl>(D))
91 if (ND->getName() == "realDecl") {
92 RegisterImportedDecl(FromD, ND);
93 return ND;
94 }
95 }
96 return ASTImporter::ImportImpl(From: FromD);
97 }
98};
99
100} // namespace
101
102struct RedirectingImporterTest : ASTImporterOptionSpecificTestBase {
103 RedirectingImporterTest() {
104 Creator = [](ASTContext &ToContext, FileManager &ToFileManager,
105 ASTContext &FromContext, FileManager &FromFileManager,
106 bool MinimalImport,
107 const std::shared_ptr<ASTImporterSharedState> &SharedState) {
108 return new RedirectingImporter(ToContext, ToFileManager, FromContext,
109 FromFileManager, MinimalImport,
110 SharedState);
111 };
112 }
113};
114
115// Test that an ASTImporter subclass can intercept an import call.
116TEST_P(RedirectingImporterTest, InterceptImport) {
117 Decl *From, *To;
118 std::tie(args&: From, args&: To) =
119 getImportedDecl(FromSrcCode: "class shouldNotBeImported {};", FromLang: Lang_CXX03,
120 ToSrcCode: "class realDecl {};", ToLang: Lang_CXX03, Identifier: "shouldNotBeImported");
121 auto *Imported = cast<CXXRecordDecl>(Val: To);
122 EXPECT_EQ(Imported->getQualifiedNameAsString(), "realDecl");
123
124 // Make sure our importer prevented the importing of the decl.
125 auto *ToTU = Imported->getTranslationUnitDecl();
126 auto Pattern = functionDecl(hasName(Name: "shouldNotBeImported"));
127 unsigned count =
128 DeclCounterWithPredicate<CXXRecordDecl>().match(ToTU, Pattern);
129 EXPECT_EQ(0U, count);
130}
131
132// Test that when we indirectly import a declaration the custom ASTImporter
133// is still intercepting the import.
134TEST_P(RedirectingImporterTest, InterceptIndirectImport) {
135 Decl *From, *To;
136 std::tie(args&: From, args&: To) =
137 getImportedDecl(FromSrcCode: "class shouldNotBeImported {};"
138 "class F { shouldNotBeImported f; };",
139 FromLang: Lang_CXX03, ToSrcCode: "class realDecl {};", ToLang: Lang_CXX03, Identifier: "F");
140
141 // Make sure our ASTImporter prevented the importing of the decl.
142 auto *ToTU = To->getTranslationUnitDecl();
143 auto Pattern = functionDecl(hasName(Name: "shouldNotBeImported"));
144 unsigned count =
145 DeclCounterWithPredicate<CXXRecordDecl>().match(ToTU, Pattern);
146 EXPECT_EQ(0U, count);
147}
148
149struct ImportPath : ASTImporterOptionSpecificTestBase {
150 Decl *FromTU;
151 FunctionDecl *D0, *D1, *D2;
152 ImportPath() {
153 FromTU = getTuDecl(SrcCode: "void f(); void f(); void f();", Lang: Lang_CXX03);
154 auto Pattern = functionDecl(hasName(Name: "f"));
155 D0 = FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
156 D2 = LastDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
157 D1 = D2->getPreviousDecl();
158 }
159};
160
161TEST_P(ImportPath, Push) {
162 ASTImporter::ImportPathTy path;
163 path.push(D0);
164 EXPECT_FALSE(path.hasCycleAtBack());
165}
166
167TEST_P(ImportPath, SmallCycle) {
168 ASTImporter::ImportPathTy path;
169 path.push(D0);
170 path.push(D0);
171 EXPECT_TRUE(path.hasCycleAtBack());
172 path.pop();
173 EXPECT_FALSE(path.hasCycleAtBack());
174 path.push(D0);
175 EXPECT_TRUE(path.hasCycleAtBack());
176}
177
178TEST_P(ImportPath, GetSmallCycle) {
179 ASTImporter::ImportPathTy path;
180 path.push(D0);
181 path.push(D0);
182 EXPECT_TRUE(path.hasCycleAtBack());
183 std::array<Decl* ,2> Res;
184 int i = 0;
185 for (Decl *Di : path.getCycleAtBack()) {
186 Res[i++] = Di;
187 }
188 ASSERT_EQ(i, 2);
189 EXPECT_EQ(Res[0], D0);
190 EXPECT_EQ(Res[1], D0);
191}
192
193TEST_P(ImportPath, GetCycle) {
194 ASTImporter::ImportPathTy path;
195 path.push(D0);
196 path.push(D1);
197 path.push(D2);
198 path.push(D0);
199 EXPECT_TRUE(path.hasCycleAtBack());
200 std::array<Decl* ,4> Res;
201 int i = 0;
202 for (Decl *Di : path.getCycleAtBack()) {
203 Res[i++] = Di;
204 }
205 ASSERT_EQ(i, 4);
206 EXPECT_EQ(Res[0], D0);
207 EXPECT_EQ(Res[1], D2);
208 EXPECT_EQ(Res[2], D1);
209 EXPECT_EQ(Res[3], D0);
210}
211
212TEST_P(ImportPath, CycleAfterCycle) {
213 ASTImporter::ImportPathTy path;
214 path.push(D0);
215 path.push(D1);
216 path.push(D0);
217 path.push(D1);
218 path.push(D2);
219 path.push(D0);
220 EXPECT_TRUE(path.hasCycleAtBack());
221 std::array<Decl* ,4> Res;
222 int i = 0;
223 for (Decl *Di : path.getCycleAtBack()) {
224 Res[i++] = Di;
225 }
226 ASSERT_EQ(i, 4);
227 EXPECT_EQ(Res[0], D0);
228 EXPECT_EQ(Res[1], D2);
229 EXPECT_EQ(Res[2], D1);
230 EXPECT_EQ(Res[3], D0);
231
232 path.pop();
233 path.pop();
234 path.pop();
235 EXPECT_TRUE(path.hasCycleAtBack());
236 i = 0;
237 for (Decl *Di : path.getCycleAtBack()) {
238 Res[i++] = Di;
239 }
240 ASSERT_EQ(i, 3);
241 EXPECT_EQ(Res[0], D0);
242 EXPECT_EQ(Res[1], D1);
243 EXPECT_EQ(Res[2], D0);
244
245 path.pop();
246 EXPECT_FALSE(path.hasCycleAtBack());
247}
248
249const internal::VariadicDynCastAllOfMatcher<Stmt, SourceLocExpr> sourceLocExpr;
250
251AST_MATCHER_P(SourceLocExpr, hasBuiltinStr, StringRef, Str) {
252 return Node.getBuiltinStr() == Str;
253}
254
255TEST_P(ImportExpr, ImportSourceLocExpr) {
256 MatchVerifier<Decl> Verifier;
257 testImport(FromCode: "void declToImport() { (void)__builtin_FILE(); }", FromLang: Lang_CXX03, ToCode: "",
258 ToLang: Lang_CXX03, Verifier,
259 AMatcher: functionDecl(hasDescendant(
260 sourceLocExpr(hasBuiltinStr(Str: "__builtin_FILE")))));
261 testImport(FromCode: "void declToImport() { (void)__builtin_FILE_NAME(); }", FromLang: Lang_CXX03,
262 ToCode: "", ToLang: Lang_CXX03, Verifier,
263 AMatcher: functionDecl(hasDescendant(
264 sourceLocExpr(hasBuiltinStr(Str: "__builtin_FILE_NAME")))));
265 testImport(FromCode: "void declToImport() { (void)__builtin_COLUMN(); }", FromLang: Lang_CXX03,
266 ToCode: "", ToLang: Lang_CXX03, Verifier,
267 AMatcher: functionDecl(hasDescendant(
268 sourceLocExpr(hasBuiltinStr(Str: "__builtin_COLUMN")))));
269}
270
271TEST_P(ImportExpr, ImportStringLiteral) {
272 MatchVerifier<Decl> Verifier;
273 testImport(FromCode: "void declToImport() { (void)\"foo\"; }", FromLang: Lang_CXX03, ToCode: "",
274 ToLang: Lang_CXX03, Verifier,
275 AMatcher: functionDecl(hasDescendant(
276 stringLiteral(hasType(InnerMatcher: asString(Name: "const char[4]"))))));
277 testImport(FromCode: "void declToImport() { (void)L\"foo\"; }", FromLang: Lang_CXX03, ToCode: "",
278 ToLang: Lang_CXX03, Verifier,
279 AMatcher: functionDecl(hasDescendant(
280 stringLiteral(hasType(InnerMatcher: asString(Name: "const wchar_t[4]"))))));
281 testImport(FromCode: "void declToImport() { (void) \"foo\" \"bar\"; }", FromLang: Lang_CXX03, ToCode: "",
282 ToLang: Lang_CXX03, Verifier,
283 AMatcher: functionDecl(hasDescendant(
284 stringLiteral(hasType(InnerMatcher: asString(Name: "const char[7]"))))));
285}
286
287TEST_P(ImportExpr, ImportChooseExpr) {
288 MatchVerifier<Decl> Verifier;
289
290 // This case tests C code that is not condition-dependent and has a true
291 // condition.
292 testImport(FromCode: "void declToImport() { (void)__builtin_choose_expr(1, 2, 3); }",
293 FromLang: Lang_C99, ToCode: "", ToLang: Lang_C99, Verifier,
294 AMatcher: functionDecl(hasDescendant(chooseExpr())));
295}
296
297const internal::VariadicDynCastAllOfMatcher<Stmt, ShuffleVectorExpr>
298 shuffleVectorExpr;
299
300TEST_P(ImportExpr, ImportShuffleVectorExpr) {
301 MatchVerifier<Decl> Verifier;
302 constexpr auto Code = R"code(
303 typedef double vector4double __attribute__((__vector_size__(32)));
304 vector4double declToImport(vector4double a, vector4double b) {
305 return __builtin_shufflevector(a, b, 0, 1, 2, 3);
306 }
307 )code";
308 const auto Pattern = functionDecl(hasDescendant(shuffleVectorExpr(
309 allOf(has(declRefExpr(to(InnerMatcher: parmVarDecl(hasName(Name: "a"))))),
310 has(declRefExpr(to(InnerMatcher: parmVarDecl(hasName(Name: "b"))))),
311 has(integerLiteral(equals(Value: 0))), has(integerLiteral(equals(Value: 1))),
312 has(integerLiteral(equals(Value: 2))), has(integerLiteral(equals(Value: 3)))))));
313 testImport(FromCode: Code, FromLang: Lang_C99, ToCode: "", ToLang: Lang_C99, Verifier, AMatcher: Pattern);
314}
315
316TEST_P(ImportExpr, ImportGNUNullExpr) {
317 MatchVerifier<Decl> Verifier;
318 testImport(FromCode: "void declToImport() { (void)__null; }", FromLang: Lang_CXX03, ToCode: "",
319 ToLang: Lang_CXX03, Verifier,
320 AMatcher: functionDecl(hasDescendant(gnuNullExpr(hasType(InnerMatcher: isInteger())))));
321}
322
323TEST_P(ImportExpr, ImportGenericSelectionExpr) {
324 MatchVerifier<Decl> Verifier;
325
326 testImport(
327 FromCode: "void declToImport() { int x; (void)_Generic(x, int: 0, float: 1); }",
328 FromLang: Lang_C99, ToCode: "", ToLang: Lang_C99, Verifier,
329 AMatcher: functionDecl(hasDescendant(genericSelectionExpr())));
330}
331
332TEST_P(ImportExpr, ImportCXXNullPtrLiteralExpr) {
333 MatchVerifier<Decl> Verifier;
334 testImport(
335 FromCode: "void declToImport() { (void)nullptr; }",
336 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
337 AMatcher: functionDecl(hasDescendant(cxxNullPtrLiteralExpr())));
338}
339
340
341TEST_P(ImportExpr, ImportFloatinglLiteralExpr) {
342 MatchVerifier<Decl> Verifier;
343 testImport(FromCode: "void declToImport() { (void)1.0; }", FromLang: Lang_C99, ToCode: "", ToLang: Lang_C99,
344 Verifier,
345 AMatcher: functionDecl(hasDescendant(
346 floatLiteral(equals(Value: 1.0), hasType(InnerMatcher: asString(Name: "double"))))));
347 testImport(FromCode: "void declToImport() { (void)1.0e-5f; }", FromLang: Lang_C99, ToCode: "", ToLang: Lang_C99,
348 Verifier,
349 AMatcher: functionDecl(hasDescendant(
350 floatLiteral(equals(Value: 1.0e-5f), hasType(InnerMatcher: asString(Name: "float"))))));
351}
352
353TEST_P(ImportFixedPointExpr, ImportFixedPointerLiteralExpr) {
354 MatchVerifier<Decl> Verifier;
355 testImport(FromCode: "void declToImport() { (void)1.0k; }", FromLang: Lang_C99, ToCode: "", ToLang: Lang_C99,
356 Verifier, AMatcher: functionDecl(hasDescendant(fixedPointLiteral())));
357 testImport(FromCode: "void declToImport() { (void)0.75r; }", FromLang: Lang_C99, ToCode: "", ToLang: Lang_C99,
358 Verifier, AMatcher: functionDecl(hasDescendant(fixedPointLiteral())));
359}
360
361TEST_P(ImportExpr, ImportImaginaryLiteralExpr) {
362 MatchVerifier<Decl> Verifier;
363 testImport(
364 FromCode: "void declToImport() { (void)1.0i; }",
365 FromLang: Lang_CXX14, ToCode: "", ToLang: Lang_CXX14, Verifier,
366 AMatcher: functionDecl(hasDescendant(imaginaryLiteral())));
367}
368
369TEST_P(ImportExpr, ImportCompoundLiteralExpr) {
370 MatchVerifier<Decl> Verifier;
371 testImport(FromCode: "void declToImport() {"
372 " struct s { int x; long y; unsigned z; }; "
373 " (void)(struct s){ 42, 0L, 1U }; }",
374 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
375 AMatcher: functionDecl(hasDescendant(compoundLiteralExpr(
376 hasType(InnerMatcher: asString(Name: "struct s")),
377 has(initListExpr(
378 hasType(InnerMatcher: asString(Name: "struct s")),
379 has(integerLiteral(equals(Value: 42), hasType(InnerMatcher: asString(Name: "int")))),
380 has(integerLiteral(equals(Value: 0), hasType(InnerMatcher: asString(Name: "long")))),
381 has(integerLiteral(
382 equals(Value: 1), hasType(InnerMatcher: asString(Name: "unsigned int"))))))))));
383}
384
385TEST_P(ImportExpr, ImportCXXThisExpr) {
386 MatchVerifier<Decl> Verifier;
387 testImport(FromCode: "class declToImport { void f() { (void)this; } };", FromLang: Lang_CXX03, ToCode: "",
388 ToLang: Lang_CXX03, Verifier,
389 AMatcher: cxxRecordDecl(hasMethod(InnerMatcher: hasDescendant(
390 cxxThisExpr(hasType(InnerMatcher: asString(Name: "class declToImport *")))))));
391}
392
393TEST_P(ImportExpr, ImportAtomicExpr) {
394 MatchVerifier<Decl> Verifier;
395 testImport(FromCode: "void declToImport() { int *ptr; __atomic_load_n(ptr, 1); }",
396 FromLang: Lang_C99, ToCode: "", ToLang: Lang_C99, Verifier,
397 AMatcher: functionDecl(hasDescendant(atomicExpr(
398 has(ignoringParenImpCasts(
399 InnerMatcher: declRefExpr(hasDeclaration(InnerMatcher: varDecl(hasName(Name: "ptr"))),
400 hasType(InnerMatcher: asString(Name: "int *"))))),
401 has(integerLiteral(equals(Value: 1), hasType(InnerMatcher: asString(Name: "int"))))))));
402}
403
404TEST_P(ImportExpr, ImportLabelDeclAndAddrLabelExpr) {
405 MatchVerifier<Decl> Verifier;
406 testImport(FromCode: "void declToImport() { loop: goto loop; (void)&&loop; }", FromLang: Lang_C99,
407 ToCode: "", ToLang: Lang_C99, Verifier,
408 AMatcher: functionDecl(hasDescendant(labelStmt(
409 hasDeclaration(InnerMatcher: labelDecl(hasName(Name: "loop"))))),
410 hasDescendant(addrLabelExpr(
411 hasDeclaration(InnerMatcher: labelDecl(hasName(Name: "loop")))))));
412}
413
414AST_MATCHER_P(TemplateDecl, hasTemplateDecl,
415 internal::Matcher<NamedDecl>, InnerMatcher) {
416 const NamedDecl *Template = Node.getTemplatedDecl();
417 return Template && InnerMatcher.matches(Node: *Template, Finder, Builder);
418}
419
420TEST_P(ImportExpr, ImportParenListExpr) {
421 MatchVerifier<Decl> Verifier;
422 testImport(
423 FromCode: "template<typename T> class dummy { void f() { dummy X(*this); } };"
424 "typedef dummy<int> declToImport;"
425 "template class dummy<int>;",
426 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
427 AMatcher: typedefDecl(hasType(InnerMatcher: elaboratedType(namesType(InnerMatcher: templateSpecializationType(
428 hasDeclaration(InnerMatcher: classTemplateSpecializationDecl(hasSpecializedTemplate(
429 InnerMatcher: classTemplateDecl(hasTemplateDecl(InnerMatcher: cxxRecordDecl(hasMethod(
430 InnerMatcher: allOf(hasName(Name: "f"),
431 hasBody(InnerMatcher: compoundStmt(has(declStmt(hasSingleDecl(InnerMatcher: varDecl(
432 hasInitializer(InnerMatcher: parenListExpr(has(unaryOperator(
433 hasOperatorName(Name: "*"),
434 hasUnaryOperand(
435 InnerMatcher: cxxThisExpr())))))))))))))))))))))))));
436}
437
438TEST_P(ImportExpr, ImportSwitch) {
439 MatchVerifier<Decl> Verifier;
440 testImport(FromCode: "void declToImport() { int b; switch (b) { case 1: break; } }",
441 FromLang: Lang_C99, ToCode: "", ToLang: Lang_C99, Verifier,
442 AMatcher: functionDecl(hasDescendant(
443 switchStmt(has(compoundStmt(has(caseStmt())))))));
444}
445
446TEST_P(ImportExpr, ImportStmtExpr) {
447 MatchVerifier<Decl> Verifier;
448 testImport(
449 FromCode: "void declToImport() { int b; int a = b ?: 1; int C = ({int X=4; X;}); }",
450 FromLang: Lang_C99, ToCode: "", ToLang: Lang_C99, Verifier,
451 AMatcher: traverse(TK: TK_AsIs,
452 InnerMatcher: functionDecl(hasDescendant(varDecl(
453 hasName(Name: "C"), hasType(InnerMatcher: asString(Name: "int")),
454 hasInitializer(InnerMatcher: stmtExpr(
455 hasAnySubstatement(InnerMatcher: declStmt(hasSingleDecl(InnerMatcher: varDecl(
456 hasName(Name: "X"), hasType(InnerMatcher: asString(Name: "int")),
457 hasInitializer(InnerMatcher: integerLiteral(equals(Value: 4))))))),
458 hasDescendant(implicitCastExpr()))))))));
459}
460
461TEST_P(ImportExpr, ImportConditionalOperator) {
462 MatchVerifier<Decl> Verifier;
463 testImport(FromCode: "void declToImport() { (void)(true ? 1 : -5); }", FromLang: Lang_CXX03, ToCode: "",
464 ToLang: Lang_CXX03, Verifier,
465 AMatcher: functionDecl(hasDescendant(conditionalOperator(
466 hasCondition(InnerMatcher: cxxBoolLiteral(equals(Value: true))),
467 hasTrueExpression(InnerMatcher: integerLiteral(equals(Value: 1))),
468 hasFalseExpression(InnerMatcher: unaryOperator(
469 hasUnaryOperand(InnerMatcher: integerLiteral(equals(Value: 5)))))))));
470}
471
472TEST_P(ImportExpr, ImportBinaryConditionalOperator) {
473 MatchVerifier<Decl> Verifier;
474 testImport(
475 FromCode: "void declToImport() { (void)(1 ?: -5); }", FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03,
476 Verifier,
477 AMatcher: traverse(TK: TK_AsIs,
478 InnerMatcher: functionDecl(hasDescendant(binaryConditionalOperator(
479 hasCondition(InnerMatcher: implicitCastExpr(
480 hasSourceExpression(InnerMatcher: opaqueValueExpr(
481 hasSourceExpression(InnerMatcher: integerLiteral(equals(Value: 1))))),
482 hasType(InnerMatcher: booleanType()))),
483 hasTrueExpression(InnerMatcher: opaqueValueExpr(
484 hasSourceExpression(InnerMatcher: integerLiteral(equals(Value: 1))))),
485 hasFalseExpression(InnerMatcher: unaryOperator(
486 hasOperatorName(Name: "-"),
487 hasUnaryOperand(InnerMatcher: integerLiteral(equals(Value: 5))))))))));
488}
489
490TEST_P(ImportExpr, ImportDesignatedInitExpr) {
491 MatchVerifier<Decl> Verifier;
492 testImport(
493 FromCode: "void declToImport() {"
494 " struct point { double x; double y; };"
495 " struct point ptarray[10] = "
496 "{ [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; }",
497 FromLang: Lang_C99, ToCode: "", ToLang: Lang_C99, Verifier,
498 AMatcher: functionDecl(hasDescendant(initListExpr(
499 has(designatedInitExpr(designatorCountIs(N: 2),
500 hasDescendant(floatLiteral(equals(Value: 1.0))),
501 hasDescendant(integerLiteral(equals(Value: 2))))),
502 has(designatedInitExpr(designatorCountIs(N: 2),
503 hasDescendant(floatLiteral(equals(Value: 2.0))),
504 hasDescendant(integerLiteral(equals(Value: 2))))),
505 has(designatedInitExpr(designatorCountIs(N: 2),
506 hasDescendant(floatLiteral(equals(Value: 1.0))),
507 hasDescendant(integerLiteral(equals(Value: 0)))))))));
508}
509
510TEST_P(ImportExpr, ImportPredefinedExpr) {
511 MatchVerifier<Decl> Verifier;
512 // __func__ expands as StringLiteral("declToImport")
513 testImport(FromCode: "void declToImport() { (void)__func__; }", FromLang: Lang_CXX03, ToCode: "",
514 ToLang: Lang_CXX03, Verifier,
515 AMatcher: functionDecl(hasDescendant(predefinedExpr(
516 hasType(InnerMatcher: asString(Name: "const char[13]")),
517 has(stringLiteral(hasType(InnerMatcher: asString(Name: "const char[13]"))))))));
518}
519
520TEST_P(ImportExpr, ImportInitListExpr) {
521 MatchVerifier<Decl> Verifier;
522 testImport(FromCode: "void declToImport() {"
523 " struct point { double x; double y; };"
524 " point ptarray[10] = { [2].y = 1.0, [2].x = 2.0,"
525 " [0].x = 1.0 }; }",
526 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
527 AMatcher: functionDecl(hasDescendant(initListExpr(
528 has(cxxConstructExpr(requiresZeroInitialization())),
529 has(initListExpr(
530 hasType(InnerMatcher: asString(Name: "point")), has(floatLiteral(equals(Value: 1.0))),
531 has(implicitValueInitExpr(hasType(InnerMatcher: asString(Name: "double")))))),
532 has(initListExpr(hasType(InnerMatcher: asString(Name: "point")),
533 has(floatLiteral(equals(Value: 2.0))),
534 has(floatLiteral(equals(Value: 1.0)))))))));
535}
536
537const internal::VariadicDynCastAllOfMatcher<Expr, CXXDefaultInitExpr>
538 cxxDefaultInitExpr;
539
540TEST_P(ImportExpr, ImportCXXDefaultInitExpr) {
541 MatchVerifier<Decl> Verifier;
542 testImport(FromCode: "class declToImport { int DefInit = 5; }; declToImport X;",
543 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
544 AMatcher: cxxRecordDecl(hasDescendant(cxxConstructorDecl(
545 hasAnyConstructorInitializer(InnerMatcher: cxxCtorInitializer(
546 withInitializer(InnerMatcher: cxxDefaultInitExpr())))))));
547 testImport(
548 FromCode: "struct X { int A = 5; }; X declToImport{};", FromLang: Lang_CXX17, ToCode: "", ToLang: Lang_CXX17,
549 Verifier,
550 AMatcher: varDecl(hasInitializer(InnerMatcher: initListExpr(hasInit(N: 0, InnerMatcher: cxxDefaultInitExpr())))));
551}
552
553const internal::VariadicDynCastAllOfMatcher<Expr, VAArgExpr> vaArgExpr;
554
555TEST_P(ImportExpr, ImportVAArgExpr) {
556 MatchVerifier<Decl> Verifier;
557 testImport(FromCode: "void declToImport(__builtin_va_list list, ...) {"
558 " (void)__builtin_va_arg(list, int); }",
559 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
560 AMatcher: functionDecl(hasDescendant(
561 cStyleCastExpr(hasSourceExpression(InnerMatcher: vaArgExpr())))));
562}
563
564const internal::VariadicDynCastAllOfMatcher<Stmt, BuiltinBitCastExpr>
565 builtinBitCastExpr;
566
567TEST_P(ImportExpr, ImportBuiltinBitCastExpr) {
568 MatchVerifier<Decl> Verifier;
569 testImport(FromCode: "void declToImport(int X) {"
570 " (void)__builtin_bit_cast(float, X); }",
571 FromLang: Lang_CXX20, ToCode: "", ToLang: Lang_CXX20, Verifier,
572 AMatcher: functionDecl(hasDescendant(
573 cStyleCastExpr(hasSourceExpression(InnerMatcher: builtinBitCastExpr())))));
574}
575
576TEST_P(ImportExpr, CXXTemporaryObjectExpr) {
577 MatchVerifier<Decl> Verifier;
578 testImport(
579 FromCode: "struct C {};"
580 "void declToImport() { C c = C(); }",
581 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
582 AMatcher: traverse(TK: TK_AsIs,
583 InnerMatcher: functionDecl(hasDescendant(exprWithCleanups(has(cxxConstructExpr(
584 has(materializeTemporaryExpr(has(implicitCastExpr(
585 has(cxxTemporaryObjectExpr()))))))))))));
586}
587
588TEST_P(ImportType, ImportAtomicType) {
589 MatchVerifier<Decl> Verifier;
590 testImport(
591 FromCode: "void declToImport() { typedef _Atomic(int) a_int; }",
592 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
593 AMatcher: functionDecl(hasDescendant(typedefDecl(has(atomicType())))));
594}
595
596TEST_P(ImportType, ImportBitIntType) {
597 const AstTypeMatcher<BitIntType> bitIntType;
598 MatchVerifier<Decl> Verifier;
599 testImport(FromCode: "_BitInt(10) declToImport;", FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
600 AMatcher: varDecl(hasType(InnerMatcher: bitIntType())));
601}
602
603TEST_P(ImportType, ImportDependentBitIntType) {
604 const AstTypeMatcher<DependentBitIntType> dependentBitIntType;
605 MatchVerifier<Decl> Verifier;
606 testImport(FromCode: "template<int Width> using declToImport = _BitInt(Width);",
607 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
608 AMatcher: typeAliasTemplateDecl(
609 has(typeAliasDecl(hasType(InnerMatcher: dependentBitIntType())))));
610}
611
612TEST_P(ImportType, ImportDependentAddressSpaceType) {
613 const AstTypeMatcher<DependentAddressSpaceType> dependentAddressSpaceType;
614 MatchVerifier<Decl> Verifier;
615 testImport(
616 FromCode: R"(
617 template<typename T, int AddrSpace>
618 using declToImport = T __attribute__((address_space(AddrSpace)));
619 )",
620 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
621 AMatcher: typeAliasTemplateDecl(
622 has(typeAliasDecl(hasType(InnerMatcher: dependentAddressSpaceType())))));
623}
624
625TEST_P(ImportType, ImportVectorType) {
626 const AstTypeMatcher<VectorType> vectorType;
627 MatchVerifier<Decl> Verifier;
628 testImport(FromCode: "typedef int __attribute__((vector_size(12))) declToImport;",
629 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
630 AMatcher: typedefDecl(hasType(InnerMatcher: vectorType())));
631}
632
633TEST_P(ImportType, ImportDependentVectorType) {
634 const AstTypeMatcher<DependentVectorType> dependentVectorType;
635 MatchVerifier<Decl> Verifier;
636 testImport(
637 FromCode: R"(
638 template<typename T, int Size>
639 using declToImport = T __attribute__((vector_size(Size)));
640 )",
641 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
642 AMatcher: typeAliasTemplateDecl(
643 has(typeAliasDecl(hasType(InnerMatcher: dependentVectorType())))));
644}
645
646struct ImportOpenCLPipe : ImportType {
647 std::vector<std::string> getExtraArgs() const override {
648 return {"-x", "cl", "-cl-no-stdinc", "-cl-std=CL2.0"};
649 }
650};
651
652TEST_P(ImportOpenCLPipe, ImportPipeType) {
653 const AstTypeMatcher<PipeType> pipeType;
654 MatchVerifier<Decl> Verifier;
655 testImport(FromCode: "typedef pipe int declToImport;", FromLang: Lang_OpenCL, ToCode: "", ToLang: Lang_OpenCL,
656 Verifier, AMatcher: typedefDecl(hasType(InnerMatcher: pipeType())));
657}
658
659struct ImportMatrixType : ImportType {
660 std::vector<std::string> getExtraArgs() const override {
661 return {"-fenable-matrix"};
662 }
663};
664
665TEST_P(ImportMatrixType, ImportConstantMatrixType) {
666 const AstTypeMatcher<ConstantMatrixType> constantMatrixType;
667 MatchVerifier<Decl> Verifier;
668 testImport(FromCode: "typedef int __attribute__((matrix_type(5, 5))) declToImport;",
669 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
670 AMatcher: typedefDecl(hasType(InnerMatcher: constantMatrixType())));
671}
672
673TEST_P(ImportMatrixType, ImportDependentSizedMatrixType) {
674 const AstTypeMatcher<DependentSizedMatrixType> dependentSizedMatrixType;
675 MatchVerifier<Decl> Verifier;
676 testImport(
677 FromCode: R"(
678 template<typename T, int Rows, int Cols>
679 using declToImport = T __attribute__((matrix_type(Rows, Cols)));
680 )",
681 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
682 AMatcher: typeAliasTemplateDecl(
683 has(typeAliasDecl(hasType(InnerMatcher: dependentSizedMatrixType())))));
684}
685
686TEST_P(ImportType, ImportUsingType) {
687 MatchVerifier<Decl> Verifier;
688 testImport(FromCode: "struct C {};"
689 "void declToImport() { using ::C; new C{}; }",
690 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
691 AMatcher: functionDecl(hasDescendant(cxxNewExpr(hasType(InnerMatcher: pointerType(
692 pointee(elaboratedType(namesType(InnerMatcher: usingType())))))))));
693}
694
695TEST_P(ImportDecl, ImportFunctionTemplateDecl) {
696 MatchVerifier<Decl> Verifier;
697 testImport(FromCode: "template <typename T> void declToImport() { };", FromLang: Lang_CXX03, ToCode: "",
698 ToLang: Lang_CXX03, Verifier, AMatcher: functionTemplateDecl());
699}
700
701TEST_P(ImportExpr, ImportCXXDependentScopeMemberExpr) {
702 MatchVerifier<Decl> Verifier;
703 testImport(FromCode: "template <typename T> struct C { T t; };"
704 "template <typename T> void declToImport() {"
705 " C<T> d;"
706 " (void)d.t;"
707 "}"
708 "void instantiate() { declToImport<int>(); }",
709 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
710 AMatcher: functionTemplateDecl(hasDescendant(
711 cStyleCastExpr(has(cxxDependentScopeMemberExpr())))));
712 testImport(FromCode: "template <typename T> struct C { T t; };"
713 "template <typename T> void declToImport() {"
714 " C<T> d;"
715 " (void)(&d)->t;"
716 "}"
717 "void instantiate() { declToImport<int>(); }",
718 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
719 AMatcher: functionTemplateDecl(hasDescendant(
720 cStyleCastExpr(has(cxxDependentScopeMemberExpr())))));
721}
722
723TEST_P(ImportType, ImportTypeAliasTemplate) {
724 MatchVerifier<Decl> Verifier;
725 testImport(
726 FromCode: "template <int K>"
727 "struct dummy { static const int i = K; };"
728 "template <int K> using dummy2 = dummy<K>;"
729 "int declToImport() { return dummy2<3>::i; }",
730 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
731 AMatcher: traverse(TK: TK_AsIs,
732 InnerMatcher: functionDecl(hasDescendant(implicitCastExpr(has(declRefExpr()))),
733 unless(hasAncestor(
734 translationUnitDecl(has(typeAliasDecl())))))));
735}
736
737const internal::VariadicDynCastAllOfMatcher<Decl, VarTemplateSpecializationDecl>
738 varTemplateSpecializationDecl;
739
740TEST_P(ImportDecl, ImportVarTemplate) {
741 MatchVerifier<Decl> Verifier;
742 testImport(
743 FromCode: "template <typename T>"
744 "T pi = T(3.1415926535897932385L);"
745 "void declToImport() { (void)pi<int>; }",
746 FromLang: Lang_CXX14, ToCode: "", ToLang: Lang_CXX14, Verifier,
747 AMatcher: functionDecl(
748 hasDescendant(declRefExpr(to(InnerMatcher: varTemplateSpecializationDecl()))),
749 unless(hasAncestor(translationUnitDecl(has(varDecl(
750 hasName(Name: "pi"), unless(varTemplateSpecializationDecl()))))))));
751}
752
753TEST_P(ImportType, ImportPackExpansion) {
754 MatchVerifier<Decl> Verifier;
755 testImport(FromCode: "template <typename... Args>"
756 "struct dummy {"
757 " dummy(Args... args) {}"
758 " static const int i = 4;"
759 "};"
760 "int declToImport() { return dummy<int>::i; }",
761 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
762 AMatcher: traverse(TK: TK_AsIs, InnerMatcher: functionDecl(hasDescendant(returnStmt(has(
763 implicitCastExpr(has(declRefExpr()))))))));
764}
765
766const internal::VariadicDynCastAllOfMatcher<Type,
767 DependentTemplateSpecializationType>
768 dependentTemplateSpecializationType;
769
770TEST_P(ImportType, ImportDependentTemplateSpecialization) {
771 MatchVerifier<Decl> Verifier;
772 testImport(FromCode: "template<typename T>"
773 "struct A;"
774 "template<typename T>"
775 "struct declToImport {"
776 " typename A<T>::template B<T> a;"
777 "};",
778 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
779 AMatcher: classTemplateDecl(has(cxxRecordDecl(has(
780 fieldDecl(hasType(InnerMatcher: dependentTemplateSpecializationType())))))));
781}
782
783TEST_P(ImportType, ImportDeducedTemplateSpecialization) {
784 MatchVerifier<Decl> Verifier;
785 testImport(FromCode: "template <typename T>"
786 "class C { public: C(T); };"
787 "C declToImport(123);",
788 FromLang: Lang_CXX17, ToCode: "", ToLang: Lang_CXX17, Verifier,
789 AMatcher: varDecl(hasType(InnerMatcher: elaboratedType(
790 namesType(InnerMatcher: deducedTemplateSpecializationType())))));
791}
792
793const internal::VariadicDynCastAllOfMatcher<Stmt, SizeOfPackExpr>
794 sizeOfPackExpr;
795
796TEST_P(ImportExpr, ImportSizeOfPackExpr) {
797 MatchVerifier<Decl> Verifier;
798 testImport(
799 FromCode: "template <typename... Ts>"
800 "void declToImport() {"
801 " const int i = sizeof...(Ts);"
802 "};"
803 "void g() { declToImport<int>(); }",
804 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
805 AMatcher: functionTemplateDecl(hasDescendant(sizeOfPackExpr())));
806 testImport(
807 FromCode: "template <typename... Ts>"
808 "using X = int[sizeof...(Ts)];"
809 "template <typename... Us>"
810 "struct Y {"
811 " X<Us..., int, double, int, Us...> f;"
812 "};"
813 "Y<float, int> declToImport;",
814 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
815 AMatcher: varDecl(hasType(InnerMatcher: classTemplateSpecializationDecl(has(fieldDecl(hasType(
816 InnerMatcher: hasUnqualifiedDesugaredType(InnerMatcher: constantArrayType(hasSize(N: 7))))))))));
817}
818
819TEST_P(ImportExpr, ImportCXXFoldExpr) {
820 auto Match1 = cxxFoldExpr(hasOperatorName(Name: "+"), isLeftFold(),
821 unless(hasFoldInit(InnerMacher: expr())));
822 auto Match2 =
823 cxxFoldExpr(hasOperatorName(Name: "-"), isLeftFold(), hasFoldInit(InnerMacher: expr()));
824 auto Match3 = cxxFoldExpr(hasOperatorName(Name: "*"), isRightFold(),
825 unless(hasFoldInit(InnerMacher: expr())));
826 auto Match4 =
827 cxxFoldExpr(hasOperatorName(Name: "/"), isRightFold(), hasFoldInit(InnerMacher: expr()));
828
829 MatchVerifier<Decl> Verifier;
830 testImport(FromCode: "template <typename... Ts>"
831 "void declToImport(Ts... args) {"
832 " const int i1 = (... + args);"
833 " const int i2 = (1 - ... - args);"
834 " const int i3 = (args * ...);"
835 " const int i4 = (args / ... / 1);"
836 "};"
837 "void g() { declToImport(1, 2, 3, 4, 5); }",
838 FromLang: Lang_CXX17, ToCode: "", ToLang: Lang_CXX17, Verifier,
839 AMatcher: functionTemplateDecl(hasDescendant(Match1), hasDescendant(Match2),
840 hasDescendant(Match3),
841 hasDescendant(Match4)));
842}
843
844/// \brief Matches __builtin_types_compatible_p:
845/// GNU extension to check equivalent types
846/// Given
847/// \code
848/// __builtin_types_compatible_p(int, int)
849/// \endcode
850// will generate TypeTraitExpr <...> 'int'
851const internal::VariadicDynCastAllOfMatcher<Stmt, TypeTraitExpr> typeTraitExpr;
852
853TEST_P(ImportExpr, ImportTypeTraitExpr) {
854 MatchVerifier<Decl> Verifier;
855 testImport(
856 FromCode: "void declToImport() { "
857 " (void)__builtin_types_compatible_p(int, int);"
858 "}",
859 FromLang: Lang_C99, ToCode: "", ToLang: Lang_C99, Verifier,
860 AMatcher: functionDecl(hasDescendant(typeTraitExpr(hasType(InnerMatcher: asString(Name: "int"))))));
861}
862
863const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTypeidExpr> cxxTypeidExpr;
864
865TEST_P(ImportExpr, ImportCXXTypeidExpr) {
866 MatchVerifier<Decl> Verifier;
867 testImport(
868 FromCode: "namespace std { class type_info {}; }"
869 "void declToImport() {"
870 " int x;"
871 " auto a = typeid(int); auto b = typeid(x);"
872 "}",
873 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
874 AMatcher: traverse(
875 TK: TK_AsIs,
876 InnerMatcher: functionDecl(
877 hasDescendant(varDecl(hasName(Name: "a"), hasInitializer(InnerMatcher: hasDescendant(
878 cxxTypeidExpr())))),
879 hasDescendant(varDecl(hasName(Name: "b"), hasInitializer(InnerMatcher: hasDescendant(
880 cxxTypeidExpr())))))));
881}
882
883TEST_P(ImportExpr, ImportTypeTraitExprValDep) {
884 MatchVerifier<Decl> Verifier;
885 testImport(
886 FromCode: "template<typename T> struct declToImport {"
887 " void m() { (void)__is_pod(T); }"
888 "};"
889 "void f() { declToImport<int>().m(); }",
890 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
891 AMatcher: classTemplateDecl(has(cxxRecordDecl(has(
892 functionDecl(hasDescendant(
893 typeTraitExpr(hasType(InnerMatcher: booleanType())))))))));
894}
895
896TEST_P(ImportDecl, ImportRecordDeclInFunc) {
897 MatchVerifier<Decl> Verifier;
898 testImport(FromCode: "int declToImport() { "
899 " struct data_t {int a;int b;};"
900 " struct data_t d;"
901 " return 0;"
902 "}",
903 FromLang: Lang_C99, ToCode: "", ToLang: Lang_C99, Verifier,
904 AMatcher: functionDecl(hasBody(InnerMatcher: compoundStmt(
905 has(declStmt(hasSingleDecl(InnerMatcher: varDecl(hasName(Name: "d")))))))));
906}
907
908TEST_P(ImportDecl, ImportedVarDeclPreservesThreadLocalStorage) {
909 MatchVerifier<Decl> Verifier;
910 testImport(FromCode: "thread_local int declToImport;", FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11,
911 Verifier, AMatcher: varDecl(hasThreadStorageDuration()));
912}
913
914TEST_P(ASTImporterOptionSpecificTestBase, ImportRecordTypeInFunc) {
915 Decl *FromTU = getTuDecl(SrcCode: "int declToImport() { "
916 " struct data_t {int a;int b;};"
917 " struct data_t d;"
918 " return 0;"
919 "}",
920 Lang: Lang_C99, FileName: "input.c");
921 auto *FromVar =
922 FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: varDecl(hasName(Name: "d")));
923 ASSERT_TRUE(FromVar);
924 auto ToType =
925 ImportType(FromType: FromVar->getType().getCanonicalType(), TUDecl: FromVar, ToLang: Lang_C99);
926 EXPECT_FALSE(ToType.isNull());
927}
928
929TEST_P(ASTImporterOptionSpecificTestBase, ImportRecordDeclInFuncParams) {
930 // This construct is not supported by ASTImporter.
931 Decl *FromTU = getTuDecl(
932 SrcCode: "int declToImport(struct data_t{int a;int b;} ***d){ return 0; }",
933 Lang: Lang_C99, FileName: "input.c");
934 auto *From = FirstDeclMatcher<FunctionDecl>().match(
935 D: FromTU, AMatcher: functionDecl(hasName(Name: "declToImport")));
936 ASSERT_TRUE(From);
937 auto *To = Import(From, Lang_C99);
938 EXPECT_EQ(To, nullptr);
939}
940
941TEST_P(ASTImporterOptionSpecificTestBase, ImportRecordDeclInFuncFromMacro) {
942 Decl *FromTU =
943 getTuDecl(SrcCode: "#define NONAME_SIZEOF(type) sizeof(struct{type *dummy;}) \n"
944 "int declToImport(){ return NONAME_SIZEOF(int); }",
945 Lang: Lang_C99, FileName: "input.c");
946 auto *From = FirstDeclMatcher<FunctionDecl>().match(
947 D: FromTU, AMatcher: functionDecl(hasName(Name: "declToImport")));
948 ASSERT_TRUE(From);
949 auto *To = Import(From, Lang_C99);
950 ASSERT_TRUE(To);
951 EXPECT_TRUE(MatchVerifier<FunctionDecl>().match(
952 To, functionDecl(hasName("declToImport"),
953 hasDescendant(unaryExprOrTypeTraitExpr()))));
954}
955
956TEST_P(ASTImporterOptionSpecificTestBase,
957 ImportRecordDeclInFuncParamsFromMacro) {
958 // This construct is not supported by ASTImporter.
959 Decl *FromTU =
960 getTuDecl(SrcCode: "#define PAIR_STRUCT(type) struct data_t{type a;type b;} \n"
961 "int declToImport(PAIR_STRUCT(int) ***d){ return 0; }",
962 Lang: Lang_C99, FileName: "input.c");
963 auto *From = FirstDeclMatcher<FunctionDecl>().match(
964 D: FromTU, AMatcher: functionDecl(hasName(Name: "declToImport")));
965 ASSERT_TRUE(From);
966 auto *To = Import(From, Lang_C99);
967 EXPECT_EQ(To, nullptr);
968}
969
970const internal::VariadicDynCastAllOfMatcher<Expr, CXXPseudoDestructorExpr>
971 cxxPseudoDestructorExpr;
972
973TEST_P(ImportExpr, ImportCXXPseudoDestructorExpr) {
974 MatchVerifier<Decl> Verifier;
975 testImport(
976 FromCode: "typedef int T;"
977 "void declToImport(int *p) {"
978 " T t;"
979 " p->T::~T();"
980 "}",
981 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
982 AMatcher: functionDecl(hasDescendant(callExpr(has(cxxPseudoDestructorExpr())))));
983}
984
985TEST_P(ImportDecl, ImportUsingDecl) {
986 MatchVerifier<Decl> Verifier;
987 testImport(FromCode: "namespace foo { int bar; }"
988 "void declToImport() { using foo::bar; }",
989 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
990 AMatcher: functionDecl(hasDescendant(usingDecl(hasName(Name: "bar")))));
991}
992
993TEST_P(ImportDecl, ImportUsingTemplate) {
994 MatchVerifier<Decl> Verifier;
995 testImport(FromCode: "namespace ns { template <typename T> struct S {}; }"
996 "template <template <typename> class T> class X {};"
997 "void declToImport() {"
998 "using ns::S; X<S> xi; }",
999 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
1000 AMatcher: functionDecl(hasDescendant(varDecl(hasTypeLoc(Inner: elaboratedTypeLoc(
1001 hasNamedTypeLoc(InnerMatcher: templateSpecializationTypeLoc(
1002 hasAnyTemplateArgumentLoc(InnerMatcher: templateArgumentLoc())))))))));
1003}
1004
1005TEST_P(ImportDecl, ImportUsingEnumDecl) {
1006 MatchVerifier<Decl> Verifier;
1007 testImport(FromCode: "namespace foo { enum bar { baz, toto, quux }; }"
1008 "void declToImport() { using enum foo::bar; }",
1009 FromLang: Lang_CXX20, ToCode: "", ToLang: Lang_CXX20, Verifier,
1010 AMatcher: functionDecl(hasDescendant(usingEnumDecl(hasName(Name: "bar")))));
1011}
1012
1013const internal::VariadicDynCastAllOfMatcher<Decl, UsingPackDecl> usingPackDecl;
1014
1015TEST_P(ImportDecl, ImportUsingPackDecl) {
1016 MatchVerifier<Decl> Verifier;
1017 testImport(
1018 FromCode: "struct A { int operator()() { return 1; } };"
1019 "struct B { int operator()() { return 2; } };"
1020 "template<typename ...T> struct C : T... { using T::operator()...; };"
1021 "C<A, B> declToImport;",
1022 FromLang: Lang_CXX20, ToCode: "", ToLang: Lang_CXX20, Verifier,
1023 AMatcher: varDecl(hasType(InnerMatcher: elaboratedType(namesType(InnerMatcher: templateSpecializationType(
1024 hasDeclaration(InnerMatcher: classTemplateSpecializationDecl(
1025 hasDescendant(usingPackDecl())))))))));
1026}
1027
1028/// \brief Matches shadow declarations introduced into a scope by a
1029/// (resolved) using declaration.
1030///
1031/// Given
1032/// \code
1033/// namespace n { int f; }
1034/// namespace declToImport { using n::f; }
1035/// \endcode
1036/// usingShadowDecl()
1037/// matches \code f \endcode
1038const internal::VariadicDynCastAllOfMatcher<Decl,
1039 UsingShadowDecl> usingShadowDecl;
1040
1041TEST_P(ImportDecl, ImportUsingShadowDecl) {
1042 MatchVerifier<Decl> Verifier;
1043 // from using-decl
1044 testImport(FromCode: "namespace foo { int bar; }"
1045 "namespace declToImport { using foo::bar; }",
1046 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
1047 AMatcher: namespaceDecl(has(usingShadowDecl(hasName(Name: "bar")))));
1048 // from using-enum-decl
1049 testImport(FromCode: "namespace foo { enum bar {baz, toto, quux }; }"
1050 "namespace declToImport { using enum foo::bar; }",
1051 FromLang: Lang_CXX20, ToCode: "", ToLang: Lang_CXX20, Verifier,
1052 AMatcher: namespaceDecl(has(usingShadowDecl(hasName(Name: "baz")))));
1053}
1054
1055TEST_P(ImportExpr, ImportUnresolvedLookupExpr) {
1056 MatchVerifier<Decl> Verifier;
1057 testImport(FromCode: "template<typename T> int foo();"
1058 "template <typename T> void declToImport() {"
1059 " (void)::foo<T>;"
1060 " (void)::template foo<T>;"
1061 "}"
1062 "void instantiate() { declToImport<int>(); }",
1063 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
1064 AMatcher: functionTemplateDecl(hasDescendant(unresolvedLookupExpr())));
1065}
1066
1067TEST_P(ImportExpr, ImportCXXUnresolvedConstructExpr) {
1068 MatchVerifier<Decl> Verifier;
1069 testImport(FromCode: "template <typename T> struct C { T t; };"
1070 "template <typename T> void declToImport() {"
1071 " C<T> d;"
1072 " d.t = T();"
1073 "}"
1074 "void instantiate() { declToImport<int>(); }",
1075 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
1076 AMatcher: functionTemplateDecl(hasDescendant(
1077 binaryOperator(has(cxxUnresolvedConstructExpr())))));
1078 testImport(FromCode: "template <typename T> struct C { T t; };"
1079 "template <typename T> void declToImport() {"
1080 " C<T> d;"
1081 " (&d)->t = T();"
1082 "}"
1083 "void instantiate() { declToImport<int>(); }",
1084 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
1085 AMatcher: functionTemplateDecl(hasDescendant(
1086 binaryOperator(has(cxxUnresolvedConstructExpr())))));
1087}
1088
1089/// Check that function "declToImport()" (which is the templated function
1090/// for corresponding FunctionTemplateDecl) is not added into DeclContext.
1091/// Same for class template declarations.
1092TEST_P(ImportDecl, ImportTemplatedDeclForTemplate) {
1093 MatchVerifier<Decl> Verifier;
1094 testImport(FromCode: "template <typename T> void declToImport() { T a = 1; }"
1095 "void instantiate() { declToImport<int>(); }",
1096 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
1097 AMatcher: functionTemplateDecl(hasAncestor(translationUnitDecl(
1098 unless(has(functionDecl(hasName(Name: "declToImport"))))))));
1099 testImport(FromCode: "template <typename T> struct declToImport { T t; };"
1100 "void instantiate() { declToImport<int>(); }",
1101 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
1102 AMatcher: classTemplateDecl(hasAncestor(translationUnitDecl(
1103 unless(has(cxxRecordDecl(hasName(Name: "declToImport"))))))));
1104}
1105
1106TEST_P(ImportDecl, ImportClassTemplatePartialSpecialization) {
1107 MatchVerifier<Decl> Verifier;
1108 auto Code =
1109 R"s(
1110 struct declToImport {
1111 template <typename T0> struct X;
1112 template <typename T0> struct X<T0 *> {};
1113 };
1114 )s";
1115 testImport(FromCode: Code, FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
1116 AMatcher: recordDecl(has(classTemplateDecl()),
1117 has(classTemplateSpecializationDecl())));
1118}
1119
1120TEST_P(ImportExpr, CXXOperatorCallExpr) {
1121 MatchVerifier<Decl> Verifier;
1122 testImport(
1123 FromCode: "class declToImport {"
1124 " void f() { *this = declToImport(); }"
1125 "};",
1126 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
1127 AMatcher: cxxRecordDecl(has(cxxMethodDecl(hasDescendant(cxxOperatorCallExpr())))));
1128}
1129
1130TEST_P(ImportExpr, DependentSizedArrayType) {
1131 MatchVerifier<Decl> Verifier;
1132 testImport(FromCode: "template<typename T, int Size> class declToImport {"
1133 " T data[Size];"
1134 "};",
1135 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
1136 AMatcher: classTemplateDecl(has(cxxRecordDecl(
1137 has(fieldDecl(hasType(InnerMatcher: dependentSizedArrayType())))))));
1138}
1139
1140TEST_P(ImportExpr, DependentSizedExtVectorType) {
1141 MatchVerifier<Decl> Verifier;
1142 testImport(FromCode: "template<typename T, int Size>"
1143 "class declToImport {"
1144 " typedef T __attribute__((ext_vector_type(Size))) type;"
1145 "};",
1146 FromLang: Lang_CXX03, ToCode: "", ToLang: Lang_CXX03, Verifier,
1147 AMatcher: classTemplateDecl(has(cxxRecordDecl(
1148 has(typedefDecl(hasType(InnerMatcher: dependentSizedExtVectorType())))))));
1149}
1150
1151TEST_P(ASTImporterOptionSpecificTestBase, ImportUsingPackDecl) {
1152 Decl *FromTU = getTuDecl(
1153 SrcCode: "struct A { int operator()() { return 1; } };"
1154 "struct B { int operator()() { return 2; } };"
1155 "template<typename ...T> struct C : T... { using T::operator()...; };"
1156 "C<A, B> Var;",
1157 Lang: Lang_CXX20);
1158
1159 auto From = FirstDeclMatcher<UsingPackDecl>().match(D: FromTU, AMatcher: usingPackDecl());
1160 ASSERT_TRUE(From);
1161 auto To = cast<UsingPackDecl>(Import(From, Lang_CXX20));
1162 ASSERT_TRUE(To);
1163
1164 ArrayRef<NamedDecl *> FromExpansions = From->expansions();
1165 ArrayRef<NamedDecl *> ToExpansions = To->expansions();
1166 ASSERT_EQ(FromExpansions.size(), ToExpansions.size());
1167 for (unsigned int I = 0; I < FromExpansions.size(); ++I) {
1168 auto ImportedExpansion = Import(From: FromExpansions[I], Lang: Lang_CXX20);
1169 EXPECT_EQ(ImportedExpansion, ToExpansions[I]);
1170 }
1171
1172 auto ImportedDC = cast<Decl>(Import(From->getDeclContext(), Lang_CXX20));
1173 EXPECT_EQ(ImportedDC, cast<Decl>(To->getDeclContext()));
1174}
1175
1176TEST_P(ASTImporterOptionSpecificTestBase, TemplateTypeParmDeclNoDefaultArg) {
1177 Decl *FromTU = getTuDecl(SrcCode: "template<typename T> struct X {};", Lang: Lang_CXX03);
1178 auto From = FirstDeclMatcher<TemplateTypeParmDecl>().match(
1179 D: FromTU, AMatcher: templateTypeParmDecl(hasName(Name: "T")));
1180 TemplateTypeParmDecl *To = Import(From, Lang_CXX03);
1181 ASSERT_FALSE(To->hasDefaultArgument());
1182}
1183
1184TEST_P(ASTImporterOptionSpecificTestBase, TemplateTypeParmDeclDefaultArg) {
1185 Decl *FromTU =
1186 getTuDecl(SrcCode: "template<typename T = int> struct X {};", Lang: Lang_CXX03);
1187 auto From = FirstDeclMatcher<TemplateTypeParmDecl>().match(
1188 D: FromTU, AMatcher: templateTypeParmDecl(hasName(Name: "T")));
1189 TemplateTypeParmDecl *To = Import(From, Lang_CXX03);
1190 ASSERT_TRUE(To->hasDefaultArgument());
1191 QualType ToArg = To->getDefaultArgument();
1192 ASSERT_EQ(ToArg, QualType(To->getASTContext().IntTy));
1193}
1194
1195TEST_P(ASTImporterOptionSpecificTestBase, ImportBeginLocOfDeclRefExpr) {
1196 Decl *FromTU =
1197 getTuDecl(SrcCode: "class A { public: static int X; }; void f() { (void)A::X; }",
1198 Lang: Lang_CXX03);
1199 auto From = FirstDeclMatcher<FunctionDecl>().match(
1200 D: FromTU, AMatcher: functionDecl(hasName(Name: "f")));
1201 ASSERT_TRUE(From);
1202 ASSERT_TRUE(
1203 cast<CStyleCastExpr>(cast<CompoundStmt>(From->getBody())->body_front())
1204 ->getSubExpr()
1205 ->getBeginLoc()
1206 .isValid());
1207 FunctionDecl *To = Import(From, Lang_CXX03);
1208 ASSERT_TRUE(To);
1209 ASSERT_TRUE(
1210 cast<CStyleCastExpr>(cast<CompoundStmt>(To->getBody())->body_front())
1211 ->getSubExpr()
1212 ->getBeginLoc()
1213 .isValid());
1214}
1215
1216TEST_P(ASTImporterOptionSpecificTestBase,
1217 TemplateTemplateParmDeclNoDefaultArg) {
1218 Decl *FromTU = getTuDecl(SrcCode: R"(
1219 template<template<typename> typename TT> struct Y {};
1220 )",
1221 Lang: Lang_CXX17);
1222 auto From = FirstDeclMatcher<TemplateTemplateParmDecl>().match(
1223 D: FromTU, AMatcher: templateTemplateParmDecl(hasName(Name: "TT")));
1224 TemplateTemplateParmDecl *To = Import(From, Lang_CXX17);
1225 ASSERT_FALSE(To->hasDefaultArgument());
1226}
1227
1228TEST_P(ASTImporterOptionSpecificTestBase, TemplateTemplateParmDeclDefaultArg) {
1229 Decl *FromTU = getTuDecl(SrcCode: R"(
1230 template<typename T> struct X {};
1231 template<template<typename> typename TT = X> struct Y {};
1232 )",
1233 Lang: Lang_CXX17);
1234 auto From = FirstDeclMatcher<TemplateTemplateParmDecl>().match(
1235 D: FromTU, AMatcher: templateTemplateParmDecl(hasName(Name: "TT")));
1236 TemplateTemplateParmDecl *To = Import(From, Lang_CXX17);
1237 ASSERT_TRUE(To->hasDefaultArgument());
1238 const TemplateArgument &ToDefaultArg = To->getDefaultArgument().getArgument();
1239 ASSERT_TRUE(To->isTemplateDecl());
1240 TemplateDecl *ToTemplate = ToDefaultArg.getAsTemplate().getAsTemplateDecl();
1241
1242 // Find the default argument template 'X' in the AST and compare it against
1243 // the default argument we got.
1244 auto ToExpectedDecl = FirstDeclMatcher<ClassTemplateDecl>().match(
1245 To->getTranslationUnitDecl(), classTemplateDecl(hasName(Name: "X")));
1246 ASSERT_EQ(ToTemplate, ToExpectedDecl);
1247}
1248
1249TEST_P(ASTImporterOptionSpecificTestBase, NonTypeTemplateParmDeclNoDefaultArg) {
1250 Decl *FromTU = getTuDecl(SrcCode: "template<int N> struct X {};", Lang: Lang_CXX03);
1251 auto From = FirstDeclMatcher<NonTypeTemplateParmDecl>().match(
1252 D: FromTU, AMatcher: nonTypeTemplateParmDecl(hasName(Name: "N")));
1253 NonTypeTemplateParmDecl *To = Import(From, Lang_CXX03);
1254 ASSERT_FALSE(To->hasDefaultArgument());
1255}
1256
1257TEST_P(ASTImporterOptionSpecificTestBase, NonTypeTemplateParmDeclDefaultArg) {
1258 Decl *FromTU = getTuDecl(SrcCode: "template<int S = 1> struct X {};", Lang: Lang_CXX03);
1259 auto From = FirstDeclMatcher<NonTypeTemplateParmDecl>().match(
1260 D: FromTU, AMatcher: nonTypeTemplateParmDecl(hasName(Name: "S")));
1261 NonTypeTemplateParmDecl *To = Import(From, Lang_CXX03);
1262 ASSERT_TRUE(To->hasDefaultArgument());
1263 Stmt *ToArg = To->getDefaultArgument();
1264 ASSERT_TRUE(isa<IntegerLiteral>(ToArg));
1265 ASSERT_EQ(cast<IntegerLiteral>(ToArg)->getValue().getLimitedValue(), 1U);
1266}
1267
1268TEST_P(ASTImporterOptionSpecificTestBase, TemplateArgumentsDefaulted) {
1269 Decl *FromTU = getTuDecl(SrcCode: R"(
1270 template<typename T> struct X {};
1271 template<typename TP = double,
1272 int NTTP = 50,
1273 template<typename> typename TT = X> struct S {};
1274 S<> s;
1275 )",
1276 Lang: Lang_CXX17);
1277 auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
1278 D: FromTU, AMatcher: classTemplateSpecializationDecl(hasName(Name: "S")));
1279 ASSERT_TRUE(FromSpec);
1280 auto *ToSpec = Import(FromSpec, Lang_CXX03);
1281 ASSERT_TRUE(ToSpec);
1282 auto const &TList = ToSpec->getTemplateArgs();
1283 for (auto const &Arg : TList.asArray()) {
1284 ASSERT_TRUE(Arg.getIsDefaulted());
1285 }
1286}
1287
1288TEST_P(ASTImporterOptionSpecificTestBase,
1289 ImportOfTemplatedDeclOfClassTemplateDecl) {
1290 Decl *FromTU = getTuDecl(SrcCode: "template<class X> struct S{};", Lang: Lang_CXX03);
1291 auto From =
1292 FirstDeclMatcher<ClassTemplateDecl>().match(D: FromTU, AMatcher: classTemplateDecl());
1293 ASSERT_TRUE(From);
1294 auto To = cast<ClassTemplateDecl>(Import(From, Lang_CXX03));
1295 ASSERT_TRUE(To);
1296 Decl *ToTemplated = To->getTemplatedDecl();
1297 Decl *ToTemplated1 = Import(From->getTemplatedDecl(), Lang_CXX03);
1298 EXPECT_TRUE(ToTemplated1);
1299 EXPECT_EQ(ToTemplated1, ToTemplated);
1300}
1301
1302TEST_P(ASTImporterOptionSpecificTestBase,
1303 ImportOfTemplatedDeclOfFunctionTemplateDecl) {
1304 Decl *FromTU = getTuDecl(SrcCode: "template<class X> void f(){}", Lang: Lang_CXX03);
1305 auto From = FirstDeclMatcher<FunctionTemplateDecl>().match(
1306 D: FromTU, AMatcher: functionTemplateDecl());
1307 ASSERT_TRUE(From);
1308 auto To = cast<FunctionTemplateDecl>(Import(From, Lang_CXX03));
1309 ASSERT_TRUE(To);
1310 Decl *ToTemplated = To->getTemplatedDecl();
1311 Decl *ToTemplated1 = Import(From->getTemplatedDecl(), Lang_CXX03);
1312 EXPECT_TRUE(ToTemplated1);
1313 EXPECT_EQ(ToTemplated1, ToTemplated);
1314}
1315
1316TEST_P(ASTImporterOptionSpecificTestBase,
1317 ImportOfTemplatedDeclShouldImportTheClassTemplateDecl) {
1318 Decl *FromTU = getTuDecl(SrcCode: "template<class X> struct S{};", Lang: Lang_CXX03);
1319 auto FromFT =
1320 FirstDeclMatcher<ClassTemplateDecl>().match(D: FromTU, AMatcher: classTemplateDecl());
1321 ASSERT_TRUE(FromFT);
1322
1323 auto ToTemplated =
1324 cast<CXXRecordDecl>(Import(FromFT->getTemplatedDecl(), Lang_CXX03));
1325 EXPECT_TRUE(ToTemplated);
1326 auto ToTU = ToTemplated->getTranslationUnitDecl();
1327 auto ToFT =
1328 FirstDeclMatcher<ClassTemplateDecl>().match(ToTU, classTemplateDecl());
1329 EXPECT_TRUE(ToFT);
1330}
1331
1332TEST_P(ASTImporterOptionSpecificTestBase,
1333 ImportOfTemplatedDeclShouldImportTheFunctionTemplateDecl) {
1334 Decl *FromTU = getTuDecl(SrcCode: "template<class X> void f(){}", Lang: Lang_CXX03);
1335 auto FromFT = FirstDeclMatcher<FunctionTemplateDecl>().match(
1336 D: FromTU, AMatcher: functionTemplateDecl());
1337 ASSERT_TRUE(FromFT);
1338
1339 auto ToTemplated =
1340 cast<FunctionDecl>(Import(FromFT->getTemplatedDecl(), Lang_CXX03));
1341 EXPECT_TRUE(ToTemplated);
1342 auto ToTU = ToTemplated->getTranslationUnitDecl();
1343 auto ToFT = FirstDeclMatcher<FunctionTemplateDecl>().match(
1344 ToTU, functionTemplateDecl());
1345 EXPECT_TRUE(ToFT);
1346}
1347
1348TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplatedDecl) {
1349 auto Code =
1350 R"(
1351 namespace x {
1352 template<class X> struct S1{};
1353 template<class X> struct S2{};
1354 template<class X> struct S3{};
1355 }
1356 )";
1357 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX03);
1358 auto FromNs =
1359 FirstDeclMatcher<NamespaceDecl>().match(D: FromTU, AMatcher: namespaceDecl());
1360 auto ToNs = cast<NamespaceDecl>(Import(FromNs, Lang_CXX03));
1361 ASSERT_TRUE(ToNs);
1362 auto From =
1363 FirstDeclMatcher<ClassTemplateDecl>().match(D: FromTU,
1364 AMatcher: classTemplateDecl(
1365 hasName(Name: "S2")));
1366 auto To =
1367 FirstDeclMatcher<ClassTemplateDecl>().match(ToNs,
1368 classTemplateDecl(
1369 hasName(Name: "S2")));
1370 ASSERT_TRUE(From);
1371 ASSERT_TRUE(To);
1372 auto ToTemplated = To->getTemplatedDecl();
1373 auto ToTemplated1 =
1374 cast<CXXRecordDecl>(Import(From->getTemplatedDecl(), Lang_CXX03));
1375 EXPECT_TRUE(ToTemplated1);
1376 ASSERT_EQ(ToTemplated1, ToTemplated);
1377}
1378
1379TEST_P(ASTImporterOptionSpecificTestBase,
1380 ImportTemplateSpecializationStaticMember) {
1381 auto FromCode =
1382 R"(
1383 template <typename H> class Test{
1384 public:
1385 static const unsigned int length;
1386 };
1387
1388 template<> const unsigned int Test<int>::length;
1389 template<> const unsigned int Test<int>::length = 0;
1390 )";
1391 auto ToCode =
1392 R"(
1393 template <typename H> class Test {
1394 public:
1395 static const unsigned int length;
1396 };
1397
1398 template <> const unsigned int Test<int>::length;
1399
1400 void foo() { int i = 1 / Test<int>::length; }
1401 )";
1402 Decl *FromTU = getTuDecl(SrcCode: FromCode, Lang: Lang_CXX14);
1403 auto FromDecl = FirstDeclMatcher<VarDecl>().match(
1404 D: FromTU, AMatcher: varDecl(hasName(Name: "length"), isDefinition()));
1405 Decl *ToTu = getToTuDecl(ToSrcCode: ToCode, ToLang: Lang_CXX14);
1406 auto ToX = Import(FromDecl, Lang_CXX03);
1407 auto ToDecl = FirstDeclMatcher<VarDecl>().match(
1408 D: ToTu, AMatcher: varDecl(hasName(Name: "length"), isDefinition()));
1409 EXPECT_TRUE(ToX);
1410 EXPECT_EQ(ToX, ToDecl);
1411}
1412
1413TEST_P(ASTImporterOptionSpecificTestBase, ImportChooseExpr) {
1414 // This tests the import of isConditionTrue directly to make sure the importer
1415 // gets it right.
1416 Decl *From, *To;
1417 std::tie(args&: From, args&: To) = getImportedDecl(
1418 FromSrcCode: "void declToImport() { (void)__builtin_choose_expr(1, 0, 1); }", FromLang: Lang_C99,
1419 ToSrcCode: "", ToLang: Lang_C99);
1420
1421 auto ToResults = match(Matcher: chooseExpr().bind(ID: "choose"), Context&: To->getASTContext());
1422 auto FromResults = match(Matcher: chooseExpr().bind(ID: "choose"), Context&: From->getASTContext());
1423
1424 const ChooseExpr *FromChooseExpr =
1425 selectFirst<ChooseExpr>(BoundTo: "choose", Results: FromResults);
1426 ASSERT_TRUE(FromChooseExpr);
1427
1428 const ChooseExpr *ToChooseExpr = selectFirst<ChooseExpr>(BoundTo: "choose", Results: ToResults);
1429 ASSERT_TRUE(ToChooseExpr);
1430
1431 EXPECT_EQ(FromChooseExpr->isConditionTrue(), ToChooseExpr->isConditionTrue());
1432 EXPECT_EQ(FromChooseExpr->isConditionDependent(),
1433 ToChooseExpr->isConditionDependent());
1434}
1435
1436TEST_P(ASTImporterOptionSpecificTestBase, ImportConvertVectorExpr) {
1437 Decl *From, *To;
1438 std::tie(args&: From, args&: To) = getImportedDecl(
1439 FromSrcCode: "typedef double v4double __attribute__((__vector_size__(32)));"
1440 "typedef float v4float __attribute__((__vector_size__(16)));"
1441 "v4float vf;"
1442 "void declToImport() { (void)__builtin_convertvector(vf, v4double); }",
1443 FromLang: Lang_CXX03, ToSrcCode: "", ToLang: Lang_CXX03);
1444
1445 auto ToResults =
1446 match(Matcher: convertVectorExpr().bind(ID: "convert"), Context&: To->getASTContext());
1447 auto FromResults =
1448 match(Matcher: convertVectorExpr().bind(ID: "convert"), Context&: From->getASTContext());
1449
1450 const ConvertVectorExpr *FromConvertVectorExpr =
1451 selectFirst<ConvertVectorExpr>(BoundTo: "convert", Results: FromResults);
1452 ASSERT_TRUE(FromConvertVectorExpr);
1453
1454 const ConvertVectorExpr *ToConvertVectorExpr =
1455 selectFirst<ConvertVectorExpr>(BoundTo: "convert", Results: ToResults);
1456 ASSERT_TRUE(ToConvertVectorExpr);
1457}
1458
1459TEST_P(ASTImporterOptionSpecificTestBase, ImportGenericSelectionExpr) {
1460 Decl *From, *To;
1461 std::tie(args&: From, args&: To) = getImportedDecl(
1462 FromSrcCode: R"(
1463 int declToImport() {
1464 int x;
1465 return _Generic(x, int: 0, default: 1);
1466 }
1467 )",
1468 FromLang: Lang_C99, ToSrcCode: "", ToLang: Lang_C99);
1469
1470 auto ToResults =
1471 match(Matcher: genericSelectionExpr().bind(ID: "expr"), Context&: To->getASTContext());
1472 auto FromResults =
1473 match(Matcher: genericSelectionExpr().bind(ID: "expr"), Context&: From->getASTContext());
1474
1475 const GenericSelectionExpr *FromGenericSelectionExpr =
1476 selectFirst<GenericSelectionExpr>(BoundTo: "expr", Results: FromResults);
1477 ASSERT_TRUE(FromGenericSelectionExpr);
1478
1479 const GenericSelectionExpr *ToGenericSelectionExpr =
1480 selectFirst<GenericSelectionExpr>(BoundTo: "expr", Results: ToResults);
1481 ASSERT_TRUE(ToGenericSelectionExpr);
1482
1483 EXPECT_EQ(FromGenericSelectionExpr->isResultDependent(),
1484 ToGenericSelectionExpr->isResultDependent());
1485 EXPECT_EQ(FromGenericSelectionExpr->getResultIndex(),
1486 ToGenericSelectionExpr->getResultIndex());
1487}
1488
1489TEST_P(ASTImporterOptionSpecificTestBase,
1490 ImportFunctionWithBackReferringParameter) {
1491 Decl *From, *To;
1492 std::tie(args&: From, args&: To) = getImportedDecl(
1493 FromSrcCode: R"(
1494 template <typename T> struct X {};
1495
1496 void declToImport(int y, X<int> &x) {}
1497
1498 template <> struct X<int> {
1499 void g() {
1500 X<int> x;
1501 declToImport(0, x);
1502 }
1503 };
1504 )",
1505 FromLang: Lang_CXX03, ToSrcCode: "", ToLang: Lang_CXX03);
1506
1507 MatchVerifier<Decl> Verifier;
1508 auto Matcher = functionDecl(hasName(Name: "declToImport"),
1509 parameterCountIs(N: 2),
1510 hasParameter(N: 0, InnerMatcher: hasName(Name: "y")),
1511 hasParameter(N: 1, InnerMatcher: hasName(Name: "x")),
1512 hasParameter(N: 1, InnerMatcher: hasType(InnerMatcher: asString(Name: "X<int> &"))));
1513 ASSERT_TRUE(Verifier.match(From, Matcher));
1514 EXPECT_TRUE(Verifier.match(To, Matcher));
1515}
1516
1517TEST_P(ASTImporterOptionSpecificTestBase,
1518 TUshouldNotContainTemplatedDeclOfFunctionTemplates) {
1519 Decl *From, *To;
1520 std::tie(args&: From, args&: To) =
1521 getImportedDecl(FromSrcCode: "template <typename T> void declToImport() { T a = 1; }"
1522 "void instantiate() { declToImport<int>(); }",
1523 FromLang: Lang_CXX03, ToSrcCode: "", ToLang: Lang_CXX03);
1524
1525 auto Check = [](Decl *D) -> bool {
1526 auto TU = D->getTranslationUnitDecl();
1527 for (auto Child : TU->decls()) {
1528 if (auto *FD = dyn_cast<FunctionDecl>(Child)) {
1529 if (FD->getNameAsString() == "declToImport") {
1530 GTEST_NONFATAL_FAILURE_(
1531 "TU should not contain any FunctionDecl with name declToImport");
1532 return false;
1533 }
1534 }
1535 }
1536 return true;
1537 };
1538
1539 ASSERT_TRUE(Check(From));
1540 EXPECT_TRUE(Check(To));
1541}
1542
1543TEST_P(ASTImporterOptionSpecificTestBase,
1544 TUshouldNotContainTemplatedDeclOfClassTemplates) {
1545 Decl *From, *To;
1546 std::tie(args&: From, args&: To) =
1547 getImportedDecl(FromSrcCode: "template <typename T> struct declToImport { T t; };"
1548 "void instantiate() { declToImport<int>(); }",
1549 FromLang: Lang_CXX03, ToSrcCode: "", ToLang: Lang_CXX03);
1550
1551 auto Check = [](Decl *D) -> bool {
1552 auto TU = D->getTranslationUnitDecl();
1553 for (auto Child : TU->decls()) {
1554 if (auto *RD = dyn_cast<CXXRecordDecl>(Child)) {
1555 if (RD->getNameAsString() == "declToImport") {
1556 GTEST_NONFATAL_FAILURE_(
1557 "TU should not contain any CXXRecordDecl with name declToImport");
1558 return false;
1559 }
1560 }
1561 }
1562 return true;
1563 };
1564
1565 ASSERT_TRUE(Check(From));
1566 EXPECT_TRUE(Check(To));
1567}
1568
1569TEST_P(ASTImporterOptionSpecificTestBase,
1570 TUshouldNotContainTemplatedDeclOfTypeAlias) {
1571 Decl *From, *To;
1572 std::tie(args&: From, args&: To) =
1573 getImportedDecl(
1574 FromSrcCode: "template <typename T> struct X {};"
1575 "template <typename T> using declToImport = X<T>;"
1576 "void instantiate() { declToImport<int> a; }",
1577 FromLang: Lang_CXX11, ToSrcCode: "", ToLang: Lang_CXX11);
1578
1579 auto Check = [](Decl *D) -> bool {
1580 auto TU = D->getTranslationUnitDecl();
1581 for (auto Child : TU->decls()) {
1582 if (auto *AD = dyn_cast<TypeAliasDecl>(Child)) {
1583 if (AD->getNameAsString() == "declToImport") {
1584 GTEST_NONFATAL_FAILURE_(
1585 "TU should not contain any TypeAliasDecl with name declToImport");
1586 return false;
1587 }
1588 }
1589 }
1590 return true;
1591 };
1592
1593 ASSERT_TRUE(Check(From));
1594 EXPECT_TRUE(Check(To));
1595}
1596
1597TEST_P(ASTImporterOptionSpecificTestBase,
1598 TUshouldNotContainClassTemplateSpecializationOfImplicitInstantiation) {
1599
1600 Decl *From, *To;
1601 std::tie(args&: From, args&: To) = getImportedDecl(
1602 FromSrcCode: R"(
1603 template<class T>
1604 class Base {};
1605 class declToImport : public Base<declToImport> {};
1606 )",
1607 FromLang: Lang_CXX03, ToSrcCode: "", ToLang: Lang_CXX03);
1608
1609 // Check that the ClassTemplateSpecializationDecl is NOT the child of the TU.
1610 auto Pattern =
1611 translationUnitDecl(unless(has(classTemplateSpecializationDecl())));
1612 ASSERT_TRUE(
1613 MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern));
1614 EXPECT_TRUE(
1615 MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
1616
1617 // Check that the ClassTemplateSpecializationDecl is the child of the
1618 // ClassTemplateDecl.
1619 Pattern = translationUnitDecl(has(classTemplateDecl(
1620 hasName(Name: "Base"), has(classTemplateSpecializationDecl()))));
1621 ASSERT_TRUE(
1622 MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern));
1623 EXPECT_TRUE(
1624 MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
1625}
1626
1627AST_MATCHER_P(RecordDecl, hasFieldOrder, std::vector<StringRef>, Order) {
1628 size_t Index = 0;
1629 for (Decl *D : Node.decls()) {
1630 if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) {
1631 auto *ND = cast<NamedDecl>(D);
1632 if (Index == Order.size())
1633 return false;
1634 if (ND->getName() != Order[Index])
1635 return false;
1636 ++Index;
1637 }
1638 }
1639 return Index == Order.size();
1640}
1641
1642TEST_P(ASTImporterOptionSpecificTestBase,
1643 TUshouldContainClassTemplateSpecializationOfExplicitInstantiation) {
1644 Decl *From, *To;
1645 std::tie(args&: From, args&: To) = getImportedDecl(
1646 FromSrcCode: R"(
1647 namespace NS {
1648 template<class T>
1649 class X {};
1650 template class X<int>;
1651 }
1652 )",
1653 FromLang: Lang_CXX03, ToSrcCode: "", ToLang: Lang_CXX03, Identifier: "NS");
1654
1655 // Check that the ClassTemplateSpecializationDecl is NOT the child of the
1656 // ClassTemplateDecl.
1657 auto Pattern = namespaceDecl(has(classTemplateDecl(
1658 hasName(Name: "X"), unless(has(classTemplateSpecializationDecl())))));
1659 ASSERT_TRUE(MatchVerifier<Decl>{}.match(From, Pattern));
1660 EXPECT_TRUE(MatchVerifier<Decl>{}.match(To, Pattern));
1661
1662 // Check that the ClassTemplateSpecializationDecl is the child of the
1663 // NamespaceDecl.
1664 Pattern = namespaceDecl(has(classTemplateSpecializationDecl(hasName(Name: "X"))));
1665 ASSERT_TRUE(MatchVerifier<Decl>{}.match(From, Pattern));
1666 EXPECT_TRUE(MatchVerifier<Decl>{}.match(To, Pattern));
1667}
1668
1669TEST_P(ASTImporterOptionSpecificTestBase,
1670 CXXRecordDeclFieldsShouldBeInCorrectOrder) {
1671 Decl *From, *To;
1672 std::tie(args&: From, args&: To) =
1673 getImportedDecl(
1674 FromSrcCode: "struct declToImport { int a; int b; };",
1675 FromLang: Lang_CXX11, ToSrcCode: "", ToLang: Lang_CXX11);
1676
1677 MatchVerifier<Decl> Verifier;
1678 ASSERT_TRUE(Verifier.match(From, cxxRecordDecl(hasFieldOrder({"a", "b"}))));
1679 EXPECT_TRUE(Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b"}))));
1680}
1681
1682TEST_P(ASTImporterOptionSpecificTestBase,
1683 CXXRecordDeclFieldOrderShouldNotDependOnImportOrder) {
1684 Decl *From, *To;
1685 std::tie(args&: From, args&: To) = getImportedDecl(
1686 // The original recursive algorithm of ASTImporter first imports 'c' then
1687 // 'b' and lastly 'a'. Therefore we must restore the order somehow.
1688 FromSrcCode: R"s(
1689 struct declToImport {
1690 int a = c + b;
1691 int b = 1;
1692 int c = 2;
1693 };
1694 )s",
1695 FromLang: Lang_CXX11, ToSrcCode: "", ToLang: Lang_CXX11);
1696
1697 MatchVerifier<Decl> Verifier;
1698 ASSERT_TRUE(
1699 Verifier.match(From, cxxRecordDecl(hasFieldOrder({"a", "b", "c"}))));
1700 EXPECT_TRUE(
1701 Verifier.match(To, cxxRecordDecl(hasFieldOrder({"a", "b", "c"}))));
1702}
1703
1704TEST_P(ASTImporterOptionSpecificTestBase,
1705 CXXRecordDeclFieldAndIndirectFieldOrder) {
1706 Decl *From, *To;
1707 std::tie(args&: From, args&: To) = getImportedDecl(
1708 // First field is "a", then the field for unnamed union, then "b" and "c"
1709 // from it (indirect fields), then "d".
1710 FromSrcCode: R"s(
1711 struct declToImport {
1712 int a = d;
1713 union {
1714 int b;
1715 int c;
1716 };
1717 int d;
1718 };
1719 )s",
1720 FromLang: Lang_CXX11, ToSrcCode: "", ToLang: Lang_CXX11);
1721
1722 MatchVerifier<Decl> Verifier;
1723 ASSERT_TRUE(Verifier.match(
1724 From, cxxRecordDecl(hasFieldOrder({"a", "", "b", "c", "d"}))));
1725 EXPECT_TRUE(Verifier.match(
1726 To, cxxRecordDecl(hasFieldOrder({"a", "", "b", "c", "d"}))));
1727}
1728
1729TEST_P(ASTImporterOptionSpecificTestBase, ShouldImportImplicitCXXRecordDecl) {
1730 Decl *From, *To;
1731 std::tie(args&: From, args&: To) = getImportedDecl(
1732 FromSrcCode: R"(
1733 struct declToImport {
1734 };
1735 )",
1736 FromLang: Lang_CXX03, ToSrcCode: "", ToLang: Lang_CXX03);
1737
1738 MatchVerifier<Decl> Verifier;
1739 // Match the implicit Decl.
1740 auto Matcher = cxxRecordDecl(has(cxxRecordDecl()));
1741 ASSERT_TRUE(Verifier.match(From, Matcher));
1742 EXPECT_TRUE(Verifier.match(To, Matcher));
1743}
1744
1745TEST_P(ASTImporterOptionSpecificTestBase,
1746 ShouldImportImplicitCXXRecordDeclOfClassTemplate) {
1747 Decl *From, *To;
1748 std::tie(args&: From, args&: To) = getImportedDecl(
1749 FromSrcCode: R"(
1750 template <typename U>
1751 struct declToImport {
1752 };
1753 )",
1754 FromLang: Lang_CXX03, ToSrcCode: "", ToLang: Lang_CXX03);
1755
1756 MatchVerifier<Decl> Verifier;
1757 // Match the implicit Decl.
1758 auto Matcher = classTemplateDecl(has(cxxRecordDecl(has(cxxRecordDecl()))));
1759 ASSERT_TRUE(Verifier.match(From, Matcher));
1760 EXPECT_TRUE(Verifier.match(To, Matcher));
1761}
1762
1763TEST_P(ASTImporterOptionSpecificTestBase,
1764 ShouldImportImplicitCXXRecordDeclOfClassTemplateSpecializationDecl) {
1765 Decl *From, *To;
1766 std::tie(args&: From, args&: To) = getImportedDecl(
1767 FromSrcCode: R"(
1768 template<class T>
1769 class Base {};
1770 class declToImport : public Base<declToImport> {};
1771 )",
1772 FromLang: Lang_CXX03, ToSrcCode: "", ToLang: Lang_CXX03);
1773
1774 auto hasImplicitClass = has(cxxRecordDecl());
1775 auto Pattern = translationUnitDecl(has(classTemplateDecl(
1776 hasName(Name: "Base"),
1777 has(classTemplateSpecializationDecl(hasImplicitClass)))));
1778 ASSERT_TRUE(
1779 MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern));
1780 EXPECT_TRUE(
1781 MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
1782}
1783
1784TEST_P(ASTImporterOptionSpecificTestBase, IDNSOrdinary) {
1785 Decl *From, *To;
1786 std::tie(args&: From, args&: To) =
1787 getImportedDecl(FromSrcCode: "void declToImport() {}", FromLang: Lang_CXX03, ToSrcCode: "", ToLang: Lang_CXX03);
1788
1789 MatchVerifier<Decl> Verifier;
1790 auto Matcher = functionDecl();
1791 ASSERT_TRUE(Verifier.match(From, Matcher));
1792 EXPECT_TRUE(Verifier.match(To, Matcher));
1793 EXPECT_EQ(From->getIdentifierNamespace(), To->getIdentifierNamespace());
1794}
1795
1796TEST_P(ASTImporterOptionSpecificTestBase, IDNSOfNonmemberOperator) {
1797 Decl *FromTU = getTuDecl(
1798 SrcCode: R"(
1799 struct X {};
1800 void operator<<(int, X);
1801 )",
1802 Lang: Lang_CXX03);
1803 Decl *From = LastDeclMatcher<Decl>{}.match(D: FromTU, AMatcher: functionDecl());
1804 const Decl *To = Import(From, ToLang: Lang_CXX03);
1805 EXPECT_EQ(From->getIdentifierNamespace(), To->getIdentifierNamespace());
1806}
1807
1808TEST_P(ASTImporterOptionSpecificTestBase,
1809 ShouldImportMembersOfClassTemplateSpecializationDecl) {
1810 Decl *From, *To;
1811 std::tie(args&: From, args&: To) = getImportedDecl(
1812 FromSrcCode: R"(
1813 template<class T>
1814 class Base { int a; };
1815 class declToImport : Base<declToImport> {};
1816 )",
1817 FromLang: Lang_CXX03, ToSrcCode: "", ToLang: Lang_CXX03);
1818
1819 auto Pattern = translationUnitDecl(has(classTemplateDecl(
1820 hasName(Name: "Base"),
1821 has(classTemplateSpecializationDecl(has(fieldDecl(hasName(Name: "a"))))))));
1822 ASSERT_TRUE(
1823 MatchVerifier<Decl>{}.match(From->getTranslationUnitDecl(), Pattern));
1824 EXPECT_TRUE(
1825 MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
1826}
1827
1828TEST_P(ASTImporterOptionSpecificTestBase,
1829 ImportDefinitionOfClassTemplateAfterFwdDecl) {
1830 {
1831 Decl *FromTU = getTuDecl(
1832 SrcCode: R"(
1833 template <typename T>
1834 struct B;
1835 )",
1836 Lang: Lang_CXX03, FileName: "input0.cc");
1837 auto *FromD = FirstDeclMatcher<ClassTemplateDecl>().match(
1838 D: FromTU, AMatcher: classTemplateDecl(hasName(Name: "B")));
1839
1840 Import(FromD, Lang_CXX03);
1841 }
1842
1843 {
1844 Decl *FromTU = getTuDecl(
1845 SrcCode: R"(
1846 template <typename T>
1847 struct B {
1848 void f();
1849 };
1850 )",
1851 Lang: Lang_CXX03, FileName: "input1.cc");
1852 FunctionDecl *FromD = FirstDeclMatcher<FunctionDecl>().match(
1853 D: FromTU, AMatcher: functionDecl(hasName(Name: "f")));
1854 Import(From: FromD, Lang: Lang_CXX03);
1855 auto *FromCTD = FirstDeclMatcher<ClassTemplateDecl>().match(
1856 D: FromTU, AMatcher: classTemplateDecl(hasName(Name: "B")));
1857 auto *ToCTD = cast<ClassTemplateDecl>(Import(FromCTD, Lang_CXX03));
1858 EXPECT_TRUE(ToCTD->isThisDeclarationADefinition());
1859 }
1860}
1861
1862TEST_P(ASTImporterOptionSpecificTestBase,
1863 ImportDefinitionOfClassTemplateIfThereIsAnExistingFwdDeclAndDefinition) {
1864 Decl *ToTU = getToTuDecl(
1865 ToSrcCode: R"(
1866 template <typename T>
1867 struct B {
1868 void f();
1869 };
1870
1871 template <typename T>
1872 struct B;
1873 )",
1874 ToLang: Lang_CXX03);
1875 ASSERT_EQ(1u, DeclCounterWithPredicate<ClassTemplateDecl>(
1876 [](const ClassTemplateDecl *T) {
1877 return T->isThisDeclarationADefinition();
1878 })
1879 .match(ToTU, classTemplateDecl()));
1880
1881 Decl *FromTU = getTuDecl(
1882 SrcCode: R"(
1883 template <typename T>
1884 struct B {
1885 void f();
1886 };
1887 )",
1888 Lang: Lang_CXX03, FileName: "input1.cc");
1889 ClassTemplateDecl *FromD = FirstDeclMatcher<ClassTemplateDecl>().match(
1890 D: FromTU, AMatcher: classTemplateDecl(hasName(Name: "B")));
1891
1892 Import(From: FromD, Lang: Lang_CXX03);
1893
1894 // We should have only one definition.
1895 EXPECT_EQ(1u, DeclCounterWithPredicate<ClassTemplateDecl>(
1896 [](const ClassTemplateDecl *T) {
1897 return T->isThisDeclarationADefinition();
1898 })
1899 .match(ToTU, classTemplateDecl()));
1900}
1901
1902TEST_P(ASTImporterOptionSpecificTestBase,
1903 ImportDefinitionOfClassIfThereIsAnExistingFwdDeclAndDefinition) {
1904 Decl *ToTU = getToTuDecl(
1905 ToSrcCode: R"(
1906 struct B {
1907 void f();
1908 };
1909
1910 struct B;
1911 )",
1912 ToLang: Lang_CXX03);
1913 ASSERT_EQ(2u, DeclCounter<CXXRecordDecl>().match(
1914 ToTU, cxxRecordDecl(unless(isImplicit()))));
1915
1916 Decl *FromTU = getTuDecl(
1917 SrcCode: R"(
1918 struct B {
1919 void f();
1920 };
1921 )",
1922 Lang: Lang_CXX03, FileName: "input1.cc");
1923 auto *FromD = FirstDeclMatcher<CXXRecordDecl>().match(
1924 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "B")));
1925
1926 Import(FromD, Lang_CXX03);
1927
1928 EXPECT_EQ(2u, DeclCounter<CXXRecordDecl>().match(
1929 ToTU, cxxRecordDecl(unless(isImplicit()))));
1930}
1931
1932static void CompareSourceLocs(FullSourceLoc Loc1, FullSourceLoc Loc2) {
1933 EXPECT_EQ(Loc1.getExpansionLineNumber(), Loc2.getExpansionLineNumber());
1934 EXPECT_EQ(Loc1.getExpansionColumnNumber(), Loc2.getExpansionColumnNumber());
1935 EXPECT_EQ(Loc1.getSpellingLineNumber(), Loc2.getSpellingLineNumber());
1936 EXPECT_EQ(Loc1.getSpellingColumnNumber(), Loc2.getSpellingColumnNumber());
1937}
1938static void CompareSourceRanges(SourceRange Range1, SourceRange Range2,
1939 SourceManager &SM1, SourceManager &SM2) {
1940 CompareSourceLocs(Loc1: FullSourceLoc{ Range1.getBegin(), SM1 },
1941 Loc2: FullSourceLoc{ Range2.getBegin(), SM2 });
1942 CompareSourceLocs(Loc1: FullSourceLoc{ Range1.getEnd(), SM1 },
1943 Loc2: FullSourceLoc{ Range2.getEnd(), SM2 });
1944}
1945TEST_P(ASTImporterOptionSpecificTestBase, ImportSourceLocs) {
1946 Decl *FromTU = getTuDecl(
1947 SrcCode: R"(
1948 #define MFOO(arg) arg = arg + 1
1949
1950 void foo() {
1951 int a = 5;
1952 MFOO(a);
1953 }
1954 )",
1955 Lang: Lang_CXX03);
1956 auto FromD = FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: functionDecl());
1957 auto ToD = Import(FromD, Lang_CXX03);
1958
1959 auto ToLHS = LastDeclMatcher<DeclRefExpr>().match(ToD, declRefExpr());
1960 auto FromLHS = LastDeclMatcher<DeclRefExpr>().match(D: FromTU, AMatcher: declRefExpr());
1961 auto ToRHS = LastDeclMatcher<IntegerLiteral>().match(ToD, integerLiteral());
1962 auto FromRHS =
1963 LastDeclMatcher<IntegerLiteral>().match(D: FromTU, AMatcher: integerLiteral());
1964
1965 SourceManager &ToSM = ToAST->getASTContext().getSourceManager();
1966 SourceManager &FromSM = FromD->getASTContext().getSourceManager();
1967 CompareSourceRanges(ToD->getSourceRange(), FromD->getSourceRange(), ToSM,
1968 FromSM);
1969 CompareSourceRanges(ToLHS->getSourceRange(), FromLHS->getSourceRange(), ToSM,
1970 FromSM);
1971 CompareSourceRanges(ToRHS->getSourceRange(), FromRHS->getSourceRange(), ToSM,
1972 FromSM);
1973}
1974
1975TEST_P(ASTImporterOptionSpecificTestBase, ImportNestedMacro) {
1976 Decl *FromTU = getTuDecl(
1977 SrcCode: R"(
1978 #define FUNC_INT void declToImport
1979 #define FUNC FUNC_INT
1980 FUNC(int a);
1981 )",
1982 Lang: Lang_CXX03);
1983 auto FromD = FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: functionDecl());
1984 auto ToD = Import(FromD, Lang_CXX03);
1985
1986 SourceManager &ToSM = ToAST->getASTContext().getSourceManager();
1987 SourceManager &FromSM = FromD->getASTContext().getSourceManager();
1988 CompareSourceRanges(ToD->getSourceRange(), FromD->getSourceRange(), ToSM,
1989 FromSM);
1990}
1991
1992TEST_P(
1993 ASTImporterOptionSpecificTestBase,
1994 ImportDefinitionOfClassTemplateSpecIfThereIsAnExistingFwdDeclAndDefinition) {
1995 Decl *ToTU = getToTuDecl(
1996 ToSrcCode: R"(
1997 template <typename T>
1998 struct B;
1999
2000 template <>
2001 struct B<int> {};
2002
2003 template <>
2004 struct B<int>;
2005 )",
2006 ToLang: Lang_CXX03);
2007 // We should have only one definition.
2008 ASSERT_EQ(1u, DeclCounterWithPredicate<ClassTemplateSpecializationDecl>(
2009 [](const ClassTemplateSpecializationDecl *T) {
2010 return T->isThisDeclarationADefinition();
2011 })
2012 .match(ToTU, classTemplateSpecializationDecl()));
2013
2014 Decl *FromTU = getTuDecl(
2015 SrcCode: R"(
2016 template <typename T>
2017 struct B;
2018
2019 template <>
2020 struct B<int> {};
2021 )",
2022 Lang: Lang_CXX03, FileName: "input1.cc");
2023 auto *FromD = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
2024 D: FromTU, AMatcher: classTemplateSpecializationDecl(hasName(Name: "B")));
2025
2026 Import(FromD, Lang_CXX03);
2027
2028 // We should have only one definition.
2029 EXPECT_EQ(1u, DeclCounterWithPredicate<ClassTemplateSpecializationDecl>(
2030 [](const ClassTemplateSpecializationDecl *T) {
2031 return T->isThisDeclarationADefinition();
2032 })
2033 .match(ToTU, classTemplateSpecializationDecl()));
2034}
2035
2036TEST_P(ASTImporterOptionSpecificTestBase, ObjectsWithUnnamedStructType) {
2037 Decl *FromTU = getTuDecl(
2038 SrcCode: R"(
2039 struct { int a; int b; } object0 = { 2, 3 };
2040 struct { int x; int y; int z; } object1;
2041 )",
2042 Lang: Lang_CXX03, FileName: "input0.cc");
2043
2044 auto *Obj0 =
2045 FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: varDecl(hasName(Name: "object0")));
2046 auto *From0 = getRecordDecl(Obj0);
2047 auto *Obj1 =
2048 FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: varDecl(hasName(Name: "object1")));
2049 auto *From1 = getRecordDecl(Obj1);
2050
2051 auto *To0 = Import(From0, Lang_CXX03);
2052 auto *To1 = Import(From1, Lang_CXX03);
2053
2054 EXPECT_TRUE(To0);
2055 EXPECT_TRUE(To1);
2056 EXPECT_NE(To0, To1);
2057 EXPECT_NE(To0->getCanonicalDecl(), To1->getCanonicalDecl());
2058}
2059
2060TEST_P(ASTImporterOptionSpecificTestBase, AnonymousRecords) {
2061 auto *Code =
2062 R"(
2063 struct X {
2064 struct { int a; };
2065 struct { int b; };
2066 };
2067 )";
2068 Decl *FromTU0 = getTuDecl(SrcCode: Code, Lang: Lang_C99, FileName: "input0.c");
2069
2070 Decl *FromTU1 = getTuDecl(SrcCode: Code, Lang: Lang_C99, FileName: "input1.c");
2071
2072 auto *X0 =
2073 FirstDeclMatcher<RecordDecl>().match(D: FromTU0, AMatcher: recordDecl(hasName(Name: "X")));
2074 auto *X1 =
2075 FirstDeclMatcher<RecordDecl>().match(D: FromTU1, AMatcher: recordDecl(hasName(Name: "X")));
2076 Import(X0, Lang_C99);
2077 Import(X1, Lang_C99);
2078
2079 auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2080 // We expect no (ODR) warning during the import.
2081 EXPECT_EQ(0u, ToTU->getASTContext().getDiagnostics().getNumWarnings());
2082 EXPECT_EQ(1u,
2083 DeclCounter<RecordDecl>().match(ToTU, recordDecl(hasName("X"))));
2084}
2085
2086TEST_P(ASTImporterOptionSpecificTestBase, AnonymousRecordsReversed) {
2087 Decl *FromTU0 = getTuDecl(
2088 SrcCode: R"(
2089 struct X {
2090 struct { int a; };
2091 struct { int b; };
2092 };
2093 )",
2094 Lang: Lang_C99, FileName: "input0.c");
2095
2096 Decl *FromTU1 = getTuDecl(
2097 SrcCode: R"(
2098 struct X { // reversed order
2099 struct { int b; };
2100 struct { int a; };
2101 };
2102 )",
2103 Lang: Lang_C99, FileName: "input1.c");
2104
2105 auto *X0 =
2106 FirstDeclMatcher<RecordDecl>().match(D: FromTU0, AMatcher: recordDecl(hasName(Name: "X")));
2107 auto *X1 =
2108 FirstDeclMatcher<RecordDecl>().match(D: FromTU1, AMatcher: recordDecl(hasName(Name: "X")));
2109 Import(X0, Lang_C99);
2110 Import(X1, Lang_C99);
2111
2112 auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2113 // We expect one (ODR) warning during the import.
2114 EXPECT_EQ(1u, ToTU->getASTContext().getDiagnostics().getNumWarnings());
2115 EXPECT_EQ(1u,
2116 DeclCounter<RecordDecl>().match(ToTU, recordDecl(hasName("X"))));
2117}
2118
2119TEST_P(ASTImporterOptionSpecificTestBase, ImportDoesUpdateUsedFlag) {
2120 auto Pattern = varDecl(hasName(Name: "x"));
2121 VarDecl *Imported1;
2122 {
2123 Decl *FromTU = getTuDecl(SrcCode: "extern int x;", Lang: Lang_CXX03, FileName: "input0.cc");
2124 auto *FromD = FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: Pattern);
2125 Imported1 = cast<VarDecl>(Import(FromD, Lang_CXX03));
2126 }
2127 VarDecl *Imported2;
2128 {
2129 Decl *FromTU = getTuDecl(SrcCode: "int x;", Lang: Lang_CXX03, FileName: "input1.cc");
2130 auto *FromD = FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: Pattern);
2131 Imported2 = cast<VarDecl>(Import(FromD, Lang_CXX03));
2132 }
2133 EXPECT_EQ(Imported1->getCanonicalDecl(), Imported2->getCanonicalDecl());
2134 EXPECT_FALSE(Imported2->isUsed(false));
2135 {
2136 Decl *FromTU = getTuDecl(SrcCode: "extern int x; int f() { return x; }", Lang: Lang_CXX03,
2137 FileName: "input2.cc");
2138 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
2139 D: FromTU, AMatcher: functionDecl(hasName(Name: "f")));
2140 Import(FromD, Lang_CXX03);
2141 }
2142 EXPECT_TRUE(Imported2->isUsed(false));
2143}
2144
2145TEST_P(ASTImporterOptionSpecificTestBase, ImportDoesUpdateUsedFlag2) {
2146 auto Pattern = varDecl(hasName(Name: "x"));
2147 VarDecl *ExistingD;
2148 {
2149 Decl *ToTU = getToTuDecl(ToSrcCode: "int x = 1;", ToLang: Lang_CXX03);
2150 ExistingD = FirstDeclMatcher<VarDecl>().match(D: ToTU, AMatcher: Pattern);
2151 }
2152 EXPECT_FALSE(ExistingD->isUsed(false));
2153 {
2154 Decl *FromTU =
2155 getTuDecl(SrcCode: "int x = 1; int f() { return x; }", Lang: Lang_CXX03, FileName: "input1.cc");
2156 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
2157 D: FromTU, AMatcher: functionDecl(hasName(Name: "f")));
2158 Import(FromD, Lang_CXX03);
2159 }
2160 EXPECT_TRUE(ExistingD->isUsed(false));
2161}
2162
2163TEST_P(ASTImporterOptionSpecificTestBase, ImportDoesUpdateUsedFlag3) {
2164 auto Pattern = varDecl(hasName(Name: "a"));
2165 VarDecl *ExistingD;
2166 {
2167 Decl *ToTU = getToTuDecl(
2168 ToSrcCode: R"(
2169 struct A {
2170 static const int a = 1;
2171 };
2172 )",
2173 ToLang: Lang_CXX03);
2174 ExistingD = FirstDeclMatcher<VarDecl>().match(D: ToTU, AMatcher: Pattern);
2175 }
2176 EXPECT_FALSE(ExistingD->isUsed(false));
2177 {
2178 Decl *FromTU = getTuDecl(
2179 SrcCode: R"(
2180 struct A {
2181 static const int a = 1;
2182 };
2183 const int *f() { return &A::a; } // requires storage,
2184 // thus used flag will be set
2185 )",
2186 Lang: Lang_CXX03, FileName: "input1.cc");
2187 auto *FromFunD = FirstDeclMatcher<FunctionDecl>().match(
2188 D: FromTU, AMatcher: functionDecl(hasName(Name: "f")));
2189 auto *FromD = FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: Pattern);
2190 ASSERT_TRUE(FromD->isUsed(false));
2191 Import(FromFunD, Lang_CXX03);
2192 }
2193 EXPECT_TRUE(ExistingD->isUsed(false));
2194}
2195
2196TEST_P(ASTImporterOptionSpecificTestBase, ReimportWithUsedFlag) {
2197 auto Pattern = varDecl(hasName(Name: "x"));
2198
2199 Decl *FromTU = getTuDecl(SrcCode: "int x;", Lang: Lang_CXX03, FileName: "input0.cc");
2200 auto *FromD = FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: Pattern);
2201
2202 auto *Imported1 = cast<VarDecl>(Import(FromD, Lang_CXX03));
2203
2204 ASSERT_FALSE(Imported1->isUsed(false));
2205
2206 FromD->setIsUsed();
2207 auto *Imported2 = cast<VarDecl>(Import(FromD, Lang_CXX03));
2208
2209 EXPECT_EQ(Imported1, Imported2);
2210 EXPECT_TRUE(Imported2->isUsed(false));
2211}
2212
2213struct ImportFunctions : ASTImporterOptionSpecificTestBase {};
2214
2215TEST_P(ImportFunctions, ImportPrototypeOfRecursiveFunction) {
2216 Decl *FromTU = getTuDecl(SrcCode: "void f(); void f() { f(); }", Lang: Lang_CXX03);
2217 auto Pattern = functionDecl(hasName(Name: "f"));
2218 auto *From =
2219 FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern); // Proto
2220
2221 Decl *ImportedD = Import(From, Lang_CXX03);
2222 Decl *ToTU = ImportedD->getTranslationUnitDecl();
2223
2224 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
2225 auto *To0 = FirstDeclMatcher<FunctionDecl>().match(D: ToTU, AMatcher: Pattern);
2226 auto *To1 = LastDeclMatcher<FunctionDecl>().match(D: ToTU, AMatcher: Pattern);
2227 EXPECT_TRUE(ImportedD == To0);
2228 EXPECT_FALSE(To0->doesThisDeclarationHaveABody());
2229 EXPECT_TRUE(To1->doesThisDeclarationHaveABody());
2230 EXPECT_EQ(To1->getPreviousDecl(), To0);
2231}
2232
2233TEST_P(ImportFunctions, ImportDefinitionOfRecursiveFunction) {
2234 Decl *FromTU = getTuDecl(SrcCode: "void f(); void f() { f(); }", Lang: Lang_CXX03);
2235 auto Pattern = functionDecl(hasName(Name: "f"));
2236 auto *From =
2237 LastDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern); // Def
2238
2239 Decl *ImportedD = Import(From, Lang_CXX03);
2240 Decl *ToTU = ImportedD->getTranslationUnitDecl();
2241
2242 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
2243 auto *To0 = FirstDeclMatcher<FunctionDecl>().match(D: ToTU, AMatcher: Pattern);
2244 auto *To1 = LastDeclMatcher<FunctionDecl>().match(D: ToTU, AMatcher: Pattern);
2245 EXPECT_TRUE(ImportedD == To1);
2246 EXPECT_FALSE(To0->doesThisDeclarationHaveABody());
2247 EXPECT_TRUE(To1->doesThisDeclarationHaveABody());
2248 EXPECT_EQ(To1->getPreviousDecl(), To0);
2249}
2250
2251TEST_P(ImportFunctions, OverriddenMethodsShouldBeImported) {
2252 auto Code =
2253 R"(
2254 struct B { virtual void f(); };
2255 void B::f() {}
2256 struct D : B { void f(); };
2257 )";
2258 auto Pattern =
2259 cxxMethodDecl(hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "D"))));
2260 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX03);
2261 CXXMethodDecl *Proto =
2262 FirstDeclMatcher<CXXMethodDecl>().match(D: FromTU, AMatcher: Pattern);
2263
2264 ASSERT_EQ(Proto->size_overridden_methods(), 1u);
2265 CXXMethodDecl *To = cast<CXXMethodDecl>(Val: Import(From: Proto, Lang: Lang_CXX03));
2266 EXPECT_EQ(To->size_overridden_methods(), 1u);
2267}
2268
2269TEST_P(ImportFunctions, VirtualFlagShouldBePreservedWhenImportingPrototype) {
2270 auto Code =
2271 R"(
2272 struct B { virtual void f(); };
2273 void B::f() {}
2274 )";
2275 auto Pattern =
2276 cxxMethodDecl(hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "B"))));
2277 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX03);
2278 CXXMethodDecl *Proto =
2279 FirstDeclMatcher<CXXMethodDecl>().match(D: FromTU, AMatcher: Pattern);
2280 CXXMethodDecl *Def = LastDeclMatcher<CXXMethodDecl>().match(D: FromTU, AMatcher: Pattern);
2281
2282 ASSERT_TRUE(Proto->isVirtual());
2283 ASSERT_TRUE(Def->isVirtual());
2284 CXXMethodDecl *To = cast<CXXMethodDecl>(Val: Import(From: Proto, Lang: Lang_CXX03));
2285 EXPECT_TRUE(To->isVirtual());
2286}
2287
2288TEST_P(ImportFunctions,
2289 ImportDefinitionIfThereIsAnExistingDefinitionAndFwdDecl) {
2290 Decl *ToTU = getToTuDecl(
2291 ToSrcCode: R"(
2292 void f() {}
2293 void f();
2294 )",
2295 ToLang: Lang_CXX03);
2296 ASSERT_EQ(1u,
2297 DeclCounterWithPredicate<FunctionDecl>([](const FunctionDecl *FD) {
2298 return FD->doesThisDeclarationHaveABody();
2299 }).match(ToTU, functionDecl()));
2300
2301 Decl *FromTU = getTuDecl(SrcCode: "void f() {}", Lang: Lang_CXX03, FileName: "input0.cc");
2302 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: functionDecl());
2303
2304 Import(FromD, Lang_CXX03);
2305
2306 EXPECT_EQ(1u,
2307 DeclCounterWithPredicate<FunctionDecl>([](const FunctionDecl *FD) {
2308 return FD->doesThisDeclarationHaveABody();
2309 }).match(ToTU, functionDecl()));
2310}
2311
2312TEST_P(ImportFunctions, ImportOverriddenMethodTwice) {
2313 auto Code =
2314 R"(
2315 struct B { virtual void f(); };
2316 struct D:B { void f(); };
2317 )";
2318 auto BFP =
2319 cxxMethodDecl(hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "B"))));
2320 auto DFP =
2321 cxxMethodDecl(hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "D"))));
2322
2323 Decl *FromTU0 = getTuDecl(SrcCode: Code, Lang: Lang_CXX03);
2324 auto *DF = FirstDeclMatcher<CXXMethodDecl>().match(D: FromTU0, AMatcher: DFP);
2325 Import(DF, Lang_CXX03);
2326
2327 Decl *FromTU1 = getTuDecl(SrcCode: Code, Lang: Lang_CXX03, FileName: "input1.cc");
2328 auto *BF = FirstDeclMatcher<CXXMethodDecl>().match(D: FromTU1, AMatcher: BFP);
2329 Import(BF, Lang_CXX03);
2330
2331 auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2332
2333 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u);
2334 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFP), 1u);
2335}
2336
2337TEST_P(ImportFunctions, ImportOverriddenMethodTwiceDefinitionFirst) {
2338 auto CodeWithoutDef =
2339 R"(
2340 struct B { virtual void f(); };
2341 struct D:B { void f(); };
2342 )";
2343 auto CodeWithDef =
2344 R"(
2345 struct B { virtual void f(){}; };
2346 struct D:B { void f(){}; };
2347 )";
2348 auto BFP =
2349 cxxMethodDecl(hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "B"))));
2350 auto DFP =
2351 cxxMethodDecl(hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "D"))));
2352 auto BFDefP = cxxMethodDecl(
2353 hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "B"))), isDefinition());
2354 auto DFDefP = cxxMethodDecl(
2355 hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "D"))), isDefinition());
2356 auto FDefAllP = cxxMethodDecl(hasName(Name: "f"), isDefinition());
2357
2358 {
2359 Decl *FromTU = getTuDecl(SrcCode: CodeWithDef, Lang: Lang_CXX03, FileName: "input0.cc");
2360 auto *FromD = FirstDeclMatcher<CXXMethodDecl>().match(D: FromTU, AMatcher: DFP);
2361 Import(FromD, Lang_CXX03);
2362 }
2363 {
2364 Decl *FromTU = getTuDecl(SrcCode: CodeWithoutDef, Lang: Lang_CXX03, FileName: "input1.cc");
2365 auto *FromB = FirstDeclMatcher<CXXMethodDecl>().match(D: FromTU, AMatcher: BFP);
2366 Import(FromB, Lang_CXX03);
2367 }
2368
2369 auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2370
2371 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u);
2372 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFP), 1u);
2373 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFDefP), 1u);
2374 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFDefP), 1u);
2375 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, FDefAllP), 2u);
2376}
2377
2378TEST_P(ImportFunctions, ImportOverriddenMethodTwiceOutOfClassDef) {
2379 auto Code =
2380 R"(
2381 struct B { virtual void f(); };
2382 struct D:B { void f(); };
2383 void B::f(){};
2384 )";
2385
2386 auto BFP =
2387 cxxMethodDecl(hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "B"))));
2388 auto BFDefP = cxxMethodDecl(
2389 hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "B"))), isDefinition());
2390 auto DFP = cxxMethodDecl(hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "D"))),
2391 unless(isDefinition()));
2392
2393 Decl *FromTU0 = getTuDecl(SrcCode: Code, Lang: Lang_CXX03);
2394 auto *D = FirstDeclMatcher<CXXMethodDecl>().match(D: FromTU0, AMatcher: DFP);
2395 Import(D, Lang_CXX03);
2396
2397 Decl *FromTU1 = getTuDecl(SrcCode: Code, Lang: Lang_CXX03, FileName: "input1.cc");
2398 auto *B = FirstDeclMatcher<CXXMethodDecl>().match(D: FromTU1, AMatcher: BFP);
2399 Import(B, Lang_CXX03);
2400
2401 auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2402
2403 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u);
2404 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFDefP), 0u);
2405
2406 auto *ToB = FirstDeclMatcher<CXXRecordDecl>().match(
2407 ToTU, cxxRecordDecl(hasName(Name: "B")));
2408 auto *ToBFInClass = FirstDeclMatcher<CXXMethodDecl>().match(ToTU, BFP);
2409 auto *ToBFOutOfClass = FirstDeclMatcher<CXXMethodDecl>().match(
2410 ToTU, cxxMethodDecl(hasName(Name: "f"), isDefinition()));
2411
2412 // The definition should be out-of-class.
2413 EXPECT_NE(ToBFInClass, ToBFOutOfClass);
2414 EXPECT_NE(ToBFInClass->getLexicalDeclContext(),
2415 ToBFOutOfClass->getLexicalDeclContext());
2416 EXPECT_EQ(ToBFOutOfClass->getDeclContext(), ToB);
2417 EXPECT_EQ(ToBFOutOfClass->getLexicalDeclContext(), ToTU);
2418
2419 // Check that the redecl chain is intact.
2420 EXPECT_EQ(ToBFOutOfClass->getPreviousDecl(), ToBFInClass);
2421}
2422
2423TEST_P(ImportFunctions,
2424 ImportOverriddenMethodTwiceOutOfClassDefInSeparateCode) {
2425 auto CodeTU0 =
2426 R"(
2427 struct B { virtual void f(); };
2428 struct D:B { void f(); };
2429 )";
2430 auto CodeTU1 =
2431 R"(
2432 struct B { virtual void f(); };
2433 struct D:B { void f(); };
2434 void B::f(){}
2435 void D::f(){}
2436 void foo(B &b, D &d) { b.f(); d.f(); }
2437 )";
2438
2439 auto BFP =
2440 cxxMethodDecl(hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "B"))));
2441 auto BFDefP = cxxMethodDecl(
2442 hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "B"))), isDefinition());
2443 auto DFP =
2444 cxxMethodDecl(hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "D"))));
2445 auto DFDefP = cxxMethodDecl(
2446 hasName(Name: "f"), hasParent(cxxRecordDecl(hasName(Name: "D"))), isDefinition());
2447 auto FooDef = functionDecl(hasName(Name: "foo"));
2448
2449 {
2450 Decl *FromTU0 = getTuDecl(SrcCode: CodeTU0, Lang: Lang_CXX03, FileName: "input0.cc");
2451 auto *D = FirstDeclMatcher<CXXMethodDecl>().match(D: FromTU0, AMatcher: DFP);
2452 Import(D, Lang_CXX03);
2453 }
2454
2455 {
2456 Decl *FromTU1 = getTuDecl(SrcCode: CodeTU1, Lang: Lang_CXX03, FileName: "input1.cc");
2457 auto *Foo = FirstDeclMatcher<FunctionDecl>().match(D: FromTU1, AMatcher: FooDef);
2458 Import(Foo, Lang_CXX03);
2459 }
2460
2461 auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2462
2463 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFP), 1u);
2464 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFP), 1u);
2465 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, BFDefP), 0u);
2466 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, DFDefP), 0u);
2467
2468 auto *ToB = FirstDeclMatcher<CXXRecordDecl>().match(
2469 ToTU, cxxRecordDecl(hasName(Name: "B")));
2470 auto *ToD = FirstDeclMatcher<CXXRecordDecl>().match(
2471 ToTU, cxxRecordDecl(hasName(Name: "D")));
2472 auto *ToBFInClass = FirstDeclMatcher<CXXMethodDecl>().match(ToTU, BFP);
2473 auto *ToBFOutOfClass = FirstDeclMatcher<CXXMethodDecl>().match(
2474 ToTU, cxxMethodDecl(hasName(Name: "f"), isDefinition()));
2475 auto *ToDFInClass = FirstDeclMatcher<CXXMethodDecl>().match(ToTU, DFP);
2476 auto *ToDFOutOfClass = LastDeclMatcher<CXXMethodDecl>().match(
2477 ToTU, cxxMethodDecl(hasName(Name: "f"), isDefinition()));
2478
2479 // The definition should be out-of-class.
2480 EXPECT_NE(ToBFInClass, ToBFOutOfClass);
2481 EXPECT_NE(ToBFInClass->getLexicalDeclContext(),
2482 ToBFOutOfClass->getLexicalDeclContext());
2483 EXPECT_EQ(ToBFOutOfClass->getDeclContext(), ToB);
2484 EXPECT_EQ(ToBFOutOfClass->getLexicalDeclContext(), ToTU);
2485
2486 EXPECT_NE(ToDFInClass, ToDFOutOfClass);
2487 EXPECT_NE(ToDFInClass->getLexicalDeclContext(),
2488 ToDFOutOfClass->getLexicalDeclContext());
2489 EXPECT_EQ(ToDFOutOfClass->getDeclContext(), ToD);
2490 EXPECT_EQ(ToDFOutOfClass->getLexicalDeclContext(), ToTU);
2491
2492 // Check that the redecl chain is intact.
2493 EXPECT_EQ(ToBFOutOfClass->getPreviousDecl(), ToBFInClass);
2494 EXPECT_EQ(ToDFOutOfClass->getPreviousDecl(), ToDFInClass);
2495}
2496
2497TEST_P(ASTImporterOptionSpecificTestBase,
2498 ImportVirtualOverriddenMethodOnALoop) {
2499 // B::f() calls => f1() ==> C ==> C::f()
2500 // \
2501 // \---- A::f()
2502 //
2503 // C::f()'s ImportOverriddenMethods() asserts B::isVirtual(), so B::f()'s
2504 // ImportOverriddenMethods() should be completed before B::f()'s body
2505 const char *Code =
2506 R"(
2507 void f1();
2508 class A {
2509 virtual void f(){}
2510 };
2511 class B: public A {
2512 void f() override {
2513 f1();
2514 }
2515 };
2516 class C: public B {
2517 void f() override {}
2518 };
2519 void f1() { C c; }
2520 )";
2521 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11);
2522
2523 auto *FromF = FirstDeclMatcher<CXXMethodDecl>().match(
2524 D: FromTU, AMatcher: cxxMethodDecl(hasName(Name: "B::f")));
2525
2526 auto *ToBF = Import(FromF, Lang_CXX11);
2527 EXPECT_TRUE(ToBF->isVirtual());
2528
2529 auto *ToCF = FirstDeclMatcher<CXXMethodDecl>().match(
2530 ToBF->getTranslationUnitDecl(), cxxMethodDecl(hasName(Name: "C::f")));
2531 EXPECT_TRUE(ToCF->isVirtual());
2532}
2533
2534TEST_P(ASTImporterOptionSpecificTestBase, ImportVariableChainInC) {
2535 std::string Code = "static int v; static int v = 0;";
2536 auto Pattern = varDecl(hasName(Name: "v"));
2537
2538 TranslationUnitDecl *FromTu = getTuDecl(SrcCode: Code, Lang: Lang_C99, FileName: "input0.c");
2539
2540 auto *From0 = FirstDeclMatcher<VarDecl>().match(FromTu, Pattern);
2541 auto *From1 = LastDeclMatcher<VarDecl>().match(FromTu, Pattern);
2542
2543 auto *To0 = Import(From0, Lang_C99);
2544 auto *To1 = Import(From1, Lang_C99);
2545
2546 EXPECT_TRUE(To0);
2547 ASSERT_TRUE(To1);
2548 EXPECT_NE(To0, To1);
2549 EXPECT_EQ(To1->getPreviousDecl(), To0);
2550}
2551
2552TEST_P(ImportFunctions, ImportFromDifferentScopedAnonNamespace) {
2553 TranslationUnitDecl *FromTu =
2554 getTuDecl(SrcCode: "namespace NS0 { namespace { void f(); } }"
2555 "namespace NS1 { namespace { void f(); } }",
2556 Lang: Lang_CXX03, FileName: "input0.cc");
2557 auto Pattern = functionDecl(hasName(Name: "f"));
2558
2559 auto *FromF0 = FirstDeclMatcher<FunctionDecl>().match(FromTu, Pattern);
2560 auto *FromF1 = LastDeclMatcher<FunctionDecl>().match(FromTu, Pattern);
2561
2562 auto *ToF0 = Import(FromF0, Lang_CXX03);
2563 auto *ToF1 = Import(FromF1, Lang_CXX03);
2564
2565 EXPECT_TRUE(ToF0);
2566 ASSERT_TRUE(ToF1);
2567 EXPECT_NE(ToF0, ToF1);
2568 EXPECT_FALSE(ToF1->getPreviousDecl());
2569}
2570
2571TEST_P(ImportFunctions, ImportFunctionFromUnnamedNamespace) {
2572 {
2573 Decl *FromTU = getTuDecl(SrcCode: "namespace { void f() {} } void g0() { f(); }",
2574 Lang: Lang_CXX03, FileName: "input0.cc");
2575 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
2576 D: FromTU, AMatcher: functionDecl(hasName(Name: "g0")));
2577
2578 Import(FromD, Lang_CXX03);
2579 }
2580 {
2581 Decl *FromTU =
2582 getTuDecl(SrcCode: "namespace { void f() { int a; } } void g1() { f(); }",
2583 Lang: Lang_CXX03, FileName: "input1.cc");
2584 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
2585 D: FromTU, AMatcher: functionDecl(hasName(Name: "g1")));
2586 Import(FromD, Lang_CXX03);
2587 }
2588
2589 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2590 ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, functionDecl(hasName("f"))),
2591 2u);
2592}
2593
2594TEST_P(ImportFunctions, ImportImplicitFunctionsInLambda) {
2595 Decl *FromTU = getTuDecl(
2596 SrcCode: R"(
2597 void foo() {
2598 (void)[]() { ; };
2599 }
2600 )",
2601 Lang: Lang_CXX11);
2602 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
2603 D: FromTU, AMatcher: functionDecl(hasName(Name: "foo")));
2604 auto *ToD = Import(FromD, Lang_CXX03);
2605 EXPECT_TRUE(ToD);
2606 CXXRecordDecl *LambdaRec =
2607 cast<LambdaExpr>(cast<CStyleCastExpr>(
2608 *cast<CompoundStmt>(ToD->getBody())->body_begin())
2609 ->getSubExpr())
2610 ->getLambdaClass();
2611 EXPECT_TRUE(LambdaRec->getDestructor());
2612}
2613
2614TEST_P(ImportFunctions,
2615 CallExprOfMemberFunctionTemplateWithExplicitTemplateArgs) {
2616 Decl *FromTU = getTuDecl(
2617 SrcCode: R"(
2618 struct X {
2619 template <typename T>
2620 void foo(){}
2621 };
2622 void f() {
2623 X x;
2624 x.foo<int>();
2625 }
2626 )",
2627 Lang: Lang_CXX03);
2628 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
2629 D: FromTU, AMatcher: functionDecl(hasName(Name: "f")));
2630 auto *ToD = Import(FromD, Lang_CXX03);
2631 EXPECT_TRUE(ToD);
2632 EXPECT_TRUE(MatchVerifier<FunctionDecl>().match(
2633 ToD, functionDecl(hasName("f"), hasDescendant(declRefExpr()))));
2634}
2635
2636TEST_P(ImportFunctions,
2637 DependentCallExprOfMemberFunctionTemplateWithExplicitTemplateArgs) {
2638 Decl *FromTU = getTuDecl(
2639 SrcCode: R"(
2640 struct X {
2641 template <typename T>
2642 void foo(){}
2643 };
2644 template <typename T>
2645 void f() {
2646 X x;
2647 x.foo<T>();
2648 }
2649 void g() {
2650 f<int>();
2651 }
2652 )",
2653 Lang: Lang_CXX03);
2654 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
2655 D: FromTU, AMatcher: functionDecl(hasName(Name: "g")));
2656 auto *ToD = Import(FromD, Lang_CXX03);
2657 EXPECT_TRUE(ToD);
2658 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2659 EXPECT_TRUE(MatchVerifier<TranslationUnitDecl>().match(
2660 ToTU, translationUnitDecl(hasDescendant(
2661 functionDecl(hasName("f"), hasDescendant(declRefExpr()))))));
2662}
2663
2664struct ImportFunctionTemplates : ASTImporterOptionSpecificTestBase {};
2665
2666TEST_P(ImportFunctionTemplates, ImportFunctionTemplateInRecordDeclTwice) {
2667 auto Code =
2668 R"(
2669 class X {
2670 template <class T>
2671 void f(T t);
2672 };
2673 )";
2674 Decl *FromTU1 = getTuDecl(SrcCode: Code, Lang: Lang_CXX03, FileName: "input1.cc");
2675 auto *FromD1 = FirstDeclMatcher<FunctionTemplateDecl>().match(
2676 D: FromTU1, AMatcher: functionTemplateDecl(hasName(Name: "f")));
2677 auto *ToD1 = Import(FromD1, Lang_CXX03);
2678 Decl *FromTU2 = getTuDecl(SrcCode: Code, Lang: Lang_CXX03, FileName: "input2.cc");
2679 auto *FromD2 = FirstDeclMatcher<FunctionTemplateDecl>().match(
2680 D: FromTU2, AMatcher: functionTemplateDecl(hasName(Name: "f")));
2681 auto *ToD2 = Import(FromD2, Lang_CXX03);
2682 EXPECT_EQ(ToD1, ToD2);
2683}
2684
2685TEST_P(ImportFunctionTemplates,
2686 ImportFunctionTemplateWithDefInRecordDeclTwice) {
2687 auto Code =
2688 R"(
2689 class X {
2690 template <class T>
2691 void f(T t);
2692 };
2693 template <class T>
2694 void X::f(T t) {};
2695 )";
2696 Decl *FromTU1 = getTuDecl(SrcCode: Code, Lang: Lang_CXX03, FileName: "input1.cc");
2697 auto *FromD1 = FirstDeclMatcher<FunctionTemplateDecl>().match(
2698 D: FromTU1, AMatcher: functionTemplateDecl(hasName(Name: "f")));
2699 auto *ToD1 = Import(FromD1, Lang_CXX03);
2700 Decl *FromTU2 = getTuDecl(SrcCode: Code, Lang: Lang_CXX03, FileName: "input2.cc");
2701 auto *FromD2 = FirstDeclMatcher<FunctionTemplateDecl>().match(
2702 D: FromTU2, AMatcher: functionTemplateDecl(hasName(Name: "f")));
2703 auto *ToD2 = Import(FromD2, Lang_CXX03);
2704 EXPECT_EQ(ToD1, ToD2);
2705}
2706
2707TEST_P(ImportFunctionTemplates,
2708 ImportFunctionWhenThereIsAFunTemplateWithSameName) {
2709 getToTuDecl(
2710 ToSrcCode: R"(
2711 template <typename T>
2712 void foo(T) {}
2713 void foo();
2714 )",
2715 ToLang: Lang_CXX03);
2716 Decl *FromTU = getTuDecl(SrcCode: "void foo();", Lang: Lang_CXX03);
2717 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
2718 D: FromTU, AMatcher: functionDecl(hasName(Name: "foo")));
2719 auto *ImportedD = Import(FromD, Lang_CXX03);
2720 EXPECT_TRUE(ImportedD);
2721}
2722
2723TEST_P(ImportFunctionTemplates,
2724 ImportConstructorWhenThereIsAFunTemplateWithSameName) {
2725 auto Code =
2726 R"(
2727 struct Foo {
2728 template <typename T>
2729 Foo(T) {}
2730 Foo();
2731 };
2732 )";
2733 getToTuDecl(ToSrcCode: Code, ToLang: Lang_CXX03);
2734 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX03);
2735 auto *FromD =
2736 LastDeclMatcher<CXXConstructorDecl>().match(D: FromTU, AMatcher: cxxConstructorDecl());
2737 auto *ImportedD = Import(FromD, Lang_CXX03);
2738 EXPECT_TRUE(ImportedD);
2739}
2740
2741TEST_P(ImportFunctionTemplates,
2742 ImportOperatorWhenThereIsAFunTemplateWithSameName) {
2743 getToTuDecl(
2744 ToSrcCode: R"(
2745 template <typename T>
2746 void operator<(T,T) {}
2747 struct X{};
2748 void operator<(X, X);
2749 )",
2750 ToLang: Lang_CXX03);
2751 Decl *FromTU = getTuDecl(
2752 SrcCode: R"(
2753 struct X{};
2754 void operator<(X, X);
2755 )",
2756 Lang: Lang_CXX03);
2757 auto *FromD = LastDeclMatcher<FunctionDecl>().match(
2758 D: FromTU, AMatcher: functionDecl(hasOverloadedOperatorName(Name: "<")));
2759 auto *ImportedD = Import(FromD, Lang_CXX03);
2760 EXPECT_TRUE(ImportedD);
2761}
2762
2763struct ImportFriendFunctions : ImportFunctions {};
2764
2765TEST_P(ImportFriendFunctions, ImportFriendFunctionRedeclChainProto) {
2766 auto Pattern = functionDecl(hasName(Name: "f"));
2767
2768 Decl *FromTU = getTuDecl(SrcCode: "struct X { friend void f(); };"
2769 "void f();",
2770 Lang: Lang_CXX03, FileName: "input0.cc");
2771 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
2772
2773 auto *ImportedD = cast<FunctionDecl>(Import(FromD, Lang_CXX03));
2774 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2775 ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
2776 EXPECT_FALSE(ImportedD->doesThisDeclarationHaveABody());
2777 auto *ToFD = LastDeclMatcher<FunctionDecl>().match(D: ToTU, AMatcher: Pattern);
2778 EXPECT_FALSE(ToFD->doesThisDeclarationHaveABody());
2779 EXPECT_EQ(ToFD->getPreviousDecl(), ImportedD);
2780}
2781
2782TEST_P(ImportFriendFunctions,
2783 ImportFriendFunctionRedeclChainProto_OutOfClassProtoFirst) {
2784 auto Pattern = functionDecl(hasName(Name: "f"));
2785
2786 Decl *FromTU = getTuDecl(SrcCode: "void f();"
2787 "struct X { friend void f(); };",
2788 Lang: Lang_CXX03, FileName: "input0.cc");
2789 auto FromD = FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
2790
2791 auto *ImportedD = cast<FunctionDecl>(Import(FromD, Lang_CXX03));
2792 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2793 ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
2794 EXPECT_FALSE(ImportedD->doesThisDeclarationHaveABody());
2795 auto *ToFD = LastDeclMatcher<FunctionDecl>().match(D: ToTU, AMatcher: Pattern);
2796 EXPECT_FALSE(ToFD->doesThisDeclarationHaveABody());
2797 EXPECT_EQ(ToFD->getPreviousDecl(), ImportedD);
2798}
2799
2800TEST_P(ImportFriendFunctions, ImportFriendFunctionRedeclChainDef) {
2801 auto Pattern = functionDecl(hasName(Name: "f"));
2802
2803 Decl *FromTU = getTuDecl(SrcCode: "struct X { friend void f(){} };"
2804 "void f();",
2805 Lang: Lang_CXX03, FileName: "input0.cc");
2806 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
2807
2808 auto *ImportedD = cast<FunctionDecl>(Import(FromD, Lang_CXX03));
2809 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2810 ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
2811 EXPECT_TRUE(ImportedD->doesThisDeclarationHaveABody());
2812 auto *ToFD = LastDeclMatcher<FunctionDecl>().match(D: ToTU, AMatcher: Pattern);
2813 EXPECT_FALSE(ToFD->doesThisDeclarationHaveABody());
2814 EXPECT_EQ(ToFD->getPreviousDecl(), ImportedD);
2815}
2816
2817TEST_P(ImportFriendFunctions,
2818 ImportFriendFunctionRedeclChainDef_OutOfClassDef) {
2819 auto Pattern = functionDecl(hasName(Name: "f"));
2820
2821 Decl *FromTU = getTuDecl(SrcCode: "struct X { friend void f(); };"
2822 "void f(){}",
2823 Lang: Lang_CXX03, FileName: "input0.cc");
2824 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
2825
2826 auto *ImportedD = cast<FunctionDecl>(Import(FromD, Lang_CXX03));
2827 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2828 ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
2829 EXPECT_FALSE(ImportedD->doesThisDeclarationHaveABody());
2830 auto *ToFD = LastDeclMatcher<FunctionDecl>().match(D: ToTU, AMatcher: Pattern);
2831 EXPECT_TRUE(ToFD->doesThisDeclarationHaveABody());
2832 EXPECT_EQ(ToFD->getPreviousDecl(), ImportedD);
2833}
2834
2835TEST_P(ImportFriendFunctions, ImportFriendFunctionRedeclChainDefWithClass) {
2836 auto Pattern = functionDecl(hasName(Name: "f"));
2837
2838 Decl *FromTU = getTuDecl(
2839 SrcCode: R"(
2840 class X;
2841 void f(X *x){}
2842 class X{
2843 friend void f(X *x);
2844 };
2845 )",
2846 Lang: Lang_CXX03, FileName: "input0.cc");
2847 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
2848
2849 auto *ImportedD = cast<FunctionDecl>(Import(FromD, Lang_CXX03));
2850 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2851 ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
2852 EXPECT_TRUE(ImportedD->doesThisDeclarationHaveABody());
2853 auto *InClassFD = cast<FunctionDecl>(Val: FirstDeclMatcher<FriendDecl>()
2854 .match(D: ToTU, AMatcher: friendDecl())
2855 ->getFriendDecl());
2856 EXPECT_FALSE(InClassFD->doesThisDeclarationHaveABody());
2857 EXPECT_EQ(InClassFD->getPreviousDecl(), ImportedD);
2858 // The parameters must refer the same type
2859 EXPECT_EQ((*InClassFD->param_begin())->getOriginalType(),
2860 (*ImportedD->param_begin())->getOriginalType());
2861}
2862
2863TEST_P(ImportFriendFunctions,
2864 ImportFriendFunctionRedeclChainDefWithClass_ImportTheProto) {
2865 auto Pattern = functionDecl(hasName(Name: "f"));
2866
2867 Decl *FromTU = getTuDecl(
2868 SrcCode: R"(
2869 class X;
2870 void f(X *x){}
2871 class X{
2872 friend void f(X *x);
2873 };
2874 )",
2875 Lang: Lang_CXX03, FileName: "input0.cc");
2876 auto *FromD = LastDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
2877
2878 auto *ImportedD = cast<FunctionDecl>(Import(FromD, Lang_CXX03));
2879 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2880 ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
2881 EXPECT_FALSE(ImportedD->doesThisDeclarationHaveABody());
2882 auto *OutOfClassFD = FirstDeclMatcher<FunctionDecl>().match(
2883 D: ToTU, AMatcher: functionDecl(unless(hasParent(friendDecl()))));
2884
2885 EXPECT_TRUE(OutOfClassFD->doesThisDeclarationHaveABody());
2886 EXPECT_EQ(ImportedD->getPreviousDecl(), OutOfClassFD);
2887 // The parameters must refer the same type
2888 EXPECT_EQ((*OutOfClassFD->param_begin())->getOriginalType(),
2889 (*ImportedD->param_begin())->getOriginalType());
2890}
2891
2892TEST_P(ImportFriendFunctions, ImportFriendFunctionFromMultipleTU) {
2893 auto Pattern = functionDecl(hasName(Name: "f"));
2894
2895 FunctionDecl *ImportedD;
2896 {
2897 Decl *FromTU =
2898 getTuDecl(SrcCode: "struct X { friend void f(){} };", Lang: Lang_CXX03, FileName: "input0.cc");
2899 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
2900 ImportedD = cast<FunctionDecl>(Import(FromD, Lang_CXX03));
2901 }
2902 FunctionDecl *ImportedD1;
2903 {
2904 Decl *FromTU = getTuDecl(SrcCode: "void f();", Lang: Lang_CXX03, FileName: "input1.cc");
2905 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: Pattern);
2906 ImportedD1 = cast<FunctionDecl>(Import(FromD, Lang_CXX03));
2907 }
2908
2909 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2910 ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
2911 EXPECT_TRUE(ImportedD->doesThisDeclarationHaveABody());
2912 EXPECT_FALSE(ImportedD1->doesThisDeclarationHaveABody());
2913 EXPECT_EQ(ImportedD1->getPreviousDecl(), ImportedD);
2914}
2915
2916TEST_P(ImportFriendFunctions, Lookup) {
2917 auto FunctionPattern = functionDecl(hasName(Name: "f"));
2918 auto ClassPattern = cxxRecordDecl(hasName(Name: "X"));
2919
2920 TranslationUnitDecl *FromTU =
2921 getTuDecl(SrcCode: "struct X { friend void f(); };", Lang: Lang_CXX03, FileName: "input0.cc");
2922 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, FunctionPattern);
2923 ASSERT_TRUE(FromD->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
2924 ASSERT_FALSE(FromD->isInIdentifierNamespace(Decl::IDNS_Ordinary));
2925 {
2926 auto FromName = FromD->getDeclName();
2927 auto *Class = FirstDeclMatcher<CXXRecordDecl>().match(FromTU, ClassPattern);
2928 auto LookupRes = Class->noload_lookup(FromName);
2929 ASSERT_TRUE(LookupRes.empty());
2930 LookupRes = FromTU->noload_lookup(Name: FromName);
2931 ASSERT_TRUE(LookupRes.isSingleResult());
2932 }
2933
2934 auto *ToD = cast<FunctionDecl>(Import(FromD, Lang_CXX03));
2935 auto ToName = ToD->getDeclName();
2936
2937 TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2938 auto *Class = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, ClassPattern);
2939 auto LookupRes = Class->noload_lookup(ToName);
2940 EXPECT_TRUE(LookupRes.empty());
2941 LookupRes = ToTU->noload_lookup(Name: ToName);
2942 EXPECT_TRUE(LookupRes.isSingleResult());
2943
2944 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, FunctionPattern), 1u);
2945 auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, FunctionPattern);
2946 EXPECT_TRUE(To0->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
2947 EXPECT_FALSE(To0->isInIdentifierNamespace(Decl::IDNS_Ordinary));
2948}
2949
2950TEST_P(ImportFriendFunctions, LookupWithProtoAfter) {
2951 auto FunctionPattern = functionDecl(hasName(Name: "f"));
2952 auto ClassPattern = cxxRecordDecl(hasName(Name: "X"));
2953
2954 TranslationUnitDecl *FromTU =
2955 getTuDecl(SrcCode: "struct X { friend void f(); };"
2956 // This proto decl makes f available to normal
2957 // lookup, otherwise it is hidden.
2958 // Normal C++ lookup (implemented in
2959 // `clang::Sema::CppLookupName()` and in `LookupDirect()`)
2960 // returns the found `NamedDecl` only if the set IDNS is matched
2961 "void f();",
2962 Lang: Lang_CXX03, FileName: "input0.cc");
2963 auto *FromFriend =
2964 FirstDeclMatcher<FunctionDecl>().match(FromTU, FunctionPattern);
2965 auto *FromNormal =
2966 LastDeclMatcher<FunctionDecl>().match(FromTU, FunctionPattern);
2967 ASSERT_TRUE(FromFriend->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
2968 ASSERT_FALSE(FromFriend->isInIdentifierNamespace(Decl::IDNS_Ordinary));
2969 ASSERT_FALSE(FromNormal->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
2970 ASSERT_TRUE(FromNormal->isInIdentifierNamespace(Decl::IDNS_Ordinary));
2971
2972 auto FromName = FromFriend->getDeclName();
2973 auto *FromClass =
2974 FirstDeclMatcher<CXXRecordDecl>().match(FromTU, ClassPattern);
2975 auto LookupRes = FromClass->noload_lookup(FromName);
2976 ASSERT_TRUE(LookupRes.empty());
2977 LookupRes = FromTU->noload_lookup(Name: FromName);
2978 ASSERT_TRUE(LookupRes.isSingleResult());
2979
2980 auto *ToFriend = cast<FunctionDecl>(Import(FromFriend, Lang_CXX03));
2981 auto ToName = ToFriend->getDeclName();
2982
2983 TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
2984 auto *ToClass = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, ClassPattern);
2985 LookupRes = ToClass->noload_lookup(ToName);
2986 EXPECT_TRUE(LookupRes.empty());
2987 LookupRes = ToTU->noload_lookup(Name: ToName);
2988 // Test is disabled because this result is 2.
2989 EXPECT_TRUE(LookupRes.isSingleResult());
2990
2991 ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, FunctionPattern), 2u);
2992 ToFriend = FirstDeclMatcher<FunctionDecl>().match(ToTU, FunctionPattern);
2993 auto *ToNormal = LastDeclMatcher<FunctionDecl>().match(ToTU, FunctionPattern);
2994 EXPECT_TRUE(ToFriend->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
2995 EXPECT_FALSE(ToFriend->isInIdentifierNamespace(Decl::IDNS_Ordinary));
2996 EXPECT_FALSE(ToNormal->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
2997 EXPECT_TRUE(ToNormal->isInIdentifierNamespace(Decl::IDNS_Ordinary));
2998}
2999
3000TEST_P(ImportFriendFunctions, LookupWithProtoBefore) {
3001 auto FunctionPattern = functionDecl(hasName(Name: "f"));
3002 auto ClassPattern = cxxRecordDecl(hasName(Name: "X"));
3003
3004 TranslationUnitDecl *FromTU = getTuDecl(SrcCode: "void f();"
3005 "struct X { friend void f(); };",
3006 Lang: Lang_CXX03, FileName: "input0.cc");
3007 auto *FromNormal =
3008 FirstDeclMatcher<FunctionDecl>().match(FromTU, FunctionPattern);
3009 auto *FromFriend =
3010 LastDeclMatcher<FunctionDecl>().match(FromTU, FunctionPattern);
3011 ASSERT_FALSE(FromNormal->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
3012 ASSERT_TRUE(FromNormal->isInIdentifierNamespace(Decl::IDNS_Ordinary));
3013 ASSERT_TRUE(FromFriend->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
3014 ASSERT_TRUE(FromFriend->isInIdentifierNamespace(Decl::IDNS_Ordinary));
3015
3016 auto FromName = FromNormal->getDeclName();
3017 auto *FromClass =
3018 FirstDeclMatcher<CXXRecordDecl>().match(FromTU, ClassPattern);
3019 auto LookupRes = FromClass->noload_lookup(FromName);
3020 ASSERT_TRUE(LookupRes.empty());
3021 LookupRes = FromTU->noload_lookup(Name: FromName);
3022 ASSERT_TRUE(LookupRes.isSingleResult());
3023
3024 auto *ToNormal = cast<FunctionDecl>(Import(FromNormal, Lang_CXX03));
3025 auto ToName = ToNormal->getDeclName();
3026 TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
3027
3028 auto *ToClass = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, ClassPattern);
3029 LookupRes = ToClass->noload_lookup(ToName);
3030 EXPECT_TRUE(LookupRes.empty());
3031 LookupRes = ToTU->noload_lookup(Name: ToName);
3032 EXPECT_TRUE(LookupRes.isSingleResult());
3033
3034 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, FunctionPattern), 2u);
3035 ToNormal = FirstDeclMatcher<FunctionDecl>().match(ToTU, FunctionPattern);
3036 auto *ToFriend = LastDeclMatcher<FunctionDecl>().match(ToTU, FunctionPattern);
3037 EXPECT_FALSE(ToNormal->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
3038 EXPECT_TRUE(ToNormal->isInIdentifierNamespace(Decl::IDNS_Ordinary));
3039 EXPECT_TRUE(ToFriend->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
3040 EXPECT_TRUE(ToFriend->isInIdentifierNamespace(Decl::IDNS_Ordinary));
3041}
3042
3043TEST_P(ImportFriendFunctions, ImportFriendChangesLookup) {
3044 auto Pattern = functionDecl(hasName(Name: "f"));
3045
3046 TranslationUnitDecl *FromNormalTU =
3047 getTuDecl(SrcCode: "void f();", Lang: Lang_CXX03, FileName: "input0.cc");
3048 auto *FromNormalF =
3049 FirstDeclMatcher<FunctionDecl>().match(FromNormalTU, Pattern);
3050 TranslationUnitDecl *FromFriendTU =
3051 getTuDecl(SrcCode: "class X { friend void f(); };", Lang: Lang_CXX03, FileName: "input1.cc");
3052 auto *FromFriendF =
3053 FirstDeclMatcher<FunctionDecl>().match(FromFriendTU, Pattern);
3054 auto FromNormalName = FromNormalF->getDeclName();
3055 auto FromFriendName = FromFriendF->getDeclName();
3056
3057 ASSERT_TRUE(FromNormalF->isInIdentifierNamespace(Decl::IDNS_Ordinary));
3058 ASSERT_FALSE(FromNormalF->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
3059 ASSERT_FALSE(FromFriendF->isInIdentifierNamespace(Decl::IDNS_Ordinary));
3060 ASSERT_TRUE(FromFriendF->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
3061 auto LookupRes = FromNormalTU->noload_lookup(Name: FromNormalName);
3062 ASSERT_TRUE(LookupRes.isSingleResult());
3063 LookupRes = FromFriendTU->noload_lookup(Name: FromFriendName);
3064 ASSERT_TRUE(LookupRes.isSingleResult());
3065
3066 auto *ToNormalF = cast<FunctionDecl>(Import(FromNormalF, Lang_CXX03));
3067 TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
3068 auto ToName = ToNormalF->getDeclName();
3069 EXPECT_TRUE(ToNormalF->isInIdentifierNamespace(Decl::IDNS_Ordinary));
3070 EXPECT_FALSE(ToNormalF->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
3071 LookupRes = ToTU->noload_lookup(Name: ToName);
3072 EXPECT_TRUE(LookupRes.isSingleResult());
3073 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
3074
3075 auto *ToFriendF = cast<FunctionDecl>(Import(FromFriendF, Lang_CXX03));
3076 LookupRes = ToTU->noload_lookup(Name: ToName);
3077 EXPECT_TRUE(LookupRes.isSingleResult());
3078 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
3079
3080 EXPECT_TRUE(ToNormalF->isInIdentifierNamespace(Decl::IDNS_Ordinary));
3081 EXPECT_FALSE(ToNormalF->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
3082
3083 EXPECT_TRUE(ToFriendF->isInIdentifierNamespace(Decl::IDNS_Ordinary));
3084 EXPECT_TRUE(ToFriendF->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
3085}
3086
3087TEST_P(ImportFriendFunctions, ImportFriendList) {
3088 TranslationUnitDecl *FromTU = getTuDecl(SrcCode: "struct X { friend void f(); };"
3089 "void f();",
3090 Lang: Lang_CXX03, FileName: "input0.cc");
3091 auto *FromFriendF = FirstDeclMatcher<FunctionDecl>().match(
3092 FromTU, functionDecl(hasName(Name: "f")));
3093
3094 auto *FromClass = FirstDeclMatcher<CXXRecordDecl>().match(
3095 FromTU, cxxRecordDecl(hasName(Name: "X")));
3096 auto *FromFriend = FirstDeclMatcher<FriendDecl>().match(FromTU, friendDecl());
3097 auto FromFriends = FromClass->friends();
3098 unsigned int FrN = 0;
3099 for (auto Fr : FromFriends) {
3100 ASSERT_EQ(Fr, FromFriend);
3101 ++FrN;
3102 }
3103 ASSERT_EQ(FrN, 1u);
3104
3105 Import(FromFriendF, Lang_CXX03);
3106 TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
3107 auto *ToClass = FirstDeclMatcher<CXXRecordDecl>().match(
3108 ToTU, cxxRecordDecl(hasName(Name: "X")));
3109 auto *ToFriend = FirstDeclMatcher<FriendDecl>().match(ToTU, friendDecl());
3110 auto ToFriends = ToClass->friends();
3111 FrN = 0;
3112 for (auto Fr : ToFriends) {
3113 EXPECT_EQ(Fr, ToFriend);
3114 ++FrN;
3115 }
3116 EXPECT_EQ(FrN, 1u);
3117}
3118
3119AST_MATCHER_P(TagDecl, hasTypedefForAnonDecl, Matcher<TypedefNameDecl>,
3120 InnerMatcher) {
3121 if (auto *Typedef = Node.getTypedefNameForAnonDecl())
3122 return InnerMatcher.matches(Node: *Typedef, Finder, Builder);
3123 return false;
3124}
3125
3126TEST_P(ImportDecl, ImportEnumSequential) {
3127 CodeFiles Samples{{"main.c",
3128 {.CodeSample: "void foo();"
3129 "void moo();"
3130 "int main() { foo(); moo(); }",
3131 .Lang: Lang_C99}},
3132
3133 {"foo.c",
3134 {.CodeSample: "typedef enum { THING_VALUE } thing_t;"
3135 "void conflict(thing_t type);"
3136 "void foo() { (void)THING_VALUE; }"
3137 "void conflict(thing_t type) {}",
3138 .Lang: Lang_C99}},
3139
3140 {"moo.c",
3141 {.CodeSample: "typedef enum { THING_VALUE } thing_t;"
3142 "void conflict(thing_t type);"
3143 "void moo() { conflict(THING_VALUE); }",
3144 .Lang: Lang_C99}}};
3145
3146 auto VerificationMatcher =
3147 enumDecl(has(enumConstantDecl(hasName(Name: "THING_VALUE"))),
3148 hasTypedefForAnonDecl(InnerMatcher: hasName(Name: "thing_t")));
3149
3150 ImportAction ImportFoo{"foo.c", "main.c", functionDecl(hasName(Name: "foo"))},
3151 ImportMoo{"moo.c", "main.c", functionDecl(hasName(Name: "moo"))};
3152
3153 testImportSequence(
3154 CodeSamples: Samples, ImportActions: {ImportFoo, ImportMoo}, // "foo", them "moo".
3155 // Just check that there is only one enum decl in the result AST.
3156 FileForFinalCheck: "main.c", FinalSelectPredicate: enumDecl(), VerificationMatcher);
3157
3158 // For different import order, result should be the same.
3159 testImportSequence(
3160 CodeSamples: Samples, ImportActions: {ImportMoo, ImportFoo}, // "moo", them "foo".
3161 // Check that there is only one enum decl in the result AST.
3162 FileForFinalCheck: "main.c", FinalSelectPredicate: enumDecl(), VerificationMatcher);
3163}
3164
3165TEST_P(ImportDecl, ImportFieldOrder) {
3166 MatchVerifier<Decl> Verifier;
3167 testImport(FromCode: "struct declToImport {"
3168 " int b = a + 2;"
3169 " int a = 5;"
3170 "};",
3171 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
3172 AMatcher: recordDecl(hasFieldOrder(Order: {"b", "a"})));
3173}
3174
3175const internal::VariadicDynCastAllOfMatcher<Expr, DependentScopeDeclRefExpr>
3176 dependentScopeDeclRefExpr;
3177
3178TEST_P(ImportExpr, DependentScopeDeclRefExpr) {
3179 MatchVerifier<Decl> Verifier;
3180 testImport(FromCode: "template <typename T> struct S { static T foo; };"
3181 "template <typename T> void declToImport() {"
3182 " (void) S<T>::foo;"
3183 "}"
3184 "void instantiate() { declToImport<int>(); }"
3185 "template <typename T> T S<T>::foo;",
3186 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
3187 AMatcher: functionTemplateDecl(has(functionDecl(has(compoundStmt(
3188 has(cStyleCastExpr(has(dependentScopeDeclRefExpr())))))))));
3189
3190 testImport(FromCode: "template <typename T> struct S {"
3191 "template<typename S> static void foo(){};"
3192 "};"
3193 "template <typename T> void declToImport() {"
3194 " S<T>::template foo<T>();"
3195 "}"
3196 "void instantiate() { declToImport<int>(); }",
3197 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
3198 AMatcher: functionTemplateDecl(has(functionDecl(has(compoundStmt(
3199 has(callExpr(has(dependentScopeDeclRefExpr())))))))));
3200}
3201
3202const internal::VariadicDynCastAllOfMatcher<Type, DependentNameType>
3203 dependentNameType;
3204
3205TEST_P(ImportExpr, DependentNameType) {
3206 MatchVerifier<Decl> Verifier;
3207 testImport(FromCode: "template <typename T> struct declToImport {"
3208 " typedef typename T::type dependent_name;"
3209 "};",
3210 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
3211 AMatcher: classTemplateDecl(has(
3212 cxxRecordDecl(has(typedefDecl(has(dependentNameType())))))));
3213}
3214
3215TEST_P(ImportExpr, UnresolvedMemberExpr) {
3216 MatchVerifier<Decl> Verifier;
3217 testImport(FromCode: "struct S { template <typename T> void mem(); };"
3218 "template <typename U> void declToImport() {"
3219 " S s;"
3220 " s.mem<U>();"
3221 "}"
3222 "void instantiate() { declToImport<int>(); }",
3223 FromLang: Lang_CXX11, ToCode: "", ToLang: Lang_CXX11, Verifier,
3224 AMatcher: functionTemplateDecl(has(functionDecl(has(
3225 compoundStmt(has(callExpr(has(unresolvedMemberExpr())))))))));
3226}
3227
3228class ImportImplicitMethods : public ASTImporterOptionSpecificTestBase {
3229public:
3230 static constexpr auto DefaultCode = R"(
3231 struct A { int x; };
3232 void f() {
3233 A a;
3234 A a1(a);
3235 A a2(A{});
3236 a = a1;
3237 a = A{};
3238 a.~A();
3239 })";
3240
3241 template <typename MatcherType>
3242 void testImportOf(
3243 const MatcherType &MethodMatcher, const char *Code = DefaultCode) {
3244 test(MethodMatcher, Code, /*ExpectedCount=*/1u);
3245 }
3246
3247 template <typename MatcherType>
3248 void testNoImportOf(
3249 const MatcherType &MethodMatcher, const char *Code = DefaultCode) {
3250 test(MethodMatcher, Code, /*ExpectedCount=*/0u);
3251 }
3252
3253private:
3254 template <typename MatcherType>
3255 void test(const MatcherType &MethodMatcher,
3256 const char *Code, unsigned int ExpectedCount) {
3257 auto ClassMatcher = cxxRecordDecl(unless(isImplicit()));
3258
3259 Decl *ToTU = getToTuDecl(ToSrcCode: Code, ToLang: Lang_CXX11);
3260 auto *ToClass = FirstDeclMatcher<CXXRecordDecl>().match(
3261 D: ToTU, AMatcher: ClassMatcher);
3262
3263 ASSERT_EQ(DeclCounter<CXXMethodDecl>().match(ToClass, MethodMatcher), 1u);
3264
3265 {
3266 CXXMethodDecl *Method =
3267 FirstDeclMatcher<CXXMethodDecl>().match(ToClass, MethodMatcher);
3268 ToClass->removeDecl(Method);
3269 SharedStatePtr->getLookupTable()->remove(Method);
3270 }
3271
3272 ASSERT_EQ(DeclCounter<CXXMethodDecl>().match(ToClass, MethodMatcher), 0u);
3273
3274 Decl *ImportedClass = nullptr;
3275 {
3276 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11, FileName: "input1.cc");
3277 auto *FromClass = FirstDeclMatcher<CXXRecordDecl>().match(
3278 D: FromTU, AMatcher: ClassMatcher);
3279 ImportedClass = Import(FromClass, Lang_CXX11);
3280 }
3281
3282 EXPECT_EQ(ToClass, ImportedClass);
3283 EXPECT_EQ(DeclCounter<CXXMethodDecl>().match(ToClass, MethodMatcher),
3284 ExpectedCount);
3285 }
3286};
3287
3288TEST_P(ImportImplicitMethods, DefaultConstructor) {
3289 testImportOf(MethodMatcher: cxxConstructorDecl(isDefaultConstructor()));
3290}
3291
3292TEST_P(ImportImplicitMethods, CopyConstructor) {
3293 testImportOf(MethodMatcher: cxxConstructorDecl(isCopyConstructor()));
3294}
3295
3296TEST_P(ImportImplicitMethods, MoveConstructor) {
3297 testImportOf(MethodMatcher: cxxConstructorDecl(isMoveConstructor()));
3298}
3299
3300TEST_P(ImportImplicitMethods, Destructor) {
3301 testImportOf(MethodMatcher: cxxDestructorDecl());
3302}
3303
3304TEST_P(ImportImplicitMethods, CopyAssignment) {
3305 testImportOf(MethodMatcher: cxxMethodDecl(isCopyAssignmentOperator()));
3306}
3307
3308TEST_P(ImportImplicitMethods, MoveAssignment) {
3309 testImportOf(MethodMatcher: cxxMethodDecl(isMoveAssignmentOperator()));
3310}
3311
3312TEST_P(ImportImplicitMethods, DoNotImportUserProvided) {
3313 auto Code = R"(
3314 struct A { A() { int x; } };
3315 )";
3316 testNoImportOf(MethodMatcher: cxxConstructorDecl(isDefaultConstructor()), Code);
3317}
3318
3319TEST_P(ImportImplicitMethods, DoNotImportDefault) {
3320 auto Code = R"(
3321 struct A { A() = default; };
3322 )";
3323 testNoImportOf(MethodMatcher: cxxConstructorDecl(isDefaultConstructor()), Code);
3324}
3325
3326TEST_P(ImportImplicitMethods, DoNotImportDeleted) {
3327 auto Code = R"(
3328 struct A { A() = delete; };
3329 )";
3330 testNoImportOf(MethodMatcher: cxxConstructorDecl(isDefaultConstructor()), Code);
3331}
3332
3333TEST_P(ImportImplicitMethods, DoNotImportOtherMethod) {
3334 auto Code = R"(
3335 struct A { void f() { } };
3336 )";
3337 testNoImportOf(MethodMatcher: cxxMethodDecl(hasName(Name: "f")), Code);
3338}
3339
3340TEST_P(ASTImporterOptionSpecificTestBase, ImportOfEquivalentRecord) {
3341 Decl *ToR1;
3342 {
3343 Decl *FromTU = getTuDecl(SrcCode: "struct A { };", Lang: Lang_CXX03, FileName: "input0.cc");
3344 auto *FromR = FirstDeclMatcher<CXXRecordDecl>().match(
3345 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A")));
3346
3347 ToR1 = Import(FromR, Lang_CXX03);
3348 }
3349
3350 Decl *ToR2;
3351 {
3352 Decl *FromTU = getTuDecl(SrcCode: "struct A { };", Lang: Lang_CXX03, FileName: "input1.cc");
3353 auto *FromR = FirstDeclMatcher<CXXRecordDecl>().match(
3354 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A")));
3355
3356 ToR2 = Import(FromR, Lang_CXX03);
3357 }
3358
3359 EXPECT_EQ(ToR1, ToR2);
3360}
3361
3362TEST_P(ASTImporterOptionSpecificTestBase, ImportOfNonEquivalentRecord) {
3363 Decl *ToR1;
3364 {
3365 Decl *FromTU = getTuDecl(SrcCode: "struct A { int x; };", Lang: Lang_CXX03, FileName: "input0.cc");
3366 auto *FromR = FirstDeclMatcher<CXXRecordDecl>().match(
3367 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A")));
3368 ToR1 = Import(FromR, Lang_CXX03);
3369 }
3370 Decl *ToR2;
3371 {
3372 Decl *FromTU =
3373 getTuDecl(SrcCode: "struct A { unsigned x; };", Lang: Lang_CXX03, FileName: "input1.cc");
3374 auto *FromR = FirstDeclMatcher<CXXRecordDecl>().match(
3375 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A")));
3376 ToR2 = Import(FromR, Lang_CXX03);
3377 }
3378 EXPECT_NE(ToR1, ToR2);
3379}
3380
3381TEST_P(ASTImporterOptionSpecificTestBase, ImportOfEquivalentField) {
3382 Decl *ToF1;
3383 {
3384 Decl *FromTU = getTuDecl(SrcCode: "struct A { int x; };", Lang: Lang_CXX03, FileName: "input0.cc");
3385 auto *FromF = FirstDeclMatcher<FieldDecl>().match(
3386 D: FromTU, AMatcher: fieldDecl(hasName(Name: "x")));
3387 ToF1 = Import(FromF, Lang_CXX03);
3388 }
3389 Decl *ToF2;
3390 {
3391 Decl *FromTU = getTuDecl(SrcCode: "struct A { int x; };", Lang: Lang_CXX03, FileName: "input1.cc");
3392 auto *FromF = FirstDeclMatcher<FieldDecl>().match(
3393 D: FromTU, AMatcher: fieldDecl(hasName(Name: "x")));
3394 ToF2 = Import(FromF, Lang_CXX03);
3395 }
3396 EXPECT_EQ(ToF1, ToF2);
3397}
3398
3399TEST_P(ASTImporterOptionSpecificTestBase, ImportBitfields) {
3400 Decl *FromTU = getTuDecl(SrcCode: "struct A { unsigned x : 3; };", Lang: Lang_CXX03);
3401 auto *FromF =
3402 FirstDeclMatcher<FieldDecl>().match(D: FromTU, AMatcher: fieldDecl(hasName(Name: "x")));
3403
3404 ASSERT_TRUE(FromF->isBitField());
3405 ASSERT_EQ(3u, FromF->getBitWidthValue(FromTU->getASTContext()));
3406 auto *ToField = Import(FromF, Lang_CXX03);
3407 auto *ToTU = ToField->getTranslationUnitDecl();
3408
3409 EXPECT_TRUE(ToField->isBitField());
3410 EXPECT_EQ(3u, ToField->getBitWidthValue(ToTU->getASTContext()));
3411
3412 const auto *FromBT = FromF->getBitWidth()->getType()->getAs<BuiltinType>();
3413 const auto *ToBT = ToField->getBitWidth()->getType()->getAs<BuiltinType>();
3414 ASSERT_TRUE(FromBT);
3415 ASSERT_EQ(BuiltinType::Int, FromBT->getKind());
3416 EXPECT_TRUE(ToBT);
3417 EXPECT_EQ(BuiltinType::Int, ToBT->getKind());
3418}
3419
3420struct ImportBlock : ASTImporterOptionSpecificTestBase {};
3421TEST_P(ImportBlock, ImportBlocksAreUnsupported) {
3422 const auto *Code = R"(
3423 void test_block__capture_null() {
3424 int *p = 0;
3425 ^(){
3426 *p = 1;
3427 }();
3428 })";
3429 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX03);
3430 auto *FromBlock = FirstDeclMatcher<BlockDecl>().match(D: FromTU, AMatcher: blockDecl());
3431 ASSERT_TRUE(FromBlock);
3432
3433 auto ToBlockOrError = importOrError(From: FromBlock, ToLang: Lang_CXX03);
3434
3435 const auto ExpectUnsupportedConstructError = [](const ASTImportError &Error) {
3436 EXPECT_EQ(ASTImportError::UnsupportedConstruct, Error.Error);
3437 };
3438 llvm::handleAllErrors(ToBlockOrError.takeError(),
3439 ExpectUnsupportedConstructError);
3440}
3441
3442TEST_P(ASTImporterOptionSpecificTestBase, ImportParmVarDecl) {
3443 const auto *Code = R"(
3444 template <typename T> struct Wrapper {
3445 Wrapper(T Value = {}) {}
3446 };
3447 template class Wrapper<int>;
3448 )";
3449 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11);
3450 auto *FromVar = FirstDeclMatcher<ParmVarDecl>().match(
3451 D: FromTU, AMatcher: parmVarDecl(hasType(InnerMatcher: asString(Name: "int"))));
3452 ASSERT_TRUE(FromVar);
3453 ASSERT_TRUE(FromVar->hasUninstantiatedDefaultArg());
3454 ASSERT_TRUE(FromVar->getUninstantiatedDefaultArg());
3455
3456 const auto *ToVar = Import(FromVar, Lang_CXX11);
3457 EXPECT_TRUE(ToVar);
3458 EXPECT_TRUE(ToVar->hasUninstantiatedDefaultArg());
3459 EXPECT_TRUE(ToVar->getUninstantiatedDefaultArg());
3460 EXPECT_NE(FromVar->getUninstantiatedDefaultArg(),
3461 ToVar->getUninstantiatedDefaultArg());
3462}
3463
3464TEST_P(ASTImporterOptionSpecificTestBase, ImportOfNonEquivalentField) {
3465 Decl *ToF1;
3466 {
3467 Decl *FromTU = getTuDecl(SrcCode: "struct A { int x; };", Lang: Lang_CXX03, FileName: "input0.cc");
3468 auto *FromF = FirstDeclMatcher<FieldDecl>().match(
3469 D: FromTU, AMatcher: fieldDecl(hasName(Name: "x")));
3470 ToF1 = Import(FromF, Lang_CXX03);
3471 }
3472 Decl *ToF2;
3473 {
3474 Decl *FromTU =
3475 getTuDecl(SrcCode: "struct A { unsigned x; };", Lang: Lang_CXX03, FileName: "input1.cc");
3476 auto *FromF = FirstDeclMatcher<FieldDecl>().match(
3477 D: FromTU, AMatcher: fieldDecl(hasName(Name: "x")));
3478 ToF2 = Import(FromF, Lang_CXX03);
3479 }
3480 EXPECT_NE(ToF1, ToF2);
3481}
3482
3483TEST_P(ASTImporterOptionSpecificTestBase, ImportOfEquivalentMethod) {
3484 Decl *ToM1;
3485 {
3486 Decl *FromTU = getTuDecl(SrcCode: "struct A { void x(); }; void A::x() { }",
3487 Lang: Lang_CXX03, FileName: "input0.cc");
3488 auto *FromM = FirstDeclMatcher<FunctionDecl>().match(
3489 D: FromTU, AMatcher: functionDecl(hasName(Name: "x"), isDefinition()));
3490 ToM1 = Import(FromM, Lang_CXX03);
3491 }
3492 Decl *ToM2;
3493 {
3494 Decl *FromTU = getTuDecl(SrcCode: "struct A { void x(); }; void A::x() { }",
3495 Lang: Lang_CXX03, FileName: "input1.cc");
3496 auto *FromM = FirstDeclMatcher<FunctionDecl>().match(
3497 D: FromTU, AMatcher: functionDecl(hasName(Name: "x"), isDefinition()));
3498 ToM2 = Import(FromM, Lang_CXX03);
3499 }
3500 EXPECT_EQ(ToM1, ToM2);
3501}
3502
3503TEST_P(ASTImporterOptionSpecificTestBase, ImportOfNonEquivalentMethod) {
3504 Decl *ToM1;
3505 {
3506 Decl *FromTU = getTuDecl(SrcCode: "struct A { void x(); }; void A::x() { }",
3507 Lang: Lang_CXX03, FileName: "input0.cc");
3508 auto *FromM = FirstDeclMatcher<FunctionDecl>().match(
3509 D: FromTU, AMatcher: functionDecl(hasName(Name: "x"), isDefinition()));
3510 ToM1 = Import(FromM, Lang_CXX03);
3511 }
3512 Decl *ToM2;
3513 {
3514 Decl *FromTU =
3515 getTuDecl(SrcCode: "struct A { void x() const; }; void A::x() const { }",
3516 Lang: Lang_CXX03, FileName: "input1.cc");
3517 auto *FromM = FirstDeclMatcher<FunctionDecl>().match(
3518 D: FromTU, AMatcher: functionDecl(hasName(Name: "x"), isDefinition()));
3519 ToM2 = Import(FromM, Lang_CXX03);
3520 }
3521 EXPECT_NE(ToM1, ToM2);
3522}
3523
3524TEST_P(ASTImporterOptionSpecificTestBase,
3525 ImportUnnamedStructsWithRecursingField) {
3526 Decl *FromTU = getTuDecl(
3527 SrcCode: R"(
3528 struct A {
3529 struct {
3530 struct A *next;
3531 } entry0;
3532 struct {
3533 struct A *next;
3534 } entry1;
3535 };
3536 )",
3537 Lang: Lang_C99, FileName: "input0.cc");
3538 auto *From =
3539 FirstDeclMatcher<RecordDecl>().match(D: FromTU, AMatcher: recordDecl(hasName(Name: "A")));
3540
3541 Import(From, Lang_C99);
3542
3543 auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
3544 auto *Entry0 =
3545 FirstDeclMatcher<FieldDecl>().match(ToTU, fieldDecl(hasName(Name: "entry0")));
3546 auto *Entry1 =
3547 FirstDeclMatcher<FieldDecl>().match(ToTU, fieldDecl(hasName(Name: "entry1")));
3548 auto *R0 = getRecordDecl(Entry0);
3549 auto *R1 = getRecordDecl(Entry1);
3550 EXPECT_NE(R0, R1);
3551 EXPECT_TRUE(MatchVerifier<RecordDecl>().match(
3552 R0, recordDecl(has(fieldDecl(hasName("next"))))));
3553 EXPECT_TRUE(MatchVerifier<RecordDecl>().match(
3554 R1, recordDecl(has(fieldDecl(hasName("next"))))));
3555}
3556
3557TEST_P(ASTImporterOptionSpecificTestBase, ImportUnnamedFieldsInCorrectOrder) {
3558 Decl *FromTU = getTuDecl(
3559 SrcCode: R"(
3560 void f(int X, int Y, bool Z) {
3561 (void)[X, Y, Z] { (void)Z; };
3562 }
3563 )",
3564 Lang: Lang_CXX11, FileName: "input0.cc");
3565 auto *FromF = FirstDeclMatcher<FunctionDecl>().match(
3566 D: FromTU, AMatcher: functionDecl(hasName(Name: "f")));
3567 auto *ToF = cast_or_null<FunctionDecl>(Import(FromF, Lang_CXX11));
3568 EXPECT_TRUE(ToF);
3569
3570 CXXRecordDecl *FromLambda =
3571 cast<LambdaExpr>(cast<CStyleCastExpr>(cast<CompoundStmt>(
3572 FromF->getBody())->body_front())->getSubExpr())->getLambdaClass();
3573
3574 auto *ToLambda = cast_or_null<CXXRecordDecl>(Val: Import(From: FromLambda, Lang: Lang_CXX11));
3575 EXPECT_TRUE(ToLambda);
3576
3577 // Check if the fields of the lambda class are imported in correct order.
3578 unsigned FromIndex = 0u;
3579 for (auto *FromField : FromLambda->fields()) {
3580 ASSERT_FALSE(FromField->getDeclName());
3581 auto *ToField = cast_or_null<FieldDecl>(Import(FromField, Lang_CXX11));
3582 EXPECT_TRUE(ToField);
3583 std::optional<unsigned> ToIndex = ASTImporter::getFieldIndex(ToField);
3584 EXPECT_TRUE(ToIndex);
3585 EXPECT_EQ(*ToIndex, FromIndex);
3586 ++FromIndex;
3587 }
3588
3589 EXPECT_EQ(FromIndex, 3u);
3590}
3591
3592TEST_P(ASTImporterOptionSpecificTestBase,
3593 MergeFieldDeclsOfClassTemplateSpecialization) {
3594 std::string ClassTemplate =
3595 R"(
3596 template <typename T>
3597 struct X {
3598 int a{0}; // FieldDecl with InitListExpr
3599 X(char) : a(3) {} // (1)
3600 X(int) {} // (2)
3601 };
3602 )";
3603 Decl *ToTU = getToTuDecl(ToSrcCode: ClassTemplate +
3604 R"(
3605 void foo() {
3606 // ClassTemplateSpec with ctor (1): FieldDecl without InitlistExpr
3607 X<char> xc('c');
3608 }
3609 )", ToLang: Lang_CXX11);
3610 auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
3611 D: ToTU, AMatcher: classTemplateSpecializationDecl(hasName(Name: "X")));
3612 // FieldDecl without InitlistExpr:
3613 auto *ToField = *ToSpec->field_begin();
3614 ASSERT_TRUE(ToField);
3615 ASSERT_FALSE(ToField->getInClassInitializer());
3616 Decl *FromTU = getTuDecl(SrcCode: ClassTemplate +
3617 R"(
3618 void bar() {
3619 // ClassTemplateSpec with ctor (2): FieldDecl WITH InitlistExpr
3620 X<char> xc(1);
3621 }
3622 )", Lang: Lang_CXX11);
3623 auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
3624 D: FromTU, AMatcher: classTemplateSpecializationDecl(hasName(Name: "X")));
3625 // FieldDecl with InitlistExpr:
3626 auto *FromField = *FromSpec->field_begin();
3627 ASSERT_TRUE(FromField);
3628 ASSERT_TRUE(FromField->getInClassInitializer());
3629
3630 auto *ImportedSpec = Import(FromSpec, Lang_CXX11);
3631 ASSERT_TRUE(ImportedSpec);
3632 EXPECT_EQ(ImportedSpec, ToSpec);
3633 // After the import, the FieldDecl has to be merged, thus it should have the
3634 // InitListExpr.
3635 EXPECT_TRUE(ToField->getInClassInitializer());
3636}
3637
3638TEST_P(ASTImporterOptionSpecificTestBase,
3639 MergeFunctionOfClassTemplateSpecialization) {
3640 std::string ClassTemplate =
3641 R"(
3642 template <typename T>
3643 struct X {
3644 void f() {}
3645 void g() {}
3646 };
3647 )";
3648 Decl *ToTU = getToTuDecl(ToSrcCode: ClassTemplate +
3649 R"(
3650 void foo() {
3651 X<char> x;
3652 x.f();
3653 }
3654 )", ToLang: Lang_CXX11);
3655 Decl *FromTU = getTuDecl(SrcCode: ClassTemplate +
3656 R"(
3657 void bar() {
3658 X<char> x;
3659 x.g();
3660 }
3661 )", Lang: Lang_CXX11);
3662 auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
3663 D: FromTU, AMatcher: classTemplateSpecializationDecl(hasName(Name: "X")));
3664 auto FunPattern = functionDecl(hasName(Name: "g"),
3665 hasParent(classTemplateSpecializationDecl()));
3666 auto *FromFun =
3667 FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: FunPattern);
3668 auto *ToFun =
3669 FirstDeclMatcher<FunctionDecl>().match(D: ToTU, AMatcher: FunPattern);
3670 ASSERT_TRUE(FromFun->hasBody());
3671 ASSERT_FALSE(ToFun->hasBody());
3672 auto *ImportedSpec = Import(FromSpec, Lang_CXX11);
3673 ASSERT_TRUE(ImportedSpec);
3674 auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
3675 D: ToTU, AMatcher: classTemplateSpecializationDecl(hasName(Name: "X")));
3676 EXPECT_EQ(ImportedSpec, ToSpec);
3677 EXPECT_TRUE(ToFun->hasBody());
3678}
3679
3680TEST_P(ASTImporterOptionSpecificTestBase, MergeTemplateSpecWithForwardDecl) {
3681 std::string ClassTemplate =
3682 R"(
3683 template<typename T>
3684 struct X { int m; };
3685 template<>
3686 struct X<int> { int m; };
3687 )";
3688 // Append a forward decl for our template specialization.
3689 getToTuDecl(ToSrcCode: ClassTemplate + "template<> struct X<int>;", ToLang: Lang_CXX11);
3690 Decl *FromTU = getTuDecl(SrcCode: ClassTemplate, Lang: Lang_CXX11);
3691 auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
3692 D: FromTU, AMatcher: classTemplateSpecializationDecl(hasName(Name: "X"), isDefinition()));
3693 auto *ImportedSpec = Import(FromSpec, Lang_CXX11);
3694 // Check that our definition got merged with the existing definition.
3695 EXPECT_TRUE(FromSpec->isThisDeclarationADefinition());
3696 EXPECT_TRUE(ImportedSpec->isThisDeclarationADefinition());
3697}
3698
3699TEST_P(ASTImporterOptionSpecificTestBase,
3700 ODRViolationOfClassTemplateSpecializationsShouldBeReported) {
3701 std::string ClassTemplate =
3702 R"(
3703 template <typename T>
3704 struct X {};
3705 )";
3706 Decl *ToTU = getToTuDecl(ToSrcCode: ClassTemplate +
3707 R"(
3708 template <>
3709 struct X<char> {
3710 int a;
3711 };
3712 void foo() {
3713 X<char> x;
3714 }
3715 )",
3716 ToLang: Lang_CXX11);
3717 Decl *FromTU = getTuDecl(SrcCode: ClassTemplate +
3718 R"(
3719 template <>
3720 struct X<char> {
3721 int b;
3722 };
3723 void foo() {
3724 X<char> x;
3725 }
3726 )",
3727 Lang: Lang_CXX11);
3728 auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
3729 D: FromTU, AMatcher: classTemplateSpecializationDecl(hasName(Name: "X")));
3730 auto *ImportedSpec = Import(FromSpec, Lang_CXX11);
3731
3732 // We expect one (ODR) warning during the import.
3733 EXPECT_EQ(1u, ToTU->getASTContext().getDiagnostics().getNumWarnings());
3734
3735 // The second specialization is different from the first, thus it violates
3736 // ODR, consequently we expect to keep the first specialization only, which is
3737 // already in the "To" context.
3738 EXPECT_FALSE(ImportedSpec);
3739 EXPECT_EQ(1u,
3740 DeclCounter<ClassTemplateSpecializationDecl>().match(
3741 ToTU, classTemplateSpecializationDecl(hasName("X"))));
3742}
3743
3744TEST_P(ASTImporterOptionSpecificTestBase,
3745 MergeCtorOfClassTemplateSpecialization) {
3746 std::string ClassTemplate =
3747 R"(
3748 template <typename T>
3749 struct X {
3750 X(char) {}
3751 X(int) {}
3752 };
3753 )";
3754 Decl *ToTU = getToTuDecl(ToSrcCode: ClassTemplate +
3755 R"(
3756 void foo() {
3757 X<char> x('c');
3758 }
3759 )", ToLang: Lang_CXX11);
3760 Decl *FromTU = getTuDecl(SrcCode: ClassTemplate +
3761 R"(
3762 void bar() {
3763 X<char> x(1);
3764 }
3765 )", Lang: Lang_CXX11);
3766 auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
3767 D: FromTU, AMatcher: classTemplateSpecializationDecl(hasName(Name: "X")));
3768 // Match the void(int) ctor.
3769 auto CtorPattern =
3770 cxxConstructorDecl(hasParameter(N: 0, InnerMatcher: varDecl(hasType(InnerMatcher: asString(Name: "int")))),
3771 hasParent(classTemplateSpecializationDecl()));
3772 auto *FromCtor =
3773 FirstDeclMatcher<CXXConstructorDecl>().match(D: FromTU, AMatcher: CtorPattern);
3774 auto *ToCtor =
3775 FirstDeclMatcher<CXXConstructorDecl>().match(D: ToTU, AMatcher: CtorPattern);
3776 ASSERT_TRUE(FromCtor->hasBody());
3777 ASSERT_FALSE(ToCtor->hasBody());
3778 auto *ImportedSpec = Import(FromSpec, Lang_CXX11);
3779 ASSERT_TRUE(ImportedSpec);
3780 auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
3781 D: ToTU, AMatcher: classTemplateSpecializationDecl(hasName(Name: "X")));
3782 EXPECT_EQ(ImportedSpec, ToSpec);
3783 EXPECT_TRUE(ToCtor->hasBody());
3784}
3785
3786TEST_P(ASTImporterOptionSpecificTestBase, ClassTemplateFriendDecl) {
3787 const auto *Code =
3788 R"(
3789 template <class T> class X { friend T; };
3790 struct Y {};
3791 template class X<Y>;
3792 )";
3793 Decl *ToTU = getToTuDecl(ToSrcCode: Code, ToLang: Lang_CXX11);
3794 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11);
3795 auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
3796 D: FromTU, AMatcher: classTemplateSpecializationDecl());
3797 auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
3798 D: ToTU, AMatcher: classTemplateSpecializationDecl());
3799
3800 auto *ImportedSpec = Import(FromSpec, Lang_CXX11);
3801 EXPECT_EQ(ImportedSpec, ToSpec);
3802 EXPECT_EQ(1u, DeclCounter<ClassTemplateSpecializationDecl>().match(
3803 ToTU, classTemplateSpecializationDecl()));
3804}
3805
3806TEST_P(ASTImporterOptionSpecificTestBase,
3807 ClassTemplatePartialSpecializationsShouldNotBeDuplicated) {
3808 auto Code =
3809 R"(
3810 // primary template
3811 template<class T1, class T2, int I>
3812 class A {};
3813
3814 // partial specialization
3815 template<class T, int I>
3816 class A<T, T*, I> {};
3817 )";
3818 Decl *ToTU = getToTuDecl(ToSrcCode: Code, ToLang: Lang_CXX11);
3819 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11);
3820 auto *FromSpec =
3821 FirstDeclMatcher<ClassTemplatePartialSpecializationDecl>().match(
3822 D: FromTU, AMatcher: classTemplatePartialSpecializationDecl());
3823 auto *ToSpec =
3824 FirstDeclMatcher<ClassTemplatePartialSpecializationDecl>().match(
3825 D: ToTU, AMatcher: classTemplatePartialSpecializationDecl());
3826
3827 auto *ImportedSpec = Import(FromSpec, Lang_CXX11);
3828 EXPECT_EQ(ImportedSpec, ToSpec);
3829 EXPECT_EQ(1u, DeclCounter<ClassTemplatePartialSpecializationDecl>().match(
3830 ToTU, classTemplatePartialSpecializationDecl()));
3831}
3832
3833TEST_P(ASTImporterOptionSpecificTestBase,
3834 ClassTemplateSpecializationsShouldNotBeDuplicated) {
3835 auto Code =
3836 R"(
3837 // primary template
3838 template<class T1, class T2, int I>
3839 class A {};
3840
3841 // full specialization
3842 template<>
3843 class A<int, int, 1> {};
3844 )";
3845 Decl *ToTU = getToTuDecl(ToSrcCode: Code, ToLang: Lang_CXX11);
3846 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11);
3847 auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
3848 D: FromTU, AMatcher: classTemplateSpecializationDecl());
3849 auto *ToSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
3850 D: ToTU, AMatcher: classTemplateSpecializationDecl());
3851
3852 auto *ImportedSpec = Import(FromSpec, Lang_CXX11);
3853 EXPECT_EQ(ImportedSpec, ToSpec);
3854 EXPECT_EQ(1u, DeclCounter<ClassTemplateSpecializationDecl>().match(
3855 ToTU, classTemplateSpecializationDecl()));
3856}
3857
3858TEST_P(ASTImporterOptionSpecificTestBase,
3859 ClassTemplateFullAndPartialSpecsShouldNotBeMixed) {
3860 std::string PrimaryTemplate =
3861 R"(
3862 template<class T1, class T2, int I>
3863 class A {};
3864 )";
3865 auto PartialSpec =
3866 R"(
3867 template<class T, int I>
3868 class A<T, T*, I> {};
3869 )";
3870 auto FullSpec =
3871 R"(
3872 template<>
3873 class A<int, int, 1> {};
3874 )";
3875 Decl *ToTU = getToTuDecl(ToSrcCode: PrimaryTemplate + FullSpec, ToLang: Lang_CXX11);
3876 Decl *FromTU = getTuDecl(SrcCode: PrimaryTemplate + PartialSpec, Lang: Lang_CXX11);
3877 auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
3878 D: FromTU, AMatcher: classTemplateSpecializationDecl());
3879
3880 auto *ImportedSpec = Import(FromSpec, Lang_CXX11);
3881 EXPECT_TRUE(ImportedSpec);
3882 // Check the number of partial specializations.
3883 EXPECT_EQ(1u, DeclCounter<ClassTemplatePartialSpecializationDecl>().match(
3884 ToTU, classTemplatePartialSpecializationDecl()));
3885 // Check the number of full specializations.
3886 EXPECT_EQ(1u, DeclCounter<ClassTemplateSpecializationDecl>().match(
3887 ToTU, classTemplateSpecializationDecl(
3888 unless(classTemplatePartialSpecializationDecl()))));
3889}
3890
3891TEST_P(ASTImporterOptionSpecificTestBase,
3892 InitListExprValueKindShouldBeImported) {
3893 Decl *TU = getTuDecl(
3894 SrcCode: R"(
3895 const int &init();
3896 void foo() { const int &a{init()}; }
3897 )", Lang: Lang_CXX11, FileName: "input0.cc");
3898 auto *FromD = FirstDeclMatcher<VarDecl>().match(D: TU, AMatcher: varDecl(hasName(Name: "a")));
3899 ASSERT_TRUE(FromD->getAnyInitializer());
3900 auto *InitExpr = FromD->getAnyInitializer();
3901 ASSERT_TRUE(InitExpr);
3902 ASSERT_TRUE(InitExpr->isGLValue());
3903
3904 auto *ToD = Import(FromD, Lang_CXX11);
3905 EXPECT_TRUE(ToD);
3906 auto *ToInitExpr = cast<VarDecl>(ToD)->getAnyInitializer();
3907 EXPECT_TRUE(ToInitExpr);
3908 EXPECT_TRUE(ToInitExpr->isGLValue());
3909}
3910
3911struct ImportVariables : ASTImporterOptionSpecificTestBase {};
3912
3913TEST_P(ImportVariables, ImportOfOneDeclBringsInTheWholeChain) {
3914 Decl *FromTU = getTuDecl(
3915 SrcCode: R"(
3916 struct A {
3917 static const int a = 1 + 2;
3918 };
3919 const int A::a;
3920 )",
3921 Lang: Lang_CXX03, FileName: "input1.cc");
3922
3923 auto *FromDWithInit = FirstDeclMatcher<VarDecl>().match(
3924 D: FromTU, AMatcher: varDecl(hasName(Name: "a"))); // Decl with init
3925 auto *FromDWithDef = LastDeclMatcher<VarDecl>().match(
3926 D: FromTU, AMatcher: varDecl(hasName(Name: "a"))); // Decl with definition
3927 ASSERT_NE(FromDWithInit, FromDWithDef);
3928 ASSERT_EQ(FromDWithDef->getPreviousDecl(), FromDWithInit);
3929
3930 auto *ToD0 = cast<VarDecl>(Import(FromDWithInit, Lang_CXX11));
3931 auto *ToD1 = cast<VarDecl>(Import(FromDWithDef, Lang_CXX11));
3932 ASSERT_TRUE(ToD0);
3933 ASSERT_TRUE(ToD1);
3934 EXPECT_NE(ToD0, ToD1);
3935 EXPECT_EQ(ToD1->getPreviousDecl(), ToD0);
3936}
3937
3938TEST_P(ImportVariables, InitAndDefinitionAreInDifferentTUs) {
3939 auto StructA =
3940 R"(
3941 struct A {
3942 static const int a = 1 + 2;
3943 };
3944 )";
3945 Decl *ToTU = getToTuDecl(ToSrcCode: StructA, ToLang: Lang_CXX03);
3946 Decl *FromTU = getTuDecl(SrcCode: std::string(StructA) + "const int A::a;", Lang: Lang_CXX03,
3947 FileName: "input1.cc");
3948
3949 auto *FromDWithInit = FirstDeclMatcher<VarDecl>().match(
3950 D: FromTU, AMatcher: varDecl(hasName(Name: "a"))); // Decl with init
3951 auto *FromDWithDef = LastDeclMatcher<VarDecl>().match(
3952 D: FromTU, AMatcher: varDecl(hasName(Name: "a"))); // Decl with definition
3953 ASSERT_EQ(FromDWithInit, FromDWithDef->getPreviousDecl());
3954 ASSERT_TRUE(FromDWithInit->getInit());
3955 ASSERT_FALSE(FromDWithInit->isThisDeclarationADefinition());
3956 ASSERT_TRUE(FromDWithDef->isThisDeclarationADefinition());
3957 ASSERT_FALSE(FromDWithDef->getInit());
3958
3959 auto *ToD = FirstDeclMatcher<VarDecl>().match(
3960 D: ToTU, AMatcher: varDecl(hasName(Name: "a"))); // Decl with init
3961 ASSERT_TRUE(ToD->getInit());
3962 ASSERT_FALSE(ToD->getDefinition());
3963
3964 auto *ImportedD = cast<VarDecl>(Import(FromDWithDef, Lang_CXX11));
3965 EXPECT_TRUE(ImportedD->getAnyInitializer());
3966 EXPECT_TRUE(ImportedD->getDefinition());
3967}
3968
3969TEST_P(ImportVariables, InitAndDefinitionAreInTheFromContext) {
3970 auto StructA =
3971 R"(
3972 struct A {
3973 static const int a;
3974 };
3975 )";
3976 Decl *ToTU = getToTuDecl(ToSrcCode: StructA, ToLang: Lang_CXX03);
3977 Decl *FromTU = getTuDecl(SrcCode: std::string(StructA) + "const int A::a = 1 + 2;",
3978 Lang: Lang_CXX03, FileName: "input1.cc");
3979
3980 auto *FromDDeclarationOnly = FirstDeclMatcher<VarDecl>().match(
3981 D: FromTU, AMatcher: varDecl(hasName(Name: "a")));
3982 auto *FromDWithDef = LastDeclMatcher<VarDecl>().match(
3983 D: FromTU, AMatcher: varDecl(hasName(Name: "a"))); // Decl with definition and with init.
3984 ASSERT_EQ(FromDDeclarationOnly, FromDWithDef->getPreviousDecl());
3985 ASSERT_FALSE(FromDDeclarationOnly->getInit());
3986 ASSERT_FALSE(FromDDeclarationOnly->isThisDeclarationADefinition());
3987 ASSERT_TRUE(FromDWithDef->isThisDeclarationADefinition());
3988 ASSERT_TRUE(FromDWithDef->getInit());
3989
3990 auto *ToD = FirstDeclMatcher<VarDecl>().match(
3991 D: ToTU, AMatcher: varDecl(hasName(Name: "a")));
3992 ASSERT_FALSE(ToD->getInit());
3993 ASSERT_FALSE(ToD->getDefinition());
3994
3995 auto *ImportedD = cast<VarDecl>(Import(FromDWithDef, Lang_CXX11));
3996 EXPECT_TRUE(ImportedD->getAnyInitializer());
3997 EXPECT_TRUE(ImportedD->getDefinition());
3998}
3999
4000TEST_P(ImportVariables, ImportBindingDecl) {
4001 Decl *From, *To;
4002 std::tie(args&: From, args&: To) = getImportedDecl(
4003 FromSrcCode: R"(
4004 void declToImport() {
4005 int a[2] = {1,2};
4006 auto [x1,y1] = a;
4007 auto& [x2,y2] = a;
4008
4009 struct S {
4010 mutable int x1 : 2;
4011 volatile double y1;
4012 };
4013 S b;
4014 const auto [x3, y3] = b;
4015 };
4016 )",
4017 FromLang: Lang_CXX17, ToSrcCode: "", ToLang: Lang_CXX17);
4018
4019 TranslationUnitDecl *FromTU = From->getTranslationUnitDecl();
4020 auto *FromF = FirstDeclMatcher<FunctionDecl>().match(
4021 FromTU, functionDecl(hasName(Name: "declToImport")));
4022 auto *ToF = Import(FromF, Lang_CXX17);
4023 EXPECT_TRUE(ToF);
4024
4025 auto VerifyImport = [&](llvm::StringRef BindName) {
4026 auto *FromB = FirstDeclMatcher<BindingDecl>().match(
4027 FromF, bindingDecl(hasName(Name: BindName)));
4028 ASSERT_TRUE(FromB);
4029 auto *ToB = Import(FromB, Lang_CXX17);
4030 EXPECT_TRUE(ToB);
4031 EXPECT_EQ(FromB->getBinding() != nullptr, ToB->getBinding() != nullptr);
4032 EXPECT_EQ(FromB->getDecomposedDecl() != nullptr,
4033 ToB->getDecomposedDecl() != nullptr);
4034 EXPECT_EQ(FromB->getHoldingVar() != nullptr,
4035 ToB->getHoldingVar() != nullptr);
4036 };
4037
4038 VerifyImport("x1");
4039 VerifyImport("y1");
4040 VerifyImport("x2");
4041 VerifyImport("y2");
4042 VerifyImport("x3");
4043 VerifyImport("y3");
4044}
4045
4046TEST_P(ImportVariables, ImportDecompositionDeclArray) {
4047 Decl *From, *To;
4048 std::tie(args&: From, args&: To) = getImportedDecl(
4049 FromSrcCode: R"(
4050 void declToImport() {
4051 int a[2] = {1,2};
4052 auto [x1,y1] = a;
4053 };
4054 )",
4055 FromLang: Lang_CXX17, ToSrcCode: "", ToLang: Lang_CXX17);
4056
4057 TranslationUnitDecl *FromTU = From->getTranslationUnitDecl();
4058 auto *FromDecomp =
4059 FirstDeclMatcher<DecompositionDecl>().match(FromTU, decompositionDecl());
4060 auto *ToDecomp = Import(FromDecomp, Lang_CXX17);
4061 EXPECT_TRUE(ToDecomp);
4062
4063 ArrayRef<BindingDecl *> FromB = FromDecomp->bindings();
4064 ArrayRef<BindingDecl *> ToB = ToDecomp->bindings();
4065 EXPECT_EQ(FromB.size(), ToB.size());
4066 for (unsigned int I = 0; I < FromB.size(); ++I) {
4067 auto *ToBI = Import(From: FromB[I], Lang: Lang_CXX17);
4068 EXPECT_EQ(ToBI, ToB[I]);
4069 }
4070}
4071
4072struct ImportClasses : ASTImporterOptionSpecificTestBase {};
4073
4074TEST_P(ImportClasses, ImportDefinitionWhenProtoIsInNestedToContext) {
4075 Decl *ToTU = getToTuDecl(ToSrcCode: "struct A { struct X *Xp; };", ToLang: Lang_C99);
4076 Decl *FromTU1 = getTuDecl(SrcCode: "struct X {};", Lang: Lang_C99, FileName: "input1.cc");
4077 auto Pattern = recordDecl(hasName(Name: "X"), unless(isImplicit()));
4078 auto ToProto = FirstDeclMatcher<RecordDecl>().match(D: ToTU, AMatcher: Pattern);
4079 auto FromDef = FirstDeclMatcher<RecordDecl>().match(D: FromTU1, AMatcher: Pattern);
4080
4081 Decl *ImportedDef = Import(FromDef, Lang_C99);
4082
4083 EXPECT_NE(ImportedDef, ToProto);
4084 EXPECT_EQ(DeclCounter<RecordDecl>().match(ToTU, Pattern), 2u);
4085 auto ToDef = LastDeclMatcher<RecordDecl>().match(D: ToTU, AMatcher: Pattern);
4086 EXPECT_TRUE(ImportedDef == ToDef);
4087 EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
4088 EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
4089 EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
4090}
4091
4092TEST_P(ImportClasses, ImportDefinitionWhenProtoIsInNestedToContextCXX) {
4093 Decl *ToTU = getToTuDecl(ToSrcCode: "struct A { struct X *Xp; };", ToLang: Lang_CXX03);
4094 Decl *FromTU1 = getTuDecl(SrcCode: "struct X {};", Lang: Lang_CXX03, FileName: "input1.cc");
4095 auto Pattern = recordDecl(hasName(Name: "X"), unless(isImplicit()));
4096 auto ToProto = FirstDeclMatcher<RecordDecl>().match(D: ToTU, AMatcher: Pattern);
4097 auto FromDef = FirstDeclMatcher<RecordDecl>().match(D: FromTU1, AMatcher: Pattern);
4098
4099 Decl *ImportedDef = Import(FromDef, Lang_CXX03);
4100
4101 EXPECT_NE(ImportedDef, ToProto);
4102 EXPECT_EQ(DeclCounter<RecordDecl>().match(ToTU, Pattern), 2u);
4103 auto ToDef = LastDeclMatcher<RecordDecl>().match(D: ToTU, AMatcher: Pattern);
4104 EXPECT_TRUE(ImportedDef == ToDef);
4105 EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
4106 EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
4107 EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
4108}
4109
4110TEST_P(ImportClasses, ImportNestedPrototypeThenDefinition) {
4111 Decl *FromTU0 =
4112 getTuDecl(SrcCode: "struct A { struct X *Xp; };", Lang: Lang_C99, FileName: "input0.cc");
4113 Decl *FromTU1 = getTuDecl(SrcCode: "struct X {};", Lang: Lang_C99, FileName: "input1.cc");
4114 auto Pattern = recordDecl(hasName(Name: "X"), unless(isImplicit()));
4115 auto FromProto = FirstDeclMatcher<RecordDecl>().match(D: FromTU0, AMatcher: Pattern);
4116 auto FromDef = FirstDeclMatcher<RecordDecl>().match(D: FromTU1, AMatcher: Pattern);
4117
4118 Decl *ImportedProto = Import(FromProto, Lang_C99);
4119 Decl *ImportedDef = Import(FromDef, Lang_C99);
4120 Decl *ToTU = ImportedDef->getTranslationUnitDecl();
4121
4122 EXPECT_NE(ImportedDef, ImportedProto);
4123 EXPECT_EQ(DeclCounter<RecordDecl>().match(ToTU, Pattern), 2u);
4124 auto ToProto = FirstDeclMatcher<RecordDecl>().match(D: ToTU, AMatcher: Pattern);
4125 auto ToDef = LastDeclMatcher<RecordDecl>().match(D: ToTU, AMatcher: Pattern);
4126 EXPECT_TRUE(ImportedDef == ToDef);
4127 EXPECT_TRUE(ImportedProto == ToProto);
4128 EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
4129 EXPECT_FALSE(ToProto->isThisDeclarationADefinition());
4130 EXPECT_EQ(ToDef->getPreviousDecl(), ToProto);
4131}
4132
4133struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {
4134 void testRecursiveFriendClassTemplate(Decl *FromTu) {
4135 auto *FromD = FirstDeclMatcher<ClassTemplateDecl>().match(
4136 D: FromTu, AMatcher: classTemplateDecl());
4137
4138 auto Pattern = classTemplateDecl(
4139 has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()))))));
4140 ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromD, Pattern));
4141
4142 auto *FromFriend =
4143 FirstDeclMatcher<FriendDecl>().match(FromD, friendDecl());
4144 auto *FromRecordOfFriend =
4145 cast<ClassTemplateDecl>(FromFriend->getFriendDecl())
4146 ->getTemplatedDecl();
4147 EXPECT_NE(FromRecordOfFriend, FromD->getTemplatedDecl());
4148 EXPECT_TRUE(FromRecordOfFriend->getPreviousDecl() == nullptr);
4149
4150 auto *FromDC = FromRecordOfFriend->getDeclContext();
4151 auto *FromLexicalDC = FromRecordOfFriend->getLexicalDeclContext();
4152 ASSERT_EQ(FromDC, cast<DeclContext>(FromTu));
4153 ASSERT_EQ(FromLexicalDC, cast<DeclContext>(FromD->getTemplatedDecl()));
4154
4155 ASSERT_FALSE(FromDC->containsDecl(FromRecordOfFriend));
4156 ASSERT_FALSE(FromLexicalDC->containsDecl(FromRecordOfFriend));
4157 ASSERT_FALSE(cast<RecordDecl>(FromRecordOfFriend)
4158 ->getLookupParent()
4159 ->lookup(FromRecordOfFriend->getDeclName())
4160 .empty());
4161
4162 auto *ToD = Import(From: FromD, Lang: Lang_CXX03);
4163 EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToD, Pattern));
4164
4165 auto *ToFriend = FirstDeclMatcher<FriendDecl>().match(ToD, friendDecl());
4166 auto *ToRecordOfFriend =
4167 cast<ClassTemplateDecl>(ToFriend->getFriendDecl())->getTemplatedDecl();
4168
4169 EXPECT_NE(ToRecordOfFriend, ToD->getTemplatedDecl());
4170 EXPECT_TRUE(ToRecordOfFriend->getPreviousDecl() == nullptr);
4171
4172 auto *ToDC = ToRecordOfFriend->getDeclContext();
4173 auto *ToLexicalDC = ToRecordOfFriend->getLexicalDeclContext();
4174 ASSERT_EQ(ToDC, cast<DeclContext>(ToD->getTranslationUnitDecl()));
4175 ASSERT_EQ(ToLexicalDC, cast<DeclContext>(ToD->getTemplatedDecl()));
4176
4177 ASSERT_FALSE(ToDC->containsDecl(ToRecordOfFriend));
4178 ASSERT_FALSE(ToLexicalDC->containsDecl(ToRecordOfFriend));
4179 ASSERT_FALSE(cast<RecordDecl>(ToRecordOfFriend)
4180 ->getLookupParent()
4181 ->lookup(ToRecordOfFriend->getDeclName())
4182 .empty());
4183 }
4184
4185 void testRepeatedFriendImport(const char *Code) {
4186 Decl *ToTu = getToTuDecl(ToSrcCode: Code, ToLang: Lang_CXX03);
4187 Decl *FromTu = getTuDecl(SrcCode: Code, Lang: Lang_CXX03, FileName: "from.cc");
4188
4189 auto *ToFriend1 = FirstDeclMatcher<FriendDecl>().match(D: ToTu, AMatcher: friendDecl());
4190 auto *ToFriend2 = LastDeclMatcher<FriendDecl>().match(D: ToTu, AMatcher: friendDecl());
4191 auto *FromFriend1 =
4192 FirstDeclMatcher<FriendDecl>().match(D: FromTu, AMatcher: friendDecl());
4193 auto *FromFriend2 =
4194 LastDeclMatcher<FriendDecl>().match(D: FromTu, AMatcher: friendDecl());
4195
4196 FriendDecl *ToImportedFriend1 = Import(FromFriend1, Lang_CXX03);
4197 FriendDecl *ToImportedFriend2 = Import(FromFriend2, Lang_CXX03);
4198
4199 EXPECT_NE(ToImportedFriend1, ToImportedFriend2);
4200 EXPECT_EQ(ToFriend1, ToImportedFriend1);
4201 EXPECT_EQ(ToFriend2, ToImportedFriend2);
4202 }
4203};
4204
4205TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
4206 Decl *FromTU = getTuDecl(
4207 SrcCode: R"(
4208 class A {
4209 template <int I> class F {};
4210 class X {
4211 template <int I> friend class F;
4212 };
4213 };
4214 )",
4215 Lang: Lang_CXX03, FileName: "input0.cc");
4216
4217 auto *FromClass = FirstDeclMatcher<CXXRecordDecl>().match(
4218 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "F"), isDefinition()));
4219 auto *FromFriendClass = LastDeclMatcher<CXXRecordDecl>().match(
4220 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "F")));
4221
4222 ASSERT_TRUE(FromClass);
4223 ASSERT_TRUE(FromFriendClass);
4224 ASSERT_NE(FromClass, FromFriendClass);
4225 ASSERT_EQ(FromFriendClass->getDefinition(), FromClass);
4226 ASSERT_EQ(FromFriendClass->getPreviousDecl(), FromClass);
4227 ASSERT_EQ(FromFriendClass->getDescribedClassTemplate()->getPreviousDecl(),
4228 FromClass->getDescribedClassTemplate());
4229
4230 auto *ToClass = cast<CXXRecordDecl>(Import(FromClass, Lang_CXX03));
4231 auto *ToFriendClass =
4232 cast<CXXRecordDecl>(Import(FromFriendClass, Lang_CXX03));
4233
4234 EXPECT_TRUE(ToClass);
4235 EXPECT_TRUE(ToFriendClass);
4236 EXPECT_NE(ToClass, ToFriendClass);
4237 EXPECT_EQ(ToFriendClass->getDefinition(), ToClass);
4238 EXPECT_EQ(ToFriendClass->getPreviousDecl(), ToClass);
4239 EXPECT_EQ(ToFriendClass->getDescribedClassTemplate()->getPreviousDecl(),
4240 ToClass->getDescribedClassTemplate());
4241}
4242
4243TEST_P(ImportFriendClasses, ImportOfRecursiveFriendClass) {
4244 Decl *FromTu = getTuDecl(
4245 SrcCode: R"(
4246 class declToImport {
4247 friend class declToImport;
4248 };
4249 )",
4250 Lang: Lang_CXX03, FileName: "input.cc");
4251
4252 auto *FromD = FirstDeclMatcher<CXXRecordDecl>().match(
4253 D: FromTu, AMatcher: cxxRecordDecl(hasName(Name: "declToImport")));
4254 auto *ToD = Import(FromD, Lang_CXX03);
4255 auto Pattern = cxxRecordDecl(has(friendDecl()));
4256 ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromD, Pattern));
4257 EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToD, Pattern));
4258}
4259
4260TEST_P(ImportFriendClasses, UndeclaredFriendClassShouldNotBeVisible) {
4261 Decl *FromTu =
4262 getTuDecl(SrcCode: "class X { friend class Y; };", Lang: Lang_CXX03, FileName: "from.cc");
4263 auto *FromX = FirstDeclMatcher<CXXRecordDecl>().match(
4264 D: FromTu, AMatcher: cxxRecordDecl(hasName(Name: "X")));
4265 auto *FromFriend = FirstDeclMatcher<FriendDecl>().match(D: FromTu, AMatcher: friendDecl());
4266 RecordDecl *FromRecordOfFriend =
4267 const_cast<RecordDecl *>(getRecordDeclOfFriend(FromFriend));
4268
4269 ASSERT_EQ(FromRecordOfFriend->getDeclContext(), cast<DeclContext>(FromTu));
4270 ASSERT_EQ(FromRecordOfFriend->getLexicalDeclContext(),
4271 cast<DeclContext>(FromX));
4272 ASSERT_FALSE(
4273 FromRecordOfFriend->getDeclContext()->containsDecl(FromRecordOfFriend));
4274 ASSERT_FALSE(FromRecordOfFriend->getLexicalDeclContext()->containsDecl(
4275 FromRecordOfFriend));
4276 ASSERT_FALSE(FromRecordOfFriend->getLookupParent()
4277 ->lookup(FromRecordOfFriend->getDeclName())
4278 .empty());
4279
4280 auto *ToX = Import(FromX, Lang_CXX03);
4281 ASSERT_TRUE(ToX);
4282
4283 Decl *ToTu = ToX->getTranslationUnitDecl();
4284 auto *ToFriend = FirstDeclMatcher<FriendDecl>().match(D: ToTu, AMatcher: friendDecl());
4285 RecordDecl *ToRecordOfFriend =
4286 const_cast<RecordDecl *>(getRecordDeclOfFriend(ToFriend));
4287
4288 ASSERT_EQ(ToRecordOfFriend->getDeclContext(), cast<DeclContext>(ToTu));
4289 ASSERT_EQ(ToRecordOfFriend->getLexicalDeclContext(), cast<DeclContext>(ToX));
4290 EXPECT_FALSE(
4291 ToRecordOfFriend->getDeclContext()->containsDecl(ToRecordOfFriend));
4292 EXPECT_FALSE(ToRecordOfFriend->getLexicalDeclContext()->containsDecl(
4293 ToRecordOfFriend));
4294 EXPECT_FALSE(ToRecordOfFriend->getLookupParent()
4295 ->lookup(ToRecordOfFriend->getDeclName())
4296 .empty());
4297}
4298
4299TEST_P(ImportFriendClasses, ImportOfRecursiveFriendClassTemplate) {
4300 Decl *FromTu = getTuDecl(
4301 SrcCode: R"(
4302 template<class A> class declToImport {
4303 template<class A1> friend class declToImport;
4304 };
4305 )",
4306 Lang: Lang_CXX03, FileName: "input.cc");
4307
4308 testRecursiveFriendClassTemplate(FromTu);
4309}
4310
4311TEST_P(ImportFriendClasses,
4312 ImportOfRecursiveFriendClassTemplateWithNonTypeParm) {
4313 Decl *FromTu = getTuDecl(
4314 SrcCode: R"(
4315 template<class A1, A1 A> class declToImport {
4316 template<class B1, B1> friend class declToImport;
4317 };
4318 )",
4319 Lang: Lang_CXX03, FileName: "input.cc");
4320 testRecursiveFriendClassTemplate(FromTu);
4321}
4322
4323TEST_P(ImportFriendClasses, ProperPrevDeclForClassTemplateDecls) {
4324 auto Pattern = classTemplateSpecializationDecl(hasName(Name: "X"));
4325
4326 ClassTemplateSpecializationDecl *Imported1;
4327 {
4328 Decl *FromTU = getTuDecl(SrcCode: "template<class T> class X;"
4329 "struct Y { friend class X<int>; };",
4330 Lang: Lang_CXX03, FileName: "input0.cc");
4331 auto *FromD = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
4332 D: FromTU, AMatcher: Pattern);
4333
4334 Imported1 =
4335 cast<ClassTemplateSpecializationDecl>(Import(FromD, Lang_CXX03));
4336 }
4337 ClassTemplateSpecializationDecl *Imported2;
4338 {
4339 Decl *FromTU = getTuDecl(SrcCode: "template<class T> class X;"
4340 "template<> class X<int>{};"
4341 "struct Z { friend class X<int>; };",
4342 Lang: Lang_CXX03, FileName: "input1.cc");
4343 auto *FromD = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
4344 D: FromTU, AMatcher: Pattern);
4345
4346 Imported2 =
4347 cast<ClassTemplateSpecializationDecl>(Import(FromD, Lang_CXX03));
4348 }
4349
4350 Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
4351 EXPECT_EQ(DeclCounter<ClassTemplateSpecializationDecl>().match(ToTU, Pattern),
4352 2u);
4353 ASSERT_TRUE(Imported2->getPreviousDecl());
4354 EXPECT_EQ(Imported2->getPreviousDecl(), Imported1);
4355}
4356
4357TEST_P(ImportFriendClasses, TypeForDeclShouldBeSetInTemplated) {
4358 Decl *FromTU0 = getTuDecl(
4359 SrcCode: R"(
4360 class X {
4361 class Y;
4362 };
4363 class X::Y {
4364 template <typename T>
4365 friend class F; // The decl context of F is the global namespace.
4366 };
4367 )",
4368 Lang: Lang_CXX03, FileName: "input0.cc");
4369 auto *Fwd = FirstDeclMatcher<ClassTemplateDecl>().match(
4370 D: FromTU0, AMatcher: classTemplateDecl(hasName(Name: "F")));
4371 auto *Imported0 = cast<ClassTemplateDecl>(Import(Fwd, Lang_CXX03));
4372 Decl *FromTU1 = getTuDecl(
4373 SrcCode: R"(
4374 template <typename T>
4375 class F {};
4376 )",
4377 Lang: Lang_CXX03, FileName: "input1.cc");
4378 auto *Definition = FirstDeclMatcher<ClassTemplateDecl>().match(
4379 D: FromTU1, AMatcher: classTemplateDecl(hasName(Name: "F")));
4380 auto *Imported1 = cast<ClassTemplateDecl>(Import(Definition, Lang_CXX03));
4381 EXPECT_EQ(Imported0->getTemplatedDecl()->getTypeForDecl(),
4382 Imported1->getTemplatedDecl()->getTypeForDecl());
4383}
4384
4385TEST_P(ImportFriendClasses, DeclsFromFriendsShouldBeInRedeclChains) {
4386 Decl *From, *To;
4387 std::tie(args&: From, args&: To) =
4388 getImportedDecl(FromSrcCode: "class declToImport {};", FromLang: Lang_CXX03,
4389 ToSrcCode: "class Y { friend class declToImport; };", ToLang: Lang_CXX03);
4390 auto *Imported = cast<CXXRecordDecl>(Val: To);
4391
4392 EXPECT_TRUE(Imported->getPreviousDecl());
4393}
4394
4395TEST_P(ImportFriendClasses, SkipComparingFriendTemplateDepth) {
4396 Decl *ToTU = getToTuDecl(
4397 ToSrcCode: R"(
4398 template <class T, T U>
4399 class A;
4400
4401 template <class T, T U>
4402 class A {
4403 public:
4404 template <class P, P Q>
4405 friend class A;
4406
4407 A(T x) :x(x) {}
4408
4409 private:
4410 T x;
4411 };
4412 )",
4413 ToLang: Lang_CXX11);
4414
4415 auto *Fwd = FirstDeclMatcher<ClassTemplateDecl>().match(
4416 D: ToTU,
4417 AMatcher: classTemplateDecl(has(cxxRecordDecl(hasDefinition(), hasName(Name: "A")))));
4418 Decl *FromTU = getTuDecl(
4419 SrcCode: R"(
4420 template <class T, T U>
4421 class A;
4422
4423 template <class T, T U>
4424 class A {
4425 public:
4426 template <class P, P Q>
4427 friend class A;
4428
4429 A(T x) : x(x) {}
4430
4431 private:
4432 T x;
4433 };
4434
4435 A<int,3> a1(0);
4436 )",
4437 Lang: Lang_CXX11, FileName: "input1.cc");
4438 auto *FromA = FirstDeclMatcher<ClassTemplateDecl>().match(
4439 D: FromTU,
4440 AMatcher: classTemplateDecl(has(cxxRecordDecl(hasDefinition(), hasName(Name: "A")))));
4441 auto *ToA = Import(FromA, Lang_CXX11);
4442 EXPECT_TRUE(ToA);
4443 EXPECT_EQ(Fwd->getTemplatedDecl()->getTypeForDecl(),
4444 ToA->getTemplatedDecl()->getTypeForDecl());
4445}
4446
4447TEST_P(ImportFriendClasses,
4448 ImportOfClassTemplateDefinitionShouldConnectToFwdFriend) {
4449 Decl *ToTU = getToTuDecl(
4450 ToSrcCode: R"(
4451 class X {
4452 class Y;
4453 };
4454 class X::Y {
4455 template <typename T>
4456 friend class F; // The decl context of F is the global namespace.
4457 };
4458 )",
4459 ToLang: Lang_CXX03);
4460 auto *ToDecl = FirstDeclMatcher<ClassTemplateDecl>().match(
4461 D: ToTU, AMatcher: classTemplateDecl(hasName(Name: "F")));
4462 Decl *FromTU = getTuDecl(
4463 SrcCode: R"(
4464 template <typename T>
4465 class F {};
4466 )",
4467 Lang: Lang_CXX03, FileName: "input0.cc");
4468 auto *Definition = FirstDeclMatcher<ClassTemplateDecl>().match(
4469 D: FromTU, AMatcher: classTemplateDecl(hasName(Name: "F")));
4470 auto *ImportedDef = cast<ClassTemplateDecl>(Import(Definition, Lang_CXX03));
4471 EXPECT_TRUE(ImportedDef->getPreviousDecl());
4472 EXPECT_EQ(ToDecl, ImportedDef->getPreviousDecl());
4473 EXPECT_EQ(ToDecl->getTemplatedDecl(),
4474 ImportedDef->getTemplatedDecl()->getPreviousDecl());
4475}
4476
4477TEST_P(ImportFriendClasses,
4478 ImportOfClassTemplateDefinitionAndFwdFriendShouldBeLinked) {
4479 Decl *FromTU0 = getTuDecl(
4480 SrcCode: R"(
4481 class X {
4482 class Y;
4483 };
4484 class X::Y {
4485 template <typename T>
4486 friend class F; // The decl context of F is the global namespace.
4487 };
4488 )",
4489 Lang: Lang_CXX03, FileName: "input0.cc");
4490 auto *Fwd = FirstDeclMatcher<ClassTemplateDecl>().match(
4491 D: FromTU0, AMatcher: classTemplateDecl(hasName(Name: "F")));
4492 auto *ImportedFwd = cast<ClassTemplateDecl>(Import(Fwd, Lang_CXX03));
4493 Decl *FromTU1 = getTuDecl(
4494 SrcCode: R"(
4495 template <typename T>
4496 class F {};
4497 )",
4498 Lang: Lang_CXX03, FileName: "input1.cc");
4499 auto *Definition = FirstDeclMatcher<ClassTemplateDecl>().match(
4500 D: FromTU1, AMatcher: classTemplateDecl(hasName(Name: "F")));
4501 auto *ImportedDef = cast<ClassTemplateDecl>(Import(Definition, Lang_CXX03));
4502 EXPECT_TRUE(ImportedDef->getPreviousDecl());
4503 EXPECT_EQ(ImportedFwd, ImportedDef->getPreviousDecl());
4504 EXPECT_EQ(ImportedFwd->getTemplatedDecl(),
4505 ImportedDef->getTemplatedDecl()->getPreviousDecl());
4506}
4507
4508TEST_P(ImportFriendClasses, ImportOfClassDefinitionAndFwdFriendShouldBeLinked) {
4509 Decl *FromTU0 = getTuDecl(
4510 SrcCode: R"(
4511 class X {
4512 class Y;
4513 };
4514 class X::Y {
4515 friend class F; // The decl context of F is the global namespace.
4516 };
4517 )",
4518 Lang: Lang_CXX03, FileName: "input0.cc");
4519 auto *Friend = FirstDeclMatcher<FriendDecl>().match(D: FromTU0, AMatcher: friendDecl());
4520 QualType FT = Friend->getFriendType()->getType();
4521 FT = FromTU0->getASTContext().getCanonicalType(T: FT);
4522 auto *Fwd = cast<TagType>(Val&: FT)->getDecl();
4523 auto *ImportedFwd = Import(Fwd, Lang_CXX03);
4524 Decl *FromTU1 = getTuDecl(
4525 SrcCode: R"(
4526 class F {};
4527 )",
4528 Lang: Lang_CXX03, FileName: "input1.cc");
4529 auto *Definition = FirstDeclMatcher<CXXRecordDecl>().match(
4530 D: FromTU1, AMatcher: cxxRecordDecl(hasName(Name: "F")));
4531 auto *ImportedDef = Import(Definition, Lang_CXX03);
4532 EXPECT_TRUE(ImportedDef->getPreviousDecl());
4533 EXPECT_EQ(ImportedFwd, ImportedDef->getPreviousDecl());
4534}
4535
4536TEST_P(ImportFriendClasses,
4537 ImportFriendTemplatesInDependentContext_DefToFriend) {
4538 Decl *ToTU = getToTuDecl(
4539 ToSrcCode: R"(
4540 template<class T1>
4541 struct X {
4542 template<class T2>
4543 friend struct Y;
4544 };
4545 )",
4546 ToLang: Lang_CXX03);
4547 auto *ToYFriend = FirstDeclMatcher<ClassTemplateDecl>().match(
4548 D: ToTU, AMatcher: classTemplateDecl(hasName(Name: "Y")));
4549 Decl *FromTU = getTuDecl(
4550 SrcCode: R"(
4551 template<class T1>
4552 struct Y {};
4553 )",
4554 Lang: Lang_CXX03, FileName: "input0.cc");
4555 auto *FromYDef = FirstDeclMatcher<ClassTemplateDecl>().match(
4556 D: FromTU, AMatcher: classTemplateDecl(hasName(Name: "Y")));
4557 auto *ImportedYDef = Import(FromYDef, Lang_CXX03);
4558 EXPECT_TRUE(ImportedYDef);
4559 EXPECT_FALSE(ImportedYDef->getPreviousDecl());
4560 EXPECT_NE(ImportedYDef, ToYFriend);
4561}
4562
4563TEST_P(ImportFriendClasses,
4564 ImportFriendTemplatesInDependentContext_DefToFriend_NE) {
4565 getToTuDecl(
4566 ToSrcCode: R"(
4567 template<class T1>
4568 struct X {
4569 template<class T2>
4570 friend struct Y;
4571 };
4572 )",
4573 ToLang: Lang_CXX03);
4574 Decl *FromTU = getTuDecl(
4575 SrcCode: R"(
4576 template<class T1, class T2>
4577 struct Y {};
4578 )",
4579 Lang: Lang_CXX03, FileName: "input0.cc");
4580 auto *FromYDef = FirstDeclMatcher<ClassTemplateDecl>().match(
4581 D: FromTU, AMatcher: classTemplateDecl(hasName(Name: "Y")));
4582 auto *ImportedYDef = Import(FromYDef, Lang_CXX03);
4583 EXPECT_FALSE(ImportedYDef);
4584}
4585
4586TEST_P(ImportFriendClasses,
4587 ImportFriendTemplatesInDependentContext_FriendToFriend) {
4588 Decl *ToTU = getToTuDecl(
4589 ToSrcCode: R"(
4590 template<class T1>
4591 struct X {
4592 template<class T2>
4593 friend struct Y;
4594 };
4595 )",
4596 ToLang: Lang_CXX03);
4597 auto *ToYFriend = FirstDeclMatcher<ClassTemplateDecl>().match(
4598 D: ToTU, AMatcher: classTemplateDecl(hasName(Name: "Y")));
4599 Decl *FromTU = getTuDecl(
4600 SrcCode: R"(
4601 template<class T1>
4602 struct X {
4603 template<class T2>
4604 friend struct Y;
4605 };
4606 )",
4607 Lang: Lang_CXX03, FileName: "input0.cc");
4608 auto *FromYFriend = FirstDeclMatcher<ClassTemplateDecl>().match(
4609 D: FromTU, AMatcher: classTemplateDecl(hasName(Name: "Y")));
4610 auto *ImportedYFriend = Import(FromYFriend, Lang_CXX03);
4611 EXPECT_TRUE(ImportedYFriend);
4612 EXPECT_FALSE(ImportedYFriend->getPreviousDecl());
4613 EXPECT_NE(ImportedYFriend, ToYFriend);
4614}
4615
4616TEST_P(ImportFriendClasses,
4617 ImportFriendTemplatesInDependentContext_FriendToFriend_NE) {
4618 getToTuDecl(
4619 ToSrcCode: R"(
4620 template<class T1>
4621 struct X {
4622 template<class T2>
4623 friend struct Y;
4624 };
4625 )",
4626 ToLang: Lang_CXX03);
4627 Decl *FromTU = getTuDecl(
4628 SrcCode: R"(
4629 template<class T1>
4630 struct X {
4631 template<class T2, class T3>
4632 friend struct Y;
4633 };
4634 )",
4635 Lang: Lang_CXX03, FileName: "input0.cc");
4636 auto *FromYFriend = FirstDeclMatcher<ClassTemplateDecl>().match(
4637 D: FromTU, AMatcher: classTemplateDecl(hasName(Name: "Y")));
4638 auto *ImportedYFriend = Import(FromYFriend, Lang_CXX03);
4639 EXPECT_FALSE(ImportedYFriend);
4640}
4641
4642TEST_P(ImportFriendClasses,
4643 ImportFriendTemplatesInDependentContext_FriendToDef) {
4644 Decl *ToTU = getToTuDecl(
4645 ToSrcCode: R"(
4646 template<class T1>
4647 struct Y {};
4648 )",
4649 ToLang: Lang_CXX03);
4650 auto *ToYDef = FirstDeclMatcher<ClassTemplateDecl>().match(
4651 D: ToTU, AMatcher: classTemplateDecl(hasName(Name: "Y")));
4652 Decl *FromTU = getTuDecl(
4653 SrcCode: R"(
4654 template<class T1>
4655 struct X {
4656 template<class T2>
4657 friend struct Y;
4658 };
4659 )",
4660 Lang: Lang_CXX03, FileName: "input0.cc");
4661 auto *FromYFriend = FirstDeclMatcher<ClassTemplateDecl>().match(
4662 D: FromTU, AMatcher: classTemplateDecl(hasName(Name: "Y")));
4663 auto *ImportedYFriend = Import(FromYFriend, Lang_CXX03);
4664 EXPECT_TRUE(ImportedYFriend);
4665 EXPECT_FALSE(ImportedYFriend->getPreviousDecl());
4666 EXPECT_NE(ImportedYFriend, ToYDef);
4667}
4668
4669TEST_P(ImportFriendClasses,
4670 ImportFriendTemplatesInDependentContext_FriendToDef_NE) {
4671 getToTuDecl(
4672 ToSrcCode: R"(
4673 template<class T1>
4674 struct Y {};
4675 )",
4676 ToLang: Lang_CXX03);
4677 Decl *FromTU = getTuDecl(
4678 SrcCode: R"(
4679 template<class T1>
4680 struct X {
4681 template<class T2, class T3>
4682 friend struct Y;
4683 };
4684 )",
4685 Lang: Lang_CXX03, FileName: "input0.cc");
4686 auto *FromYFriend = FirstDeclMatcher<ClassTemplateDecl>().match(
4687 D: FromTU, AMatcher: classTemplateDecl(hasName(Name: "Y")));
4688 auto *ImportedYFriend = Import(FromYFriend, Lang_CXX03);
4689 EXPECT_FALSE(ImportedYFriend);
4690}
4691
4692TEST_P(ImportFriendClasses, ImportOfRepeatedFriendType) {
4693 const char *Code =
4694 R"(
4695 class Container {
4696 friend class X;
4697 friend class X;
4698 };
4699 )";
4700 testRepeatedFriendImport(Code);
4701}
4702
4703TEST_P(ImportFriendClasses, ImportOfRepeatedFriendDecl) {
4704 const char *Code =
4705 R"(
4706 class Container {
4707 friend void f();
4708 friend void f();
4709 };
4710 )";
4711 testRepeatedFriendImport(Code);
4712}
4713
4714TEST_P(ImportFriendClasses, ImportOfRepeatedFriendFunctionTemplateDecl) {
4715 const char *Code =
4716 R"(
4717 template <class T>
4718 class Container {
4719 template <class U> friend void m();
4720 template <class U> friend void m();
4721 };
4722 )";
4723 testRepeatedFriendImport(Code);
4724}
4725
4726TEST_P(ImportFriendClasses, ImportOfRepeatedFriendClassTemplateDecl) {
4727 const char *Code =
4728 R"(
4729 template <class T>
4730 class Container {
4731 template <class U> friend class X;
4732 template <class U> friend class X;
4733 };
4734 )";
4735 testRepeatedFriendImport(Code);
4736}
4737
4738TEST_P(ASTImporterOptionSpecificTestBase, FriendFunInClassTemplate) {
4739 auto *Code = R"(
4740 template <class T>
4741 struct X {
4742 friend void foo(){}
4743 };
4744 )";
4745 TranslationUnitDecl *ToTU = getToTuDecl(ToSrcCode: Code, ToLang: Lang_CXX03);
4746 auto *ToFoo = FirstDeclMatcher<FunctionDecl>().match(
4747 ToTU, functionDecl(hasName(Name: "foo")));
4748
4749 TranslationUnitDecl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX03, FileName: "input.cc");
4750 auto *FromFoo = FirstDeclMatcher<FunctionDecl>().match(
4751 FromTU, functionDecl(hasName(Name: "foo")));
4752 auto *ImportedFoo = Import(FromFoo, Lang_CXX03);
4753 EXPECT_EQ(ImportedFoo, ToFoo);
4754}
4755
4756struct DeclContextTest : ASTImporterOptionSpecificTestBase {};
4757
4758TEST_P(DeclContextTest, removeDeclOfClassTemplateSpecialization) {
4759 Decl *TU = getTuDecl(
4760 SrcCode: R"(
4761 namespace NS {
4762
4763 template <typename T>
4764 struct S {};
4765 template struct S<int>;
4766
4767 inline namespace INS {
4768 template <typename T>
4769 struct S {};
4770 template struct S<int>;
4771 }
4772
4773 }
4774 )", Lang: Lang_CXX11, FileName: "input0.cc");
4775 auto *NS = FirstDeclMatcher<NamespaceDecl>().match(
4776 D: TU, AMatcher: namespaceDecl());
4777 auto *Spec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
4778 D: TU, AMatcher: classTemplateSpecializationDecl());
4779 ASSERT_TRUE(NS->containsDecl(Spec));
4780
4781 NS->removeDecl(Spec);
4782 EXPECT_FALSE(NS->containsDecl(Spec));
4783}
4784
4785TEST_P(DeclContextTest,
4786 removeDeclShouldNotFailEvenIfWeHaveExternalVisibleStorage) {
4787 Decl *TU = getTuDecl(SrcCode: "extern int A; int A;", Lang: Lang_CXX03);
4788 auto *A0 = FirstDeclMatcher<VarDecl>().match(D: TU, AMatcher: varDecl(hasName(Name: "A")));
4789 auto *A1 = LastDeclMatcher<VarDecl>().match(D: TU, AMatcher: varDecl(hasName(Name: "A")));
4790
4791 // Investigate the list.
4792 auto *DC = A0->getDeclContext();
4793 ASSERT_TRUE(DC->containsDecl(A0));
4794 ASSERT_TRUE(DC->containsDecl(A1));
4795
4796 // Investigate the lookup table.
4797 auto *Map = DC->getLookupPtr();
4798 ASSERT_TRUE(Map);
4799 auto I = Map->find(A0->getDeclName());
4800 ASSERT_NE(I, Map->end());
4801 StoredDeclsList &L = I->second;
4802 // The lookup table contains the most recent decl of A.
4803 ASSERT_NE(L.getAsDecl(), A0);
4804 ASSERT_EQ(L.getAsDecl(), A1);
4805
4806 ASSERT_TRUE(L.getAsDecl());
4807 // Simulate the private function DeclContext::reconcileExternalVisibleStorage.
4808 // We do not have a list with one element.
4809 L.setHasExternalDecls();
4810 ASSERT_FALSE(L.getAsList());
4811 auto Results = L.getLookupResult();
4812 ASSERT_EQ(1u, std::distance(Results.begin(), Results.end()));
4813
4814 // This asserts in the old implementation.
4815 DC->removeDecl(A0);
4816 EXPECT_FALSE(DC->containsDecl(A0));
4817
4818 // Make sure we do not leave a StoredDeclsList with no entries.
4819 DC->removeDecl(A1);
4820 ASSERT_EQ(Map->find(A1->getDeclName()), Map->end());
4821}
4822
4823struct ImportFunctionTemplateSpecializations
4824 : ASTImporterOptionSpecificTestBase {};
4825
4826TEST_P(ImportFunctionTemplateSpecializations,
4827 TUshouldNotContainFunctionTemplateImplicitInstantiation) {
4828
4829 Decl *FromTU = getTuDecl(
4830 SrcCode: R"(
4831 template<class T>
4832 int f() { return 0; }
4833 void foo() { f<int>(); }
4834 )",
4835 Lang: Lang_CXX03, FileName: "input0.cc");
4836
4837 // Check that the function template instantiation is NOT the child of the TU.
4838 auto Pattern = translationUnitDecl(
4839 unless(has(functionDecl(hasName(Name: "f"), isTemplateInstantiation()))));
4840 ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromTU, Pattern));
4841
4842 auto *Foo = FirstDeclMatcher<FunctionDecl>().match(
4843 D: FromTU, AMatcher: functionDecl(hasName(Name: "foo")));
4844 ASSERT_TRUE(Import(Foo, Lang_CXX03));
4845
4846 auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
4847 EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToTU, Pattern));
4848}
4849
4850TEST_P(ImportFunctionTemplateSpecializations,
4851 TUshouldNotContainFunctionTemplateExplicitInstantiation) {
4852
4853 Decl *FromTU = getTuDecl(
4854 SrcCode: R"(
4855 template<class T>
4856 int f() { return 0; }
4857 template int f<int>();
4858 )",
4859 Lang: Lang_CXX03, FileName: "input0.cc");
4860
4861 // Check that the function template instantiation is NOT the child of the TU.
4862 auto Instantiation = functionDecl(hasName(Name: "f"), isTemplateInstantiation());
4863 auto Pattern = translationUnitDecl(unless(has(Instantiation)));
4864 ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromTU, Pattern));
4865
4866 ASSERT_TRUE(Import(FirstDeclMatcher<Decl>().match(FromTU, Instantiation),
4867 Lang_CXX03));
4868
4869 auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
4870 EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToTU, Pattern));
4871}
4872
4873TEST_P(ImportFunctionTemplateSpecializations,
4874 TUshouldContainFunctionTemplateSpecialization) {
4875
4876 Decl *FromTU = getTuDecl(
4877 SrcCode: R"(
4878 template<class T>
4879 int f() { return 0; }
4880 template <> int f<int>() { return 4; }
4881 )",
4882 Lang: Lang_CXX03, FileName: "input0.cc");
4883
4884 // Check that the function template specialization is the child of the TU.
4885 auto Specialization =
4886 functionDecl(hasName(Name: "f"), isExplicitTemplateSpecialization());
4887 auto Pattern = translationUnitDecl(has(Specialization));
4888 ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromTU, Pattern));
4889
4890 ASSERT_TRUE(Import(FirstDeclMatcher<Decl>().match(FromTU, Specialization),
4891 Lang_CXX03));
4892
4893 auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
4894 EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToTU, Pattern));
4895}
4896
4897TEST_P(ImportFunctionTemplateSpecializations,
4898 FunctionTemplateSpecializationRedeclChain) {
4899
4900 Decl *FromTU = getTuDecl(
4901 SrcCode: R"(
4902 template<class T>
4903 int f() { return 0; }
4904 template <> int f<int>() { return 4; }
4905 )",
4906 Lang: Lang_CXX03, FileName: "input0.cc");
4907
4908 auto Spec = functionDecl(hasName(Name: "f"), isExplicitTemplateSpecialization(),
4909 hasParent(translationUnitDecl()));
4910 auto *FromSpecD = FirstDeclMatcher<Decl>().match(D: FromTU, AMatcher: Spec);
4911 {
4912 auto *TU = FromTU;
4913 auto *SpecD = FromSpecD;
4914 auto *TemplateD = FirstDeclMatcher<FunctionTemplateDecl>().match(
4915 TU, functionTemplateDecl());
4916 auto *FirstSpecD = *(TemplateD->spec_begin());
4917 ASSERT_EQ(SpecD, FirstSpecD);
4918 ASSERT_TRUE(SpecD->getPreviousDecl());
4919 ASSERT_FALSE(cast<FunctionDecl>(SpecD->getPreviousDecl())
4920 ->doesThisDeclarationHaveABody());
4921 }
4922
4923 ASSERT_TRUE(Import(FromSpecD, Lang_CXX03));
4924
4925 {
4926 auto *TU = ToAST->getASTContext().getTranslationUnitDecl();
4927 auto *SpecD = FirstDeclMatcher<Decl>().match(TU, Spec);
4928 auto *TemplateD = FirstDeclMatcher<FunctionTemplateDecl>().match(
4929 TU, functionTemplateDecl());
4930 auto *FirstSpecD = *(TemplateD->spec_begin());
4931 EXPECT_EQ(SpecD, FirstSpecD);
4932 ASSERT_TRUE(SpecD->getPreviousDecl());
4933 EXPECT_FALSE(cast<FunctionDecl>(SpecD->getPreviousDecl())
4934 ->doesThisDeclarationHaveABody());
4935 }
4936}
4937
4938TEST_P(ImportFunctionTemplateSpecializations,
4939 MatchNumberOfFunctionTemplateSpecializations) {
4940
4941 Decl *FromTU = getTuDecl(
4942 SrcCode: R"(
4943 template <typename T> constexpr int f() { return 0; }
4944 template <> constexpr int f<int>() { return 4; }
4945 void foo() {
4946 static_assert(f<char>() == 0, "");
4947 static_assert(f<int>() == 4, "");
4948 }
4949 )",
4950 Lang: Lang_CXX11, FileName: "input0.cc");
4951 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
4952 D: FromTU, AMatcher: functionDecl(hasName(Name: "foo")));
4953
4954 Import(FromD, Lang_CXX11);
4955 auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
4956 EXPECT_EQ(
4957 DeclCounter<FunctionDecl>().match(FromTU, functionDecl(hasName("f"))),
4958 DeclCounter<FunctionDecl>().match(ToTU, functionDecl(hasName("f"))));
4959}
4960
4961TEST_P(ASTImporterOptionSpecificTestBase,
4962 ImportShouldNotReportFalseODRErrorWhenRecordIsBeingDefined) {
4963 {
4964 Decl *FromTU = getTuDecl(
4965 SrcCode: R"(
4966 template <typename T>
4967 struct B;
4968 )",
4969 Lang: Lang_CXX03, FileName: "input0.cc");
4970 auto *FromD = FirstDeclMatcher<ClassTemplateDecl>().match(
4971 D: FromTU, AMatcher: classTemplateDecl(hasName(Name: "B")));
4972
4973 Import(FromD, Lang_CXX03);
4974 }
4975
4976 {
4977 Decl *FromTU = getTuDecl(
4978 SrcCode: R"(
4979 template <typename T>
4980 struct B {
4981 void f();
4982 B* b;
4983 };
4984 )",
4985 Lang: Lang_CXX03, FileName: "input1.cc");
4986 FunctionDecl *FromD = FirstDeclMatcher<FunctionDecl>().match(
4987 D: FromTU, AMatcher: functionDecl(hasName(Name: "f")));
4988 Import(From: FromD, Lang: Lang_CXX03);
4989 auto *FromCTD = FirstDeclMatcher<ClassTemplateDecl>().match(
4990 D: FromTU, AMatcher: classTemplateDecl(hasName(Name: "B")));
4991 auto *ToCTD = cast<ClassTemplateDecl>(Import(FromCTD, Lang_CXX03));
4992 EXPECT_TRUE(ToCTD->isThisDeclarationADefinition());
4993
4994 // We expect no (ODR) warning during the import.
4995 auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
4996 EXPECT_EQ(0u, ToTU->getASTContext().getDiagnostics().getNumWarnings());
4997 }
4998}
4999
5000TEST_P(ASTImporterOptionSpecificTestBase,
5001 ImportingTypedefShouldImportTheCompleteType) {
5002 // We already have an incomplete underlying type in the "To" context.
5003 auto Code =
5004 R"(
5005 template <typename T>
5006 struct S {
5007 void foo();
5008 };
5009 using U = S<int>;
5010 )";
5011 Decl *ToTU = getToTuDecl(ToSrcCode: Code, ToLang: Lang_CXX11);
5012 auto *ToD = FirstDeclMatcher<TypedefNameDecl>().match(D: ToTU,
5013 AMatcher: typedefNameDecl(hasName(Name: "U")));
5014 ASSERT_TRUE(ToD->getUnderlyingType()->isIncompleteType());
5015
5016 // The "From" context has the same typedef, but the underlying type is
5017 // complete this time.
5018 Decl *FromTU = getTuDecl(SrcCode: std::string(Code) +
5019 R"(
5020 void foo(U* u) {
5021 u->foo();
5022 }
5023 )", Lang: Lang_CXX11);
5024 auto *FromD = FirstDeclMatcher<TypedefNameDecl>().match(D: FromTU,
5025 AMatcher: typedefNameDecl(hasName(Name: "U")));
5026 ASSERT_FALSE(FromD->getUnderlyingType()->isIncompleteType());
5027
5028 // The imported type should be complete.
5029 auto *ImportedD = cast<TypedefNameDecl>(Import(FromD, Lang_CXX11));
5030 EXPECT_FALSE(ImportedD->getUnderlyingType()->isIncompleteType());
5031}
5032
5033TEST_P(ASTImporterOptionSpecificTestBase, ImportTemplateParameterLists) {
5034 auto Code =
5035 R"(
5036 template<class T>
5037 int f() { return 0; }
5038 template <> int f<int>() { return 4; }
5039 )";
5040
5041 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX03);
5042 auto *FromD = FirstDeclMatcher<FunctionDecl>().match(D: FromTU,
5043 AMatcher: functionDecl(hasName(Name: "f"), isExplicitTemplateSpecialization()));
5044 ASSERT_EQ(FromD->getNumTemplateParameterLists(), 1u);
5045
5046 auto *ToD = Import(FromD, Lang_CXX03);
5047 // The template parameter list should exist.
5048 EXPECT_EQ(ToD->getNumTemplateParameterLists(), 1u);
5049}
5050
5051const internal::VariadicDynCastAllOfMatcher<Decl, VarTemplateDecl>
5052 varTemplateDecl;
5053
5054const internal::VariadicDynCastAllOfMatcher<
5055 Decl, VarTemplatePartialSpecializationDecl>
5056 varTemplatePartialSpecializationDecl;
5057
5058TEST_P(ASTImporterOptionSpecificTestBase,
5059 FunctionTemplateParameterDeclContext) {
5060 constexpr auto Code =
5061 R"(
5062 template<class T>
5063 void f() {};
5064 )";
5065
5066 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11);
5067
5068 auto *FromD = FirstDeclMatcher<FunctionTemplateDecl>().match(
5069 D: FromTU, AMatcher: functionTemplateDecl(hasName(Name: "f")));
5070
5071 ASSERT_EQ(FromD->getTemplateParameters()->getParam(0)->getDeclContext(),
5072 FromD->getTemplatedDecl());
5073
5074 auto *ToD = Import(FromD, Lang_CXX11);
5075 EXPECT_EQ(ToD->getTemplateParameters()->getParam(0)->getDeclContext(),
5076 ToD->getTemplatedDecl());
5077 EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains(
5078 ToD->getTemplatedDecl(), ToD->getTemplateParameters()->getParam(0)));
5079}
5080
5081TEST_P(ASTImporterOptionSpecificTestBase, ClassTemplateParameterDeclContext) {
5082 constexpr auto Code =
5083 R"(
5084 template<class T1, class T2>
5085 struct S {};
5086 template<class T2>
5087 struct S<int, T2> {};
5088 )";
5089
5090 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11);
5091
5092 auto *FromD = FirstDeclMatcher<ClassTemplateDecl>().match(
5093 D: FromTU, AMatcher: classTemplateDecl(hasName(Name: "S")));
5094 auto *FromDPart =
5095 FirstDeclMatcher<ClassTemplatePartialSpecializationDecl>().match(
5096 D: FromTU, AMatcher: classTemplatePartialSpecializationDecl(hasName(Name: "S")));
5097
5098 ASSERT_EQ(FromD->getTemplateParameters()->getParam(0)->getDeclContext(),
5099 FromD->getTemplatedDecl());
5100 ASSERT_EQ(FromDPart->getTemplateParameters()->getParam(0)->getDeclContext(),
5101 FromDPart);
5102
5103 auto *ToD = Import(FromD, Lang_CXX11);
5104 auto *ToDPart = Import(FromDPart, Lang_CXX11);
5105
5106 EXPECT_EQ(ToD->getTemplateParameters()->getParam(0)->getDeclContext(),
5107 ToD->getTemplatedDecl());
5108 EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains(
5109 ToD->getTemplatedDecl(), ToD->getTemplateParameters()->getParam(0)));
5110
5111 EXPECT_EQ(ToDPart->getTemplateParameters()->getParam(0)->getDeclContext(),
5112 ToDPart);
5113 EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains(
5114 ToDPart, ToDPart->getTemplateParameters()->getParam(0)));
5115}
5116
5117TEST_P(ASTImporterOptionSpecificTestBase,
5118 CXXDeductionGuideTemplateParameterDeclContext) {
5119 Decl *FromTU = getTuDecl(
5120 SrcCode: R"(
5121 template <typename T> struct A {
5122 A(T);
5123 };
5124 A a{(int)0};
5125 )",
5126 Lang: Lang_CXX17, FileName: "input.cc");
5127// clang-format off
5128/*
5129|-ClassTemplateDecl 0x1fe5000 <input.cc:2:7, line:4:7> line:2:36 A
5130| |-TemplateTypeParmDecl 0x1fe4eb0 <col:17, col:26> col:26 referenced typename depth 0 index 0 T
5131| |-CXXRecordDecl 0x1fe4f70 <col:29, line:4:7> line:2:36 struct A definition
5132
5133|-FunctionTemplateDecl 0x1fe5860 <line:2:7, line:3:12> col:9 implicit <deduction guide for A>
5134| |-TemplateTypeParmDecl 0x1fe4eb0 <line:2:17, col:26> col:26 referenced typename depth 0 index 0 T
5135| |-CXXDeductionGuideDecl 0x1fe57a8 <line:3:9, col:12> col:9 implicit <deduction guide for A> 'auto (T) -> A<T>'
5136| | `-ParmVarDecl 0x1fe56b0 <col:11> col:12 'T'
5137| `-CXXDeductionGuideDecl 0x20515d8 <col:9, col:12> col:9 implicit used <deduction guide for A> 'auto (int) -> A<int>'
5138| |-TemplateArgument type 'int'
5139| | `-BuiltinType 0x20587e0 'int'
5140| `-ParmVarDecl 0x2051388 <col:11> col:12 'int'
5141`-FunctionTemplateDecl 0x1fe5a78 <line:2:7, col:36> col:36 implicit <deduction guide for A>
5142 |-TemplateTypeParmDecl 0x1fe4eb0 <col:17, col:26> col:26 referenced typename depth 0 index 0 T
5143 `-CXXDeductionGuideDecl 0x1fe59c0 <col:36> col:36 implicit <deduction guide for A> 'auto (A<T>) -> A<T>'
5144 `-ParmVarDecl 0x1fe5958 <col:36> col:36 'A<T>'
5145*/
5146// clang-format on
5147 auto *FromD1 = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
5148 D: FromTU, AMatcher: cxxDeductionGuideDecl());
5149 auto *FromD2 = LastDeclMatcher<CXXDeductionGuideDecl>().match(
5150 D: FromTU, AMatcher: cxxDeductionGuideDecl());
5151
5152 NamedDecl *P1 =
5153 FromD1->getDescribedFunctionTemplate()->getTemplateParameters()->getParam(
5154 0);
5155 NamedDecl *P2 =
5156 FromD2->getDescribedFunctionTemplate()->getTemplateParameters()->getParam(
5157 0);
5158 DeclContext *DC = P1->getDeclContext();
5159
5160 ASSERT_EQ(P1, P2);
5161 ASSERT_TRUE(DC == FromD1 || DC == FromD2);
5162
5163 auto *ToD1 = Import(FromD1, Lang_CXX17);
5164 auto *ToD2 = Import(FromD2, Lang_CXX17);
5165 ASSERT_TRUE(ToD1 && ToD2);
5166
5167 P1 = ToD1->getDescribedFunctionTemplate()->getTemplateParameters()->getParam(
5168 0);
5169 P2 = ToD2->getDescribedFunctionTemplate()->getTemplateParameters()->getParam(
5170 0);
5171 DC = P1->getDeclContext();
5172
5173 EXPECT_EQ(P1, P2);
5174 EXPECT_TRUE(DC == ToD1 || DC == ToD2);
5175
5176 ASTImporterLookupTable *Tbl = SharedStatePtr->getLookupTable();
5177 if (Tbl->contains(DC: ToD1, ND: P1)) {
5178 EXPECT_FALSE(Tbl->contains(ToD2, P1));
5179 } else {
5180 EXPECT_TRUE(Tbl->contains(ToD2, P1));
5181 }
5182}
5183
5184TEST_P(ASTImporterOptionSpecificTestBase, RecordVarTemplateDecl) {
5185 Decl *ToTU = getToTuDecl(
5186 ToSrcCode: R"(
5187 template <class T>
5188 class A {
5189 public:
5190 template <class U>
5191 static constexpr bool X = true;
5192 };
5193 )",
5194 ToLang: Lang_CXX14);
5195
5196 auto *ToTUX = FirstDeclMatcher<VarTemplateDecl>().match(
5197 D: ToTU, AMatcher: varTemplateDecl(hasName(Name: "X")));
5198 Decl *FromTU = getTuDecl(
5199 SrcCode: R"(
5200 template <class T>
5201 class A {
5202 public:
5203 template <class U>
5204 static constexpr bool X = true;
5205 };
5206 )",
5207 Lang: Lang_CXX14, FileName: "input1.cc");
5208 auto *FromX = FirstDeclMatcher<VarTemplateDecl>().match(
5209 D: FromTU, AMatcher: varTemplateDecl(hasName(Name: "X")));
5210 auto *ToX = Import(FromX, Lang_CXX11);
5211 EXPECT_TRUE(ToX);
5212 EXPECT_EQ(ToTUX, ToX);
5213}
5214
5215TEST_P(ASTImporterOptionSpecificTestBase, VarTemplateDeclConflict) {
5216 getToTuDecl(
5217 ToSrcCode: R"(
5218 template <class U>
5219 constexpr int X = 1;
5220 )",
5221 ToLang: Lang_CXX14);
5222
5223 Decl *FromTU = getTuDecl(
5224 SrcCode: R"(
5225 template <class U>
5226 constexpr int X = 2;
5227 )",
5228 Lang: Lang_CXX14, FileName: "input1.cc");
5229 auto *FromX = FirstDeclMatcher<VarTemplateDecl>().match(
5230 D: FromTU, AMatcher: varTemplateDecl(hasName(Name: "X")));
5231 auto *ToX = Import(FromX, Lang_CXX11);
5232 // FIXME: This import should fail.
5233 EXPECT_TRUE(ToX);
5234}
5235
5236TEST_P(ASTImporterOptionSpecificTestBase, VarTemplateStaticDefinition) {
5237 Decl *ToTU = getToTuDecl(
5238 ToSrcCode: R"(
5239 struct A {
5240 template <class U>
5241 static int X;
5242 };
5243 )",
5244 ToLang: Lang_CXX14);
5245 auto *ToX = FirstDeclMatcher<VarTemplateDecl>().match(
5246 D: ToTU, AMatcher: varTemplateDecl(hasName(Name: "X")));
5247 ASSERT_FALSE(ToX->isThisDeclarationADefinition());
5248
5249 Decl *FromTU = getTuDecl(
5250 SrcCode: R"(
5251 struct A {
5252 template <class U>
5253 static int X;
5254 };
5255 template <class U>
5256 int A::X = 2;
5257 )",
5258 Lang: Lang_CXX14, FileName: "input1.cc");
5259 auto *FromXDef = LastDeclMatcher<VarTemplateDecl>().match(
5260 D: FromTU, AMatcher: varTemplateDecl(hasName(Name: "X")));
5261 ASSERT_TRUE(FromXDef->isThisDeclarationADefinition());
5262 auto *ToXDef = Import(FromXDef, Lang_CXX14);
5263 EXPECT_TRUE(ToXDef);
5264 EXPECT_TRUE(ToXDef->isThisDeclarationADefinition());
5265 EXPECT_EQ(ToXDef->getPreviousDecl(), ToX);
5266}
5267
5268TEST_P(ASTImporterOptionSpecificTestBase, VarTemplateSpecializationDeclValue) {
5269 Decl *ToTU = getToTuDecl(
5270 ToSrcCode: R"(
5271 template <class U>
5272 constexpr int X = U::Value;
5273 struct A { static constexpr int Value = 1; };
5274 constexpr int Y = X<A>;
5275 )",
5276 ToLang: Lang_CXX14);
5277
5278 auto *ToTUX = FirstDeclMatcher<VarTemplateSpecializationDecl>().match(
5279 D: ToTU, AMatcher: varTemplateSpecializationDecl(hasName(Name: "X")));
5280 Decl *FromTU = getTuDecl(
5281 SrcCode: R"(
5282 template <class U>
5283 constexpr int X = U::Value;
5284 struct A { static constexpr int Value = 1; };
5285 constexpr int Y = X<A>;
5286 )",
5287 Lang: Lang_CXX14, FileName: "input1.cc");
5288 auto *FromX = FirstDeclMatcher<VarTemplateSpecializationDecl>().match(
5289 D: FromTU, AMatcher: varTemplateSpecializationDecl(hasName(Name: "X")));
5290 auto *ToX = Import(FromX, Lang_CXX14);
5291 EXPECT_TRUE(ToX);
5292 EXPECT_EQ(ToTUX, ToX);
5293}
5294
5295TEST_P(ASTImporterOptionSpecificTestBase,
5296 VarTemplateSpecializationDeclValueConflict) {
5297 getToTuDecl(
5298 ToSrcCode: R"(
5299 template <class U>
5300 constexpr int X = U::Value;
5301 struct A { static constexpr int Value = 1; };
5302 constexpr int Y = X<A>;
5303 )",
5304 ToLang: Lang_CXX14);
5305
5306 Decl *FromTU = getTuDecl(
5307 SrcCode: R"(
5308 template <class U>
5309 constexpr int X = U::Value;
5310 struct A { static constexpr int Value = 2; };
5311 constexpr int Y = X<A>;
5312 )",
5313 Lang: Lang_CXX14, FileName: "input1.cc");
5314 auto *FromX = FirstDeclMatcher<VarTemplateSpecializationDecl>().match(
5315 D: FromTU, AMatcher: varTemplateSpecializationDecl(hasName(Name: "X")));
5316 auto *ToX = Import(FromX, Lang_CXX14);
5317 EXPECT_FALSE(ToX);
5318}
5319
5320TEST_P(ASTImporterOptionSpecificTestBase, VarTemplateDeclInlineWithCXX17) {
5321 Decl *FromTU = getTuDecl(
5322 SrcCode: R"(
5323 struct S {
5324 template <unsigned> static constexpr bool X = true;
5325 };
5326 )",
5327 Lang: Lang_CXX17, FileName: "input1.cc");
5328 Decl *FromTU2 = getTuDecl(
5329 SrcCode: R"(
5330 struct S {
5331 template <unsigned> static constexpr bool X = true;
5332 template <typename T> void get() { X<sizeof(T)>; }
5333 };
5334 template <typename U> U qvariant_cast(const S &v) { return v.get; }
5335 )",
5336 Lang: Lang_CXX17, FileName: "input2.cc");
5337 auto *FromX = FirstDeclMatcher<VarTemplateDecl>().match(
5338 D: FromTU, AMatcher: varTemplateDecl(hasName(Name: "X")));
5339 auto *ToX = Import(FromX, Lang_CXX17);
5340 ASSERT_TRUE(ToX);
5341 auto *FromX2 = FirstDeclMatcher<VarTemplateDecl>().match(
5342 D: FromTU2, AMatcher: varTemplateDecl(hasName(Name: "X")));
5343 auto *ToX2 = Import(FromX2, Lang_CXX17);
5344 EXPECT_TRUE(ToX2);
5345 EXPECT_EQ(ToX, ToX2);
5346}
5347
5348TEST_P(ASTImporterOptionSpecificTestBase, VarTemplateParameterDeclContext) {
5349 constexpr auto Code =
5350 R"(
5351 template<class T1, class T2>
5352 int X1;
5353 template<class T2>
5354 int X1<int, T2>;
5355
5356 namespace Ns {
5357 template<class T1, class T2>
5358 int X2;
5359 template<class T2>
5360 int X2<int, T2>;
5361 }
5362 )";
5363
5364 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX14);
5365
5366 auto *FromD1 = FirstDeclMatcher<VarTemplateDecl>().match(
5367 D: FromTU, AMatcher: varTemplateDecl(hasName(Name: "X1")));
5368 auto *FromD1Part =
5369 FirstDeclMatcher<VarTemplatePartialSpecializationDecl>().match(
5370 D: FromTU, AMatcher: varTemplatePartialSpecializationDecl(hasName(Name: "X1")));
5371 auto *FromD2 = FirstDeclMatcher<VarTemplateDecl>().match(
5372 D: FromTU, AMatcher: varTemplateDecl(hasName(Name: "X2")));
5373 auto *FromD2Part =
5374 FirstDeclMatcher<VarTemplatePartialSpecializationDecl>().match(
5375 D: FromTU, AMatcher: varTemplatePartialSpecializationDecl(hasName(Name: "X2")));
5376
5377 ASSERT_EQ(FromD1->getTemplateParameters()->getParam(0)->getDeclContext(),
5378 FromD1->getDeclContext());
5379 ASSERT_EQ(FromD2->getTemplateParameters()->getParam(0)->getDeclContext(),
5380 FromD2->getDeclContext());
5381
5382 ASSERT_EQ(FromD1Part->getTemplateParameters()->getParam(0)->getDeclContext(),
5383 FromD1Part->getDeclContext());
5384 // FIXME: VarTemplatePartialSpecializationDecl does not update ("adopt")
5385 // template parameter decl context
5386 // ASSERT_EQ(FromD2Part->getTemplateParameters()->getParam(0)->getDeclContext(),
5387 // FromD2Part->getDeclContext());
5388
5389 auto *ToD1 = Import(FromD1, Lang_CXX14);
5390 auto *ToD2 = Import(FromD2, Lang_CXX14);
5391
5392 auto *ToD1Part = Import(FromD1Part, Lang_CXX14);
5393 auto *ToD2Part = Import(FromD2Part, Lang_CXX14);
5394
5395 EXPECT_EQ(ToD1->getTemplateParameters()->getParam(0)->getDeclContext(),
5396 ToD1->getDeclContext());
5397 EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains(
5398 ToD1->getDeclContext(), ToD1->getTemplateParameters()->getParam(0)));
5399 EXPECT_EQ(ToD2->getTemplateParameters()->getParam(0)->getDeclContext(),
5400 ToD2->getDeclContext());
5401 EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains(
5402 ToD2->getDeclContext(), ToD2->getTemplateParameters()->getParam(0)));
5403
5404 EXPECT_EQ(ToD1Part->getTemplateParameters()->getParam(0)->getDeclContext(),
5405 ToD1Part->getDeclContext());
5406 EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains(
5407 ToD1Part->getDeclContext(),
5408 ToD1Part->getTemplateParameters()->getParam(0)));
5409 // EXPECT_EQ(ToD2Part->getTemplateParameters()->getParam(0)->getDeclContext(),
5410 // ToD2Part->getDeclContext());
5411 // EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains(
5412 // ToD2Part->getDeclContext(),
5413 // ToD2Part->getTemplateParameters()->getParam(0)));
5414 (void)ToD2Part;
5415}
5416
5417TEST_P(ASTImporterOptionSpecificTestBase,
5418 TypeAliasTemplateParameterDeclContext) {
5419 constexpr auto Code =
5420 R"(
5421 template<class T1, class T2>
5422 struct S {};
5423 template<class T> using S1 = S<T, int>;
5424 namespace Ns {
5425 template<class T> using S2 = S<T, int>;
5426 }
5427 )";
5428
5429 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11);
5430
5431 auto *FromD1 = FirstDeclMatcher<TypeAliasTemplateDecl>().match(
5432 D: FromTU, AMatcher: typeAliasTemplateDecl(hasName(Name: "S1")));
5433 auto *FromD2 = FirstDeclMatcher<TypeAliasTemplateDecl>().match(
5434 D: FromTU, AMatcher: typeAliasTemplateDecl(hasName(Name: "S2")));
5435
5436 ASSERT_EQ(FromD1->getTemplateParameters()->getParam(0)->getDeclContext(),
5437 FromD1->getDeclContext());
5438 ASSERT_EQ(FromD2->getTemplateParameters()->getParam(0)->getDeclContext(),
5439 FromD2->getDeclContext());
5440
5441 auto *ToD1 = Import(FromD1, Lang_CXX11);
5442 auto *ToD2 = Import(FromD2, Lang_CXX11);
5443
5444 EXPECT_EQ(ToD1->getTemplateParameters()->getParam(0)->getDeclContext(),
5445 ToD1->getDeclContext());
5446 EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains(
5447 ToD1->getDeclContext(), ToD1->getTemplateParameters()->getParam(0)));
5448 EXPECT_EQ(ToD2->getTemplateParameters()->getParam(0)->getDeclContext(),
5449 ToD2->getDeclContext());
5450 EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains(
5451 ToD2->getDeclContext(), ToD2->getTemplateParameters()->getParam(0)));
5452}
5453
5454TEST_P(ASTImporterOptionSpecificTestBase, ImportSubstTemplateTypeParmType) {
5455 constexpr auto Code = R"(
5456 template <class A1, class... A2> struct A {
5457 using B = A1(A2...);
5458 };
5459 template struct A<void, char, float, int, short>;
5460 )";
5461 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11, FileName: "input.cpp");
5462 auto *FromClass = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
5463 D: FromTU, AMatcher: classTemplateSpecializationDecl());
5464
5465 auto testType = [&](ASTContext &Ctx, const char *Name,
5466 std::optional<unsigned> PackIndex) {
5467 const auto *Subst = selectFirst<SubstTemplateTypeParmType>(
5468 BoundTo: "sttp", Results: match(Matcher: substTemplateTypeParmType(
5469 hasReplacementType(hasCanonicalType(InnerMatcher: asString(Name))))
5470 .bind(ID: "sttp"),
5471 Context&: Ctx));
5472 const char *ExpectedTemplateParamName = PackIndex ? "A2" : "A1";
5473 ASSERT_TRUE(Subst);
5474 ASSERT_EQ(Subst->getReplacedParameter()->getIdentifier()->getName(),
5475 ExpectedTemplateParamName);
5476 ASSERT_EQ(Subst->getPackIndex(), PackIndex);
5477 };
5478 auto tests = [&](ASTContext &Ctx) {
5479 testType(Ctx, "void", std::nullopt);
5480 testType(Ctx, "char", 3);
5481 testType(Ctx, "float", 2);
5482 testType(Ctx, "int", 1);
5483 testType(Ctx, "short", 0);
5484 };
5485
5486 tests(FromTU->getASTContext());
5487
5488 ClassTemplateSpecializationDecl *ToClass = Import(FromClass, Lang_CXX11);
5489 tests(ToClass->getASTContext());
5490}
5491
5492const AstTypeMatcher<SubstTemplateTypeParmPackType>
5493 substTemplateTypeParmPackType;
5494
5495TEST_P(ASTImporterOptionSpecificTestBase, ImportSubstTemplateTypeParmPackType) {
5496 constexpr auto Code = R"(
5497 template<typename ...T> struct D {
5498 template<typename... U> using B = int(int (*...p)(T, U));
5499 template<typename U1, typename U2> D(B<U1, U2>*);
5500 };
5501 int f(int(int, int), int(int, int));
5502
5503 using asd = D<float, double, float>::B<int, long, int>;
5504 )";
5505 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11, FileName: "input.cpp");
5506 auto *FromClass = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
5507 D: FromTU, AMatcher: classTemplateSpecializationDecl());
5508
5509 {
5510 ASTContext &FromCtx = FromTU->getASTContext();
5511 const auto *FromSubstPack = selectFirst<SubstTemplateTypeParmPackType>(
5512 BoundTo: "pack", Results: match(Matcher: substTemplateTypeParmPackType().bind(ID: "pack"), Context&: FromCtx));
5513
5514 ASSERT_TRUE(FromSubstPack);
5515 ASSERT_EQ(FromSubstPack->getIdentifier()->getName(), "T");
5516 ArrayRef<TemplateArgument> FromArgPack =
5517 FromSubstPack->getArgumentPack().pack_elements();
5518 ASSERT_EQ(FromArgPack.size(), 3u);
5519 ASSERT_EQ(FromArgPack[0].getAsType(), FromCtx.FloatTy);
5520 ASSERT_EQ(FromArgPack[1].getAsType(), FromCtx.DoubleTy);
5521 ASSERT_EQ(FromArgPack[2].getAsType(), FromCtx.FloatTy);
5522 }
5523 {
5524 // Let's do the import.
5525 ClassTemplateSpecializationDecl *ToClass = Import(FromClass, Lang_CXX11);
5526 ASTContext &ToCtx = ToClass->getASTContext();
5527
5528 const auto *ToSubstPack = selectFirst<SubstTemplateTypeParmPackType>(
5529 BoundTo: "pack", Results: match(Matcher: substTemplateTypeParmPackType().bind(ID: "pack"), Context&: ToCtx));
5530
5531 // Check if it meets the requirements.
5532 ASSERT_TRUE(ToSubstPack);
5533 ASSERT_EQ(ToSubstPack->getIdentifier()->getName(), "T");
5534 ArrayRef<TemplateArgument> ToArgPack =
5535 ToSubstPack->getArgumentPack().pack_elements();
5536 ASSERT_EQ(ToArgPack.size(), 3u);
5537 ASSERT_EQ(ToArgPack[0].getAsType(), ToCtx.FloatTy);
5538 ASSERT_EQ(ToArgPack[1].getAsType(), ToCtx.DoubleTy);
5539 ASSERT_EQ(ToArgPack[2].getAsType(), ToCtx.FloatTy);
5540 }
5541}
5542
5543struct ASTImporterLookupTableTest : ASTImporterOptionSpecificTestBase {};
5544
5545TEST_P(ASTImporterLookupTableTest, OneDecl) {
5546 auto *ToTU = getToTuDecl(ToSrcCode: "int a;", ToLang: Lang_CXX03);
5547 auto *D = FirstDeclMatcher<VarDecl>().match(ToTU, varDecl(hasName(Name: "a")));
5548 ASTImporterLookupTable LT(*ToTU);
5549 auto Res = LT.lookup(DC: ToTU, Name: D->getDeclName());
5550 ASSERT_EQ(Res.size(), 1u);
5551 EXPECT_EQ(*Res.begin(), D);
5552}
5553
5554static Decl *findInDeclListOfDC(DeclContext *DC, DeclarationName Name) {
5555 for (Decl *D : DC->decls()) {
5556 if (auto *ND = dyn_cast<NamedDecl>(Val: D))
5557 if (ND->getDeclName() == Name)
5558 return ND;
5559 }
5560 return nullptr;
5561}
5562
5563TEST_P(ASTImporterLookupTableTest,
5564 FriendWhichIsnotFoundByNormalLookupShouldBeFoundByImporterSpecificLookup) {
5565 auto *Code = R"(
5566 template <class T>
5567 struct X {
5568 friend void foo(){}
5569 };
5570 )";
5571 TranslationUnitDecl *ToTU = getToTuDecl(ToSrcCode: Code, ToLang: Lang_CXX03);
5572 auto *X = FirstDeclMatcher<ClassTemplateDecl>().match(
5573 ToTU, classTemplateDecl(hasName(Name: "X")));
5574 auto *Foo = FirstDeclMatcher<FunctionDecl>().match(
5575 ToTU, functionDecl(hasName(Name: "foo")));
5576 DeclContext *FooDC = Foo->getDeclContext();
5577 DeclContext *FooLexicalDC = Foo->getLexicalDeclContext();
5578 ASSERT_EQ(cast<Decl>(FooLexicalDC), X->getTemplatedDecl());
5579 ASSERT_EQ(cast<Decl>(FooDC), ToTU);
5580 DeclarationName FooName = Foo->getDeclName();
5581
5582 // Cannot find in the LookupTable of its DC (TUDecl)
5583 SmallVector<NamedDecl *, 2> FoundDecls;
5584 FooDC->getRedeclContext()->localUncachedLookup(Name: FooName, Results&: FoundDecls);
5585 EXPECT_EQ(FoundDecls.size(), 0u);
5586
5587 // Cannot find in the LookupTable of its LexicalDC (X)
5588 FooLexicalDC->getRedeclContext()->localUncachedLookup(Name: FooName, Results&: FoundDecls);
5589 EXPECT_EQ(FoundDecls.size(), 0u);
5590
5591 // Can't find in the list of Decls of the DC.
5592 EXPECT_EQ(findInDeclListOfDC(FooDC, FooName), nullptr);
5593
5594 // Can't find in the list of Decls of the LexicalDC
5595 EXPECT_EQ(findInDeclListOfDC(FooLexicalDC, FooName), nullptr);
5596
5597 // ASTImporter specific lookup finds it.
5598 ASTImporterLookupTable LT(*ToTU);
5599 auto Res = LT.lookup(DC: FooDC, Name: Foo->getDeclName());
5600 ASSERT_EQ(Res.size(), 1u);
5601 EXPECT_EQ(*Res.begin(), Foo);
5602}
5603
5604TEST_P(ASTImporterLookupTableTest,
5605 FwdDeclStructShouldBeFoundByImporterSpecificLookup) {
5606 TranslationUnitDecl *ToTU =
5607 getToTuDecl(ToSrcCode: "struct A { struct Foo *p; };", ToLang: Lang_C99);
5608 auto *Foo =
5609 FirstDeclMatcher<RecordDecl>().match(ToTU, recordDecl(hasName(Name: "Foo")));
5610 auto *A =
5611 FirstDeclMatcher<RecordDecl>().match(ToTU, recordDecl(hasName(Name: "A")));
5612 DeclContext *FooDC = Foo->getDeclContext();
5613 DeclContext *FooLexicalDC = Foo->getLexicalDeclContext();
5614 ASSERT_EQ(cast<Decl>(FooLexicalDC), A);
5615 ASSERT_EQ(cast<Decl>(FooDC), ToTU);
5616 DeclarationName FooName = Foo->getDeclName();
5617
5618 // Cannot find in the LookupTable of its DC (TUDecl).
5619 SmallVector<NamedDecl *, 2> FoundDecls;
5620 FooDC->getRedeclContext()->localUncachedLookup(Name: FooName, Results&: FoundDecls);
5621 EXPECT_EQ(FoundDecls.size(), 0u);
5622
5623 // Finds via linear search of its LexicalDC (A).
5624 FooLexicalDC->getRedeclContext()->localUncachedLookup(Name: FooName, Results&: FoundDecls);
5625 EXPECT_EQ(FoundDecls.size(), 1u);
5626
5627 // Can't find in the list of Decls of the DC.
5628 EXPECT_EQ(findInDeclListOfDC(FooDC, FooName), nullptr);
5629
5630 // Can find in the list of Decls of the LexicalDC.
5631 EXPECT_EQ(findInDeclListOfDC(FooLexicalDC, FooName), Foo);
5632
5633 // ASTImporter specific lookup finds it.
5634 ASTImporterLookupTable LT(*ToTU);
5635 auto Res = LT.lookup(DC: FooDC, Name: Foo->getDeclName());
5636 ASSERT_EQ(Res.size(), 1u);
5637 EXPECT_EQ(*Res.begin(), Foo);
5638}
5639
5640TEST_P(ASTImporterLookupTableTest, LookupFindsNamesInDifferentDC) {
5641 TranslationUnitDecl *ToTU =
5642 getToTuDecl(ToSrcCode: "int V; struct A { int V; }; struct B { int V; };", ToLang: Lang_C99);
5643 DeclarationName VName = FirstDeclMatcher<VarDecl>()
5644 .match(ToTU, varDecl(hasName(Name: "V")))
5645 ->getDeclName();
5646 auto *A =
5647 FirstDeclMatcher<RecordDecl>().match(ToTU, recordDecl(hasName(Name: "A")));
5648 auto *B =
5649 FirstDeclMatcher<RecordDecl>().match(ToTU, recordDecl(hasName(Name: "B")));
5650
5651 ASTImporterLookupTable LT(*ToTU);
5652
5653 auto Res = LT.lookup(DC: cast<DeclContext>(A), Name: VName);
5654 ASSERT_EQ(Res.size(), 1u);
5655 EXPECT_EQ(*Res.begin(), FirstDeclMatcher<FieldDecl>().match(
5656 ToTU, fieldDecl(hasName("V"),
5657 hasParent(recordDecl(hasName("A"))))));
5658 Res = LT.lookup(DC: cast<DeclContext>(B), Name: VName);
5659 ASSERT_EQ(Res.size(), 1u);
5660 EXPECT_EQ(*Res.begin(), FirstDeclMatcher<FieldDecl>().match(
5661 ToTU, fieldDecl(hasName("V"),
5662 hasParent(recordDecl(hasName("B"))))));
5663 Res = LT.lookup(ToTU, VName);
5664 ASSERT_EQ(Res.size(), 1u);
5665 EXPECT_EQ(*Res.begin(), FirstDeclMatcher<VarDecl>().match(
5666 ToTU, varDecl(hasName("V"),
5667 hasParent(translationUnitDecl()))));
5668}
5669
5670TEST_P(ASTImporterLookupTableTest, LookupFindsOverloadedNames) {
5671 TranslationUnitDecl *ToTU = getToTuDecl(
5672 ToSrcCode: R"(
5673 void foo();
5674 void foo(int);
5675 void foo(int, int);
5676 )",
5677 ToLang: Lang_CXX03);
5678
5679 ASTImporterLookupTable LT(*ToTU);
5680 auto *F0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, functionDecl());
5681 auto *F2 = LastDeclMatcher<FunctionDecl>().match(ToTU, functionDecl());
5682 DeclarationName Name = F0->getDeclName();
5683 auto Res = LT.lookup(ToTU, Name);
5684 EXPECT_EQ(Res.size(), 3u);
5685 EXPECT_EQ(Res.count(F0), 1u);
5686 EXPECT_EQ(Res.count(F2), 1u);
5687}
5688
5689TEST_P(ASTImporterLookupTableTest,
5690 DifferentOperatorsShouldHaveDifferentResultSet) {
5691 TranslationUnitDecl *ToTU = getToTuDecl(
5692 ToSrcCode: R"(
5693 struct X{};
5694 void operator+(X, X);
5695 void operator-(X, X);
5696 )",
5697 ToLang: Lang_CXX03);
5698
5699 ASTImporterLookupTable LT(*ToTU);
5700 auto *FPlus = FirstDeclMatcher<FunctionDecl>().match(
5701 ToTU, functionDecl(hasOverloadedOperatorName(Name: "+")));
5702 auto *FMinus = FirstDeclMatcher<FunctionDecl>().match(
5703 ToTU, functionDecl(hasOverloadedOperatorName(Name: "-")));
5704 DeclarationName NamePlus = FPlus->getDeclName();
5705 auto ResPlus = LT.lookup(ToTU, NamePlus);
5706 EXPECT_EQ(ResPlus.size(), 1u);
5707 EXPECT_EQ(ResPlus.count(FPlus), 1u);
5708 EXPECT_EQ(ResPlus.count(FMinus), 0u);
5709 DeclarationName NameMinus = FMinus->getDeclName();
5710 auto ResMinus = LT.lookup(ToTU, NameMinus);
5711 EXPECT_EQ(ResMinus.size(), 1u);
5712 EXPECT_EQ(ResMinus.count(FMinus), 1u);
5713 EXPECT_EQ(ResMinus.count(FPlus), 0u);
5714 EXPECT_NE(*ResMinus.begin(), *ResPlus.begin());
5715}
5716
5717TEST_P(ASTImporterLookupTableTest, LookupDeclNamesFromDifferentTUs) {
5718 TranslationUnitDecl *ToTU = getToTuDecl(
5719 ToSrcCode: R"(
5720 struct X {};
5721 void operator+(X, X);
5722 )",
5723 ToLang: Lang_CXX03);
5724 auto *ToPlus = FirstDeclMatcher<FunctionDecl>().match(
5725 ToTU, functionDecl(hasOverloadedOperatorName(Name: "+")));
5726
5727 Decl *FromTU = getTuDecl(
5728 SrcCode: R"(
5729 struct X {};
5730 void operator+(X, X);
5731 )",
5732 Lang: Lang_CXX03);
5733 auto *FromPlus = FirstDeclMatcher<FunctionDecl>().match(
5734 D: FromTU, AMatcher: functionDecl(hasOverloadedOperatorName(Name: "+")));
5735
5736 // FromPlus have a different TU, thus its DeclarationName is different too.
5737 ASSERT_NE(ToPlus->getDeclName(), FromPlus->getDeclName());
5738
5739 ASTImporterLookupTable LT(*ToTU);
5740 auto Res = LT.lookup(DC: ToTU, Name: ToPlus->getDeclName());
5741 ASSERT_EQ(Res.size(), 1u);
5742 EXPECT_EQ(*Res.begin(), ToPlus);
5743
5744 // FromPlus have a different TU, thus its DeclarationName is different too.
5745 Res = LT.lookup(DC: ToTU, Name: FromPlus->getDeclName());
5746 ASSERT_EQ(Res.size(), 0u);
5747}
5748
5749TEST_P(ASTImporterLookupTableTest,
5750 LookupFindsFwdFriendClassDeclWithElaboratedType) {
5751 TranslationUnitDecl *ToTU = getToTuDecl(
5752 ToSrcCode: R"(
5753 class Y { friend class F; };
5754 )",
5755 ToLang: Lang_CXX03);
5756
5757 // In this case, the CXXRecordDecl is hidden, the FriendDecl is not a parent.
5758 // So we must dig up the underlying CXXRecordDecl.
5759 ASTImporterLookupTable LT(*ToTU);
5760 auto *FriendD = FirstDeclMatcher<FriendDecl>().match(ToTU, friendDecl());
5761 const RecordDecl *RD = getRecordDeclOfFriend(FriendD);
5762 auto *Y = FirstDeclMatcher<CXXRecordDecl>().match(
5763 ToTU, cxxRecordDecl(hasName(Name: "Y")));
5764
5765 DeclarationName Name = RD->getDeclName();
5766 auto Res = LT.lookup(ToTU, Name);
5767 EXPECT_EQ(Res.size(), 1u);
5768 EXPECT_EQ(*Res.begin(), RD);
5769
5770 Res = LT.lookup(DC: Y, Name);
5771 EXPECT_EQ(Res.size(), 0u);
5772}
5773
5774TEST_P(ASTImporterLookupTableTest,
5775 LookupFindsFwdFriendClassDeclWithUnelaboratedType) {
5776 TranslationUnitDecl *ToTU = getToTuDecl(
5777 ToSrcCode: R"(
5778 class F;
5779 class Y { friend F; };
5780 )",
5781 ToLang: Lang_CXX11);
5782
5783 // In this case, the CXXRecordDecl is hidden, the FriendDecl is not a parent.
5784 // So we must dig up the underlying CXXRecordDecl.
5785 ASTImporterLookupTable LT(*ToTU);
5786 auto *FriendD = FirstDeclMatcher<FriendDecl>().match(ToTU, friendDecl());
5787 const RecordDecl *RD = getRecordDeclOfFriend(FriendD);
5788 auto *Y = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, cxxRecordDecl(hasName(Name: "Y")));
5789
5790 DeclarationName Name = RD->getDeclName();
5791 auto Res = LT.lookup(ToTU, Name);
5792 EXPECT_EQ(Res.size(), 1u);
5793 EXPECT_EQ(*Res.begin(), RD);
5794
5795 Res = LT.lookup(DC: Y, Name);
5796 EXPECT_EQ(Res.size(), 0u);
5797}
5798
5799TEST_P(ASTImporterLookupTableTest,
5800 LookupFindsFriendClassDeclWithTypeAliasDoesNotAssert) {
5801 TranslationUnitDecl *ToTU = getToTuDecl(
5802 ToSrcCode: R"(
5803 class F;
5804 using alias_of_f = F;
5805 class Y { friend alias_of_f; };
5806 )",
5807 ToLang: Lang_CXX11);
5808
5809 // ASTImporterLookupTable constructor handles using declarations correctly,
5810 // no assert is expected.
5811 ASTImporterLookupTable LT(*ToTU);
5812
5813 auto *Alias = FirstDeclMatcher<TypeAliasDecl>().match(
5814 ToTU, typeAliasDecl(hasName(Name: "alias_of_f")));
5815 DeclarationName Name = Alias->getDeclName();
5816 auto Res = LT.lookup(ToTU, Name);
5817 EXPECT_EQ(Res.count(Alias), 1u);
5818}
5819
5820TEST_P(ASTImporterLookupTableTest,
5821 LookupFindsFriendClassDeclWithUsingTypeDoesNotAssert) {
5822 TranslationUnitDecl *ToTU = getToTuDecl(
5823 ToSrcCode: R"(
5824 namespace a {
5825 namespace b { class InnerClass; }
5826 using b::InnerClass;
5827 }
5828 class B {
5829 friend a::InnerClass;
5830 };
5831 )",
5832 ToLang: Lang_CXX11);
5833
5834 // ASTImporterLookupTable constructor handles friend with using-type without
5835 // asserts.
5836 ASTImporterLookupTable LT(*ToTU);
5837
5838 auto *Using = FirstDeclMatcher<UsingDecl>().match(
5839 ToTU, usingDecl(hasName(Name: "InnerClass")));
5840 DeclarationName Name = Using->getDeclName();
5841 auto Res = LT.lookup(ToTU, Name);
5842 EXPECT_EQ(Res.size(), 0u);
5843 auto *NsA = FirstDeclMatcher<NamespaceDecl>().match(
5844 ToTU, namespaceDecl(hasName(Name: "a")));
5845 auto *RecordB = FirstDeclMatcher<CXXRecordDecl>().match(
5846 ToTU, cxxRecordDecl(hasName(Name: "B")));
5847 auto Res1 = LT.lookup(DC: NsA, Name);
5848 EXPECT_EQ(Res1.count(Using), 1u);
5849 auto Res2 = LT.lookup(DC: RecordB, Name);
5850 EXPECT_EQ(Res2.size(), 0u);
5851}
5852
5853TEST_P(ASTImporterLookupTableTest, LookupFindsFwdFriendClassTemplateDecl) {
5854 TranslationUnitDecl *ToTU = getToTuDecl(
5855 ToSrcCode: R"(
5856 class Y { template <class T> friend class F; };
5857 )",
5858 ToLang: Lang_CXX03);
5859
5860 ASTImporterLookupTable LT(*ToTU);
5861 auto *F = FirstDeclMatcher<ClassTemplateDecl>().match(
5862 ToTU, classTemplateDecl(hasName(Name: "F")));
5863 DeclarationName Name = F->getDeclName();
5864 auto Res = LT.lookup(ToTU, Name);
5865 EXPECT_EQ(Res.size(), 2u);
5866 EXPECT_EQ(Res.count(F), 1u);
5867 EXPECT_EQ(Res.count(F->getTemplatedDecl()), 1u);
5868}
5869
5870TEST_P(ASTImporterLookupTableTest, DependentFriendClass) {
5871 TranslationUnitDecl *ToTU = getToTuDecl(
5872 ToSrcCode: R"(
5873 template <typename T>
5874 class F;
5875
5876 template <typename T>
5877 class Y {
5878 friend class F<T>;
5879 };
5880 )",
5881 ToLang: Lang_CXX03);
5882
5883 ASTImporterLookupTable LT(*ToTU);
5884 auto *F = FirstDeclMatcher<ClassTemplateDecl>().match(
5885 ToTU, classTemplateDecl(hasName(Name: "F")));
5886 DeclarationName Name = F->getDeclName();
5887 auto Res = LT.lookup(ToTU, Name);
5888 EXPECT_EQ(Res.size(), 2u);
5889 EXPECT_EQ(Res.count(F), 1u);
5890 EXPECT_EQ(Res.count(F->getTemplatedDecl()), 1u);
5891}
5892
5893TEST_P(ASTImporterLookupTableTest, FriendClassTemplateSpecialization) {
5894 TranslationUnitDecl *ToTU = getToTuDecl(
5895 ToSrcCode: R"(
5896 template <typename T>
5897 class F;
5898
5899 class Y {
5900 friend class F<int>;
5901 };
5902 )",
5903 ToLang: Lang_CXX03);
5904
5905 ASTImporterLookupTable LT(*ToTU);
5906 auto *F = FirstDeclMatcher<ClassTemplateDecl>().match(
5907 ToTU, classTemplateDecl(hasName(Name: "F")));
5908 DeclarationName Name = F->getDeclName();
5909 auto Res = LT.lookup(ToTU, Name);
5910 ASSERT_EQ(Res.size(), 3u);
5911 EXPECT_EQ(Res.count(F), 1u);
5912 EXPECT_EQ(Res.count(F->getTemplatedDecl()), 1u);
5913 EXPECT_EQ(Res.count(*F->spec_begin()), 1u);
5914}
5915
5916TEST_P(ASTImporterLookupTableTest, LookupFindsFwdFriendFunctionDecl) {
5917 TranslationUnitDecl *ToTU = getToTuDecl(
5918 ToSrcCode: R"(
5919 class Y { friend void F(); };
5920 )",
5921 ToLang: Lang_CXX03);
5922
5923 ASTImporterLookupTable LT(*ToTU);
5924 auto *F =
5925 FirstDeclMatcher<FunctionDecl>().match(ToTU, functionDecl(hasName(Name: "F")));
5926 DeclarationName Name = F->getDeclName();
5927 auto Res = LT.lookup(ToTU, Name);
5928 EXPECT_EQ(Res.size(), 1u);
5929 EXPECT_EQ(*Res.begin(), F);
5930}
5931
5932TEST_P(ASTImporterLookupTableTest,
5933 LookupFindsDeclsInClassTemplateSpecialization) {
5934 TranslationUnitDecl *ToTU = getToTuDecl(
5935 ToSrcCode: R"(
5936 template <typename T>
5937 struct X {
5938 int F;
5939 };
5940 void foo() {
5941 X<char> xc;
5942 }
5943 )",
5944 ToLang: Lang_CXX03);
5945
5946 ASTImporterLookupTable LT(*ToTU);
5947
5948 auto *Template = FirstDeclMatcher<ClassTemplateDecl>().match(
5949 ToTU, classTemplateDecl(hasName(Name: "X")));
5950 auto *FieldInTemplate = FirstDeclMatcher<FieldDecl>().match(
5951 ToTU,
5952 fieldDecl(hasParent(cxxRecordDecl(hasParent(classTemplateDecl())))));
5953
5954 auto *Spec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
5955 ToTU, classTemplateSpecializationDecl(hasName(Name: "X")));
5956 FieldDecl *FieldInSpec = *Spec->field_begin();
5957 ASSERT_TRUE(FieldInSpec);
5958
5959 DeclarationName Name = FieldInSpec->getDeclName();
5960 auto TemplateDC = cast<DeclContext>(Template->getTemplatedDecl());
5961
5962 SmallVector<NamedDecl *, 2> FoundDecls;
5963 TemplateDC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
5964 EXPECT_EQ(FoundDecls.size(), 1u);
5965 EXPECT_EQ(FoundDecls[0], FieldInTemplate);
5966
5967 auto Res = LT.lookup(DC: TemplateDC, Name);
5968 ASSERT_EQ(Res.size(), 1u);
5969 EXPECT_EQ(*Res.begin(), FieldInTemplate);
5970
5971 cast<DeclContext>(Spec)->getRedeclContext()->localUncachedLookup(Name,
5972 FoundDecls);
5973 EXPECT_EQ(FoundDecls.size(), 1u);
5974 EXPECT_EQ(FoundDecls[0], FieldInSpec);
5975
5976 Res = LT.lookup(DC: cast<DeclContext>(Spec), Name);
5977 ASSERT_EQ(Res.size(), 1u);
5978 EXPECT_EQ(*Res.begin(), FieldInSpec);
5979}
5980
5981TEST_P(ASTImporterLookupTableTest, LookupFindsFwdFriendFunctionTemplateDecl) {
5982 TranslationUnitDecl *ToTU = getToTuDecl(
5983 ToSrcCode: R"(
5984 class Y { template <class T> friend void F(); };
5985 )",
5986 ToLang: Lang_CXX03);
5987
5988 ASTImporterLookupTable LT(*ToTU);
5989 auto *F = FirstDeclMatcher<FunctionTemplateDecl>().match(
5990 ToTU, functionTemplateDecl(hasName(Name: "F")));
5991 DeclarationName Name = F->getDeclName();
5992 auto Res = LT.lookup(ToTU, Name);
5993 EXPECT_EQ(Res.size(), 2u);
5994 EXPECT_EQ(Res.count(F), 1u);
5995 EXPECT_EQ(Res.count(F->getTemplatedDecl()), 1u);
5996}
5997
5998TEST_P(ASTImporterLookupTableTest, MultipleBefriendingClasses) {
5999 TranslationUnitDecl *ToTU = getToTuDecl(
6000 ToSrcCode: R"(
6001 struct X;
6002 struct A {
6003 friend struct X;
6004 };
6005 struct B {
6006 friend struct X;
6007 };
6008 )",
6009 ToLang: Lang_CXX03);
6010
6011 ASTImporterLookupTable LT(*ToTU);
6012 auto *X = FirstDeclMatcher<CXXRecordDecl>().match(
6013 ToTU, cxxRecordDecl(hasName(Name: "X")));
6014 auto *FriendD0 = FirstDeclMatcher<FriendDecl>().match(ToTU, friendDecl());
6015 auto *FriendD1 = LastDeclMatcher<FriendDecl>().match(ToTU, friendDecl());
6016 const RecordDecl *RD0 = getRecordDeclOfFriend(FriendD0);
6017 const RecordDecl *RD1 = getRecordDeclOfFriend(FriendD1);
6018 ASSERT_EQ(RD0, RD1);
6019 ASSERT_EQ(RD1, X);
6020
6021 DeclarationName Name = X->getDeclName();
6022 auto Res = LT.lookup(ToTU, Name);
6023 EXPECT_EQ(Res.size(), 1u);
6024 EXPECT_EQ(*Res.begin(), X);
6025}
6026
6027TEST_P(ASTImporterLookupTableTest, EnumConstantDecl) {
6028 TranslationUnitDecl *ToTU = getToTuDecl(
6029 ToSrcCode: R"(
6030 enum E {
6031 A,
6032 B
6033 };
6034 )",
6035 ToLang: Lang_C99);
6036
6037 ASTImporterLookupTable LT(*ToTU);
6038 auto *E = FirstDeclMatcher<EnumDecl>().match(ToTU, enumDecl(hasName(Name: "E")));
6039 auto *A = FirstDeclMatcher<EnumConstantDecl>().match(
6040 ToTU, enumConstantDecl(hasName(Name: "A")));
6041
6042 DeclarationName Name = A->getDeclName();
6043 // Redecl context is the TU.
6044 ASSERT_EQ(E->getRedeclContext(), ToTU);
6045
6046 SmallVector<NamedDecl *, 2> FoundDecls;
6047 // Normal lookup finds in the DC.
6048 E->localUncachedLookup(Name, FoundDecls);
6049 EXPECT_EQ(FoundDecls.size(), 1u);
6050
6051 // Normal lookup finds in the Redecl context.
6052 ToTU->localUncachedLookup(Name, FoundDecls);
6053 EXPECT_EQ(FoundDecls.size(), 1u);
6054
6055 // Import specific lookup finds in the DC.
6056 auto Res = LT.lookup(DC: E, Name);
6057 ASSERT_EQ(Res.size(), 1u);
6058 EXPECT_EQ(*Res.begin(), A);
6059
6060 // Import specific lookup finds in the Redecl context.
6061 Res = LT.lookup(ToTU, Name);
6062 ASSERT_EQ(Res.size(), 1u);
6063 EXPECT_EQ(*Res.begin(), A);
6064}
6065
6066TEST_P(ASTImporterLookupTableTest, LookupSearchesInTheWholeRedeclChain) {
6067 TranslationUnitDecl *ToTU = getToTuDecl(
6068 ToSrcCode: R"(
6069 namespace N {
6070 int A;
6071 }
6072 namespace N {
6073 }
6074 )",
6075 ToLang: Lang_CXX03);
6076 auto *N1 =
6077 LastDeclMatcher<NamespaceDecl>().match(ToTU, namespaceDecl(hasName(Name: "N")));
6078 auto *A = FirstDeclMatcher<VarDecl>().match(ToTU, varDecl(hasName(Name: "A")));
6079 DeclarationName Name = A->getDeclName();
6080
6081 ASTImporterLookupTable LT(*ToTU);
6082 auto Res = LT.lookup(DC: N1, Name);
6083 ASSERT_EQ(Res.size(), 1u);
6084 EXPECT_EQ(*Res.begin(), A);
6085}
6086
6087TEST_P(ASTImporterOptionSpecificTestBase,
6088 RedeclChainShouldBeCorrectAmongstNamespaces) {
6089 Decl *FromTU = getTuDecl(
6090 SrcCode: R"(
6091 namespace NS {
6092 struct X;
6093 struct Y {
6094 static const int I = 3;
6095 };
6096 }
6097 namespace NS {
6098 struct X { // <--- To be imported
6099 void method(int i = Y::I) {}
6100 int f;
6101 };
6102 }
6103 )",
6104 Lang: Lang_CXX03);
6105 auto *FromFwd = FirstDeclMatcher<CXXRecordDecl>().match(
6106 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "X"), unless(isImplicit())));
6107 auto *FromDef = LastDeclMatcher<CXXRecordDecl>().match(
6108 D: FromTU,
6109 AMatcher: cxxRecordDecl(hasName(Name: "X"), isDefinition(), unless(isImplicit())));
6110 ASSERT_NE(FromFwd, FromDef);
6111 ASSERT_FALSE(FromFwd->isThisDeclarationADefinition());
6112 ASSERT_TRUE(FromDef->isThisDeclarationADefinition());
6113 ASSERT_EQ(FromFwd->getCanonicalDecl(), FromDef->getCanonicalDecl());
6114
6115 auto *ToDef = cast_or_null<CXXRecordDecl>(Import(FromDef, Lang_CXX03));
6116 auto *ToFwd = cast_or_null<CXXRecordDecl>(Import(FromFwd, Lang_CXX03));
6117 EXPECT_NE(ToFwd, ToDef);
6118 EXPECT_FALSE(ToFwd->isThisDeclarationADefinition());
6119 EXPECT_TRUE(ToDef->isThisDeclarationADefinition());
6120 EXPECT_EQ(ToFwd->getCanonicalDecl(), ToDef->getCanonicalDecl());
6121 auto *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
6122 // We expect no (ODR) warning during the import.
6123 EXPECT_EQ(0u, ToTU->getASTContext().getDiagnostics().getNumWarnings());
6124}
6125
6126struct ImportFriendFunctionTemplates : ASTImporterOptionSpecificTestBase {};
6127
6128TEST_P(ImportFriendFunctionTemplates, LookupShouldFindPreviousFriend) {
6129 Decl *ToTU = getToTuDecl(
6130 ToSrcCode: R"(
6131 class X {
6132 template <typename T> friend void foo();
6133 };
6134 )",
6135 ToLang: Lang_CXX03);
6136 auto *Friend = FirstDeclMatcher<FunctionTemplateDecl>().match(
6137 D: ToTU, AMatcher: functionTemplateDecl(hasName(Name: "foo")));
6138
6139 Decl *FromTU = getTuDecl(
6140 SrcCode: R"(
6141 template <typename T> void foo();
6142 )",
6143 Lang: Lang_CXX03);
6144 auto *FromFoo = FirstDeclMatcher<FunctionTemplateDecl>().match(
6145 D: FromTU, AMatcher: functionTemplateDecl(hasName(Name: "foo")));
6146 auto *Imported = Import(FromFoo, Lang_CXX03);
6147
6148 EXPECT_EQ(Imported->getPreviousDecl(), Friend);
6149}
6150
6151TEST_P(ImportFriendFunctionTemplates, ImportFriendFunctionInsideClassTemplate) {
6152 Decl *From, *To;
6153 std::tie(args&: From, args&: To) = getImportedDecl(
6154 FromSrcCode: R"(
6155 template <typename T> struct X {
6156 template <typename U> friend void f();
6157 };
6158 )",
6159 FromLang: Lang_CXX03, ToSrcCode: "", ToLang: Lang_CXX03, Identifier: "X");
6160
6161 auto *FromFriend = FirstDeclMatcher<FriendDecl>().match(D: From, AMatcher: friendDecl());
6162 auto *ToFriend = FirstDeclMatcher<FriendDecl>().match(D: To, AMatcher: friendDecl());
6163
6164 EXPECT_TRUE(FromFriend ==
6165 LastDeclMatcher<FriendDecl>().match(From, friendDecl()));
6166 EXPECT_TRUE(ToFriend ==
6167 LastDeclMatcher<FriendDecl>().match(To, friendDecl()));
6168
6169 auto *FromDecl = FromFriend->getFriendDecl();
6170 auto *FromDC = FromFriend->getDeclContext();
6171 auto *FromLexicalDC = FromFriend->getLexicalDeclContext();
6172
6173 EXPECT_TRUE(FromDC->containsDecl(FromFriend));
6174 EXPECT_FALSE(FromDC->containsDecl(FromDecl));
6175 EXPECT_TRUE(FromLexicalDC->containsDecl(FromFriend));
6176 EXPECT_FALSE(FromLexicalDC->containsDecl(FromDecl));
6177
6178 auto *ToDecl = ToFriend->getFriendDecl();
6179 auto *ToDC = ToFriend->getDeclContext();
6180 auto *ToLexicalDC = ToFriend->getLexicalDeclContext();
6181
6182 EXPECT_TRUE(ToDC->containsDecl(ToFriend));
6183 EXPECT_FALSE(ToDC->containsDecl(ToDecl));
6184 EXPECT_TRUE(ToLexicalDC->containsDecl(ToFriend));
6185 EXPECT_FALSE(ToLexicalDC->containsDecl(ToDecl));
6186}
6187
6188struct ASTImporterWithFakeErrors : ASTImporter {
6189 using ASTImporter::ASTImporter;
6190 bool returnWithErrorInTest() override { return true; }
6191};
6192
6193struct ErrorHandlingTest : ASTImporterOptionSpecificTestBase {
6194 ErrorHandlingTest() {
6195 Creator = [](ASTContext &ToContext, FileManager &ToFileManager,
6196 ASTContext &FromContext, FileManager &FromFileManager,
6197 bool MinimalImport,
6198 const std::shared_ptr<ASTImporterSharedState> &SharedState) {
6199 return new ASTImporterWithFakeErrors(ToContext, ToFileManager,
6200 FromContext, FromFileManager,
6201 MinimalImport, SharedState);
6202 };
6203 }
6204 // In this test we purposely report an error (UnsupportedConstruct) when
6205 // importing the below stmt.
6206 static constexpr auto* ErroneousStmt = R"( asm(""); )";
6207};
6208
6209// Check a case when no new AST node is created in the AST before encountering
6210// the error.
6211TEST_P(ErrorHandlingTest, ErrorHappensBeforeCreatingANewNode) {
6212 TranslationUnitDecl *ToTU = getToTuDecl(
6213 ToSrcCode: R"(
6214 template <typename T>
6215 class X {};
6216 template <>
6217 class X<int> { int a; };
6218 )",
6219 ToLang: Lang_CXX03);
6220 TranslationUnitDecl *FromTU = getTuDecl(
6221 SrcCode: R"(
6222 template <typename T>
6223 class X {};
6224 template <>
6225 class X<int> { double b; };
6226 )",
6227 Lang: Lang_CXX03);
6228 auto *FromSpec = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
6229 FromTU, classTemplateSpecializationDecl(hasName(Name: "X")));
6230 ClassTemplateSpecializationDecl *ImportedSpec = Import(FromSpec, Lang_CXX03);
6231 EXPECT_FALSE(ImportedSpec);
6232
6233 // The original Decl is kept, no new decl is created.
6234 EXPECT_EQ(DeclCounter<ClassTemplateSpecializationDecl>().match(
6235 ToTU, classTemplateSpecializationDecl(hasName("X"))),
6236 1u);
6237
6238 // But an error is set to the counterpart in the "from" context.
6239 ASTImporter *Importer = findFromTU(From: FromSpec)->Importer.get();
6240 std::optional<ASTImportError> OptErr =
6241 Importer->getImportDeclErrorIfAny(FromD: FromSpec);
6242 ASSERT_TRUE(OptErr);
6243 EXPECT_EQ(OptErr->Error, ASTImportError::NameConflict);
6244}
6245
6246// Check a case when a new AST node is created but not linked to the AST before
6247// encountering the error.
6248TEST_P(ErrorHandlingTest,
6249 ErrorHappensAfterCreatingTheNodeButBeforeLinkingThatToTheAST) {
6250 TranslationUnitDecl *FromTU = getTuDecl(
6251 SrcCode: std::string("void foo() { ") + ErroneousStmt + " }", Lang: Lang_CXX03);
6252 auto *FromFoo = FirstDeclMatcher<FunctionDecl>().match(
6253 FromTU, functionDecl(hasName(Name: "foo")));
6254
6255 FunctionDecl *ImportedFoo = Import(FromFoo, Lang_CXX03);
6256 EXPECT_FALSE(ImportedFoo);
6257
6258 TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
6259 // Created, but not linked.
6260 EXPECT_EQ(
6261 DeclCounter<FunctionDecl>().match(ToTU, functionDecl(hasName("foo"))),
6262 0u);
6263
6264 ASTImporter *Importer = findFromTU(From: FromFoo)->Importer.get();
6265 std::optional<ASTImportError> OptErr =
6266 Importer->getImportDeclErrorIfAny(FromD: FromFoo);
6267 ASSERT_TRUE(OptErr);
6268 EXPECT_EQ(OptErr->Error, ASTImportError::UnsupportedConstruct);
6269}
6270
6271// Check a case when a new AST node is created and linked to the AST before
6272// encountering the error. The error is set for the counterpart of the nodes in
6273// the "from" context.
6274TEST_P(ErrorHandlingTest, ErrorHappensAfterNodeIsCreatedAndLinked) {
6275 TranslationUnitDecl *FromTU = getTuDecl(SrcCode: std::string(R"(
6276 void f();
6277 void f() { )") + ErroneousStmt + R"( }
6278 )",
6279 Lang: Lang_CXX03);
6280 auto *FromProto = FirstDeclMatcher<FunctionDecl>().match(
6281 FromTU, functionDecl(hasName(Name: "f")));
6282 auto *FromDef =
6283 LastDeclMatcher<FunctionDecl>().match(FromTU, functionDecl(hasName(Name: "f")));
6284 FunctionDecl *ImportedProto = Import(FromProto, Lang_CXX03);
6285 EXPECT_FALSE(ImportedProto); // Could not import.
6286 // However, we created two nodes in the AST. 1) the fwd decl 2) the
6287 // definition. The definition is not added to its DC, but the fwd decl is
6288 // there.
6289 TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
6290 EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, functionDecl(hasName("f"))),
6291 1u);
6292 // Match the fwd decl.
6293 auto *ToProto =
6294 FirstDeclMatcher<FunctionDecl>().match(ToTU, functionDecl(hasName(Name: "f")));
6295 EXPECT_TRUE(ToProto);
6296 // An error is set to the counterpart in the "from" context both for the fwd
6297 // decl and the definition.
6298 ASTImporter *Importer = findFromTU(From: FromProto)->Importer.get();
6299 std::optional<ASTImportError> OptErr =
6300 Importer->getImportDeclErrorIfAny(FromD: FromProto);
6301 ASSERT_TRUE(OptErr);
6302 EXPECT_EQ(OptErr->Error, ASTImportError::UnsupportedConstruct);
6303 OptErr = Importer->getImportDeclErrorIfAny(FromD: FromDef);
6304 ASSERT_TRUE(OptErr);
6305 EXPECT_EQ(OptErr->Error, ASTImportError::UnsupportedConstruct);
6306}
6307
6308// An error should be set for a class if we cannot import one member.
6309TEST_P(ErrorHandlingTest, ErrorIsPropagatedFromMemberToClass) {
6310 TranslationUnitDecl *FromTU = getTuDecl(SrcCode: std::string(R"(
6311 class X {
6312 void f() { )") + ErroneousStmt + R"( } // This member has the error
6313 // during import.
6314 void ok(); // The error should not prevent importing this.
6315 }; // An error will be set for X too.
6316 )",
6317 Lang: Lang_CXX03);
6318 auto *FromX = FirstDeclMatcher<CXXRecordDecl>().match(
6319 FromTU, cxxRecordDecl(hasName(Name: "X")));
6320 CXXRecordDecl *ImportedX = Import(FromX, Lang_CXX03);
6321
6322 // An error is set for X.
6323 EXPECT_FALSE(ImportedX);
6324 ASTImporter *Importer = findFromTU(From: FromX)->Importer.get();
6325 std::optional<ASTImportError> OptErr =
6326 Importer->getImportDeclErrorIfAny(FromD: FromX);
6327 ASSERT_TRUE(OptErr);
6328 EXPECT_EQ(OptErr->Error, ASTImportError::UnsupportedConstruct);
6329
6330 // An error is set for f().
6331 auto *FromF = FirstDeclMatcher<CXXMethodDecl>().match(
6332 FromTU, cxxMethodDecl(hasName(Name: "f")));
6333 OptErr = Importer->getImportDeclErrorIfAny(FromD: FromF);
6334 ASSERT_TRUE(OptErr);
6335 EXPECT_EQ(OptErr->Error, ASTImportError::UnsupportedConstruct);
6336 // And any subsequent import should fail.
6337 CXXMethodDecl *ImportedF = Import(FromF, Lang_CXX03);
6338 EXPECT_FALSE(ImportedF);
6339
6340 // There is an error set for the other member too.
6341 auto *FromOK = FirstDeclMatcher<CXXMethodDecl>().match(
6342 FromTU, cxxMethodDecl(hasName(Name: "ok")));
6343 OptErr = Importer->getImportDeclErrorIfAny(FromD: FromOK);
6344 EXPECT_TRUE(OptErr);
6345 // Cannot import the other member.
6346 CXXMethodDecl *ImportedOK = Import(FromOK, Lang_CXX03);
6347 EXPECT_FALSE(ImportedOK);
6348}
6349
6350// Check that an error propagates to the dependent AST nodes.
6351// In the below code it means that an error in X should propagate to A.
6352// And even to F since the containing A is erroneous.
6353// And to all AST nodes which we visit during the import process which finally
6354// ends up in a failure (in the error() function).
6355TEST_P(ErrorHandlingTest, ErrorPropagatesThroughImportCycles) {
6356 Decl *FromTU = getTuDecl(SrcCode: std::string(R"(
6357 namespace NS {
6358 class A {
6359 template <int I> class F {};
6360 class X {
6361 template <int I> friend class F;
6362 void error() { )") +
6363 ErroneousStmt + R"( }
6364 };
6365 };
6366
6367 class B {};
6368 } // NS
6369 )",
6370 Lang: Lang_CXX03, FileName: "input0.cc");
6371
6372 auto *FromFRD = FirstDeclMatcher<CXXRecordDecl>().match(
6373 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "F"), isDefinition()));
6374 auto *FromA = FirstDeclMatcher<CXXRecordDecl>().match(
6375 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A"), isDefinition()));
6376 auto *FromB = FirstDeclMatcher<CXXRecordDecl>().match(
6377 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "B"), isDefinition()));
6378 auto *FromNS = FirstDeclMatcher<NamespaceDecl>().match(
6379 D: FromTU, AMatcher: namespaceDecl(hasName(Name: "NS")));
6380
6381 // Start by importing the templated CXXRecordDecl of F.
6382 // Import fails for that.
6383 EXPECT_FALSE(Import(FromFRD, Lang_CXX03));
6384 // Import fails for A.
6385 EXPECT_FALSE(Import(FromA, Lang_CXX03));
6386 // But we should be able to import the independent B.
6387 EXPECT_TRUE(Import(FromB, Lang_CXX03));
6388 // And the namespace.
6389 EXPECT_TRUE(Import(FromNS, Lang_CXX03));
6390
6391 // An error is set to the templated CXXRecordDecl of F.
6392 ASTImporter *Importer = findFromTU(From: FromFRD)->Importer.get();
6393 std::optional<ASTImportError> OptErr =
6394 Importer->getImportDeclErrorIfAny(FromD: FromFRD);
6395 EXPECT_TRUE(OptErr);
6396
6397 // An error is set to A.
6398 OptErr = Importer->getImportDeclErrorIfAny(FromD: FromA);
6399 EXPECT_TRUE(OptErr);
6400
6401 // There is no error set to B.
6402 OptErr = Importer->getImportDeclErrorIfAny(FromD: FromB);
6403 EXPECT_FALSE(OptErr);
6404
6405 // There is no error set to NS.
6406 OptErr = Importer->getImportDeclErrorIfAny(FromD: FromNS);
6407 EXPECT_FALSE(OptErr);
6408
6409 // Check some of those decls whose ancestor is X, they all should have an
6410 // error set if we visited them during an import process which finally failed.
6411 // These decls are part of a cycle in an ImportPath.
6412 // There would not be any error set for these decls if we hadn't follow the
6413 // ImportPaths and the cycles.
6414 OptErr = Importer->getImportDeclErrorIfAny(
6415 FirstDeclMatcher<ClassTemplateDecl>().match(
6416 D: FromTU, AMatcher: classTemplateDecl(hasName(Name: "F"))));
6417 // An error is set to the 'F' ClassTemplateDecl.
6418 EXPECT_TRUE(OptErr);
6419 // An error is set to the FriendDecl.
6420 OptErr = Importer->getImportDeclErrorIfAny(
6421 FirstDeclMatcher<FriendDecl>().match(
6422 D: FromTU, AMatcher: friendDecl()));
6423 EXPECT_TRUE(OptErr);
6424 // An error is set to the implicit class of A.
6425 OptErr =
6426 Importer->getImportDeclErrorIfAny(FirstDeclMatcher<CXXRecordDecl>().match(
6427 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A"), isImplicit())));
6428 EXPECT_TRUE(OptErr);
6429 // An error is set to the implicit class of X.
6430 OptErr =
6431 Importer->getImportDeclErrorIfAny(FirstDeclMatcher<CXXRecordDecl>().match(
6432 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "X"), isImplicit())));
6433 EXPECT_TRUE(OptErr);
6434}
6435
6436TEST_P(ErrorHandlingTest, ErrorIsNotPropagatedFromMemberToNamespace) {
6437 TranslationUnitDecl *FromTU = getTuDecl(SrcCode: std::string(R"(
6438 namespace X {
6439 void f() { )") + ErroneousStmt + R"( } // This member has the error
6440 // during import.
6441 void ok(); // The error should not prevent importing this.
6442 }; // An error will be set for X too.
6443 )",
6444 Lang: Lang_CXX03);
6445 auto *FromX = FirstDeclMatcher<NamespaceDecl>().match(
6446 FromTU, namespaceDecl(hasName(Name: "X")));
6447 NamespaceDecl *ImportedX = Import(FromX, Lang_CXX03);
6448
6449 // There is no error set for X.
6450 EXPECT_TRUE(ImportedX);
6451 ASTImporter *Importer = findFromTU(From: FromX)->Importer.get();
6452 std::optional<ASTImportError> OptErr =
6453 Importer->getImportDeclErrorIfAny(FromD: FromX);
6454 ASSERT_FALSE(OptErr);
6455
6456 // An error is set for f().
6457 auto *FromF = FirstDeclMatcher<FunctionDecl>().match(
6458 FromTU, functionDecl(hasName(Name: "f")));
6459 OptErr = Importer->getImportDeclErrorIfAny(FromD: FromF);
6460 ASSERT_TRUE(OptErr);
6461 EXPECT_EQ(OptErr->Error, ASTImportError::UnsupportedConstruct);
6462 // And any subsequent import should fail.
6463 FunctionDecl *ImportedF = Import(FromF, Lang_CXX03);
6464 EXPECT_FALSE(ImportedF);
6465
6466 // There is no error set for ok().
6467 auto *FromOK = FirstDeclMatcher<FunctionDecl>().match(
6468 FromTU, functionDecl(hasName(Name: "ok")));
6469 OptErr = Importer->getImportDeclErrorIfAny(FromD: FromOK);
6470 EXPECT_FALSE(OptErr);
6471 // And we should be able to import.
6472 FunctionDecl *ImportedOK = Import(FromOK, Lang_CXX03);
6473 EXPECT_TRUE(ImportedOK);
6474}
6475
6476TEST_P(ErrorHandlingTest, ODRViolationWithinTypedefDecls) {
6477 // Importing `z` should fail - instead of crashing - due to an ODR violation.
6478 // The `bar::e` typedef sets it's DeclContext after the import is done.
6479 // However, if the importation fails, it will be left as a nullptr.
6480 // During the cleanup of the failed import, we should check whether the
6481 // DeclContext is null or not - instead of dereferencing that unconditionally.
6482 constexpr auto ToTUCode = R"(
6483 namespace X {
6484 struct bar {
6485 int odr_violation;
6486 };
6487 })";
6488 constexpr auto FromTUCode = R"(
6489 namespace X {
6490 enum b {};
6491 struct bar {
6492 typedef b e;
6493 static e d;
6494 };
6495 }
6496 int z = X::bar::d;
6497 )";
6498 Decl *ToTU = getToTuDecl(ToSrcCode: ToTUCode, ToLang: Lang_CXX11);
6499 static_cast<void>(ToTU);
6500 Decl *FromTU = getTuDecl(SrcCode: FromTUCode, Lang: Lang_CXX11);
6501 auto *FromZ =
6502 FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: varDecl(hasName(Name: "z")));
6503 ASSERT_TRUE(FromZ);
6504 ASSERT_TRUE(FromZ->hasInit());
6505
6506 auto *ImportedZ = Import(FromZ, Lang_CXX11);
6507 EXPECT_FALSE(ImportedZ);
6508}
6509
6510// An error should be set for a class if it had a previous import with an error
6511// from another TU.
6512TEST_P(ErrorHandlingTest,
6513 ImportedDeclWithErrorShouldFailTheImportOfDeclWhichMapToIt) {
6514 // We already have a fwd decl.
6515 TranslationUnitDecl *ToTU = getToTuDecl(ToSrcCode: "class X;", ToLang: Lang_CXX03);
6516 // Then we import a definition.
6517 {
6518 TranslationUnitDecl *FromTU = getTuDecl(SrcCode: std::string(R"(
6519 class X {
6520 void f() { )") + ErroneousStmt + R"( }
6521 void ok();
6522 };
6523 )",
6524 Lang: Lang_CXX03);
6525 auto *FromX = FirstDeclMatcher<CXXRecordDecl>().match(
6526 FromTU, cxxRecordDecl(hasName(Name: "X")));
6527 CXXRecordDecl *ImportedX = Import(FromX, Lang_CXX03);
6528
6529 // An error is set for X ...
6530 EXPECT_FALSE(ImportedX);
6531 ASTImporter *Importer = findFromTU(From: FromX)->Importer.get();
6532 std::optional<ASTImportError> OptErr =
6533 Importer->getImportDeclErrorIfAny(FromD: FromX);
6534 ASSERT_TRUE(OptErr);
6535 EXPECT_EQ(OptErr->Error, ASTImportError::UnsupportedConstruct);
6536 }
6537 // ... but the node had been created.
6538 auto *ToXDef = FirstDeclMatcher<CXXRecordDecl>().match(
6539 ToTU, cxxRecordDecl(hasName(Name: "X"), isDefinition()));
6540 // An error is set for "ToXDef" in the shared state.
6541 std::optional<ASTImportError> OptErr =
6542 SharedStatePtr->getImportDeclErrorIfAny(ToD: ToXDef);
6543 ASSERT_TRUE(OptErr);
6544 EXPECT_EQ(OptErr->Error, ASTImportError::UnsupportedConstruct);
6545
6546 auto *ToXFwd = FirstDeclMatcher<CXXRecordDecl>().match(
6547 ToTU, cxxRecordDecl(hasName(Name: "X"), unless(isDefinition())));
6548 // An error is NOT set for the fwd Decl of X in the shared state.
6549 OptErr = SharedStatePtr->getImportDeclErrorIfAny(ToD: ToXFwd);
6550 ASSERT_FALSE(OptErr);
6551
6552 // Try to import X again but from another TU.
6553 {
6554 TranslationUnitDecl *FromTU = getTuDecl(SrcCode: std::string(R"(
6555 class X {
6556 void f() { )") + ErroneousStmt + R"( }
6557 void ok();
6558 };
6559 )",
6560 Lang: Lang_CXX03, FileName: "input1.cc");
6561
6562 auto *FromX = FirstDeclMatcher<CXXRecordDecl>().match(
6563 FromTU, cxxRecordDecl(hasName(Name: "X")));
6564 CXXRecordDecl *ImportedX = Import(FromX, Lang_CXX03);
6565
6566 // If we did not save the errors for the "to" context then the below checks
6567 // would fail, because the lookup finds the fwd Decl of the existing
6568 // definition in the "to" context. We can reach the existing definition via
6569 // the found fwd Decl. That existing definition is structurally equivalent
6570 // (we check only the fields) with this one we want to import, so we return
6571 // with the existing definition, which is erroneous (one method is missing).
6572
6573 // The import should fail.
6574 EXPECT_FALSE(ImportedX);
6575 ASTImporter *Importer = findFromTU(From: FromX)->Importer.get();
6576 std::optional<ASTImportError> OptErr =
6577 Importer->getImportDeclErrorIfAny(FromD: FromX);
6578 // And an error is set for this new X in the "from" ctx.
6579 ASSERT_TRUE(OptErr);
6580 EXPECT_EQ(OptErr->Error, ASTImportError::UnsupportedConstruct);
6581 }
6582}
6583
6584TEST_P(ErrorHandlingTest, ImportOfOverriddenMethods) {
6585 auto MatchFooA =
6586 functionDecl(hasName(Name: "foo"), hasAncestor(cxxRecordDecl(hasName(Name: "A"))));
6587 auto MatchFooB =
6588 functionDecl(hasName(Name: "foo"), hasAncestor(cxxRecordDecl(hasName(Name: "B"))));
6589 auto MatchFooC =
6590 functionDecl(hasName(Name: "foo"), hasAncestor(cxxRecordDecl(hasName(Name: "C"))));
6591
6592 // Provoke import of a method that has overridden methods with import error.
6593 TranslationUnitDecl *FromTU = getTuDecl(SrcCode: std::string(R"(
6594 struct C;
6595 struct A {
6596 virtual void foo();
6597 void f1(C *);
6598 };
6599 void A::foo() {
6600 )") + ErroneousStmt + R"(
6601 }
6602 struct B : public A {
6603 void foo() override;
6604 };
6605 struct C : public B {
6606 void foo() override;
6607 };
6608 )",
6609 Lang: Lang_CXX11);
6610 auto *FromFooA = FirstDeclMatcher<FunctionDecl>().match(FromTU, MatchFooA);
6611 auto *FromFooB = FirstDeclMatcher<FunctionDecl>().match(FromTU, MatchFooB);
6612 auto *FromFooC = FirstDeclMatcher<FunctionDecl>().match(FromTU, MatchFooC);
6613
6614 EXPECT_FALSE(Import(FromFooA, Lang_CXX11));
6615 ASTImporter *Importer = findFromTU(From: FromFooA)->Importer.get();
6616 auto CheckError = [&Importer](Decl *FromD) {
6617 std::optional<ASTImportError> OptErr =
6618 Importer->getImportDeclErrorIfAny(FromD);
6619 ASSERT_TRUE(OptErr);
6620 EXPECT_EQ(OptErr->Error, ASTImportError::UnsupportedConstruct);
6621 };
6622 CheckError(FromFooA);
6623 EXPECT_FALSE(Import(FromFooB, Lang_CXX11));
6624 CheckError(FromFooB);
6625 EXPECT_FALSE(Import(FromFooC, Lang_CXX11));
6626 CheckError(FromFooC);
6627}
6628
6629TEST_P(ErrorHandlingTest, ODRViolationWithinParmVarDecls) {
6630 // Importing of 'f' and parameter 'P' should cause an ODR error.
6631 // The error happens after the ParmVarDecl for 'P' was already created.
6632 // This is a special case because the ParmVarDecl has a temporary DeclContext.
6633 // Expected is no crash at error handling of ASTImporter.
6634 constexpr auto ToTUCode = R"(
6635 struct X {
6636 char A;
6637 };
6638 )";
6639 constexpr auto FromTUCode = R"(
6640 struct X {
6641 enum Y { Z };
6642 };
6643 void f(int P = X::Z);
6644 )";
6645 Decl *ToTU = getToTuDecl(ToSrcCode: ToTUCode, ToLang: Lang_CXX11);
6646 static_cast<void>(ToTU);
6647 Decl *FromTU = getTuDecl(SrcCode: FromTUCode, Lang: Lang_CXX11);
6648 auto *FromF = FirstDeclMatcher<FunctionDecl>().match(
6649 D: FromTU, AMatcher: functionDecl(hasName(Name: "f")));
6650 ASSERT_TRUE(FromF);
6651
6652 auto *ImportedF = Import(FromF, Lang_CXX11);
6653 EXPECT_FALSE(ImportedF);
6654}
6655
6656TEST_P(ErrorHandlingTest, DoNotInheritErrorFromNonDependentChild) {
6657 // Declarations should not inherit an import error from a child object
6658 // if the declaration has no direct dependence to such a child.
6659 // For example a namespace should not get import error if one of the
6660 // declarations inside it fails to import.
6661 // There was a special case in error handling (when "import path circles" are
6662 // encountered) when this property was not held. This case is provoked by the
6663 // following code.
6664 constexpr auto ToTUCode = R"(
6665 namespace ns {
6666 struct Err {
6667 char A;
6668 };
6669 }
6670 )";
6671 constexpr auto FromTUCode = R"(
6672 namespace ns {
6673 struct A {
6674 using U = struct Err;
6675 };
6676 }
6677 namespace ns {
6678 struct Err {}; // ODR violation
6679 void f(A) {}
6680 }
6681 )";
6682
6683 Decl *ToTU = getToTuDecl(ToSrcCode: ToTUCode, ToLang: Lang_CXX11);
6684 static_cast<void>(ToTU);
6685 Decl *FromTU = getTuDecl(SrcCode: FromTUCode, Lang: Lang_CXX11);
6686 auto *FromA = FirstDeclMatcher<CXXRecordDecl>().match(
6687 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A"), hasDefinition()));
6688 ASSERT_TRUE(FromA);
6689 auto *ImportedA = Import(FromA, Lang_CXX11);
6690 // 'A' can not be imported: ODR error at 'Err'
6691 EXPECT_FALSE(ImportedA);
6692 // When import of 'A' failed there was a "saved import path circle" that
6693 // contained namespace 'ns' (A - U - Err - ns - f - A). This should not mean
6694 // that every object in this path fails to import.
6695
6696 Decl *FromNS = FirstDeclMatcher<NamespaceDecl>().match(
6697 D: FromTU, AMatcher: namespaceDecl(hasName(Name: "ns")));
6698 EXPECT_TRUE(FromNS);
6699 auto *ImportedNS = Import(From: FromNS, ToLang: Lang_CXX11);
6700 EXPECT_TRUE(ImportedNS);
6701}
6702
6703TEST_P(ASTImporterOptionSpecificTestBase, LambdaInFunctionBody) {
6704 Decl *FromTU = getTuDecl(
6705 SrcCode: R"(
6706 void f() {
6707 auto L = [](){};
6708 }
6709 )",
6710 Lang: Lang_CXX11, FileName: "input0.cc");
6711 auto Pattern = lambdaExpr();
6712 CXXRecordDecl *FromL =
6713 FirstDeclMatcher<LambdaExpr>().match(D: FromTU, AMatcher: Pattern)->getLambdaClass();
6714
6715 auto ToL = Import(From: FromL, Lang: Lang_CXX11);
6716 unsigned ToLSize = std::distance(ToL->decls().begin(), ToL->decls().end());
6717 unsigned FromLSize =
6718 std::distance(FromL->decls().begin(), FromL->decls().end());
6719 EXPECT_NE(ToLSize, 0u);
6720 EXPECT_EQ(ToLSize, FromLSize);
6721 EXPECT_FALSE(FromL->isDependentLambda());
6722}
6723
6724TEST_P(ASTImporterOptionSpecificTestBase,
6725 ReturnTypeDeclaredInsideOfCXX11LambdaWithoutTrailingReturn) {
6726 Decl *From, *To;
6727 std::tie(args&: From, args&: To) = getImportedDecl(
6728 FromSrcCode: R"(
6729 void foo() {
6730 (void) []() {
6731 struct X {};
6732 return X();
6733 };
6734 }
6735 )",
6736 FromLang: Lang_CXX11, ToSrcCode: "", ToLang: Lang_CXX11, Identifier: "foo"); // c++11 only
6737 auto *ToLambda = FirstDeclMatcher<LambdaExpr>().match(D: To, AMatcher: lambdaExpr());
6738 EXPECT_TRUE(ToLambda);
6739}
6740
6741TEST_P(ASTImporterOptionSpecificTestBase, LambdaInFunctionParam) {
6742 Decl *FromTU = getTuDecl(
6743 SrcCode: R"(
6744 template <typename F>
6745 void f(F L = [](){}) {}
6746 )",
6747 Lang: Lang_CXX11, FileName: "input0.cc");
6748 auto Pattern = lambdaExpr();
6749 CXXRecordDecl *FromL =
6750 FirstDeclMatcher<LambdaExpr>().match(D: FromTU, AMatcher: Pattern)->getLambdaClass();
6751
6752 auto ToL = Import(From: FromL, Lang: Lang_CXX11);
6753 unsigned ToLSize = std::distance(ToL->decls().begin(), ToL->decls().end());
6754 unsigned FromLSize =
6755 std::distance(FromL->decls().begin(), FromL->decls().end());
6756 EXPECT_NE(ToLSize, 0u);
6757 EXPECT_EQ(ToLSize, FromLSize);
6758 EXPECT_TRUE(FromL->isDependentLambda());
6759}
6760
6761TEST_P(ASTImporterOptionSpecificTestBase, LambdaInGlobalScope) {
6762 Decl *FromTU = getTuDecl(
6763 SrcCode: R"(
6764 auto l1 = [](unsigned lp) { return 1; };
6765 auto l2 = [](int lp) { return 2; };
6766 int f(int p) {
6767 return l1(p) + l2(p);
6768 }
6769 )",
6770 Lang: Lang_CXX11, FileName: "input0.cc");
6771 FunctionDecl *FromF = FirstDeclMatcher<FunctionDecl>().match(
6772 D: FromTU, AMatcher: functionDecl(hasName(Name: "f")));
6773 FunctionDecl *ToF = Import(From: FromF, Lang: Lang_CXX11);
6774 EXPECT_TRUE(ToF);
6775}
6776
6777TEST_P(ASTImporterOptionSpecificTestBase,
6778 ImportExistingFriendClassTemplateDef) {
6779 auto Code =
6780 R"(
6781 template <class T1, class T2>
6782 struct Base {
6783 template <class U1, class U2>
6784 friend struct Class;
6785 };
6786 template <class T1, class T2>
6787 struct Class { };
6788 )";
6789
6790 TranslationUnitDecl *ToTU = getToTuDecl(ToSrcCode: Code, ToLang: Lang_CXX03);
6791 TranslationUnitDecl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX03, FileName: "input.cc");
6792
6793 auto *ToClassProto = FirstDeclMatcher<ClassTemplateDecl>().match(
6794 ToTU, classTemplateDecl(hasName(Name: "Class")));
6795 auto *ToClassDef = LastDeclMatcher<ClassTemplateDecl>().match(
6796 ToTU, classTemplateDecl(hasName(Name: "Class")));
6797 ASSERT_FALSE(ToClassProto->isThisDeclarationADefinition());
6798 ASSERT_TRUE(ToClassDef->isThisDeclarationADefinition());
6799 // Previous friend decl is not linked to it!
6800 ASSERT_FALSE(ToClassDef->getPreviousDecl());
6801 ASSERT_EQ(ToClassDef->getMostRecentDecl(), ToClassDef);
6802 ASSERT_EQ(ToClassProto->getMostRecentDecl(), ToClassProto);
6803
6804 auto *FromClassProto = FirstDeclMatcher<ClassTemplateDecl>().match(
6805 FromTU, classTemplateDecl(hasName(Name: "Class")));
6806 auto *FromClassDef = LastDeclMatcher<ClassTemplateDecl>().match(
6807 FromTU, classTemplateDecl(hasName(Name: "Class")));
6808 ASSERT_FALSE(FromClassProto->isThisDeclarationADefinition());
6809 ASSERT_TRUE(FromClassDef->isThisDeclarationADefinition());
6810 ASSERT_FALSE(FromClassDef->getPreviousDecl());
6811 ASSERT_EQ(FromClassDef->getMostRecentDecl(), FromClassDef);
6812 ASSERT_EQ(FromClassProto->getMostRecentDecl(), FromClassProto);
6813
6814 auto *ImportedDef = Import(FromClassDef, Lang_CXX03);
6815 // At import we should find the definition for 'Class' even if the
6816 // prototype (inside 'friend') for it comes first in the AST and is not
6817 // linked to the definition.
6818 EXPECT_EQ(ImportedDef, ToClassDef);
6819}
6820
6821struct LLDBLookupTest : ASTImporterOptionSpecificTestBase {
6822 LLDBLookupTest() {
6823 Creator = [](ASTContext &ToContext, FileManager &ToFileManager,
6824 ASTContext &FromContext, FileManager &FromFileManager,
6825 bool MinimalImport,
6826 const std::shared_ptr<ASTImporterSharedState> &SharedState) {
6827 return new ASTImporter(ToContext, ToFileManager, FromContext,
6828 FromFileManager, MinimalImport,
6829 // We use the regular lookup.
6830 /*SharedState=*/nullptr);
6831 };
6832 }
6833};
6834
6835TEST_P(LLDBLookupTest, ImporterShouldFindInTransparentContext) {
6836 TranslationUnitDecl *ToTU = getToTuDecl(
6837 ToSrcCode: R"(
6838 extern "C" {
6839 class X{};
6840 };
6841 )",
6842 ToLang: Lang_CXX03);
6843 auto *ToX = FirstDeclMatcher<CXXRecordDecl>().match(
6844 ToTU, cxxRecordDecl(hasName(Name: "X")));
6845
6846 // Set up a stub external storage.
6847 ToTU->setHasExternalLexicalStorage(true);
6848 // Set up DeclContextBits.HasLazyExternalLexicalLookups to true.
6849 ToTU->setMustBuildLookupTable();
6850 struct TestExternalASTSource : ExternalASTSource {};
6851 ToTU->getASTContext().setExternalSource(new TestExternalASTSource());
6852
6853 Decl *FromTU = getTuDecl(
6854 SrcCode: R"(
6855 class X;
6856 )",
6857 Lang: Lang_CXX03);
6858 auto *FromX = FirstDeclMatcher<CXXRecordDecl>().match(
6859 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "X")));
6860 auto *ImportedX = Import(FromX, Lang_CXX03);
6861 // The lookup must find the existing class definition in the LinkageSpecDecl.
6862 // Then the importer renders the existing and the new decl into one chain.
6863 EXPECT_EQ(ImportedX->getCanonicalDecl(), ToX->getCanonicalDecl());
6864}
6865
6866struct SVEBuiltins : ASTImporterOptionSpecificTestBase {};
6867
6868TEST_P(SVEBuiltins, ImportTypes) {
6869 static const char *const TypeNames[] = {
6870 "__SVInt8_t", "__SVInt16_t", "__SVInt32_t", "__SVInt64_t",
6871 "__SVUint8_t", "__SVUint16_t", "__SVUint32_t", "__SVUint64_t",
6872 "__SVFloat16_t", "__SVBfloat16_t", "__SVFloat32_t", "__SVFloat64_t",
6873 "__SVBool_t"};
6874
6875 TranslationUnitDecl *ToTU = getToTuDecl(ToSrcCode: "", ToLang: Lang_CXX03);
6876 TranslationUnitDecl *FromTU = getTuDecl(SrcCode: "", Lang: Lang_CXX03, FileName: "input.cc");
6877 for (auto *TypeName : TypeNames) {
6878 auto *ToTypedef = FirstDeclMatcher<TypedefDecl>().match(
6879 ToTU, typedefDecl(hasName(Name: TypeName)));
6880 QualType ToType = ToTypedef->getUnderlyingType();
6881
6882 auto *FromTypedef = FirstDeclMatcher<TypedefDecl>().match(
6883 FromTU, typedefDecl(hasName(Name: TypeName)));
6884 QualType FromType = FromTypedef->getUnderlyingType();
6885
6886 QualType ImportedType = ImportType(FromType, TUDecl: FromTypedef, ToLang: Lang_CXX03);
6887 EXPECT_EQ(ImportedType, ToType);
6888 }
6889}
6890
6891TEST_P(ASTImporterOptionSpecificTestBase, ImportOfDefaultImplicitFunctions) {
6892 // Test that import of implicit functions works and the functions
6893 // are merged into one chain.
6894 auto GetDeclToImport = [this](StringRef File) {
6895 Decl *FromTU = getTuDecl(
6896 SrcCode: R"(
6897 struct X { };
6898 // Force generating some implicit operator definitions for X.
6899 void f() { X x1, x2; x1 = x2; X *x3 = new X; delete x3; }
6900 )",
6901 Lang: Lang_CXX11, FileName: File);
6902 auto *FromD = FirstDeclMatcher<CXXRecordDecl>().match(
6903 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "X"), unless(isImplicit())));
6904 // Destructor is picked as one example of implicit function.
6905 return FromD->getDestructor();
6906 };
6907
6908 auto *ToD1 = Import(GetDeclToImport("input1.cc"), Lang_CXX11);
6909 ASSERT_TRUE(ToD1);
6910
6911 auto *ToD2 = Import(GetDeclToImport("input2.cc"), Lang_CXX11);
6912 ASSERT_TRUE(ToD2);
6913
6914 EXPECT_EQ(ToD1->getCanonicalDecl(), ToD2->getCanonicalDecl());
6915}
6916
6917TEST_P(ASTImporterOptionSpecificTestBase,
6918 ImportOfExplicitlyDefaultedOrDeleted) {
6919 Decl *FromTU = getTuDecl(
6920 SrcCode: R"(
6921 struct X { X() = default; X(const X&) = delete; };
6922 )",
6923 Lang: Lang_CXX11);
6924 auto *FromX = FirstDeclMatcher<CXXRecordDecl>().match(
6925 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "X")));
6926 auto *ImportedX = Import(FromX, Lang_CXX11);
6927 auto *Constr1 = FirstDeclMatcher<CXXConstructorDecl>().match(
6928 ImportedX, cxxConstructorDecl(hasName(Name: "X"), unless(isImplicit())));
6929 auto *Constr2 = LastDeclMatcher<CXXConstructorDecl>().match(
6930 ImportedX, cxxConstructorDecl(hasName(Name: "X"), unless(isImplicit())));
6931
6932 ASSERT_TRUE(ImportedX);
6933 EXPECT_TRUE(Constr1->isDefaulted());
6934 EXPECT_TRUE(Constr1->isExplicitlyDefaulted());
6935 EXPECT_TRUE(Constr2->isDeletedAsWritten());
6936 EXPECT_EQ(ImportedX->isAggregate(), FromX->isAggregate());
6937}
6938
6939INSTANTIATE_TEST_SUITE_P(ParameterizedTests, SVEBuiltins,
6940 ::testing::Values(std::vector<std::string>{
6941 "-target", "aarch64-linux-gnu"}));
6942
6943INSTANTIATE_TEST_SUITE_P(ParameterizedTests, DeclContextTest,
6944 ::testing::Values(std::vector<std::string>()));
6945
6946INSTANTIATE_TEST_SUITE_P(ParameterizedTests, CanonicalRedeclChain,
6947 ::testing::Values(std::vector<std::string>()));
6948
6949TEST_P(ASTImporterOptionSpecificTestBase, LambdasAreDifferentiated) {
6950 Decl *FromTU = getTuDecl(
6951 SrcCode: R"(
6952 void f() {
6953 auto L0 = [](){};
6954 auto L1 = [](){};
6955 }
6956 )",
6957 Lang: Lang_CXX11, FileName: "input0.cc");
6958 auto Pattern = lambdaExpr();
6959 CXXRecordDecl *FromL0 =
6960 FirstDeclMatcher<LambdaExpr>().match(D: FromTU, AMatcher: Pattern)->getLambdaClass();
6961 CXXRecordDecl *FromL1 =
6962 LastDeclMatcher<LambdaExpr>().match(D: FromTU, AMatcher: Pattern)->getLambdaClass();
6963 ASSERT_NE(FromL0, FromL1);
6964
6965 CXXRecordDecl *ToL0 = Import(From: FromL0, Lang: Lang_CXX11);
6966 CXXRecordDecl *ToL1 = Import(From: FromL1, Lang: Lang_CXX11);
6967 EXPECT_NE(ToL0, ToL1);
6968}
6969
6970TEST_P(ASTImporterOptionSpecificTestBase,
6971 LambdasInFunctionParamsAreDifferentiated) {
6972 Decl *FromTU = getTuDecl(
6973 SrcCode: R"(
6974 template <typename F0, typename F1>
6975 void f(F0 L0 = [](){}, F1 L1 = [](){}) {}
6976 )",
6977 Lang: Lang_CXX11, FileName: "input0.cc");
6978 auto Pattern = cxxRecordDecl(isLambda());
6979 CXXRecordDecl *FromL0 =
6980 FirstDeclMatcher<CXXRecordDecl>().match(D: FromTU, AMatcher: Pattern);
6981 CXXRecordDecl *FromL1 =
6982 LastDeclMatcher<CXXRecordDecl>().match(D: FromTU, AMatcher: Pattern);
6983 ASSERT_NE(FromL0, FromL1);
6984
6985 CXXRecordDecl *ToL0 = Import(From: FromL0, Lang: Lang_CXX11);
6986 CXXRecordDecl *ToL1 = Import(From: FromL1, Lang: Lang_CXX11);
6987 ASSERT_NE(ToL0, ToL1);
6988}
6989
6990TEST_P(ASTImporterOptionSpecificTestBase,
6991 LambdasInFunctionParamsAreDifferentiatedWhenMacroIsUsed) {
6992 Decl *FromTU = getTuDecl(
6993 SrcCode: R"(
6994 #define LAMBDA [](){}
6995 template <typename F0, typename F1>
6996 void f(F0 L0 = LAMBDA, F1 L1 = LAMBDA) {}
6997 )",
6998 Lang: Lang_CXX11, FileName: "input0.cc");
6999 auto Pattern = cxxRecordDecl(isLambda());
7000 CXXRecordDecl *FromL0 =
7001 FirstDeclMatcher<CXXRecordDecl>().match(D: FromTU, AMatcher: Pattern);
7002 CXXRecordDecl *FromL1 =
7003 LastDeclMatcher<CXXRecordDecl>().match(D: FromTU, AMatcher: Pattern);
7004 ASSERT_NE(FromL0, FromL1);
7005
7006 Import(From: FromL0, Lang: Lang_CXX11);
7007 Import(From: FromL1, Lang: Lang_CXX11);
7008 CXXRecordDecl *ToL0 = Import(From: FromL0, Lang: Lang_CXX11);
7009 CXXRecordDecl *ToL1 = Import(From: FromL1, Lang: Lang_CXX11);
7010 ASSERT_NE(ToL0, ToL1);
7011}
7012
7013TEST_P(ASTImporterOptionSpecificTestBase, ImportAssignedLambda) {
7014 Decl *FromTU = getTuDecl(
7015 SrcCode: R"(
7016 void f() {
7017 auto x = []{} = {}; auto x2 = x;
7018 }
7019 )",
7020 Lang: Lang_CXX20, FileName: "input0.cc");
7021 auto FromF = FirstDeclMatcher<FunctionDecl>().match(
7022 D: FromTU, AMatcher: functionDecl(hasName(Name: "f")));
7023 // We have only one lambda class.
7024 ASSERT_EQ(
7025 DeclCounter<CXXRecordDecl>().match(FromTU, cxxRecordDecl(isLambda())),
7026 1u);
7027
7028 FunctionDecl *ToF = Import(FromF, Lang_CXX20);
7029 EXPECT_TRUE(ToF);
7030 TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
7031 // We have only one lambda class after the import.
7032 EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, cxxRecordDecl(isLambda())),
7033 1u);
7034}
7035
7036TEST_P(ASTImporterOptionSpecificTestBase, ImportDefaultConstructibleLambdas) {
7037 Decl *FromTU = getTuDecl(
7038 SrcCode: R"(
7039 void f() {
7040 auto x = []{} = {};
7041 auto xb = []{} = {};
7042 }
7043 )",
7044 Lang: Lang_CXX20, FileName: "input0.cc");
7045 auto FromF = FirstDeclMatcher<FunctionDecl>().match(
7046 D: FromTU, AMatcher: functionDecl(hasName(Name: "f")));
7047 // We have two lambda classes.
7048 ASSERT_EQ(
7049 DeclCounter<CXXRecordDecl>().match(FromTU, cxxRecordDecl(isLambda())),
7050 2u);
7051
7052 FunctionDecl *ToF = Import(FromF, Lang_CXX20);
7053 EXPECT_TRUE(ToF);
7054 TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
7055 // We have two lambda classes after the import.
7056 EXPECT_EQ(DeclCounter<CXXRecordDecl>().match(ToTU, cxxRecordDecl(isLambda())),
7057 2u);
7058}
7059
7060TEST_P(ASTImporterOptionSpecificTestBase,
7061 ImportFunctionDeclWithTypeSourceInfoWithSourceDecl) {
7062 // This code results in a lambda with implicit constructor.
7063 // The constructor's TypeSourceInfo points out the function prototype.
7064 // This prototype has an EST_Unevaluated in its exception information and a
7065 // SourceDecl that is the function declaration itself.
7066 // The test verifies that AST import of such AST does not crash.
7067 // (Here the function's TypeSourceInfo references the function itself.)
7068 Decl *FromTU = getTuDecl(
7069 SrcCode: R"(
7070 template<typename T> void f(T) { auto X = [](){}; }
7071 void g() { f(10); }
7072 )",
7073 Lang: Lang_CXX11, FileName: "input0.cc");
7074
7075 // Use LastDeclMatcher to find the LambdaExpr in the template specialization.
7076 CXXRecordDecl *FromL = LastDeclMatcher<LambdaExpr>()
7077 .match(D: FromTU, AMatcher: lambdaExpr())
7078 ->getLambdaClass();
7079
7080 CXXConstructorDecl *FromCtor = *FromL->ctor_begin();
7081 ASSERT_TRUE(FromCtor->isCopyConstructor());
7082 ASSERT_TRUE(FromCtor->getTypeSourceInfo());
7083 const auto *FromFPT = FromCtor->getType()->getAs<FunctionProtoType>();
7084 ASSERT_TRUE(FromFPT);
7085 EXPECT_EQ(FromCtor->getTypeSourceInfo()->getType().getTypePtr(), FromFPT);
7086 FunctionProtoType::ExtProtoInfo FromEPI = FromFPT->getExtProtoInfo();
7087 // If type is EST_Unevaluated, SourceDecl should be set to the parent Decl.
7088 EXPECT_EQ(FromEPI.ExceptionSpec.Type, EST_Unevaluated);
7089 EXPECT_EQ(FromEPI.ExceptionSpec.SourceDecl, FromCtor);
7090
7091 auto ToL = Import(From: FromL, Lang: Lang_CXX11);
7092
7093 // Check if the import was correct.
7094 CXXConstructorDecl *ToCtor = *ToL->ctor_begin();
7095 EXPECT_TRUE(ToCtor->getTypeSourceInfo());
7096 const auto *ToFPT = ToCtor->getType()->getAs<FunctionProtoType>();
7097 ASSERT_TRUE(ToFPT);
7098 EXPECT_EQ(ToCtor->getTypeSourceInfo()->getType().getTypePtr(), ToFPT);
7099 FunctionProtoType::ExtProtoInfo ToEPI = ToFPT->getExtProtoInfo();
7100 EXPECT_EQ(ToEPI.ExceptionSpec.Type, EST_Unevaluated);
7101 EXPECT_EQ(ToEPI.ExceptionSpec.SourceDecl, ToCtor);
7102}
7103
7104struct ImportAutoFunctions : ASTImporterOptionSpecificTestBase {
7105 void testImport(llvm::StringRef Code, clang::TestLanguage Lang = Lang_CXX14,
7106 bool FindLast = false) {
7107 Decl *FromTU = getTuDecl(SrcCode: Code, Lang, FileName: "input0.cc");
7108 FunctionDecl *From = FindLast ? LastDeclMatcher<FunctionDecl>().match(
7109 D: FromTU, AMatcher: functionDecl(hasName(Name: "foo")))
7110 : FirstDeclMatcher<FunctionDecl>().match(
7111 D: FromTU, AMatcher: functionDecl(hasName(Name: "foo")));
7112
7113 FunctionDecl *To = Import(From, Lang);
7114 EXPECT_TRUE(To);
7115 // We check here only that the type is auto type.
7116 // These tests are to verify that no crash happens.
7117 // The crash possibility is the presence of a reference to a declaration
7118 // in the function's body from the return type, if the function has auto
7119 // return type.
7120 EXPECT_TRUE(isa<AutoType>(To->getReturnType()));
7121 }
7122};
7123
7124TEST_P(ImportAutoFunctions, ReturnWithFunctionTemplate1) {
7125 testImport(
7126 Code: R"(
7127 template<class C>
7128 C f1() { return C(); }
7129 auto foo() {
7130 struct B {};
7131 return f1<B>();
7132 }
7133 )");
7134}
7135
7136TEST_P(ImportAutoFunctions, ReturnWithFunctionTemplate2) {
7137 testImport(
7138 Code: R"(
7139 template<class T>
7140 int f1(T t) { return 1; }
7141 auto foo() {
7142 struct B {};
7143 return f1(B());
7144 }
7145 )");
7146}
7147
7148TEST_P(ImportAutoFunctions, ReturnWithFunctionTemplate3) {
7149 testImport(
7150 Code: R"(
7151 template<class A> struct S1 {};
7152 template<class A> struct S2 {};
7153 template<class C>
7154 S1<C> f1() { return S1<C>(); }
7155 auto foo() {
7156 struct B {};
7157 return f1<S2<B *>>();
7158 }
7159 )");
7160}
7161
7162TEST_P(ImportAutoFunctions, ReturnWithFunctionTemplate4) {
7163 testImport(
7164 Code: R"(
7165 template<class... A> struct S1 {};
7166 template<class... A> struct S2 {};
7167 template<class... C>
7168 S1<C...> f1() { return S1<C...>(); }
7169 auto foo() {
7170 struct B {};
7171 return f1<S2<int, B *>, bool>();
7172 }
7173 )");
7174}
7175
7176TEST_P(ImportAutoFunctions, ReturnWithVarTemplate1) {
7177 testImport(
7178 Code: R"(
7179 template<class T> T X;
7180 auto foo() {
7181 struct A {};
7182 return X<A>;
7183 }
7184 )");
7185}
7186
7187TEST_P(ImportAutoFunctions, ReturnWithVarTemplate2) {
7188 testImport(
7189 Code: R"(
7190 template<class A> struct S1 {};
7191 template<class T> S1<T> X;
7192 auto foo() {
7193 struct A {};
7194 return X<S1<A>>;
7195 }
7196 )");
7197}
7198
7199TEST_P(ImportAutoFunctions, ReturnWithVarTemplate3) {
7200 testImport(
7201 Code: R"(
7202 template<class... A> struct S1 {};
7203 template<class... T> S1<T...> X;
7204 auto foo() {
7205 struct A {};
7206 return X<bool, S1<A, int>>;
7207 }
7208 )");
7209}
7210
7211TEST_P(ImportAutoFunctions, ReturnWithAutoUnresolvedArg) {
7212 testImport(
7213 Code: R"(
7214 template<int A>
7215 auto foo() {
7216 return 22;
7217 }
7218 )");
7219}
7220
7221TEST_P(ImportAutoFunctions, ReturnWithTemplateWithTemplateTemplateArg) {
7222 // FIXME: Is it possible to have the template arg inside the function?
7223 testImport(
7224 Code: R"(
7225 template<int> struct Tmpl {};
7226 template<template<int> class> struct TmplTmpl {};
7227 auto foo() {
7228 return TmplTmpl<Tmpl>();
7229 }
7230 )");
7231}
7232
7233TEST_P(ImportAutoFunctions, ReturnWithTemplateWithDeclarationTemplateArg) {
7234 // FIXME: Is it possible to have the template arg inside the function?
7235 testImport(
7236 Code: R"(
7237 template<const int *> struct Tmpl {};
7238 int A[10];
7239 auto foo() {
7240 return Tmpl<A>();
7241 }
7242 )");
7243}
7244
7245TEST_P(ImportAutoFunctions, ReturnWithTemplateWithNullPtrTemplateArg) {
7246 testImport(
7247 Code: R"(
7248 template<int *> struct Tmpl {};
7249 auto foo() {
7250 constexpr int* A = nullptr;
7251 return Tmpl<A>();
7252 }
7253 )");
7254}
7255
7256TEST_P(ImportAutoFunctions, ReturnWithTemplateWithIntegralTemplateArg) {
7257 testImport(
7258 Code: R"(
7259 template<int> struct Tmpl {};
7260 auto foo() {
7261 using Int = int;
7262 constexpr Int A = 7;
7263 return Tmpl<A>();
7264 }
7265 )");
7266}
7267
7268TEST_P(ImportAutoFunctions, ReturnWithTemplateWithDecltypeTypeDeclaredInside) {
7269 testImport(
7270 Code: R"(
7271 template<class> struct Tmpl {};
7272 auto foo() {
7273 struct X {};
7274 X x;
7275 return Tmpl<decltype(x)>();
7276 }
7277 )");
7278}
7279
7280TEST_P(ImportAutoFunctions, ReturnWithTemplateWithUsingTypeDeclaredInside) {
7281 testImport(
7282 Code: R"(
7283 template<class> struct Tmpl {};
7284 namespace A { struct X {}; }
7285 auto foo() {
7286 using A::X;
7287 return Tmpl<X>();
7288 }
7289 )");
7290}
7291
7292TEST_P(ImportAutoFunctions, ReturnWithTemplateWithArrayTypeDeclaredInside) {
7293 testImport(
7294 Code: R"(
7295 template<class> struct Tmpl {};
7296 auto foo() {
7297 struct X {};
7298 return Tmpl<X[10]>();
7299 }
7300 )");
7301}
7302
7303TEST_P(ImportAutoFunctions, ReturnWithTemplateWithArraySizeExprDeclaredInside) {
7304 testImport(
7305 Code: R"(
7306 template<class> struct Tmpl {};
7307 auto foo() {
7308 constexpr int S = 10;
7309 return Tmpl<int[S]>();
7310 }
7311 )");
7312}
7313
7314TEST_P(ImportAutoFunctions, ReturnWithTemplateWithPackArgDeclaredInside) {
7315 testImport(
7316 Code: R"(
7317 template<class ...> struct Tmpl {};
7318 auto foo() {
7319 using X = bool;
7320 return Tmpl<int, X>();
7321 }
7322 )");
7323}
7324
7325TEST_P(ImportAutoFunctions, ReturnWithTemplateWithIntegerArgDeclaredInside) {
7326 testImport(
7327 Code: R"(
7328 template<int> struct Tmpl {};
7329 auto foo() {
7330 constexpr int X = 1;
7331 return Tmpl<X>();
7332 }
7333 )");
7334}
7335
7336TEST_P(ImportAutoFunctions, ReturnWithTemplateWithPtrToStructDeclaredInside) {
7337 testImport(
7338 Code: R"(
7339 template<class> struct Tmpl {};
7340 auto foo() {
7341 struct X {};
7342 return Tmpl<X *>();
7343 }
7344 )");
7345}
7346
7347TEST_P(ImportAutoFunctions, ReturnWithTemplateWithRefToStructDeclaredInside) {
7348 testImport(
7349 Code: R"(
7350 template<class> struct Tmpl {};
7351 struct X {};
7352 auto foo() {
7353 using Y = X;
7354 return Tmpl<Y &>();
7355 }
7356 )");
7357}
7358
7359TEST_P(ImportAutoFunctions, ReturnWithTemplateWithStructDeclaredInside1) {
7360 testImport(
7361 Code: R"(
7362 template<class> struct Tmpl {};
7363 auto foo() {
7364 struct X {};
7365 return Tmpl<X>();
7366 }
7367 )");
7368}
7369
7370TEST_P(ImportAutoFunctions, ReturnWithTemplateWithStructDeclaredInside2) {
7371 testImport(
7372 Code: R"(
7373 template<class> struct Tmpl {};
7374 auto foo() {
7375 struct X {};
7376 return Tmpl<Tmpl<X>>();
7377 }
7378 )");
7379}
7380
7381TEST_P(ImportAutoFunctions, ReturnWithTemplateWithTypedefDeclaredInside) {
7382 testImport(
7383 Code: R"(
7384 template<class> struct Tmpl {};
7385 auto foo() {
7386 struct X {};
7387 using x_type = X;
7388 return Tmpl<x_type>();
7389 }
7390 )");
7391}
7392
7393TEST_P(ImportAutoFunctions, ReturnWithTypedefDeclaredInside) {
7394 Decl *FromTU = getTuDecl(
7395 SrcCode: R"(
7396 auto X = [](long l) {
7397 using int_type = long;
7398 auto dur = 13;
7399 return static_cast<int_type>(dur);
7400 };
7401 )",
7402 Lang: Lang_CXX14, FileName: "input0.cc");
7403 CXXMethodDecl *From =
7404 FirstDeclMatcher<CXXMethodDecl>().match(D: FromTU, AMatcher: cxxMethodDecl());
7405
7406 // Explicitly set the return type of the lambda's operator() to the TypeAlias.
7407 // Normally the return type would be the built-in 'long' type. However, there
7408 // are cases when Clang does not use the canonical type and the TypeAlias is
7409 // used. I could not create such an AST from regular source code, it requires
7410 // some special state in the preprocessor. I've found such an AST when Clang
7411 // parsed libcxx/src/filesystem/directory_iterator.cpp, but could not reduce
7412 // that with creduce, because after preprocessing, the AST no longer
7413 // contained the TypeAlias as a return type of the lambda.
7414 ASTContext &Ctx = From->getASTContext();
7415 TypeAliasDecl *FromTA =
7416 FirstDeclMatcher<TypeAliasDecl>().match(D: FromTU, AMatcher: typeAliasDecl());
7417 QualType TT = Ctx.getTypedefType(FromTA);
7418 const FunctionProtoType *FPT = cast<FunctionProtoType>(From->getType());
7419 QualType NewFunType =
7420 Ctx.getFunctionType(ResultTy: TT, Args: FPT->getParamTypes(), EPI: FPT->getExtProtoInfo());
7421 From->setType(NewFunType);
7422
7423 CXXMethodDecl *To = Import(From, Lang: Lang_CXX14);
7424 EXPECT_TRUE(To);
7425 EXPECT_TRUE(isa<TypedefType>(To->getReturnType()));
7426}
7427
7428TEST_P(ImportAutoFunctions, ReturnWithStructDeclaredInside) {
7429 testImport(
7430 Code: R"(
7431 auto foo() {
7432 struct X {};
7433 return X();
7434 }
7435 )");
7436}
7437
7438TEST_P(ImportAutoFunctions, ReturnWithStructDeclaredInside2) {
7439 Decl *FromTU = getTuDecl(
7440 SrcCode: R"(
7441 auto foo() {
7442 struct X {};
7443 return X();
7444 }
7445 )",
7446 Lang: Lang_CXX14, FileName: "input0.cc");
7447 FunctionDecl *From =
7448 FirstDeclMatcher<FunctionDecl>().match(D: FromTU, AMatcher: functionDecl());
7449
7450 // This time import the type directly.
7451 QualType ToT = ImportType(FromType: From->getType(), TUDecl: From, ToLang: Lang_CXX14);
7452 const FunctionProtoType *FPT = cast<FunctionProtoType>(Val&: ToT);
7453 EXPECT_TRUE(isa<AutoType>(FPT->getReturnType()));
7454}
7455
7456TEST_P(ImportAutoFunctions, ReturnWithStructDeclaredInside3) {
7457 Decl *FromTU = getTuDecl(
7458 SrcCode: R"(
7459 struct S {
7460 constexpr auto foo();
7461 };
7462 constexpr auto S::foo() {
7463 struct X {};
7464 return X();
7465 }
7466 )",
7467 Lang: Lang_CXX14, FileName: "input0.cc");
7468 FunctionDecl *From = FirstDeclMatcher<FunctionDecl>().match(
7469 D: FromTU, AMatcher: functionDecl(hasName(Name: "foo"), unless(hasBody(InnerMatcher: stmt()))));
7470 ASSERT_FALSE(From->isThisDeclarationADefinition());
7471
7472 FunctionDecl *To = Import(From, Lang: Lang_CXX17);
7473 EXPECT_TRUE(To);
7474 EXPECT_TRUE(isa<AutoType>(To->getReturnType()));
7475 EXPECT_FALSE(To->isThisDeclarationADefinition());
7476}
7477
7478TEST_P(ImportAutoFunctions, ReturnWithTypedefToStructDeclaredInside) {
7479 testImport(
7480 Code: R"(
7481 auto foo() {
7482 struct X {};
7483 using Y = X;
7484 return Y();
7485 }
7486 )");
7487}
7488
7489TEST_P(ImportAutoFunctions, ReturnWithStructDeclaredNestedInside) {
7490 testImport(
7491 Code: R"(
7492 auto foo() {
7493 struct X { struct Y{}; };
7494 return X::Y();
7495 }
7496 )");
7497}
7498
7499TEST_P(ImportAutoFunctions, ReturnWithInternalLambdaType) {
7500 testImport(
7501 Code: R"(
7502 auto foo() {
7503 auto l = []() {
7504 struct X {};
7505 return X();
7506 };
7507 return l();
7508 }
7509 )",
7510 Lang: Lang_CXX17);
7511}
7512
7513TEST_P(ImportAutoFunctions, ReturnWithTypeInIf) {
7514 testImport(
7515 Code: R"(
7516 auto foo() {
7517 if (struct X {} x; true)
7518 return X();
7519 else
7520 return X();
7521 }
7522 )",
7523 Lang: Lang_CXX17);
7524}
7525
7526TEST_P(ImportAutoFunctions, ReturnWithTypeInFor) {
7527 testImport(
7528 Code: R"(
7529 auto foo() {
7530 for (struct X {} x;;)
7531 return X();
7532 }
7533 )",
7534 Lang: Lang_CXX17);
7535}
7536
7537TEST_P(ImportAutoFunctions, ReturnWithTypeInSwitch) {
7538 testImport(
7539 Code: R"(
7540 auto foo() {
7541 switch (struct X {} x; 10) {
7542 case 10:
7543 return X();
7544 }
7545 }
7546 )",
7547 Lang: Lang_CXX17);
7548}
7549
7550TEST_P(ImportAutoFunctions, ReturnWithAutoTemplateType) {
7551 testImport(
7552 Code: R"(
7553 template<class T>
7554 struct S {};
7555 template<class T>
7556 auto foo() {
7557 return S<T>{};
7558 }
7559 auto a = foo<int>();
7560 )",
7561 Lang: Lang_CXX14, /*FindLast=*/true);
7562}
7563
7564TEST_P(ImportAutoFunctions, ReturnWithSubstNonTypeTemplateParmExpr) {
7565 const char *Code =
7566 R"(
7567 template<int>
7568 struct array {};
7569
7570 template <int N>
7571 auto foo() { return array<N>(); }
7572
7573 void bar() { foo<0>(); }
7574 )";
7575 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX17);
7576
7577 auto *FromBar = FirstDeclMatcher<FunctionDecl>().match(
7578 D: FromTU, AMatcher: functionDecl(hasName(Name: "bar")));
7579
7580 auto *ToBar = Import(FromBar, Lang_CXX17);
7581 EXPECT_TRUE(ToBar);
7582}
7583
7584struct ImportSourceLocations : ASTImporterOptionSpecificTestBase {};
7585
7586TEST_P(ImportSourceLocations, PreserveFileIDTreeStructure) {
7587 // Tests that the FileID tree structure (with the links being the include
7588 // chains) is preserved while importing other files (which need to be
7589 // added to this structure with fake include locations.
7590
7591 SourceLocation Location1;
7592 {
7593 auto Pattern = varDecl(hasName(Name: "X"));
7594 Decl *FromTU = getTuDecl(SrcCode: "int X;", Lang: Lang_C99, FileName: "input0.c");
7595 auto *FromD = FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: Pattern);
7596
7597 Location1 = Import(FromD, Lang_C99)->getLocation();
7598 }
7599 SourceLocation Location2;
7600 {
7601 auto Pattern = varDecl(hasName(Name: "Y"));
7602 Decl *FromTU = getTuDecl(SrcCode: "int Y;", Lang: Lang_C99, FileName: "input1.c");
7603 auto *FromD = FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: Pattern);
7604
7605 Location2 = Import(FromD, Lang_C99)->getLocation();
7606 }
7607
7608 SourceManager &ToSM = ToAST->getSourceManager();
7609 FileID FileID1 = ToSM.getFileID(SpellingLoc: Location1);
7610 FileID FileID2 = ToSM.getFileID(SpellingLoc: Location2);
7611
7612 // Check that the imported files look like as if they were included from the
7613 // start of the main file.
7614 SourceLocation FileStart = ToSM.getLocForStartOfFile(FID: ToSM.getMainFileID());
7615 EXPECT_NE(FileID1, ToSM.getMainFileID());
7616 EXPECT_NE(FileID2, ToSM.getMainFileID());
7617 EXPECT_EQ(ToSM.getIncludeLoc(FileID1), FileStart);
7618 EXPECT_EQ(ToSM.getIncludeLoc(FileID2), FileStart);
7619
7620 // Let the SourceManager check the order of the locations. The order should
7621 // be the order in which the declarations are imported.
7622 EXPECT_TRUE(ToSM.isBeforeInTranslationUnit(Location1, Location2));
7623 EXPECT_FALSE(ToSM.isBeforeInTranslationUnit(Location2, Location1));
7624}
7625
7626TEST_P(ImportSourceLocations, NormalFileBuffer) {
7627 // Test importing normal file buffers.
7628
7629 std::string Path = "input0.c";
7630 std::string Source = "int X;";
7631 TranslationUnitDecl *FromTU = getTuDecl(SrcCode: Source, Lang: Lang_C99, FileName: Path);
7632
7633 SourceLocation ImportedLoc;
7634 {
7635 // Import the VarDecl to trigger the importing of the FileID.
7636 auto Pattern = varDecl(hasName(Name: "X"));
7637 VarDecl *FromD = FirstDeclMatcher<VarDecl>().match(FromTU, Pattern);
7638 ImportedLoc = Import(From: FromD, Lang: Lang_C99)->getLocation();
7639 }
7640
7641 // Make sure the imported buffer has the original contents.
7642 SourceManager &ToSM = ToAST->getSourceManager();
7643 FileID ImportedID = ToSM.getFileID(SpellingLoc: ImportedLoc);
7644 EXPECT_EQ(Source,
7645 ToSM.getBufferOrFake(ImportedID, SourceLocation()).getBuffer());
7646}
7647
7648TEST_P(ImportSourceLocations, OverwrittenFileBuffer) {
7649 // Test importing overwritten file buffers.
7650
7651 std::string Path = "input0.c";
7652 TranslationUnitDecl *FromTU = getTuDecl(SrcCode: "int X;", Lang: Lang_C99, FileName: Path);
7653
7654 // Overwrite the file buffer for our input file with new content.
7655 const std::string Contents = "overwritten contents";
7656 SourceLocation ImportedLoc;
7657 {
7658 SourceManager &FromSM = FromTU->getASTContext().getSourceManager();
7659 clang::FileManager &FM = FromSM.getFileManager();
7660 clang::FileEntryRef FE =
7661 FM.getVirtualFileRef(Filename: Path, Size: static_cast<off_t>(Contents.size()), ModificationTime: 0);
7662
7663 llvm::SmallVector<char, 64> Buffer;
7664 Buffer.append(in_start: Contents.begin(), in_end: Contents.end());
7665 auto FileContents = std::make_unique<llvm::SmallVectorMemoryBuffer>(
7666 args: std::move(Buffer), args&: Path, /*RequiresNullTerminator=*/args: false);
7667 FromSM.overrideFileContents(SourceFile: FE, Buffer: std::move(FileContents));
7668
7669 // Import the VarDecl to trigger the importing of the FileID.
7670 auto Pattern = varDecl(hasName(Name: "X"));
7671 VarDecl *FromD = FirstDeclMatcher<VarDecl>().match(FromTU, Pattern);
7672 ImportedLoc = Import(From: FromD, Lang: Lang_C99)->getLocation();
7673 }
7674
7675 // Make sure the imported buffer has the overwritten contents.
7676 SourceManager &ToSM = ToAST->getSourceManager();
7677 FileID ImportedID = ToSM.getFileID(SpellingLoc: ImportedLoc);
7678 EXPECT_EQ(Contents,
7679 ToSM.getBufferOrFake(ImportedID, SourceLocation()).getBuffer());
7680}
7681
7682struct ImportAttributes : public ASTImporterOptionSpecificTestBase {
7683 void checkAttrImportCommon(const Attr *From, const Attr *To,
7684 const Decl *ToD) {
7685
7686 // Verify that dump does not crash because invalid data.
7687 ToD->dump(Out&: llvm::nulls());
7688
7689 EXPECT_EQ(From->getParsedKind(), To->getParsedKind());
7690 EXPECT_EQ(From->getSyntax(), To->getSyntax());
7691 if (From->getAttrName()) {
7692 EXPECT_TRUE(To->getAttrName());
7693 EXPECT_STREQ(From->getAttrName()->getNameStart(),
7694 To->getAttrName()->getNameStart());
7695 } else {
7696 EXPECT_FALSE(To->getAttrName());
7697 }
7698 if (From->getScopeName()) {
7699 EXPECT_TRUE(To->getScopeName());
7700 EXPECT_STREQ(From->getScopeName()->getNameStart(),
7701 To->getScopeName()->getNameStart());
7702 } else {
7703 EXPECT_FALSE(To->getScopeName());
7704 }
7705 EXPECT_EQ(From->getSpellingListIndex(), To->getSpellingListIndex());
7706 EXPECT_STREQ(From->getSpelling(), To->getSpelling());
7707 EXPECT_EQ(From->isInherited(), To->isInherited());
7708 EXPECT_EQ(From->isImplicit(), To->isImplicit());
7709 EXPECT_EQ(From->isPackExpansion(), To->isPackExpansion());
7710 EXPECT_EQ(From->isLateParsed(), To->isLateParsed());
7711 }
7712
7713 template <class DT, class AT>
7714 void importAttr(const char *Code, AT *&FromAttr, AT *&ToAttr,
7715 TestLanguage Lang = Lang_CXX11) {
7716 static_assert(std::is_base_of<Attr, AT>::value, "AT should be an Attr");
7717 static_assert(std::is_base_of<Decl, DT>::value, "DT should be a Decl");
7718
7719 Decl *FromTU = getTuDecl(SrcCode: Code, Lang, FileName: "input.cc");
7720 DT *FromD =
7721 FirstDeclMatcher<DT>().match(FromTU, namedDecl(hasName(Name: "test")));
7722 ASSERT_TRUE(FromD);
7723
7724 DT *ToD = Import(FromD, Lang_CXX11);
7725 ASSERT_TRUE(ToD);
7726
7727 FromAttr = FromD->template getAttr<AT>();
7728 ToAttr = ToD->template getAttr<AT>();
7729 ASSERT_TRUE(FromAttr);
7730 EXPECT_TRUE(ToAttr);
7731
7732 checkAttrImportCommon(From: FromAttr, To: ToAttr, ToD);
7733 }
7734
7735 template <class T> void checkImported(const T *From, const T *To) {
7736 EXPECT_TRUE(To);
7737 EXPECT_NE(From, To);
7738 }
7739
7740 template <class T>
7741 void checkImportVariadicArg(const llvm::iterator_range<T **> &From,
7742 const llvm::iterator_range<T **> &To) {
7743 for (auto FromI = From.begin(), ToI = To.begin(); FromI != From.end();
7744 ++FromI, ++ToI) {
7745 ASSERT_NE(ToI, To.end());
7746 checkImported(*FromI, *ToI);
7747 }
7748 }
7749};
7750
7751template <>
7752void ImportAttributes::checkImported<Decl>(const Decl *From, const Decl *To) {
7753 EXPECT_TRUE(To);
7754 EXPECT_NE(From, To);
7755 EXPECT_EQ(To->getTranslationUnitDecl(),
7756 ToAST->getASTContext().getTranslationUnitDecl());
7757}
7758
7759TEST_P(ImportAttributes, ImportAligned) {
7760 AlignedAttr *FromAttr, *ToAttr;
7761 importAttr<RecordDecl>(
7762 R"(
7763 struct __attribute__((packed)) A { int __attribute__((aligned(8))) X; };
7764 struct alignas(alignof(A)) test {};
7765 )",
7766 FromAttr, ToAttr);
7767 checkImported(FromAttr->getAlignmentExpr(), ToAttr->getAlignmentExpr());
7768
7769 auto *ToA = FirstDeclMatcher<CXXRecordDecl>().match(
7770 ToAST->getASTContext().getTranslationUnitDecl(),
7771 cxxRecordDecl(hasName(Name: "A"), unless(isImplicit())));
7772 // Ensure that 'struct A' was imported (through reference from attribute of
7773 // struct 'test').
7774 EXPECT_TRUE(ToA);
7775}
7776
7777TEST_P(ImportAttributes, ImportAlignValue) {
7778 AlignValueAttr *FromAttr, *ToAttr;
7779 importAttr<VarDecl>(
7780 R"(
7781 void *test __attribute__((align_value(64)));
7782 )",
7783 FromAttr, ToAttr);
7784 checkImported(FromAttr->getAlignment(), ToAttr->getAlignment());
7785}
7786
7787TEST_P(ImportAttributes, ImportFormat) {
7788 FormatAttr *FromAttr, *ToAttr;
7789 importAttr<FunctionDecl>(
7790 R"(
7791 int test(const char * fmt, ...)
7792 __attribute__ ((__format__ (__scanf__, 1, 2)));
7793 )",
7794 FromAttr, ToAttr);
7795
7796 EXPECT_EQ(FromAttr->getType()->getName(), ToAttr->getType()->getName());
7797 EXPECT_EQ(FromAttr->getFirstArg(), ToAttr->getFirstArg());
7798 EXPECT_EQ(FromAttr->getFormatIdx(), ToAttr->getFormatIdx());
7799}
7800
7801TEST_P(ImportAttributes, ImportEnableIf) {
7802 EnableIfAttr *FromAttr, *ToAttr;
7803 importAttr<FunctionDecl>(
7804 "void test(int A) __attribute__((enable_if(A == 1, \"message\")));",
7805 FromAttr, ToAttr);
7806 checkImported(FromAttr->getCond(), ToAttr->getCond());
7807 EXPECT_EQ(FromAttr->getMessage(), ToAttr->getMessage());
7808}
7809
7810TEST_P(ImportAttributes, ImportGuardedVar) {
7811 GuardedVarAttr *FromAttr, *ToAttr;
7812 importAttr<VarDecl>("int test __attribute__((guarded_var));", FromAttr,
7813 ToAttr);
7814}
7815
7816TEST_P(ImportAttributes, ImportPtGuardedVar) {
7817 PtGuardedVarAttr *FromAttr, *ToAttr;
7818 importAttr<VarDecl>("int *test __attribute__((pt_guarded_var));", FromAttr,
7819 ToAttr);
7820}
7821
7822TEST_P(ImportAttributes, ImportScopedLockable) {
7823 ScopedLockableAttr *FromAttr, *ToAttr;
7824 importAttr<CXXRecordDecl>("struct __attribute__((scoped_lockable)) test {};",
7825 FromAttr, ToAttr);
7826}
7827
7828TEST_P(ImportAttributes, ImportCapability) {
7829 CapabilityAttr *FromAttr, *ToAttr;
7830 importAttr<CXXRecordDecl>(
7831 "struct __attribute__((capability(\"cap\"))) test {};", FromAttr, ToAttr);
7832 EXPECT_EQ(FromAttr->getName(), ToAttr->getName());
7833}
7834
7835TEST_P(ImportAttributes, ImportAssertCapability) {
7836 AssertCapabilityAttr *FromAttr, *ToAttr;
7837 importAttr<FunctionDecl>(
7838 "void test(int A1, int A2) __attribute__((assert_capability(A1, A2)));",
7839 FromAttr, ToAttr);
7840 checkImportVariadicArg(FromAttr->args(), ToAttr->args());
7841}
7842
7843TEST_P(ImportAttributes, ImportAcquireCapability) {
7844 AcquireCapabilityAttr *FromAttr, *ToAttr;
7845 importAttr<FunctionDecl>(
7846 "void test(int A1, int A2) __attribute__((acquire_capability(A1, A2)));",
7847 FromAttr, ToAttr);
7848 checkImportVariadicArg(FromAttr->args(), ToAttr->args());
7849}
7850
7851TEST_P(ImportAttributes, ImportTryAcquireCapability) {
7852 TryAcquireCapabilityAttr *FromAttr, *ToAttr;
7853 importAttr<FunctionDecl>(
7854 "void test(int A1, int A2) __attribute__((try_acquire_capability(1, A1, "
7855 "A2)));",
7856 FromAttr, ToAttr);
7857 checkImported(FromAttr->getSuccessValue(), ToAttr->getSuccessValue());
7858 checkImportVariadicArg(FromAttr->args(), ToAttr->args());
7859}
7860
7861TEST_P(ImportAttributes, ImportReleaseCapability) {
7862 ReleaseCapabilityAttr *FromAttr, *ToAttr;
7863 importAttr<FunctionDecl>(
7864 "void test(int A1, int A2) __attribute__((release_capability(A1, A2)));",
7865 FromAttr, ToAttr);
7866 checkImportVariadicArg(FromAttr->args(), ToAttr->args());
7867}
7868
7869TEST_P(ImportAttributes, ImportRequiresCapability) {
7870 RequiresCapabilityAttr *FromAttr, *ToAttr;
7871 importAttr<FunctionDecl>(
7872 "void test(int A1, int A2) __attribute__((requires_capability(A1, A2)));",
7873 FromAttr, ToAttr);
7874 checkImportVariadicArg(FromAttr->args(), ToAttr->args());
7875}
7876
7877TEST_P(ImportAttributes, ImportNoThreadSafetyAnalysis) {
7878 NoThreadSafetyAnalysisAttr *FromAttr, *ToAttr;
7879 importAttr<FunctionDecl>(
7880 "void test() __attribute__((no_thread_safety_analysis));", FromAttr,
7881 ToAttr);
7882}
7883
7884TEST_P(ImportAttributes, ImportGuardedBy) {
7885 GuardedByAttr *FromAttr, *ToAttr;
7886 importAttr<VarDecl>(
7887 R"(
7888 int G;
7889 int test __attribute__((guarded_by(G)));
7890 )",
7891 FromAttr, ToAttr);
7892 checkImported(FromAttr->getArg(), ToAttr->getArg());
7893}
7894
7895TEST_P(ImportAttributes, ImportPtGuardedBy) {
7896 PtGuardedByAttr *FromAttr, *ToAttr;
7897 importAttr<VarDecl>(
7898 R"(
7899 int G;
7900 int *test __attribute__((pt_guarded_by(G)));
7901 )",
7902 FromAttr, ToAttr);
7903 checkImported(FromAttr->getArg(), ToAttr->getArg());
7904}
7905
7906TEST_P(ImportAttributes, ImportAcquiredAfter) {
7907 AcquiredAfterAttr *FromAttr, *ToAttr;
7908 importAttr<VarDecl>(
7909 R"(
7910 struct __attribute__((lockable)) L {};
7911 L A1;
7912 L A2;
7913 L test __attribute__((acquired_after(A1, A2)));
7914 )",
7915 FromAttr, ToAttr);
7916 checkImportVariadicArg(FromAttr->args(), ToAttr->args());
7917}
7918
7919TEST_P(ImportAttributes, ImportAcquiredBefore) {
7920 AcquiredBeforeAttr *FromAttr, *ToAttr;
7921 importAttr<VarDecl>(
7922 R"(
7923 struct __attribute__((lockable)) L {};
7924 L A1;
7925 L A2;
7926 L test __attribute__((acquired_before(A1, A2)));
7927 )",
7928 FromAttr, ToAttr);
7929 checkImportVariadicArg(FromAttr->args(), ToAttr->args());
7930}
7931
7932TEST_P(ImportAttributes, ImportAssertExclusiveLock) {
7933 AssertExclusiveLockAttr *FromAttr, *ToAttr;
7934 importAttr<FunctionDecl>("void test(int A1, int A2) "
7935 "__attribute__((assert_exclusive_lock(A1, A2)));",
7936 FromAttr, ToAttr);
7937 checkImportVariadicArg(FromAttr->args(), ToAttr->args());
7938}
7939
7940TEST_P(ImportAttributes, ImportAssertSharedLock) {
7941 AssertSharedLockAttr *FromAttr, *ToAttr;
7942 importAttr<FunctionDecl>(
7943 "void test(int A1, int A2) __attribute__((assert_shared_lock(A1, A2)));",
7944 FromAttr, ToAttr);
7945 checkImportVariadicArg(FromAttr->args(), ToAttr->args());
7946}
7947
7948TEST_P(ImportAttributes, ImportExclusiveTrylockFunction) {
7949 ExclusiveTrylockFunctionAttr *FromAttr, *ToAttr;
7950 importAttr<FunctionDecl>(
7951 "void test(int A1, int A2) __attribute__((exclusive_trylock_function(1, "
7952 "A1, A2)));",
7953 FromAttr, ToAttr);
7954 checkImported(FromAttr->getSuccessValue(), ToAttr->getSuccessValue());
7955 checkImportVariadicArg(FromAttr->args(), ToAttr->args());
7956}
7957
7958TEST_P(ImportAttributes, ImportSharedTrylockFunction) {
7959 SharedTrylockFunctionAttr *FromAttr, *ToAttr;
7960 importAttr<FunctionDecl>(
7961 "void test(int A1, int A2) __attribute__((shared_trylock_function(1, A1, "
7962 "A2)));",
7963 FromAttr, ToAttr);
7964 checkImported(FromAttr->getSuccessValue(), ToAttr->getSuccessValue());
7965 checkImportVariadicArg(FromAttr->args(), ToAttr->args());
7966}
7967
7968TEST_P(ImportAttributes, ImportLockReturned) {
7969 LockReturnedAttr *FromAttr, *ToAttr;
7970 importAttr<FunctionDecl>(
7971 "void test(int A1) __attribute__((lock_returned(A1)));", FromAttr,
7972 ToAttr);
7973 checkImported(FromAttr->getArg(), ToAttr->getArg());
7974}
7975
7976TEST_P(ImportAttributes, ImportLocksExcluded) {
7977 LocksExcludedAttr *FromAttr, *ToAttr;
7978 importAttr<FunctionDecl>(
7979 "void test(int A1, int A2) __attribute__((locks_excluded(A1, A2)));",
7980 FromAttr, ToAttr);
7981 checkImportVariadicArg(FromAttr->args(), ToAttr->args());
7982}
7983
7984TEST_P(ImportAttributes, ImportC99NoThrowAttr) {
7985 NoThrowAttr *FromAttr, *ToAttr;
7986 importAttr<FunctionDecl>("void test () __attribute__ ((__nothrow__));",
7987 FromAttr, ToAttr, Lang_C99);
7988 checkImported(FromAttr->getAttrName(), ToAttr->getAttrName());
7989}
7990
7991template <typename T>
7992auto ExtendWithOptions(const T &Values, const std::vector<std::string> &Args) {
7993 auto Copy = Values;
7994 for (std::vector<std::string> &ArgV : Copy) {
7995 for (const std::string &Arg : Args) {
7996 ArgV.push_back(x: Arg);
7997 }
7998 }
7999 return ::testing::ValuesIn(Copy);
8000}
8001
8002struct ImportWithExternalSource : ASTImporterOptionSpecificTestBase {
8003 ImportWithExternalSource() {
8004 Creator = [](ASTContext &ToContext, FileManager &ToFileManager,
8005 ASTContext &FromContext, FileManager &FromFileManager,
8006 bool MinimalImport,
8007 const std::shared_ptr<ASTImporterSharedState> &SharedState) {
8008 return new ASTImporter(ToContext, ToFileManager, FromContext,
8009 // Use minimal import for these tests.
8010 FromFileManager, /*MinimalImport=*/true,
8011 // We use the regular lookup.
8012 /*SharedState=*/nullptr);
8013 };
8014 }
8015};
8016
8017/// An ExternalASTSource that keeps track of the tags is completed.
8018struct SourceWithCompletedTagList : clang::ExternalASTSource {
8019 std::vector<clang::TagDecl *> &CompletedTags;
8020 SourceWithCompletedTagList(std::vector<clang::TagDecl *> &CompletedTags)
8021 : CompletedTags(CompletedTags) {}
8022 void CompleteType(TagDecl *Tag) override {
8023 auto *Record = cast<CXXRecordDecl>(Val: Tag);
8024 Record->startDefinition();
8025 Record->completeDefinition();
8026 CompletedTags.push_back(x: Tag);
8027 }
8028 using clang::ExternalASTSource::CompleteType;
8029};
8030
8031TEST_P(ImportWithExternalSource, CompleteRecordBeforeImporting) {
8032 // Create an empty TU.
8033 TranslationUnitDecl *FromTU = getTuDecl(SrcCode: "", Lang: Lang_CXX03, FileName: "input.cpp");
8034
8035 // Create and add the test ExternalASTSource.
8036 std::vector<clang::TagDecl *> CompletedTags;
8037 IntrusiveRefCntPtr<ExternalASTSource> source =
8038 new SourceWithCompletedTagList(CompletedTags);
8039 clang::ASTContext &Context = FromTU->getASTContext();
8040 Context.setExternalSource(std::move(source));
8041
8042 // Create a dummy class by hand with external lexical storage.
8043 IdentifierInfo &Ident = Context.Idents.get(Name: "test_class");
8044 auto *Record =
8045 CXXRecordDecl::Create(Context, TagTypeKind::Class, FromTU,
8046 SourceLocation(), SourceLocation(), &Ident);
8047 Record->setHasExternalLexicalStorage();
8048 FromTU->addDecl(D: Record);
8049
8050 // Do a minimal import of the created class.
8051 EXPECT_EQ(0U, CompletedTags.size());
8052 Import(Record, Lang_CXX03);
8053 EXPECT_EQ(0U, CompletedTags.size());
8054
8055 // Import the definition of the created class.
8056 llvm::Error Err = findFromTU(From: Record)->Importer->ImportDefinition(Record);
8057 EXPECT_FALSE((bool)Err);
8058 consumeError(Err: std::move(Err));
8059
8060 // Make sure the class was completed once.
8061 EXPECT_EQ(1U, CompletedTags.size());
8062 EXPECT_EQ(Record, CompletedTags.front());
8063}
8064
8065TEST_P(ImportFunctions, CTADImplicit) {
8066 Decl *FromTU = getTuDecl(
8067 SrcCode: R"(
8068 template <typename T> struct A {
8069 A(T);
8070 };
8071 A a{(int)0};
8072 )",
8073 Lang: Lang_CXX17, FileName: "input.cc");
8074 auto *FromD = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
8075 D: FromTU,
8076 AMatcher: cxxDeductionGuideDecl(hasParameter(N: 0, InnerMatcher: hasType(InnerMatcher: asString(Name: "A<T>")))));
8077 auto *ToD = Import(FromD, Lang_CXX17);
8078 ASSERT_TRUE(ToD);
8079 EXPECT_EQ(ToD->getDeductionCandidateKind(), DeductionCandidate::Copy);
8080 // Check that the deduced class template is also imported.
8081 EXPECT_TRUE(findFromTU(FromD)->Importer->GetAlreadyImportedOrNull(
8082 FromD->getDeducedTemplate()));
8083}
8084
8085TEST_P(ImportFunctions, CTADUserDefinedExplicit) {
8086 Decl *FromTU = getTuDecl(
8087 SrcCode: R"(
8088 template <typename T> struct A {
8089 A(T);
8090 };
8091 template <typename T> explicit A(T) -> A<float>;
8092 A a{(int)0}; // calls A<float>::A(float)
8093 )",
8094 Lang: Lang_CXX17, FileName: "input.cc");
8095 auto *FromD = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
8096 D: FromTU, AMatcher: cxxDeductionGuideDecl(unless(isImplicit())));
8097 // Not-implicit: i.e. not compiler-generated, user defined.
8098 ASSERT_FALSE(FromD->isImplicit());
8099 ASSERT_TRUE(FromD->isExplicit()); // Has the explicit keyword.
8100 auto *ToD = Import(FromD, Lang_CXX17);
8101 ASSERT_TRUE(ToD);
8102 EXPECT_FALSE(FromD->isImplicit());
8103 EXPECT_TRUE(ToD->isExplicit());
8104}
8105
8106TEST_P(ImportFunctions, CTADWithLocalTypedef) {
8107 Decl *TU = getTuDecl(
8108 SrcCode: R"(
8109 template <typename T> struct A {
8110 typedef T U;
8111 A(U);
8112 };
8113 A a{(int)0};
8114 )",
8115 Lang: Lang_CXX17, FileName: "input.cc");
8116 auto *FromD = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
8117 D: TU, AMatcher: cxxDeductionGuideDecl());
8118 auto *ToD = Import(FromD, Lang_CXX17);
8119 ASSERT_TRUE(ToD);
8120}
8121
8122TEST_P(ImportFunctions, ParmVarDeclDeclContext) {
8123 constexpr auto FromTUCode = R"(
8124 void f(int P);
8125 )";
8126 Decl *FromTU = getTuDecl(SrcCode: FromTUCode, Lang: Lang_CXX11);
8127 auto *FromF = FirstDeclMatcher<FunctionDecl>().match(
8128 D: FromTU, AMatcher: functionDecl(hasName(Name: "f")));
8129 ASSERT_TRUE(FromF);
8130
8131 auto *ImportedF = Import(FromF, Lang_CXX11);
8132 EXPECT_TRUE(ImportedF);
8133 EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains(
8134 ImportedF, ImportedF->getParamDecl(0)));
8135}
8136
8137// FIXME Move these tests out of ASTImporterTest. For that we need to factor
8138// out the ASTImporter specific pars from ASTImporterOptionSpecificTestBase
8139// into a new test Fixture. Then we should lift up this Fixture to its own
8140// implementation file and only then could we reuse the Fixture in other AST
8141// unitttests.
8142struct CTAD : ASTImporterOptionSpecificTestBase {};
8143
8144TEST_P(CTAD, DeductionGuideShouldReferToANonLocalTypedef) {
8145 Decl *TU = getTuDecl(
8146 SrcCode: R"(
8147 typedef int U;
8148 template <typename T> struct A {
8149 A(U, T);
8150 };
8151 A a{(int)0, (int)0};
8152 )",
8153 Lang: Lang_CXX17, FileName: "input.cc");
8154 auto *Guide = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
8155 D: TU, AMatcher: cxxDeductionGuideDecl());
8156 auto *Typedef = FirstDeclMatcher<TypedefNameDecl>().match(
8157 D: TU, AMatcher: typedefNameDecl(hasName(Name: "U")));
8158 ParmVarDecl *Param = Guide->getParamDecl(0);
8159 // The type of the first param (which is a typedef) should match the typedef
8160 // in the global scope.
8161 EXPECT_EQ(Param->getType()->getAs<TypedefType>()->getDecl(), Typedef);
8162}
8163
8164TEST_P(CTAD, DeductionGuideShouldReferToANonLocalTypedefInParamPtr) {
8165 Decl *TU = getTuDecl(
8166 SrcCode: R"(
8167 typedef int U;
8168 template <typename T> struct A {
8169 A(U*, T);
8170 };
8171 A a{(int*)0, (int)0};
8172 )",
8173 Lang: Lang_CXX17, FileName: "input.cc");
8174 auto *Guide = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
8175 D: TU, AMatcher: cxxDeductionGuideDecl());
8176 auto *Typedef = FirstDeclMatcher<TypedefNameDecl>().match(
8177 D: TU, AMatcher: typedefNameDecl(hasName(Name: "U")));
8178 ParmVarDecl *Param = Guide->getParamDecl(0);
8179 EXPECT_EQ(Param->getType()
8180 ->getAs<PointerType>()
8181 ->getPointeeType()
8182 ->getAs<TypedefType>()
8183 ->getDecl(),
8184 Typedef);
8185}
8186
8187TEST_P(CTAD, DeductionGuideShouldCopyALocalTypedef) {
8188 Decl *TU = getTuDecl(
8189 SrcCode: R"(
8190 template <typename T> struct A {
8191 typedef T U;
8192 A(U, T);
8193 };
8194 A a{(int)0, (int)0};
8195 )",
8196 Lang: Lang_CXX17, FileName: "input.cc");
8197 auto *Guide = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
8198 D: TU, AMatcher: cxxDeductionGuideDecl());
8199 auto *Typedef = FirstDeclMatcher<TypedefNameDecl>().match(
8200 D: TU, AMatcher: typedefNameDecl(hasName(Name: "U")));
8201 ParmVarDecl *Param = Guide->getParamDecl(0);
8202 EXPECT_NE(Param->getType()->getAs<TypedefType>()->getDecl(), Typedef);
8203}
8204
8205INSTANTIATE_TEST_SUITE_P(ParameterizedTests, CTAD,
8206 DefaultTestValuesForRunOptions);
8207
8208TEST_P(ASTImporterOptionSpecificTestBase, TypedefWithAttribute) {
8209 Decl *TU = getTuDecl(
8210 SrcCode: R"(
8211 namespace N {
8212 typedef int X __attribute__((annotate("A")));
8213 }
8214 )",
8215 Lang: Lang_CXX17, FileName: "input.cc");
8216 auto *FromD =
8217 FirstDeclMatcher<TypedefDecl>().match(D: TU, AMatcher: typedefDecl(hasName(Name: "X")));
8218 auto *ToD = Import(FromD, Lang_CXX17);
8219 ASSERT_TRUE(ToD);
8220 ASSERT_EQ(ToD->getAttrs().size(), 1U);
8221 auto *ToAttr = dyn_cast<AnnotateAttr>(ToD->getAttrs()[0]);
8222 ASSERT_TRUE(ToAttr);
8223 EXPECT_EQ(ToAttr->getAnnotation(), "A");
8224}
8225
8226TEST_P(ASTImporterOptionSpecificTestBase,
8227 ImportOfTemplatedDeclWhenPreviousDeclHasNoDescribedTemplateSet) {
8228 Decl *FromTU = getTuDecl(
8229 SrcCode: R"(
8230
8231 namespace std {
8232 template<typename T>
8233 class basic_stringbuf;
8234 }
8235 namespace std {
8236 class char_traits;
8237 template<typename T = char_traits>
8238 class basic_stringbuf;
8239 }
8240 namespace std {
8241 template<typename T>
8242 class basic_stringbuf {};
8243 }
8244
8245 )",
8246 Lang: Lang_CXX11);
8247
8248 auto *From1 = FirstDeclMatcher<ClassTemplateDecl>().match(
8249 D: FromTU,
8250 AMatcher: classTemplateDecl(hasName(Name: "basic_stringbuf"), unless(isImplicit())));
8251 auto *To1 = cast_or_null<ClassTemplateDecl>(Import(From1, Lang_CXX11));
8252 EXPECT_TRUE(To1);
8253
8254 auto *From2 = LastDeclMatcher<ClassTemplateDecl>().match(
8255 D: FromTU,
8256 AMatcher: classTemplateDecl(hasName(Name: "basic_stringbuf"), unless(isImplicit())));
8257 auto *To2 = cast_or_null<ClassTemplateDecl>(Import(From2, Lang_CXX11));
8258 EXPECT_TRUE(To2);
8259}
8260
8261TEST_P(ASTImporterOptionSpecificTestBase, ImportOfCapturedVLAType) {
8262 Decl *FromTU = getTuDecl(
8263 SrcCode: R"(
8264 void declToImport(int N) {
8265 int VLA[N];
8266 [&VLA] {}; // FieldDecl inside the lambda.
8267 }
8268 )",
8269 Lang: Lang_CXX14);
8270 auto *FromFD = FirstDeclMatcher<FieldDecl>().match(D: FromTU, AMatcher: fieldDecl());
8271 ASSERT_TRUE(FromFD);
8272 ASSERT_TRUE(FromFD->hasCapturedVLAType());
8273
8274 auto *ToFD = Import(FromFD, Lang_CXX14);
8275 EXPECT_TRUE(ToFD);
8276 EXPECT_TRUE(ToFD->hasCapturedVLAType());
8277 EXPECT_NE(FromFD->getCapturedVLAType(), ToFD->getCapturedVLAType());
8278}
8279
8280TEST_P(ASTImporterOptionSpecificTestBase, ImportEnumMemberSpecialization) {
8281 Decl *FromTU = getTuDecl(
8282 SrcCode: R"(
8283 template <class T> struct A {
8284 enum tagname { enumerator };
8285 };
8286 template struct A<int>;
8287 )",
8288 Lang: Lang_CXX03);
8289 auto *FromD = FirstDeclMatcher<EnumDecl>().match(
8290 D: FromTU, AMatcher: enumDecl(hasName(Name: "tagname"),
8291 hasParent(classTemplateSpecializationDecl())));
8292 ASSERT_TRUE(FromD);
8293 ASSERT_TRUE(FromD->getMemberSpecializationInfo());
8294
8295 auto *ToD = Import(FromD, Lang_CXX03);
8296 EXPECT_TRUE(ToD);
8297 EXPECT_TRUE(ToD->getMemberSpecializationInfo());
8298 EXPECT_EQ(FromD->getTemplateSpecializationKind(),
8299 ToD->getTemplateSpecializationKind());
8300}
8301
8302TEST_P(ASTImporterOptionSpecificTestBase, ImportIsInheritingConstructorBit) {
8303 Decl *FromTU = getTuDecl(
8304 SrcCode: R"(
8305 struct A {
8306 A(int);
8307 };
8308 struct B : A {
8309 using A::A; // Inherited ctor.
8310 };
8311 void f() {
8312 (B(0));
8313 }
8314 )",
8315 Lang: Lang_CXX11);
8316 auto *FromD = FirstDeclMatcher<CXXConstructorDecl>().match(
8317 D: FromTU, AMatcher: cxxConstructorDecl(isInheritingConstructor()));
8318 ASSERT_TRUE(FromD);
8319 ASSERT_TRUE(FromD->isInheritingConstructor());
8320
8321 auto *ToD = Import(FromD, Lang_CXX11);
8322 ASSERT_TRUE(ToD);
8323 EXPECT_TRUE(ToD->isInheritingConstructor());
8324}
8325
8326TEST_P(ASTImporterOptionSpecificTestBase, ImportConstructorUsingShadow) {
8327 TranslationUnitDecl *FromTU = getTuDecl(
8328 SrcCode: R"(
8329 struct A {
8330 A(int, int);
8331 };
8332 struct B : A {
8333 using A::A;
8334 };
8335 struct C : B {
8336 using B::B;
8337 };
8338 )",
8339 Lang: Lang_CXX11);
8340
8341 auto CheckAST = [](TranslationUnitDecl *TU, CXXRecordDecl *RecordC) {
8342 auto *RecordA = FirstDeclMatcher<CXXRecordDecl>().match(
8343 TU, cxxRecordDecl(hasName(Name: "A")));
8344 auto *RecordB = FirstDeclMatcher<CXXRecordDecl>().match(
8345 TU, cxxRecordDecl(hasName(Name: "B")));
8346 auto *ConstrA = FirstDeclMatcher<CXXConstructorDecl>().match(
8347 TU, cxxConstructorDecl(hasParent(equalsNode(RecordA)),
8348 parameterCountIs(N: 2)));
8349 auto *ShadowBA = cast<ConstructorUsingShadowDecl>(
8350 FirstDeclMatcher<UsingShadowDecl>().match(
8351 TU, usingShadowDecl(hasParent(equalsNode(RecordB)),
8352 hasTargetDecl(equalsNode(ConstrA)))));
8353 auto *ShadowCA = cast<ConstructorUsingShadowDecl>(
8354 FirstDeclMatcher<UsingShadowDecl>().match(
8355 TU, usingShadowDecl(hasParent(equalsNode(RecordC)),
8356 hasTargetDecl(equalsNode(ConstrA)))));
8357 EXPECT_EQ(ShadowBA->getTargetDecl(), ConstrA);
8358 EXPECT_EQ(ShadowBA->getNominatedBaseClass(), RecordA);
8359 EXPECT_EQ(ShadowBA->getConstructedBaseClass(), RecordA);
8360 EXPECT_EQ(ShadowBA->getNominatedBaseClassShadowDecl(), nullptr);
8361 EXPECT_EQ(ShadowBA->getConstructedBaseClassShadowDecl(), nullptr);
8362 EXPECT_FALSE(ShadowBA->constructsVirtualBase());
8363 EXPECT_EQ(ShadowCA->getTargetDecl(), ConstrA);
8364 EXPECT_EQ(ShadowCA->getNominatedBaseClass(), RecordB);
8365 EXPECT_EQ(ShadowCA->getConstructedBaseClass(), RecordB);
8366 EXPECT_EQ(ShadowCA->getNominatedBaseClassShadowDecl(), ShadowBA);
8367 EXPECT_EQ(ShadowCA->getConstructedBaseClassShadowDecl(), ShadowBA);
8368 EXPECT_FALSE(ShadowCA->constructsVirtualBase());
8369 };
8370
8371 auto *FromC = FirstDeclMatcher<CXXRecordDecl>().match(
8372 FromTU, cxxRecordDecl(hasName(Name: "C")));
8373
8374 auto *ToC = Import(FromC, Lang_CXX11);
8375 TranslationUnitDecl *ToTU = ToC->getTranslationUnitDecl();
8376
8377 CheckAST(FromTU, FromC);
8378 CheckAST(ToTU, ToC);
8379}
8380
8381TEST_P(ASTImporterOptionSpecificTestBase,
8382 ImportFunctionDeclBitShouldNotOverwriteCtorDeclBits) {
8383 Decl *From, *To;
8384 std::tie(args&: From, args&: To) = getImportedDecl(
8385 FromSrcCode: R"s(
8386 struct A {
8387 A() : m() {}
8388 int m;
8389 };
8390
8391 A foo() { A a; return a; }
8392 A bar() { return {}; }
8393 )s",
8394 FromLang: Lang_CXX17,
8395 ToSrcCode: R"s(
8396 struct A {
8397 A() : m() {}
8398 int m;
8399 };
8400 A baz() { return {}; }
8401 )s",
8402 ToLang: Lang_CXX17, Identifier: "A");
8403
8404 auto HasCtorInit =
8405 hasAnyConstructorInitializer(InnerMatcher: cxxCtorInitializer(isMemberInitializer()));
8406 auto ImpMoveCtor =
8407 cxxConstructorDecl(isMoveConstructor(), isImplicit(), HasCtorInit);
8408
8409 auto *FromImpMoveCtor = FirstDeclMatcher<CXXConstructorDecl>().match(
8410 D: From, AMatcher: ImpMoveCtor);
8411 auto *ToImpMoveCtor = FirstDeclMatcher<CXXConstructorDecl>().match(
8412 D: To, AMatcher: ImpMoveCtor);
8413
8414 EXPECT_TRUE(FromImpMoveCtor->getNumCtorInitializers() == 1);
8415 EXPECT_FALSE(FromImpMoveCtor->FriendConstraintRefersToEnclosingTemplate());
8416
8417 EXPECT_TRUE(ToImpMoveCtor->getNumCtorInitializers() == 1);
8418 EXPECT_FALSE(ToImpMoveCtor->FriendConstraintRefersToEnclosingTemplate());
8419 EXPECT_TRUE(*ToImpMoveCtor->init_begin());
8420}
8421
8422AST_MATCHER_P(UsingShadowDecl, hasIntroducerDecl, internal::Matcher<NamedDecl>,
8423 InnerMatcher) {
8424 return InnerMatcher.matches(*Node.getIntroducer(), Finder, Builder);
8425}
8426
8427TEST_P(ASTImporterOptionSpecificTestBase,
8428 ImportConstructorUsingShadowVirtualBase) {
8429 TranslationUnitDecl *FromTU = getTuDecl(
8430 SrcCode: R"(
8431 struct A { A(int, int); };
8432 struct B : A { using A::A; };
8433
8434 struct V1 : virtual B { using B::B; };
8435 struct V2 : virtual B { using B::B; };
8436
8437 struct D2 : V1, V2 {
8438 using V1::V1;
8439 using V2::V2;
8440 };
8441 )",
8442 Lang: Lang_CXX11);
8443
8444 auto CheckAST = [](TranslationUnitDecl *TU, CXXRecordDecl *RecordD2) {
8445 auto *RecordA = FirstDeclMatcher<CXXRecordDecl>().match(
8446 TU, cxxRecordDecl(hasName(Name: "A")));
8447 auto *RecordB = FirstDeclMatcher<CXXRecordDecl>().match(
8448 TU, cxxRecordDecl(hasName(Name: "B")));
8449 auto *RecordV1 = FirstDeclMatcher<CXXRecordDecl>().match(
8450 TU, cxxRecordDecl(hasName(Name: "V1")));
8451 auto *RecordV2 = FirstDeclMatcher<CXXRecordDecl>().match(
8452 TU, cxxRecordDecl(hasName(Name: "V2")));
8453 auto *ConstrA = FirstDeclMatcher<CXXConstructorDecl>().match(
8454 TU, cxxConstructorDecl(hasParent(equalsNode(RecordA)),
8455 parameterCountIs(N: 2)));
8456 auto *ConstrB = FirstDeclMatcher<CXXConstructorDecl>().match(
8457 TU, cxxConstructorDecl(hasParent(equalsNode(RecordB)),
8458 isCopyConstructor()));
8459 auto *UsingD2V1 = FirstDeclMatcher<UsingDecl>().match(
8460 TU, usingDecl(hasParent(equalsNode(RecordD2))));
8461 auto *UsingD2V2 = LastDeclMatcher<UsingDecl>().match(
8462 TU, usingDecl(hasParent(equalsNode(RecordD2))));
8463 auto *ShadowBA = cast<ConstructorUsingShadowDecl>(
8464 FirstDeclMatcher<UsingShadowDecl>().match(
8465 TU, usingShadowDecl(hasParent(equalsNode(RecordB)),
8466 hasTargetDecl(equalsNode(ConstrA)))));
8467 auto *ShadowV1A = cast<ConstructorUsingShadowDecl>(
8468 FirstDeclMatcher<UsingShadowDecl>().match(
8469 TU, usingShadowDecl(hasParent(equalsNode(RecordV1)),
8470 hasTargetDecl(equalsNode(ConstrA)))));
8471 auto *ShadowV1B = cast<ConstructorUsingShadowDecl>(
8472 FirstDeclMatcher<UsingShadowDecl>().match(
8473 TU, usingShadowDecl(hasParent(equalsNode(RecordV1)),
8474 hasTargetDecl(equalsNode(ConstrB)))));
8475 auto *ShadowV2A = cast<ConstructorUsingShadowDecl>(
8476 FirstDeclMatcher<UsingShadowDecl>().match(
8477 TU, usingShadowDecl(hasParent(equalsNode(RecordV2)),
8478 hasTargetDecl(equalsNode(ConstrA)))));
8479 auto *ShadowV2B = cast<ConstructorUsingShadowDecl>(
8480 FirstDeclMatcher<UsingShadowDecl>().match(
8481 TU, usingShadowDecl(hasParent(equalsNode(RecordV2)),
8482 hasTargetDecl(equalsNode(ConstrB)))));
8483 auto *ShadowD2V1A = cast<ConstructorUsingShadowDecl>(
8484 FirstDeclMatcher<UsingShadowDecl>().match(
8485 TU, usingShadowDecl(hasParent(equalsNode(RecordD2)),
8486 hasIntroducerDecl(equalsNode(UsingD2V1)),
8487 hasTargetDecl(equalsNode(ConstrA)))));
8488 auto *ShadowD2V1B = cast<ConstructorUsingShadowDecl>(
8489 FirstDeclMatcher<UsingShadowDecl>().match(
8490 TU, usingShadowDecl(hasParent(equalsNode(RecordD2)),
8491 hasIntroducerDecl(equalsNode(UsingD2V1)),
8492 hasTargetDecl(equalsNode(ConstrB)))));
8493 auto *ShadowD2V2A = cast<ConstructorUsingShadowDecl>(
8494 FirstDeclMatcher<UsingShadowDecl>().match(
8495 TU, usingShadowDecl(hasParent(equalsNode(RecordD2)),
8496 hasIntroducerDecl(equalsNode(UsingD2V2)),
8497 hasTargetDecl(equalsNode(ConstrA)))));
8498 auto *ShadowD2V2B = cast<ConstructorUsingShadowDecl>(
8499 FirstDeclMatcher<UsingShadowDecl>().match(
8500 TU, usingShadowDecl(hasParent(equalsNode(RecordD2)),
8501 hasIntroducerDecl(equalsNode(UsingD2V2)),
8502 hasTargetDecl(equalsNode(ConstrB)))));
8503
8504 EXPECT_EQ(ShadowD2V1A->getTargetDecl(), ConstrA);
8505 EXPECT_EQ(ShadowD2V1A->getNominatedBaseClassShadowDecl(), ShadowV1A);
8506 EXPECT_EQ(ShadowD2V1A->getNominatedBaseClass(), RecordV1);
8507 EXPECT_EQ(ShadowD2V1A->getConstructedBaseClassShadowDecl(), ShadowBA);
8508 EXPECT_EQ(ShadowD2V1A->getConstructedBaseClass(), RecordB);
8509 EXPECT_TRUE(ShadowD2V1A->constructsVirtualBase());
8510 EXPECT_EQ(ShadowD2V1B->getTargetDecl(), ConstrB);
8511 EXPECT_EQ(ShadowD2V1B->getNominatedBaseClassShadowDecl(), ShadowV1B);
8512 EXPECT_EQ(ShadowD2V1B->getNominatedBaseClass(), RecordV1);
8513 EXPECT_EQ(ShadowD2V1B->getConstructedBaseClassShadowDecl(), nullptr);
8514 EXPECT_EQ(ShadowD2V1B->getConstructedBaseClass(), RecordB);
8515 EXPECT_TRUE(ShadowD2V1B->constructsVirtualBase());
8516 EXPECT_EQ(ShadowD2V2A->getTargetDecl(), ConstrA);
8517 EXPECT_EQ(ShadowD2V2A->getNominatedBaseClassShadowDecl(), ShadowV2A);
8518 EXPECT_EQ(ShadowD2V2A->getNominatedBaseClass(), RecordV2);
8519 EXPECT_EQ(ShadowD2V2A->getConstructedBaseClassShadowDecl(), ShadowBA);
8520 EXPECT_EQ(ShadowD2V2A->getConstructedBaseClass(), RecordB);
8521 EXPECT_TRUE(ShadowD2V2A->constructsVirtualBase());
8522 EXPECT_EQ(ShadowD2V2B->getTargetDecl(), ConstrB);
8523 EXPECT_EQ(ShadowD2V2B->getNominatedBaseClassShadowDecl(), ShadowV2B);
8524 EXPECT_EQ(ShadowD2V2B->getNominatedBaseClass(), RecordV2);
8525 EXPECT_EQ(ShadowD2V2B->getConstructedBaseClassShadowDecl(), nullptr);
8526 EXPECT_EQ(ShadowD2V2B->getConstructedBaseClass(), RecordB);
8527 EXPECT_TRUE(ShadowD2V2B->constructsVirtualBase());
8528
8529 EXPECT_TRUE(ShadowV1A->constructsVirtualBase());
8530 EXPECT_TRUE(ShadowV1B->constructsVirtualBase());
8531 EXPECT_TRUE(ShadowV2A->constructsVirtualBase());
8532 EXPECT_TRUE(ShadowV2B->constructsVirtualBase());
8533 EXPECT_FALSE(ShadowBA->constructsVirtualBase());
8534 };
8535
8536 auto *FromD2 = FirstDeclMatcher<CXXRecordDecl>().match(
8537 FromTU, cxxRecordDecl(hasName(Name: "D2")));
8538
8539 auto *ToD2 = Import(FromD2, Lang_CXX11);
8540 TranslationUnitDecl *ToTU = ToD2->getTranslationUnitDecl();
8541
8542 CheckAST(FromTU, FromD2);
8543 CheckAST(ToTU, ToD2);
8544}
8545
8546TEST_P(ASTImporterOptionSpecificTestBase, ImportUsingShadowList) {
8547 TranslationUnitDecl *FromTU = getTuDecl(
8548 SrcCode: R"(
8549 struct A {
8550 void f();
8551 void f(int);
8552 };
8553 struct B : A {
8554 using A::f;
8555 };
8556 )",
8557 Lang: Lang_CXX11);
8558
8559 auto *FromB = FirstDeclMatcher<CXXRecordDecl>().match(
8560 FromTU, cxxRecordDecl(hasName(Name: "B")));
8561
8562 auto *ToB = Import(FromB, Lang_CXX11);
8563 TranslationUnitDecl *ToTU = ToB->getTranslationUnitDecl();
8564
8565 auto *ToUsing = FirstDeclMatcher<UsingDecl>().match(
8566 ToTU, usingDecl(hasParent(equalsNode(ToB))));
8567 auto *ToUsingShadowF1 = FirstDeclMatcher<UsingShadowDecl>().match(
8568 ToTU, usingShadowDecl(hasTargetDecl(
8569 InnerMatcher: functionDecl(hasName(Name: "f"), parameterCountIs(N: 0)))));
8570 auto *ToUsingShadowF2 = FirstDeclMatcher<UsingShadowDecl>().match(
8571 ToTU, usingShadowDecl(hasTargetDecl(
8572 InnerMatcher: functionDecl(hasName(Name: "f"), parameterCountIs(N: 1)))));
8573
8574 EXPECT_EQ(ToUsing->shadow_size(), 2u);
8575 auto ShadowI = ToUsing->shadow_begin();
8576 EXPECT_EQ(*ShadowI, ToUsingShadowF1);
8577 ++ShadowI;
8578 EXPECT_EQ(*ShadowI, ToUsingShadowF2);
8579}
8580
8581AST_MATCHER_P(FunctionTemplateDecl, templateParameterCountIs, unsigned, Cnt) {
8582 return Node.getTemplateParameters()->size() == Cnt;
8583}
8584
8585TEST_P(ASTImporterOptionSpecificTestBase, ImportDeductionGuide) {
8586 TranslationUnitDecl *FromTU = getTuDecl(
8587 SrcCode: R"(
8588 template<class> class A { };
8589 template<class T> class B {
8590 template<class T1, typename = A<T>> B(T1);
8591 };
8592 template<class T>
8593 B(T, T) -> B<int>;
8594 )",
8595 Lang: Lang_CXX17);
8596
8597 // Get the implicit deduction guide for (non-default) constructor of 'B'.
8598 auto *FromDGCtor = FirstDeclMatcher<FunctionTemplateDecl>().match(
8599 FromTU, functionTemplateDecl(templateParameterCountIs(Cnt: 3)));
8600 // Implicit deduction guide for copy constructor of 'B'.
8601 auto *FromDGCopyCtor = FirstDeclMatcher<FunctionTemplateDecl>().match(
8602 FromTU, functionTemplateDecl(templateParameterCountIs(Cnt: 1), isImplicit()));
8603 // User defined deduction guide.
8604 auto *FromDGOther = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
8605 FromTU, cxxDeductionGuideDecl(unless(isImplicit())));
8606
8607 TemplateParameterList *FromDGCtorTP = FromDGCtor->getTemplateParameters();
8608 // Don't know why exactly but this is the DeclContext here.
8609 EXPECT_EQ(FromDGCtorTP->getParam(0)->getDeclContext(),
8610 FromDGCopyCtor->getTemplatedDecl());
8611 EXPECT_EQ(FromDGCtorTP->getParam(1)->getDeclContext(),
8612 FromDGCtor->getTemplatedDecl());
8613 EXPECT_EQ(FromDGCtorTP->getParam(2)->getDeclContext(),
8614 FromDGCtor->getTemplatedDecl());
8615 EXPECT_EQ(
8616 FromDGCopyCtor->getTemplateParameters()->getParam(0)->getDeclContext(),
8617 FromDGCopyCtor->getTemplatedDecl());
8618 EXPECT_EQ(FromDGOther->getDescribedTemplate()
8619 ->getTemplateParameters()
8620 ->getParam(0)
8621 ->getDeclContext(),
8622 FromDGOther);
8623
8624 auto *ToDGCtor = Import(FromDGCtor, Lang_CXX17);
8625 auto *ToDGCopyCtor = Import(FromDGCopyCtor, Lang_CXX17);
8626 auto *ToDGOther = Import(FromDGOther, Lang_CXX17);
8627 ASSERT_TRUE(ToDGCtor);
8628 ASSERT_TRUE(ToDGCopyCtor);
8629 ASSERT_TRUE(ToDGOther);
8630
8631 TemplateParameterList *ToDGCtorTP = ToDGCtor->getTemplateParameters();
8632 EXPECT_EQ(ToDGCtorTP->getParam(0)->getDeclContext(),
8633 ToDGCopyCtor->getTemplatedDecl());
8634 EXPECT_EQ(ToDGCtorTP->getParam(1)->getDeclContext(),
8635 ToDGCtor->getTemplatedDecl());
8636 EXPECT_EQ(ToDGCtorTP->getParam(2)->getDeclContext(),
8637 ToDGCtor->getTemplatedDecl());
8638 EXPECT_EQ(
8639 ToDGCopyCtor->getTemplateParameters()->getParam(0)->getDeclContext(),
8640 ToDGCopyCtor->getTemplatedDecl());
8641 EXPECT_EQ(ToDGOther->getDescribedTemplate()
8642 ->getTemplateParameters()
8643 ->getParam(0)
8644 ->getDeclContext(),
8645 ToDGOther);
8646}
8647
8648TEST_P(ASTImporterOptionSpecificTestBase, ImportDeductionGuideDifferentOrder) {
8649 // This test demonstrates that the DeclContext of the imported object is
8650 // dependent on the order of import. The test is an exact copy of the previous
8651 // one except at the indicated locations.
8652 TranslationUnitDecl *FromTU = getTuDecl(
8653 SrcCode: R"(
8654 template<class> class A { };
8655 template<class T> class B {
8656 template<class T1, typename = A<T>> B(T1);
8657 };
8658 template<class T>
8659 B(T, T) -> B<int>;
8660 )",
8661 Lang: Lang_CXX17);
8662
8663 // Get the implicit deduction guide for (non-default) constructor of 'B'.
8664 auto *FromDGCtor = FirstDeclMatcher<FunctionTemplateDecl>().match(
8665 FromTU, functionTemplateDecl(templateParameterCountIs(Cnt: 3)));
8666 // Implicit deduction guide for copy constructor of 'B'.
8667 auto *FromDGCopyCtor = FirstDeclMatcher<FunctionTemplateDecl>().match(
8668 FromTU, functionTemplateDecl(templateParameterCountIs(Cnt: 1), isImplicit()));
8669 // User defined deduction guide.
8670 auto *FromDGOther = FirstDeclMatcher<CXXDeductionGuideDecl>().match(
8671 FromTU, cxxDeductionGuideDecl(unless(isImplicit())));
8672
8673 TemplateParameterList *FromDGCtorTP = FromDGCtor->getTemplateParameters();
8674 // Don't know why exactly but this is the DeclContext here.
8675 EXPECT_EQ(FromDGCtorTP->getParam(0)->getDeclContext(),
8676 FromDGCopyCtor->getTemplatedDecl());
8677 EXPECT_EQ(FromDGCtorTP->getParam(1)->getDeclContext(),
8678 FromDGCtor->getTemplatedDecl());
8679 EXPECT_EQ(FromDGCtorTP->getParam(2)->getDeclContext(),
8680 FromDGCtor->getTemplatedDecl());
8681 EXPECT_EQ(
8682 FromDGCopyCtor->getTemplateParameters()->getParam(0)->getDeclContext(),
8683 FromDGCopyCtor->getTemplatedDecl());
8684 EXPECT_EQ(FromDGOther->getDescribedTemplate()
8685 ->getTemplateParameters()
8686 ->getParam(0)
8687 ->getDeclContext(),
8688 FromDGOther);
8689
8690 // Here the import of 'ToDGCopyCtor' and 'ToDGCtor' is reversed relative to
8691 // the previous test.
8692 auto *ToDGCopyCtor = Import(FromDGCopyCtor, Lang_CXX17);
8693 auto *ToDGCtor = Import(FromDGCtor, Lang_CXX17);
8694 auto *ToDGOther = Import(FromDGOther, Lang_CXX17);
8695 ASSERT_TRUE(ToDGCtor);
8696 ASSERT_TRUE(ToDGCopyCtor);
8697 ASSERT_TRUE(ToDGOther);
8698
8699 TemplateParameterList *ToDGCtorTP = ToDGCtor->getTemplateParameters();
8700 // Next line: DeclContext is different relative to the previous test.
8701 EXPECT_EQ(ToDGCtorTP->getParam(0)->getDeclContext(),
8702 ToDGCtor->getTemplatedDecl());
8703 EXPECT_EQ(ToDGCtorTP->getParam(1)->getDeclContext(),
8704 ToDGCtor->getTemplatedDecl());
8705 EXPECT_EQ(ToDGCtorTP->getParam(2)->getDeclContext(),
8706 ToDGCtor->getTemplatedDecl());
8707 // Next line: DeclContext is different relative to the previous test.
8708 EXPECT_EQ(
8709 ToDGCopyCtor->getTemplateParameters()->getParam(0)->getDeclContext(),
8710 ToDGCtor->getTemplatedDecl());
8711 EXPECT_EQ(ToDGOther->getDescribedTemplate()
8712 ->getTemplateParameters()
8713 ->getParam(0)
8714 ->getDeclContext(),
8715 ToDGOther);
8716}
8717
8718TEST_P(ASTImporterOptionSpecificTestBase,
8719 ImportFieldsFirstForCorrectRecordLayout) {
8720 // UnaryOperator(&) triggers RecordLayout computation, which relies on
8721 // correctly imported fields.
8722 auto Code =
8723 R"(
8724 class A {
8725 int m() {
8726 return &((A *)0)->f1 - &((A *)0)->f2;
8727 }
8728 int f1;
8729 int f2;
8730 };
8731 )";
8732 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11);
8733
8734 auto *FromF = FirstDeclMatcher<CXXMethodDecl>().match(
8735 D: FromTU, AMatcher: cxxMethodDecl(hasName(Name: "A::m")));
8736 Import(FromF, Lang_CXX11);
8737}
8738
8739TEST_P(ASTImporterOptionSpecificTestBase,
8740 ImportCirularRefFieldsWithoutCorruptedRecordLayoutCache) {
8741 // Import sequence: A => A.b => B => B.f() => ... => UnaryOperator(&) => ...
8742 //
8743 // UnaryOperator(&) should not introduce invalid RecordLayout since 'A' is
8744 // still not completely imported.
8745 auto Code =
8746 R"(
8747 class B;
8748 class A {
8749 B* b;
8750 int c;
8751 };
8752 class B {
8753 A *f() { return &((B *)0)->a; }
8754 A a;
8755 };
8756 )";
8757
8758 auto *FromR = FirstDeclMatcher<CXXRecordDecl>().match(
8759 getTuDecl(SrcCode: Code, Lang: Lang_CXX11), cxxRecordDecl(hasName(Name: "A")));
8760 FromR = FromR->getDefinition();
8761 auto &FromAST = FromR->getASTContext();
8762 auto *ToR = Import(FromR, Lang_CXX11);
8763 auto &ToAST = ToR->getASTContext();
8764
8765 uint64_t SecondFieldOffset = FromAST.getTypeSize(FromAST.VoidPtrTy);
8766
8767 EXPECT_TRUE(FromR->isCompleteDefinition());
8768 const auto &FromLayout = FromAST.getASTRecordLayout(FromR);
8769 EXPECT_TRUE(FromLayout.getFieldOffset(0) == 0);
8770 EXPECT_TRUE(FromLayout.getFieldOffset(1) == SecondFieldOffset);
8771
8772 EXPECT_TRUE(ToR->isCompleteDefinition());
8773 const auto &ToLayout = ToAST.getASTRecordLayout(ToR);
8774 EXPECT_TRUE(ToLayout.getFieldOffset(0) == 0);
8775 EXPECT_TRUE(ToLayout.getFieldOffset(1) == SecondFieldOffset);
8776}
8777
8778TEST_P(ASTImporterOptionSpecificTestBase,
8779 ImportRecordWithLayoutRequestingExpr) {
8780 TranslationUnitDecl *FromTU = getTuDecl(
8781 SrcCode: R"(
8782 struct A {
8783 int idx;
8784 static void foo(A x) {
8785 (void)&"text"[x.idx];
8786 }
8787 };
8788 )",
8789 Lang: Lang_CXX11);
8790
8791 auto *FromA = FirstDeclMatcher<CXXRecordDecl>().match(
8792 FromTU, cxxRecordDecl(hasName(Name: "A")));
8793
8794 // Test that during import of 'foo' the record layout can be obtained without
8795 // crash.
8796 auto *ToA = Import(FromA, Lang_CXX11);
8797 EXPECT_TRUE(ToA);
8798 EXPECT_TRUE(ToA->isCompleteDefinition());
8799}
8800
8801TEST_P(ASTImporterOptionSpecificTestBase,
8802 ImportRecordWithLayoutRequestingExprDifferentRecord) {
8803 TranslationUnitDecl *FromTU = getTuDecl(
8804 SrcCode: R"(
8805 struct B;
8806 struct A {
8807 int idx;
8808 B *b;
8809 };
8810 struct B {
8811 static void foo(A x) {
8812 (void)&"text"[x.idx];
8813 }
8814 };
8815 )",
8816 Lang: Lang_CXX11);
8817
8818 auto *FromA = FirstDeclMatcher<CXXRecordDecl>().match(
8819 FromTU, cxxRecordDecl(hasName(Name: "A")));
8820
8821 // Test that during import of 'foo' the record layout (of 'A') can be obtained
8822 // without crash. It is not possible to have all of the fields of 'A' imported
8823 // at that time (without big code changes).
8824 auto *ToA = Import(FromA, Lang_CXX11);
8825 EXPECT_TRUE(ToA);
8826 EXPECT_TRUE(ToA->isCompleteDefinition());
8827}
8828
8829TEST_P(ASTImporterOptionSpecificTestBase, ImportInClassInitializerFromField) {
8830 // Encounter import of a field when the field already exists but has the
8831 // in-class initializer expression not yet set. Such case can occur in the AST
8832 // of generated template specializations.
8833 // The first code forces to create a template specialization of
8834 // `A<int>` but without implicit constructors.
8835 // The second ("From") code contains a variable of type `A<int>`, this
8836 // results in a template specialization that has constructors and
8837 // CXXDefaultInitExpr nodes.
8838 Decl *ToTU = getToTuDecl(
8839 ToSrcCode: R"(
8840 void f();
8841 template<typename> struct A { int X = 1; };
8842 struct B { A<int> Y; };
8843 )",
8844 ToLang: Lang_CXX11);
8845 auto *ToX = FirstDeclMatcher<FieldDecl>().match(
8846 D: ToTU,
8847 AMatcher: fieldDecl(hasName(Name: "X"), hasParent(classTemplateSpecializationDecl())));
8848 ASSERT_TRUE(ToX->hasInClassInitializer());
8849 ASSERT_FALSE(ToX->getInClassInitializer());
8850
8851 Decl *FromTU = getTuDecl(
8852 SrcCode: R"(
8853 void f();
8854 template<typename> struct A { int X = 1; };
8855 struct B { A<int> Y; };
8856 //
8857 A<int> Z;
8858 )",
8859 Lang: Lang_CXX11, FileName: "input1.cc");
8860 auto *FromX = FirstDeclMatcher<FieldDecl>().match(
8861 D: FromTU,
8862 AMatcher: fieldDecl(hasName(Name: "X"), hasParent(classTemplateSpecializationDecl())));
8863
8864 auto *ToXImported = Import(FromX, Lang_CXX11);
8865 EXPECT_EQ(ToXImported, ToX);
8866 EXPECT_TRUE(ToX->getInClassInitializer());
8867}
8868
8869TEST_P(ASTImporterOptionSpecificTestBase,
8870 ImportInClassInitializerFromCXXDefaultInitExpr) {
8871 // Encounter AST import of a CXXDefaultInitExpr where the "to-field"
8872 // of it exists but has the in-class initializer not set yet.
8873 Decl *ToTU = getToTuDecl(
8874 ToSrcCode: R"(
8875 namespace N {
8876 template<typename> int b;
8877 struct X;
8878 }
8879 template<typename> struct A { N::X *X = nullptr; };
8880 struct B { A<int> Y; };
8881 )",
8882 ToLang: Lang_CXX14);
8883 auto *ToX = FirstDeclMatcher<FieldDecl>().match(
8884 D: ToTU,
8885 AMatcher: fieldDecl(hasName(Name: "X"), hasParent(classTemplateSpecializationDecl())));
8886 ASSERT_TRUE(ToX->hasInClassInitializer());
8887 ASSERT_FALSE(ToX->getInClassInitializer());
8888
8889 Decl *FromTU = getTuDecl(
8890 SrcCode: R"(
8891 namespace N {
8892 template<typename> int b;
8893 struct X;
8894 }
8895 template<typename> struct A { N::X *X = nullptr; };
8896 struct B { A<int> Y; };
8897 //
8898 void f() {
8899 (void)A<int>{};
8900 }
8901 struct C {
8902 C(): attr(new A<int>{}){}
8903 A<int> *attr;
8904 const int value = N::b<C>;
8905 };
8906 )",
8907 Lang: Lang_CXX14, FileName: "input1.cc");
8908 auto *FromF = FirstDeclMatcher<FunctionDecl>().match(
8909 D: FromTU, AMatcher: functionDecl(hasName(Name: "f"), isDefinition()));
8910 auto *ToF = Import(FromF, Lang_CXX11);
8911 EXPECT_TRUE(ToF);
8912 EXPECT_TRUE(ToX->getInClassInitializer());
8913}
8914
8915TEST_P(ASTImporterOptionSpecificTestBase, ImportRecursiveFieldInitializer) {
8916 const char *Code =
8917 R"(
8918 struct AP_TECS;
8919
8920 struct AP_Landing {
8921 AP_TECS *TECS_controller;
8922 };
8923
8924 struct AP_TECS {
8925 AP_Landing landing;
8926 };
8927
8928 class Plane {
8929 AP_TECS TECS_controller{landing};
8930 AP_Landing landing{&TECS_controller};
8931 };
8932 )";
8933 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11);
8934
8935 auto *FromR = FirstDeclMatcher<CXXRecordDecl>().match(
8936 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "Plane")));
8937 for (FieldDecl *F : FromR->fields())
8938 EXPECT_TRUE(F->getInClassInitializer());
8939 auto *ToR = Import(FromR, Lang_CXX11);
8940 for (FieldDecl *F : ToR->fields())
8941 EXPECT_TRUE(F->getInClassInitializer());
8942}
8943
8944TEST_P(ASTImporterOptionSpecificTestBase, ImportFieldInitializerWithItself) {
8945 const char *Code =
8946 R"(
8947 class A {
8948 int a{a};
8949 };
8950 )";
8951 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11);
8952 auto *FromA = FirstDeclMatcher<CXXRecordDecl>().match(
8953 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A")));
8954 EXPECT_TRUE(FromA->field_begin()->getInClassInitializer());
8955 auto *ToA = Import(FromA, Lang_CXX11);
8956 EXPECT_TRUE(ToA->field_begin()->getInClassInitializer());
8957}
8958
8959TEST_P(ASTImporterOptionSpecificTestBase, ImportRecursiveFieldInitializer1) {
8960 // FIXME: This is a example of recursive field initialization that is not
8961 // supported.
8962 // The following import chain occurs (not complete):
8963 // import of A => A.a => in-class initializer of A.a => ref_B() => B => B.b
8964 // => in-class initializer of B.b => ref_A() => CXXConstructExpr for A =>
8965 // CXXDefaultInitExpr for A.a => in-class initializer of A.a
8966 // in-class initializer of A.a is created in two different instances in this
8967 // case (import of FieldDecl and CXXDefaultInitExpr). Probably not a big
8968 // problem because it is an Expr (the second construction can be ignored
8969 // instead of assert). But such recursive init code should not occur in
8970 // practice.
8971 const char *Code =
8972 R"(
8973 static int ref_A();
8974 static int ref_B();
8975 struct A {
8976 int a = ref_B();
8977 };
8978 struct B {
8979 int b = ref_A();
8980 };
8981 int ref_B() { B b; return b.b; }
8982 int ref_A() { A a; return a.a; }
8983 )";
8984 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11);
8985 auto *FromA = FirstDeclMatcher<CXXRecordDecl>().match(
8986 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A")));
8987 EXPECT_TRUE(FromA->field_begin()->getInClassInitializer());
8988 // auto *ToA = Import(FromA, Lang_CXX11);
8989 // EXPECT_TRUE(ToA->field_begin()->getInClassInitializer());
8990}
8991
8992TEST_P(ASTImporterOptionSpecificTestBase, isNewDecl) {
8993 Decl *FromTU = getTuDecl(
8994 SrcCode: R"(
8995 int bar() {
8996 return 0;
8997 }
8998 void other() {
8999 bar();
9000 }
9001 )",
9002 Lang: Lang_CXX11);
9003 Decl *ToTU = getToTuDecl(
9004 ToSrcCode: R"(
9005 int bar() {
9006 return 0;
9007 }
9008 )",
9009 ToLang: Lang_CXX11);
9010 auto *FromOther = FirstDeclMatcher<FunctionDecl>().match(
9011 D: FromTU, AMatcher: functionDecl(hasName(Name: "other")));
9012 ASSERT_TRUE(FromOther);
9013
9014 auto *ToOther = Import(FromOther, Lang_CXX11);
9015 ASSERT_TRUE(ToOther);
9016
9017 auto *ToBar = FirstDeclMatcher<FunctionDecl>().match(
9018 D: ToTU, AMatcher: functionDecl(hasName(Name: "bar")));
9019
9020 EXPECT_TRUE(SharedStatePtr->isNewDecl(ToOther));
9021 EXPECT_FALSE(SharedStatePtr->isNewDecl(ToBar));
9022}
9023
9024struct ImportInjectedClassNameType : public ASTImporterOptionSpecificTestBase {
9025protected:
9026 const CXXRecordDecl *findInjected(const CXXRecordDecl *Parent) {
9027 for (Decl *Found : Parent->decls()) {
9028 const auto *Record = dyn_cast<CXXRecordDecl>(Found);
9029 if (Record && Record->isInjectedClassName())
9030 return Record;
9031 }
9032 return nullptr;
9033 }
9034
9035 void checkInjType(const CXXRecordDecl *D) {
9036 // The whole redecl chain should have the same InjectedClassNameType
9037 // instance. The injected record declaration is a separate chain, this
9038 // should contain the same type too.
9039 const Type *Ty = nullptr;
9040 for (const Decl *ReD : D->redecls()) {
9041 const auto *ReRD = cast<CXXRecordDecl>(ReD);
9042 EXPECT_TRUE(ReRD->getTypeForDecl());
9043 EXPECT_TRUE(!Ty || Ty == ReRD->getTypeForDecl());
9044 Ty = ReRD->getTypeForDecl();
9045 }
9046 ASSERT_TRUE(Ty);
9047 const auto *InjTy = Ty->castAs<InjectedClassNameType>();
9048 EXPECT_TRUE(InjTy);
9049 if (CXXRecordDecl *Def = D->getDefinition()) {
9050 const CXXRecordDecl *InjRD = findInjected(Parent: Def);
9051 EXPECT_TRUE(InjRD);
9052 EXPECT_EQ(InjRD->getTypeForDecl(), InjTy);
9053 }
9054 }
9055
9056 void testImport(Decl *ToTU, Decl *FromTU, Decl *FromD) {
9057 checkInjType(D: cast<CXXRecordDecl>(Val: FromD));
9058 Decl *ToD = Import(From: FromD, ToLang: Lang_CXX11);
9059 if (auto *ToRD = dyn_cast<CXXRecordDecl>(Val: ToD))
9060 checkInjType(D: ToRD);
9061 }
9062
9063 const char *ToCodeA =
9064 R"(
9065 template <class T>
9066 struct A;
9067 )";
9068 const char *ToCodeADef =
9069 R"(
9070 template <class T>
9071 struct A {
9072 typedef A T1;
9073 };
9074 )";
9075 const char *ToCodeC =
9076 R"(
9077 template <class T>
9078 struct C;
9079 )";
9080 const char *ToCodeCDef =
9081 R"(
9082 template <class T>
9083 struct A {
9084 typedef A T1;
9085 };
9086
9087 template <class T1, class T2>
9088 struct B {};
9089
9090 template<class T>
9091 struct C {
9092 typedef typename A<T>::T1 T1;
9093 typedef B<T1, T> T2;
9094 typedef B<T1, C> T3;
9095 };
9096 )";
9097 const char *FromCode =
9098 R"(
9099 template <class T>
9100 struct A;
9101 template <class T>
9102 struct A {
9103 typedef A T1;
9104 };
9105 template <class T>
9106 struct A;
9107
9108 template <class T1, class T2>
9109 struct B {};
9110
9111 template <class T>
9112 struct C;
9113 template <class T>
9114 struct C {
9115 typedef typename A<T>::T1 T1;
9116 typedef B<T1, T> T2;
9117 typedef B<T1, C> T3;
9118 };
9119 template <class T>
9120 struct C;
9121
9122 template <class T>
9123 struct D {
9124 void f(typename C<T>::T3 *);
9125 };
9126 )";
9127};
9128
9129TEST_P(ImportInjectedClassNameType, ImportADef) {
9130 Decl *ToTU = getToTuDecl(ToSrcCode: ToCodeA, ToLang: Lang_CXX11);
9131 Decl *FromTU = getTuDecl(SrcCode: FromCode, Lang: Lang_CXX11);
9132 auto *FromA = FirstDeclMatcher<CXXRecordDecl>().match(
9133 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A"), isDefinition()));
9134 testImport(ToTU, FromTU, FromD: FromA);
9135}
9136
9137TEST_P(ImportInjectedClassNameType, ImportAFirst) {
9138 Decl *ToTU = getToTuDecl(ToSrcCode: ToCodeA, ToLang: Lang_CXX11);
9139 Decl *FromTU = getTuDecl(SrcCode: FromCode, Lang: Lang_CXX11);
9140 auto *FromA = FirstDeclMatcher<CXXRecordDecl>().match(
9141 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A")));
9142 testImport(ToTU, FromTU, FromD: FromA);
9143}
9144
9145TEST_P(ImportInjectedClassNameType, ImportALast) {
9146 Decl *ToTU = getToTuDecl(ToSrcCode: ToCodeA, ToLang: Lang_CXX11);
9147 Decl *FromTU = getTuDecl(SrcCode: FromCode, Lang: Lang_CXX11);
9148 auto *FromA = LastDeclMatcher<CXXRecordDecl>().match(
9149 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A")));
9150 testImport(ToTU, FromTU, FromD: FromA);
9151}
9152
9153TEST_P(ImportInjectedClassNameType, ImportADefToDef) {
9154 Decl *ToTU = getToTuDecl(ToSrcCode: ToCodeADef, ToLang: Lang_CXX11);
9155 Decl *FromTU = getTuDecl(SrcCode: FromCode, Lang: Lang_CXX11);
9156 auto *FromA = FirstDeclMatcher<CXXRecordDecl>().match(
9157 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A"), isDefinition()));
9158 testImport(ToTU, FromTU, FromD: FromA);
9159}
9160
9161TEST_P(ImportInjectedClassNameType, ImportAFirstToDef) {
9162 Decl *ToTU = getToTuDecl(ToSrcCode: ToCodeADef, ToLang: Lang_CXX11);
9163 Decl *FromTU = getTuDecl(SrcCode: FromCode, Lang: Lang_CXX11);
9164 auto *FromA = FirstDeclMatcher<CXXRecordDecl>().match(
9165 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A")));
9166 testImport(ToTU, FromTU, FromD: FromA);
9167}
9168
9169TEST_P(ImportInjectedClassNameType, ImportALastToDef) {
9170 Decl *ToTU = getToTuDecl(ToSrcCode: ToCodeADef, ToLang: Lang_CXX11);
9171 Decl *FromTU = getTuDecl(SrcCode: FromCode, Lang: Lang_CXX11);
9172 auto *FromA = LastDeclMatcher<CXXRecordDecl>().match(
9173 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A")));
9174 testImport(ToTU, FromTU, FromD: FromA);
9175}
9176
9177TEST_P(ImportInjectedClassNameType, ImportCDef) {
9178 Decl *ToTU = getToTuDecl(ToSrcCode: ToCodeC, ToLang: Lang_CXX11);
9179 Decl *FromTU = getTuDecl(SrcCode: FromCode, Lang: Lang_CXX11);
9180 auto *FromC = FirstDeclMatcher<CXXRecordDecl>().match(
9181 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "C"), isDefinition()));
9182 testImport(ToTU, FromTU, FromD: FromC);
9183}
9184
9185TEST_P(ImportInjectedClassNameType, ImportCLast) {
9186 Decl *ToTU = getToTuDecl(ToSrcCode: ToCodeC, ToLang: Lang_CXX11);
9187 Decl *FromTU = getTuDecl(SrcCode: FromCode, Lang: Lang_CXX11);
9188 auto *FromC = LastDeclMatcher<CXXRecordDecl>().match(
9189 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "C")));
9190 testImport(ToTU, FromTU, FromD: FromC);
9191}
9192
9193TEST_P(ImportInjectedClassNameType, ImportCDefToDef) {
9194 Decl *ToTU = getToTuDecl(ToSrcCode: ToCodeCDef, ToLang: Lang_CXX11);
9195 Decl *FromTU = getTuDecl(SrcCode: FromCode, Lang: Lang_CXX11);
9196 auto *FromC = FirstDeclMatcher<CXXRecordDecl>().match(
9197 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "C"), isDefinition()));
9198 testImport(ToTU, FromTU, FromD: FromC);
9199}
9200
9201TEST_P(ImportInjectedClassNameType, ImportCLastToDef) {
9202 Decl *ToTU = getToTuDecl(ToSrcCode: ToCodeCDef, ToLang: Lang_CXX11);
9203 Decl *FromTU = getTuDecl(SrcCode: FromCode, Lang: Lang_CXX11);
9204 auto *FromC = LastDeclMatcher<CXXRecordDecl>().match(
9205 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "C")));
9206 testImport(ToTU, FromTU, FromD: FromC);
9207}
9208
9209TEST_P(ImportInjectedClassNameType, ImportD) {
9210 Decl *ToTU = getToTuDecl(ToSrcCode: "", ToLang: Lang_CXX11);
9211 Decl *FromTU = getTuDecl(SrcCode: FromCode, Lang: Lang_CXX11);
9212 auto *FromD = FirstDeclMatcher<CXXRecordDecl>().match(
9213 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "D"), isDefinition()));
9214 testImport(ToTU, FromTU, FromD: FromD);
9215}
9216
9217TEST_P(ImportInjectedClassNameType, ImportDToDef) {
9218 Decl *ToTU = getToTuDecl(ToSrcCode: ToCodeCDef, ToLang: Lang_CXX11);
9219 Decl *FromTU = getTuDecl(SrcCode: FromCode, Lang: Lang_CXX11);
9220 auto *FromD = FirstDeclMatcher<CXXRecordDecl>().match(
9221 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "D"), isDefinition()));
9222 testImport(ToTU, FromTU, FromD: FromD);
9223}
9224
9225TEST_P(ImportInjectedClassNameType, ImportTypedefType) {
9226 Decl *ToTU = getToTuDecl(
9227 ToSrcCode: R"(
9228 template <class T>
9229 struct A {
9230 typedef A A1;
9231 void f(A1 *);
9232 };
9233 )",
9234 ToLang: Lang_CXX11);
9235 Decl *FromTU = getTuDecl(
9236 SrcCode: R"(
9237 template <class T>
9238 struct A {
9239 typedef A A1;
9240 void f(A1 *);
9241 };
9242 template<class T>
9243 void A<T>::f(A::A1 *) {}
9244 )",
9245 Lang: Lang_CXX11);
9246
9247 auto *FromF = FirstDeclMatcher<FunctionDecl>().match(
9248 D: FromTU, AMatcher: functionDecl(hasName(Name: "f"), isDefinition()));
9249 auto *ToF = Import(FromF, Lang_CXX11);
9250 EXPECT_TRUE(ToF);
9251 ASTContext &ToCtx = ToF->getDeclContext()->getParentASTContext();
9252
9253 auto *ToA1 =
9254 FirstDeclMatcher<TypedefDecl>().match(D: ToTU, AMatcher: typedefDecl(hasName(Name: "A1")));
9255 QualType ToInjTypedef = ToA1->getUnderlyingType().getCanonicalType();
9256 QualType ToInjParmVar =
9257 ToF->parameters()[0]->getType().getDesugaredType(ToCtx);
9258 ToInjParmVar =
9259 ToInjParmVar->getAs<PointerType>()->getPointeeType().getCanonicalType();
9260 EXPECT_TRUE(isa<InjectedClassNameType>(ToInjTypedef));
9261 EXPECT_TRUE(isa<InjectedClassNameType>(ToInjParmVar));
9262 EXPECT_TRUE(ToCtx.hasSameType(ToInjTypedef, ToInjParmVar));
9263}
9264
9265TEST_P(ASTImporterOptionSpecificTestBase, ImportMacroQualifiedType) {
9266 Decl *From, *To;
9267 std::tie(args&: From, args&: To) = getImportedDecl(
9268 FromSrcCode: R"(
9269 #define CDECL __attribute__((cdecl))
9270 typedef void (CDECL *X)();
9271 )",
9272 FromLang: Lang_CXX03, ToSrcCode: "", ToLang: Lang_CXX03, Identifier: "X");
9273
9274 auto *FromTy =
9275 FirstDeclMatcher<MacroQualifiedType>().match(D: From, AMatcher: macroQualifiedType());
9276 auto *ToTy =
9277 FirstDeclMatcher<MacroQualifiedType>().match(D: To, AMatcher: macroQualifiedType());
9278
9279 EXPECT_TRUE(isa<AttributedType>(FromTy->getUnderlyingType()));
9280 EXPECT_TRUE(isa<AttributedType>(ToTy->getUnderlyingType()));
9281}
9282
9283TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplateName) {
9284 constexpr auto TestCode = R"(
9285 template <class T>
9286 struct A;
9287 template <class T>
9288 struct A {};
9289 template <template<class> class T = A>
9290 struct B {};
9291 using C = B<>;
9292 )";
9293 Decl *ToTU = getToTuDecl(ToSrcCode: TestCode, ToLang: Lang_CXX11);
9294 Decl *FromTU = getTuDecl(SrcCode: TestCode, Lang: Lang_CXX11);
9295
9296 auto *ToUsingFirst = FirstDeclMatcher<TypeAliasDecl>().match(
9297 D: ToTU, AMatcher: typeAliasDecl(hasName(Name: "C")));
9298
9299 auto *FromUsing = FirstDeclMatcher<TypeAliasDecl>().match(
9300 D: FromTU, AMatcher: typeAliasDecl(hasName(Name: "C")));
9301 auto *ToUsing = Import(FromUsing, Lang_CXX11);
9302 EXPECT_TRUE(ToUsing);
9303
9304 auto *ToB = FirstDeclMatcher<ClassTemplateDecl>().match(
9305 D: ToTU, AMatcher: classTemplateDecl(hasName(Name: "B")));
9306 auto *ToB1 = LastDeclMatcher<ClassTemplateDecl>().match(
9307 D: ToTU, AMatcher: classTemplateDecl(hasName(Name: "B")));
9308 // One template definition of 'B' should exist.
9309 EXPECT_EQ(ToB, ToB1);
9310
9311 // These declarations are imported separately.
9312 EXPECT_NE(ToUsingFirst, ToUsing);
9313
9314 auto SpB = ToB->spec_begin();
9315 auto SpE = ToB->spec_end();
9316 EXPECT_TRUE(SpB != SpE);
9317 ClassTemplateSpecializationDecl *Spec1 = *SpB;
9318 ++SpB;
9319 // The template 'B' should have one specialization (with default argument).
9320 EXPECT_TRUE(SpB == SpE);
9321
9322 // Even if 'B' has one specialization with the default arguments, the AST
9323 // contains after the import two specializations that are linked in the
9324 // declaration chain. The 'spec_begin' iteration does not find these because
9325 // the template arguments are the same. But the imported type alias has the
9326 // link to the second specialization. The template name object in these
9327 // specializations must point to the same (and one) instance of definition of
9328 // 'B'.
9329 auto *Spec2 = cast<ClassTemplateSpecializationDecl>(
9330 ToUsing->getUnderlyingType()
9331 ->getAs<TemplateSpecializationType>()
9332 ->getAsRecordDecl());
9333 EXPECT_NE(Spec1, Spec2);
9334 EXPECT_TRUE(Spec1->getPreviousDecl() == Spec2 ||
9335 Spec2->getPreviousDecl() == Spec1);
9336 TemplateDecl *Templ1 =
9337 Spec1->getTemplateArgs()[0].getAsTemplate().getAsTemplateDecl();
9338 TemplateDecl *Templ2 =
9339 Spec2->getTemplateArgs()[0].getAsTemplate().getAsTemplateDecl();
9340 EXPECT_EQ(Templ1, Templ2);
9341}
9342
9343TEST_P(ASTImporterOptionSpecificTestBase, VaListC) {
9344 Decl *FromTU = getTuDecl(SrcCode: R"(typedef __builtin_va_list va_list;)", Lang: Lang_C99);
9345
9346 auto *FromVaList = FirstDeclMatcher<TypedefDecl>().match(
9347 D: FromTU, AMatcher: typedefDecl(hasName(Name: "va_list")));
9348 ASSERT_TRUE(FromVaList);
9349
9350 auto *ToVaList = Import(FromVaList, Lang_C99);
9351 ASSERT_TRUE(ToVaList);
9352
9353 auto *ToBuiltinVaList = FirstDeclMatcher<TypedefDecl>().match(
9354 ToAST->getASTContext().getTranslationUnitDecl(),
9355 typedefDecl(hasName(Name: "__builtin_va_list")));
9356
9357 ASSERT_TRUE(ToAST->getASTContext().hasSameType(
9358 ToVaList->getUnderlyingType(), ToBuiltinVaList->getUnderlyingType()));
9359}
9360
9361TEST_P(ASTImporterOptionSpecificTestBase, VaListCpp) {
9362 Decl *FromTU = getTuDecl(SrcCode: R"(typedef __builtin_va_list va_list;)", Lang: Lang_CXX03);
9363
9364 auto *FromVaList = FirstDeclMatcher<TypedefDecl>().match(
9365 D: FromTU, AMatcher: typedefDecl(hasName(Name: "va_list")));
9366 ASSERT_TRUE(FromVaList);
9367
9368 auto *ToVaList = Import(FromVaList, Lang_CXX03);
9369 ASSERT_TRUE(ToVaList);
9370
9371 auto *ToBuiltinVaList = FirstDeclMatcher<TypedefDecl>().match(
9372 ToAST->getASTContext().getTranslationUnitDecl(),
9373 typedefDecl(hasName(Name: "__builtin_va_list")));
9374
9375 ASSERT_TRUE(ToAST->getASTContext().hasSameType(
9376 ToVaList->getUnderlyingType(), ToBuiltinVaList->getUnderlyingType()));
9377}
9378
9379TEST_P(ASTImporterOptionSpecificTestBase,
9380 ImportDefinitionOfEmptyClassWithNoUniqueAddressField) {
9381 Decl *FromTU = getTuDecl(
9382 SrcCode: R"(
9383 struct B {};
9384 struct A { B b; };
9385 )",
9386 Lang: Lang_CXX20);
9387
9388 CXXRecordDecl *FromD = FirstDeclMatcher<CXXRecordDecl>().match(
9389 D: FromTU, AMatcher: cxxRecordDecl(hasName(Name: "A")));
9390
9391 for (auto *FD : FromD->fields())
9392 FD->addAttr(clang::NoUniqueAddressAttr::Create(FromD->getASTContext(),
9393 clang::SourceRange()));
9394 FromD->markEmpty();
9395
9396 CXXRecordDecl *ToD = Import(From: FromD, Lang: Lang_CXX20);
9397 EXPECT_TRUE(ToD->isEmpty());
9398 for (auto *FD : ToD->fields())
9399 EXPECT_EQ(true, FD->hasAttr<NoUniqueAddressAttr>());
9400}
9401
9402TEST_P(ASTImporterOptionSpecificTestBase, ImportExistingTypedefToRecord) {
9403 const char *Code =
9404 R"(
9405 struct S { int i; };
9406 typedef struct S T;
9407 extern T x;
9408 )";
9409 Decl *ToTU = getToTuDecl(ToSrcCode: Code, ToLang: Lang_C99);
9410 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_C99);
9411
9412 auto *FromX =
9413 FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: varDecl(hasName(Name: "x")));
9414 auto *ToX = Import(FromX, Lang_C99);
9415 EXPECT_TRUE(ToX);
9416
9417 auto *Typedef1 =
9418 FirstDeclMatcher<TypedefDecl>().match(D: ToTU, AMatcher: typedefDecl(hasName(Name: "T")));
9419 auto *Typedef2 =
9420 LastDeclMatcher<TypedefDecl>().match(D: ToTU, AMatcher: typedefDecl(hasName(Name: "T")));
9421 EXPECT_EQ(Typedef1, Typedef2);
9422}
9423
9424TEST_P(ASTImporterOptionSpecificTestBase,
9425 ImportExistingTypedefToUnnamedRecord) {
9426 const char *Code =
9427 R"(
9428 typedef const struct { int f; } T;
9429 extern T x;
9430 )";
9431 Decl *ToTU = getToTuDecl(ToSrcCode: Code, ToLang: Lang_C99);
9432 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_C99);
9433
9434 auto *FromX =
9435 FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: varDecl(hasName(Name: "x")));
9436 auto *ToX = Import(FromX, Lang_C99);
9437 EXPECT_TRUE(ToX);
9438
9439 auto *Typedef1 =
9440 FirstDeclMatcher<TypedefDecl>().match(D: ToTU, AMatcher: typedefDecl(hasName(Name: "T")));
9441 auto *Typedef2 =
9442 LastDeclMatcher<TypedefDecl>().match(D: ToTU, AMatcher: typedefDecl(hasName(Name: "T")));
9443 EXPECT_NE(Typedef1, Typedef2);
9444 EXPECT_NE(Typedef1->getUnderlyingType().getTypePtr(),
9445 Typedef2->getUnderlyingType().getTypePtr());
9446 EXPECT_EQ(ToX->getType()->getAs<TypedefType>()->getDecl(), Typedef2);
9447}
9448
9449TEST_P(ASTImporterOptionSpecificTestBase, ImportTwoTypedefsToUnnamedRecord) {
9450 const char *Code =
9451 R"(
9452 typedef struct { int f; } T1;
9453 typedef struct { int f; } T2;
9454 extern T1 x1;
9455 extern T2 x2;
9456 )";
9457 Decl *ToTU = getToTuDecl(ToSrcCode: "", ToLang: Lang_C99);
9458 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_C99);
9459
9460 auto *FromX1 =
9461 FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: varDecl(hasName(Name: "x1")));
9462 auto *FromX2 =
9463 FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: varDecl(hasName(Name: "x2")));
9464 auto *ToX1 = Import(FromX1, Lang_C99);
9465 EXPECT_TRUE(ToX1);
9466 auto *ToX2 = Import(FromX2, Lang_C99);
9467 EXPECT_TRUE(ToX2);
9468
9469 auto *Typedef1 =
9470 FirstDeclMatcher<TypedefDecl>().match(D: ToTU, AMatcher: typedefDecl(hasName(Name: "T1")));
9471 auto *Typedef2 =
9472 FirstDeclMatcher<TypedefDecl>().match(D: ToTU, AMatcher: typedefDecl(hasName(Name: "T2")));
9473 EXPECT_NE(Typedef1->getUnderlyingType().getTypePtr(),
9474 Typedef2->getUnderlyingType().getTypePtr());
9475}
9476
9477TEST_P(ASTImporterOptionSpecificTestBase,
9478 ImportExistingTypedefToUnnamedRecordPtr) {
9479 const char *Code =
9480 R"(
9481 typedef const struct { int fff; } * const T;
9482 extern T x;
9483 )";
9484 Decl *ToTU = getToTuDecl(ToSrcCode: Code, ToLang: Lang_C99);
9485 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_C99);
9486
9487 auto *FromX =
9488 FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: varDecl(hasName(Name: "x")));
9489 auto *ToX = Import(FromX, Lang_C99);
9490 EXPECT_TRUE(ToX);
9491
9492 auto *Typedef1 =
9493 FirstDeclMatcher<TypedefDecl>().match(D: ToTU, AMatcher: typedefDecl(hasName(Name: "T")));
9494 auto *Typedef2 =
9495 LastDeclMatcher<TypedefDecl>().match(D: ToTU, AMatcher: typedefDecl(hasName(Name: "T")));
9496 // FIXME: These should be imported separately, like in the test above.
9497 // Or: In the test above these should be merged too.
9498 EXPECT_EQ(Typedef1, Typedef2);
9499
9500 auto *FromR = FirstDeclMatcher<RecordDecl>().match(
9501 D: FromTU, AMatcher: recordDecl(hasDescendant(fieldDecl(hasName(Name: "fff")))));
9502 auto *ToRExisting = FirstDeclMatcher<RecordDecl>().match(
9503 D: ToTU, AMatcher: recordDecl(hasDescendant(fieldDecl(hasName(Name: "fff")))));
9504 ASSERT_TRUE(FromR);
9505 auto *ToRImported = Import(FromR, Lang_C99);
9506 // FIXME: If typedefs are not imported separately, do not import ToRImported
9507 // separately.
9508 EXPECT_NE(ToRExisting, ToRImported);
9509}
9510
9511TEST_P(ASTImporterOptionSpecificTestBase,
9512 ImportTypedefWithDifferentUnderlyingType) {
9513 const char *Code =
9514 R"(
9515 using X1 = int;
9516 using Y1 = int;
9517
9518 using RPB1 = X1*;
9519 typedef RPB1 RPX1;
9520 using RPB1 = Y1*; // redeclared
9521 typedef RPB1 RPY1;
9522
9523 auto X = 0 ? (RPX1){} : (RPY1){};
9524 )";
9525 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11);
9526
9527 auto *FromX =
9528 FirstDeclMatcher<VarDecl>().match(D: FromTU, AMatcher: varDecl(hasName(Name: "X")));
9529
9530 auto *FromXType = FromX->getType()->getAs<TypedefType>();
9531 EXPECT_FALSE(FromXType->typeMatchesDecl());
9532
9533 auto *ToX = Import(FromX, Lang_CXX11);
9534 auto *ToXType = ToX->getType()->getAs<TypedefType>();
9535 // FIXME: This should be false.
9536 EXPECT_TRUE(ToXType->typeMatchesDecl());
9537}
9538
9539TEST_P(ASTImporterOptionSpecificTestBase,
9540 ImportTemplateArgumentWithPointerToDifferentInstantiation) {
9541 const char *CodeTo =
9542 R"(
9543 template<class A>
9544 A f1() {
9545 return A();
9546 }
9547 template<class A, A (B)()>
9548 class X {};
9549
9550 X<int, f1<int>> x;
9551 )";
9552 const char *CodeFrom =
9553 R"(
9554 template<class A>
9555 A f1();
9556 template<class A, A (B)()>
9557 class X {};
9558
9559 X<int, f1<int>> x;
9560 )";
9561 Decl *ToTU = getToTuDecl(ToSrcCode: CodeTo, ToLang: Lang_CXX11);
9562 Decl *FromTU = getTuDecl(SrcCode: CodeFrom, Lang: Lang_CXX11);
9563
9564 auto *ToF1 = FirstDeclMatcher<FunctionDecl>().match(
9565 D: ToTU, AMatcher: functionDecl(hasName(Name: "f1"), isInstantiated()));
9566 auto *FromF1 = FirstDeclMatcher<FunctionDecl>().match(
9567 D: FromTU, AMatcher: functionDecl(hasName(Name: "f1"), isInstantiated()));
9568 EXPECT_TRUE(ToF1->isThisDeclarationADefinition());
9569 EXPECT_FALSE(FromF1->isThisDeclarationADefinition());
9570
9571 auto *ToX = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
9572 D: ToTU, AMatcher: classTemplateSpecializationDecl(hasName(Name: "X")));
9573 auto *FromX = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
9574 D: FromTU, AMatcher: classTemplateSpecializationDecl(hasName(Name: "X")));
9575
9576 Decl *ToTArgF = ToX->getTemplateArgs().get(1).getAsDecl();
9577 Decl *FromTArgF = FromX->getTemplateArgs().get(1).getAsDecl();
9578 EXPECT_EQ(ToTArgF, ToF1);
9579 EXPECT_EQ(FromTArgF, FromF1);
9580
9581 auto *ToXImported = Import(FromX, Lang_CXX11);
9582 // The template argument 1 of 'X' in the "From" code points to a function
9583 // that has no definition. The import must ensure that this template argument
9584 // is imported in a way that it will point to the existing 'f1' function, not
9585 // to the 'f1' that is imported. In this way when specialization of 'X' is
9586 // imported it will have the same template arguments as the existing one.
9587 EXPECT_EQ(ToXImported, ToX);
9588 // FIXME: This matcher causes a crash "Tried to match orphan node".
9589 // The code is removed until the problem is fixed.
9590 // auto *ToF1Imported =
9591 // LastDeclMatcher<FunctionDecl>().match(ToTU,
9592 // functionDecl(hasName("f1"),isInstantiated()));
9593 // EXPECT_NE(ToF1Imported, ToF1);
9594 // EXPECT_EQ(ToF1Imported->getPreviousDecl(), ToF1);
9595}
9596
9597TEST_P(ASTImporterOptionSpecificTestBase,
9598 ImportTypeAliasTemplateAfterSimilarCalledTemplateTypeParm) {
9599 const char *Code =
9600 R"(
9601 struct S;
9602 template <typename>
9603 using Callable = S;
9604 template <typename Callable>
9605 int bindingFunctionVTable;
9606 )";
9607 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX17);
9608
9609 auto *FromCallable = FirstDeclMatcher<TypeAliasTemplateDecl>().match(
9610 D: FromTU, AMatcher: typeAliasTemplateDecl(hasName(Name: "Callable")));
9611
9612 auto *FromCallableParm = FirstDeclMatcher<TemplateTypeParmDecl>().match(
9613 D: FromTU, AMatcher: templateTypeParmDecl(hasName(Name: "Callable")));
9614
9615 auto *ToFromCallableParm = Import(FromCallableParm, Lang_CXX17);
9616 auto *ToCallable = Import(FromCallable, Lang_CXX17);
9617 EXPECT_TRUE(ToFromCallableParm);
9618 EXPECT_TRUE(ToCallable);
9619}
9620
9621TEST_P(ASTImporterOptionSpecificTestBase, ImportConflictTypeAliasTemplate) {
9622 const char *ToCode =
9623 R"(
9624 struct S;
9625 template <typename, typename>
9626 using Callable = S;
9627 )";
9628 const char *Code =
9629 R"(
9630 struct S;
9631 template <typename>
9632 using Callable = S;
9633 )";
9634 (void)getToTuDecl(ToSrcCode: ToCode, ToLang: Lang_CXX17);
9635 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX17);
9636
9637 auto *FromCallable = FirstDeclMatcher<TypeAliasTemplateDecl>().match(
9638 D: FromTU, AMatcher: typeAliasTemplateDecl(hasName(Name: "Callable")));
9639
9640 auto *ImportedCallable = Import(FromCallable, Lang_CXX17);
9641 EXPECT_FALSE(ImportedCallable);
9642}
9643
9644AST_MATCHER(ClassTemplateSpecializationDecl, hasInstantiatedFromMember) {
9645 if (auto Instantiate = Node.getInstantiatedFrom()) {
9646 if (auto *FromPartialSpecialization =
9647 Instantiate.get<ClassTemplatePartialSpecializationDecl *>()) {
9648 return nullptr != FromPartialSpecialization->getInstantiatedFromMember();
9649 }
9650 }
9651 return false;
9652}
9653
9654TEST_P(ASTImporterOptionSpecificTestBase, ImportInstantiatedFromMember) {
9655 const char *Code =
9656 R"(
9657 template <typename> struct B {
9658 template <typename, bool = false> union D;
9659 template <typename T> union D<T> {};
9660 D<int> d;
9661 };
9662 B<int> b;
9663 )";
9664 Decl *FromTU = getTuDecl(SrcCode: Code, Lang: Lang_CXX11);
9665 auto *FromD = FirstDeclMatcher<ClassTemplateSpecializationDecl>().match(
9666 D: FromTU, AMatcher: classTemplateSpecializationDecl(hasName(Name: "D"),
9667 hasInstantiatedFromMember()));
9668 auto *FromPartialSpecialization =
9669 cast<ClassTemplatePartialSpecializationDecl *>(
9670 FromD->getInstantiatedFrom());
9671 ASSERT_TRUE(FromPartialSpecialization->getInstantiatedFromMember());
9672 auto *ImportedPartialSpecialization =
9673 Import(FromPartialSpecialization, Lang_CXX11);
9674 EXPECT_TRUE(ImportedPartialSpecialization->getInstantiatedFromMember());
9675}
9676
9677INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterLookupTableTest,
9678 DefaultTestValuesForRunOptions);
9679
9680INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportPath,
9681 ::testing::Values(std::vector<std::string>()));
9682
9683INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportExpr,
9684 DefaultTestValuesForRunOptions);
9685
9686INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportFixedPointExpr,
9687 ExtendWithOptions(DefaultTestArrayForRunOptions,
9688 std::vector<std::string>{
9689 "-ffixed-point"}));
9690
9691INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportBlock,
9692 ExtendWithOptions(DefaultTestArrayForRunOptions,
9693 std::vector<std::string>{
9694 "-fblocks"}));
9695
9696INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportType,
9697 DefaultTestValuesForRunOptions);
9698
9699INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportDecl,
9700 DefaultTestValuesForRunOptions);
9701
9702INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterOptionSpecificTestBase,
9703 DefaultTestValuesForRunOptions);
9704
9705INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ErrorHandlingTest,
9706 DefaultTestValuesForRunOptions);
9707
9708INSTANTIATE_TEST_SUITE_P(ParameterizedTests, RedirectingImporterTest,
9709 DefaultTestValuesForRunOptions);
9710
9711INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportFunctions,
9712 DefaultTestValuesForRunOptions);
9713
9714INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportAutoFunctions,
9715 DefaultTestValuesForRunOptions);
9716
9717INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportFunctionTemplates,
9718 DefaultTestValuesForRunOptions);
9719
9720INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportFriendFunctionTemplates,
9721 DefaultTestValuesForRunOptions);
9722
9723INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportClasses,
9724 DefaultTestValuesForRunOptions);
9725
9726INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportFriendFunctions,
9727 DefaultTestValuesForRunOptions);
9728
9729INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportFriendClasses,
9730 DefaultTestValuesForRunOptions);
9731
9732INSTANTIATE_TEST_SUITE_P(ParameterizedTests,
9733 ImportFunctionTemplateSpecializations,
9734 DefaultTestValuesForRunOptions);
9735
9736INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportImplicitMethods,
9737 DefaultTestValuesForRunOptions);
9738
9739INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportVariables,
9740 DefaultTestValuesForRunOptions);
9741
9742INSTANTIATE_TEST_SUITE_P(ParameterizedTests, LLDBLookupTest,
9743 DefaultTestValuesForRunOptions);
9744
9745INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportSourceLocations,
9746 DefaultTestValuesForRunOptions);
9747
9748INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportWithExternalSource,
9749 DefaultTestValuesForRunOptions);
9750
9751INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportAttributes,
9752 DefaultTestValuesForRunOptions);
9753
9754INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportInjectedClassNameType,
9755 DefaultTestValuesForRunOptions);
9756
9757INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportMatrixType,
9758 DefaultTestValuesForRunOptions);
9759
9760// FIXME: Make ImportOpenCLPipe test work.
9761// INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportOpenCLPipe,
9762// DefaultTestValuesForRunOptions);
9763GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ImportOpenCLPipe);
9764
9765} // end namespace ast_matchers
9766} // end namespace clang
9767

source code of clang/unittests/AST/ASTImporterTest.cpp