blob: 493b847fa5fa0905a043820d1b660c08db0bea97 [file] [log] [blame]
Gabor Marton1f667532018-05-24 08:41:07 +00001#include "clang/AST/ASTContext.h"
Gabor Marton1f667532018-05-24 08:41:07 +00002#include "clang/AST/ASTStructuralEquivalence.h"
Reid Kleckner213aea42020-03-11 15:39:28 -07003#include "clang/ASTMatchers/ASTMatchers.h"
Gabor Marton1f667532018-05-24 08:41:07 +00004#include "clang/Frontend/ASTUnit.h"
5#include "clang/Tooling/Tooling.h"
Reid Kleckner213aea42020-03-11 15:39:28 -07006#include "llvm/Support/Host.h"
Gabor Marton1f667532018-05-24 08:41:07 +00007
8#include "Language.h"
9#include "DeclMatcher.h"
10
11#include "gtest/gtest.h"
12
13namespace clang {
14namespace ast_matchers {
15
16using std::get;
17
18struct StructuralEquivalenceTest : ::testing::Test {
19 std::unique_ptr<ASTUnit> AST0, AST1;
20 std::string Code0, Code1; // Buffers for SourceManager
21
Balazs Keric7797c42018-07-11 09:37:24 +000022 // Get a pair of node pointers into the synthesized AST from the given code
23 // snippets. To determine the returned node, a separate matcher is specified
24 // for both snippets. The first matching node is returned.
25 template <typename NodeType, typename MatcherType>
26 std::tuple<NodeType *, NodeType *> makeDecls(
27 const std::string &SrcCode0, const std::string &SrcCode1, Language Lang,
28 const MatcherType &Matcher0, const MatcherType &Matcher1) {
Gabor Marton1f667532018-05-24 08:41:07 +000029 this->Code0 = SrcCode0;
30 this->Code1 = SrcCode1;
31 ArgVector Args = getBasicRunOptionsForLanguage(Lang);
32
33 const char *const InputFileName = "input.cc";
34
35 AST0 = tooling::buildASTFromCodeWithArgs(Code0, Args, InputFileName);
36 AST1 = tooling::buildASTFromCodeWithArgs(Code1, Args, InputFileName);
37
Balazs Keric7797c42018-07-11 09:37:24 +000038 NodeType *D0 = FirstDeclMatcher<NodeType>().match(
39 AST0->getASTContext().getTranslationUnitDecl(), Matcher0);
40 NodeType *D1 = FirstDeclMatcher<NodeType>().match(
41 AST1->getASTContext().getTranslationUnitDecl(), Matcher1);
Gabor Marton1f667532018-05-24 08:41:07 +000042
Gabor Marton1f667532018-05-24 08:41:07 +000043 return std::make_tuple(D0, D1);
44 }
45
Gabor Martonf086fa82018-07-17 12:06:36 +000046 std::tuple<TranslationUnitDecl *, TranslationUnitDecl *> makeTuDecls(
47 const std::string &SrcCode0, const std::string &SrcCode1, Language Lang) {
48 this->Code0 = SrcCode0;
49 this->Code1 = SrcCode1;
50 ArgVector Args = getBasicRunOptionsForLanguage(Lang);
51
52 const char *const InputFileName = "input.cc";
53
54 AST0 = tooling::buildASTFromCodeWithArgs(Code0, Args, InputFileName);
55 AST1 = tooling::buildASTFromCodeWithArgs(Code1, Args, InputFileName);
56
57 return std::make_tuple(AST0->getASTContext().getTranslationUnitDecl(),
58 AST1->getASTContext().getTranslationUnitDecl());
59 }
60
Balazs Keric7797c42018-07-11 09:37:24 +000061 // Get a pair of node pointers into the synthesized AST from the given code
62 // snippets. The same matcher is used for both snippets.
63 template <typename NodeType, typename MatcherType>
64 std::tuple<NodeType *, NodeType *> makeDecls(
65 const std::string &SrcCode0, const std::string &SrcCode1, Language Lang,
66 const MatcherType &AMatcher) {
67 return makeDecls<NodeType, MatcherType>(
68 SrcCode0, SrcCode1, Lang, AMatcher, AMatcher);
69 }
70
71 // Get a pair of Decl pointers to the synthesized declarations from the given
72 // code snippets. We search for the first NamedDecl with given name in both
73 // snippets.
74 std::tuple<NamedDecl *, NamedDecl *> makeNamedDecls(
75 const std::string &SrcCode0, const std::string &SrcCode1,
76 Language Lang, const char *const Identifier = "foo") {
77 auto Matcher = namedDecl(hasName(Identifier));
78 return makeDecls<NamedDecl>(SrcCode0, SrcCode1, Lang, Matcher);
79 }
80
Gabor Martonf086fa82018-07-17 12:06:36 +000081 bool testStructuralMatch(Decl *D0, Decl *D1) {
Balazs Keria0a81b12018-08-08 15:04:27 +000082 llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls01;
83 llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls10;
84 StructuralEquivalenceContext Ctx01(
85 D0->getASTContext(), D1->getASTContext(),
86 NonEquivalentDecls01, StructuralEquivalenceKind::Default, false, false);
87 StructuralEquivalenceContext Ctx10(
88 D1->getASTContext(), D0->getASTContext(),
89 NonEquivalentDecls10, StructuralEquivalenceKind::Default, false, false);
90 bool Eq01 = Ctx01.IsEquivalent(D0, D1);
91 bool Eq10 = Ctx10.IsEquivalent(D1, D0);
92 EXPECT_EQ(Eq01, Eq10);
93 return Eq01;
Gabor Marton1f667532018-05-24 08:41:07 +000094 }
95
Gabor Martonf086fa82018-07-17 12:06:36 +000096 bool testStructuralMatch(std::tuple<Decl *, Decl *> t) {
Gabor Marton1f667532018-05-24 08:41:07 +000097 return testStructuralMatch(get<0>(t), get<1>(t));
98 }
99};
100
101TEST_F(StructuralEquivalenceTest, Int) {
102 auto Decls = makeNamedDecls("int foo;", "int foo;", Lang_CXX);
103 EXPECT_TRUE(testStructuralMatch(Decls));
104}
105
106TEST_F(StructuralEquivalenceTest, IntVsSignedInt) {
107 auto Decls = makeNamedDecls("int foo;", "signed int foo;", Lang_CXX);
108 EXPECT_TRUE(testStructuralMatch(Decls));
109}
110
111TEST_F(StructuralEquivalenceTest, Char) {
112 auto Decls = makeNamedDecls("char foo;", "char foo;", Lang_CXX);
113 EXPECT_TRUE(testStructuralMatch(Decls));
114}
115
116// This test is disabled for now.
117// FIXME Whether this is equivalent is dependendant on the target.
118TEST_F(StructuralEquivalenceTest, DISABLED_CharVsSignedChar) {
119 auto Decls = makeNamedDecls("char foo;", "signed char foo;", Lang_CXX);
120 EXPECT_FALSE(testStructuralMatch(Decls));
121}
122
123TEST_F(StructuralEquivalenceTest, ForwardRecordDecl) {
124 auto Decls = makeNamedDecls("struct foo;", "struct foo;", Lang_CXX);
125 EXPECT_TRUE(testStructuralMatch(Decls));
126}
127
128TEST_F(StructuralEquivalenceTest, IntVsSignedIntInStruct) {
129 auto Decls = makeNamedDecls("struct foo { int x; };",
130 "struct foo { signed int x; };", Lang_CXX);
131 EXPECT_TRUE(testStructuralMatch(Decls));
132}
133
134TEST_F(StructuralEquivalenceTest, CharVsSignedCharInStruct) {
135 auto Decls = makeNamedDecls("struct foo { char x; };",
136 "struct foo { signed char x; };", Lang_CXX);
137 EXPECT_FALSE(testStructuralMatch(Decls));
138}
139
140TEST_F(StructuralEquivalenceTest, IntVsSignedIntTemplateSpec) {
Balazs Keric7797c42018-07-11 09:37:24 +0000141 auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
142 R"(template <class T> struct foo; template<> struct foo<int>{};)",
143 R"(template <class T> struct foo; template<> struct foo<signed int>{};)",
144 Lang_CXX,
145 classTemplateSpecializationDecl());
146 auto Spec0 = get<0>(Decls);
147 auto Spec1 = get<1>(Decls);
Gabor Marton1f667532018-05-24 08:41:07 +0000148 EXPECT_TRUE(testStructuralMatch(Spec0, Spec1));
149}
150
151TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpec) {
Balazs Keric7797c42018-07-11 09:37:24 +0000152 auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
153 R"(template <class T> struct foo; template<> struct foo<char>{};)",
154 R"(template <class T> struct foo; template<> struct foo<signed char>{};)",
155 Lang_CXX,
156 classTemplateSpecializationDecl());
157 auto Spec0 = get<0>(Decls);
158 auto Spec1 = get<1>(Decls);
Gabor Marton1f667532018-05-24 08:41:07 +0000159 EXPECT_FALSE(testStructuralMatch(Spec0, Spec1));
160}
161
162TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpecWithInheritance) {
Balazs Keric7797c42018-07-11 09:37:24 +0000163 auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
Gabor Marton1f667532018-05-24 08:41:07 +0000164 R"(
165 struct true_type{};
166 template <class T> struct foo;
167 template<> struct foo<char> : true_type {};
168 )",
169 R"(
170 struct true_type{};
171 template <class T> struct foo;
172 template<> struct foo<signed char> : true_type {};
173 )",
Balazs Keric7797c42018-07-11 09:37:24 +0000174 Lang_CXX,
175 classTemplateSpecializationDecl());
176 EXPECT_FALSE(testStructuralMatch(Decls));
Gabor Marton1f667532018-05-24 08:41:07 +0000177}
178
179// This test is disabled for now.
180// FIXME Enable it, once the check is implemented.
181TEST_F(StructuralEquivalenceTest, DISABLED_WrongOrderInNamespace) {
182 auto Code =
183 R"(
184 namespace NS {
185 template <class T> class Base {
186 int a;
187 };
188 class Derived : Base<Derived> {
189 };
190 }
191 void foo(NS::Derived &);
192 )";
193 auto Decls = makeNamedDecls(Code, Code, Lang_CXX);
194
195 NamespaceDecl *NS =
196 LastDeclMatcher<NamespaceDecl>().match(get<1>(Decls), namespaceDecl());
197 ClassTemplateDecl *TD = LastDeclMatcher<ClassTemplateDecl>().match(
198 get<1>(Decls), classTemplateDecl(hasName("Base")));
199
200 // Reorder the decls, move the TD to the last place in the DC.
201 NS->removeDecl(TD);
202 NS->addDeclInternal(TD);
203
204 EXPECT_FALSE(testStructuralMatch(Decls));
205}
206
207TEST_F(StructuralEquivalenceTest, WrongOrderOfFieldsInClass) {
208 auto Code = "class X { int a; int b; };";
209 auto Decls = makeNamedDecls(Code, Code, Lang_CXX, "X");
210
211 CXXRecordDecl *RD = FirstDeclMatcher<CXXRecordDecl>().match(
212 get<1>(Decls), cxxRecordDecl(hasName("X")));
213 FieldDecl *FD =
214 FirstDeclMatcher<FieldDecl>().match(get<1>(Decls), fieldDecl(hasName("a")));
215
216 // Reorder the FieldDecls
217 RD->removeDecl(FD);
218 RD->addDeclInternal(FD);
219
220 EXPECT_FALSE(testStructuralMatch(Decls));
221}
222
Balazs Keric7797c42018-07-11 09:37:24 +0000223struct StructuralEquivalenceFunctionTest : StructuralEquivalenceTest {
224};
225
Balazs Keria0a81b12018-08-08 15:04:27 +0000226TEST_F(StructuralEquivalenceFunctionTest, TemplateVsNonTemplate) {
227 auto t = makeNamedDecls(
228 "void foo();",
229 "template<class T> void foo();",
230 Lang_CXX);
231 EXPECT_FALSE(testStructuralMatch(t));
232}
233
Gabor Martonfc638d62019-02-08 08:55:32 +0000234TEST_F(StructuralEquivalenceFunctionTest, DifferentOperators) {
235 auto t = makeDecls<FunctionDecl>(
236 "struct X{}; bool operator<(X, X);",
237 "struct X{}; bool operator==(X, X);", Lang_CXX,
238 functionDecl(hasOverloadedOperatorName("<")),
239 functionDecl(hasOverloadedOperatorName("==")));
240 EXPECT_FALSE(testStructuralMatch(t));
241}
242
243TEST_F(StructuralEquivalenceFunctionTest, SameOperators) {
244 auto t = makeDecls<FunctionDecl>(
245 "struct X{}; bool operator<(X, X);",
246 "struct X{}; bool operator<(X, X);", Lang_CXX,
247 functionDecl(hasOverloadedOperatorName("<")),
248 functionDecl(hasOverloadedOperatorName("<")));
249 EXPECT_TRUE(testStructuralMatch(t));
250}
251
252TEST_F(StructuralEquivalenceFunctionTest, CtorVsDtor) {
253 auto t = makeDecls<FunctionDecl>(
254 "struct X{ X(); };",
255 "struct X{ ~X(); };", Lang_CXX,
256 cxxConstructorDecl(),
257 cxxDestructorDecl());
258 EXPECT_FALSE(testStructuralMatch(t));
259}
260
Balazs Keric7797c42018-07-11 09:37:24 +0000261TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) {
262 auto t = makeNamedDecls("void foo(int&);",
263 "void foo(const int&);", Lang_CXX);
264 EXPECT_FALSE(testStructuralMatch(t));
265}
266
267TEST_F(StructuralEquivalenceFunctionTest, ParamConstSimple) {
268 auto t = makeNamedDecls("void foo(int);",
269 "void foo(const int);", Lang_CXX);
270 EXPECT_TRUE(testStructuralMatch(t));
271 // consider this OK
272}
273
274TEST_F(StructuralEquivalenceFunctionTest, Throw) {
275 auto t = makeNamedDecls("void foo();",
276 "void foo() throw();", Lang_CXX);
277 EXPECT_FALSE(testStructuralMatch(t));
278}
279
280TEST_F(StructuralEquivalenceFunctionTest, Noexcept) {
281 auto t = makeNamedDecls("void foo();",
282 "void foo() noexcept;", Lang_CXX11);
283 EXPECT_FALSE(testStructuralMatch(t));
284}
285
286TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexcept) {
287 auto t = makeNamedDecls("void foo() throw();",
288 "void foo() noexcept;", Lang_CXX11);
289 EXPECT_FALSE(testStructuralMatch(t));
290}
291
292TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptFalse) {
293 auto t = makeNamedDecls("void foo() throw();",
294 "void foo() noexcept(false);", Lang_CXX11);
295 EXPECT_FALSE(testStructuralMatch(t));
296}
297
298TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptTrue) {
299 auto t = makeNamedDecls("void foo() throw();",
300 "void foo() noexcept(true);", Lang_CXX11);
301 EXPECT_FALSE(testStructuralMatch(t));
302}
303
Gabor Marton1d51e3e2019-05-20 10:38:14 +0000304TEST_F(StructuralEquivalenceFunctionTest, NoexceptNonMatch) {
Balazs Keric7797c42018-07-11 09:37:24 +0000305 auto t = makeNamedDecls("void foo() noexcept(false);",
306 "void foo() noexcept(true);", Lang_CXX11);
307 EXPECT_FALSE(testStructuralMatch(t));
308}
309
310TEST_F(StructuralEquivalenceFunctionTest, NoexceptMatch) {
311 auto t = makeNamedDecls("void foo() noexcept(false);",
312 "void foo() noexcept(false);", Lang_CXX11);
313 EXPECT_TRUE(testStructuralMatch(t));
314}
315
316TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptFalse) {
317 auto t = makeNamedDecls("void foo() noexcept;",
318 "void foo() noexcept(false);", Lang_CXX11);
319 EXPECT_FALSE(testStructuralMatch(t));
320}
321
322TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptTrue) {
323 auto t = makeNamedDecls("void foo() noexcept;",
324 "void foo() noexcept(true);", Lang_CXX11);
325 EXPECT_FALSE(testStructuralMatch(t));
326}
327
328TEST_F(StructuralEquivalenceFunctionTest, ReturnType) {
329 auto t = makeNamedDecls("char foo();",
330 "int foo();", Lang_CXX);
331 EXPECT_FALSE(testStructuralMatch(t));
332}
333
334TEST_F(StructuralEquivalenceFunctionTest, ReturnConst) {
335 auto t = makeNamedDecls("char foo();",
336 "const char foo();", Lang_CXX);
337 EXPECT_FALSE(testStructuralMatch(t));
338}
339
340TEST_F(StructuralEquivalenceFunctionTest, ReturnRef) {
341 auto t = makeNamedDecls("char &foo();",
342 "char &&foo();", Lang_CXX11);
343 EXPECT_FALSE(testStructuralMatch(t));
344}
345
346TEST_F(StructuralEquivalenceFunctionTest, ParamCount) {
347 auto t = makeNamedDecls("void foo(int);",
348 "void foo(int, int);", Lang_CXX);
349 EXPECT_FALSE(testStructuralMatch(t));
350}
351
352TEST_F(StructuralEquivalenceFunctionTest, ParamType) {
353 auto t = makeNamedDecls("void foo(int);",
354 "void foo(char);", Lang_CXX);
355 EXPECT_FALSE(testStructuralMatch(t));
356}
357
358TEST_F(StructuralEquivalenceFunctionTest, ParamName) {
359 auto t = makeNamedDecls("void foo(int a);",
360 "void foo(int b);", Lang_CXX);
361 EXPECT_TRUE(testStructuralMatch(t));
362}
363
364TEST_F(StructuralEquivalenceFunctionTest, Variadic) {
365 auto t = makeNamedDecls("void foo(int x...);",
366 "void foo(int x);", Lang_CXX);
367 EXPECT_FALSE(testStructuralMatch(t));
368}
369
370TEST_F(StructuralEquivalenceFunctionTest, ParamPtr) {
371 auto t = makeNamedDecls("void foo(int *);",
372 "void foo(int);", Lang_CXX);
373 EXPECT_FALSE(testStructuralMatch(t));
374}
375
376TEST_F(StructuralEquivalenceFunctionTest, NameInParen) {
377 auto t = makeNamedDecls(
378 "void ((foo))();",
379 "void foo();",
380 Lang_CXX);
381 EXPECT_TRUE(testStructuralMatch(t));
382}
383
384TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithExceptionSpec) {
385 auto t = makeNamedDecls(
386 "void (foo)() throw(int);",
387 "void (foo)() noexcept;",
388 Lang_CXX11);
389 EXPECT_FALSE(testStructuralMatch(t));
390}
391
392TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithConst) {
393 auto t = makeNamedDecls(
394 "struct A { void (foo)() const; };",
395 "struct A { void (foo)(); };",
396 Lang_CXX11);
397 EXPECT_FALSE(testStructuralMatch(t));
398}
399
Gabor Marton41f20462019-01-24 14:47:44 +0000400TEST_F(StructuralEquivalenceFunctionTest, FunctionsWithDifferentNoreturnAttr) {
401 auto t = makeNamedDecls(
402 "__attribute__((noreturn)) void foo();",
403 " void foo();",
404 Lang_C);
405 EXPECT_TRUE(testStructuralMatch(t));
406}
407
408TEST_F(StructuralEquivalenceFunctionTest,
409 FunctionsWithDifferentCallingConventions) {
David Green1be906a2019-02-02 08:31:22 +0000410 // These attributes may not be available on certain platforms.
411 if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getArch() !=
412 llvm::Triple::x86_64)
413 return;
Gabor Marton41f20462019-01-24 14:47:44 +0000414 auto t = makeNamedDecls(
Gabor Marton23a06fb2019-01-24 15:42:20 +0000415 "__attribute__((preserve_all)) void foo();",
Gabor Marton41f20462019-01-24 14:47:44 +0000416 "__attribute__((ms_abi)) void foo();",
417 Lang_C);
418 EXPECT_FALSE(testStructuralMatch(t));
419}
420
421TEST_F(StructuralEquivalenceFunctionTest, FunctionsWithDifferentSavedRegsAttr) {
David Green1be906a2019-02-02 08:31:22 +0000422 if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getArch() !=
423 llvm::Triple::x86_64)
424 return;
Gabor Marton41f20462019-01-24 14:47:44 +0000425 auto t = makeNamedDecls(
426 "__attribute__((no_caller_saved_registers)) void foo();",
427 " void foo();",
428 Lang_C);
429 EXPECT_FALSE(testStructuralMatch(t));
430}
431
Balazs Keric7797c42018-07-11 09:37:24 +0000432struct StructuralEquivalenceCXXMethodTest : StructuralEquivalenceTest {
433};
434
435TEST_F(StructuralEquivalenceCXXMethodTest, Virtual) {
436 auto t = makeDecls<CXXMethodDecl>(
437 "struct X { void foo(); };",
438 "struct X { virtual void foo(); };", Lang_CXX,
439 cxxMethodDecl(hasName("foo")));
440 EXPECT_FALSE(testStructuralMatch(t));
441}
442
443TEST_F(StructuralEquivalenceCXXMethodTest, Pure) {
444 auto t = makeNamedDecls("struct X { virtual void foo(); };",
445 "struct X { virtual void foo() = 0; };", Lang_CXX);
446 EXPECT_FALSE(testStructuralMatch(t));
447}
448
449TEST_F(StructuralEquivalenceCXXMethodTest, DISABLED_Final) {
450 // The final-ness is not checked yet.
451 auto t = makeNamedDecls("struct X { virtual void foo(); };",
452 "struct X { virtual void foo() final; };", Lang_CXX);
453 EXPECT_FALSE(testStructuralMatch(t));
454}
455
456TEST_F(StructuralEquivalenceCXXMethodTest, Const) {
457 auto t = makeNamedDecls("struct X { void foo(); };",
458 "struct X { void foo() const; };", Lang_CXX);
459 EXPECT_FALSE(testStructuralMatch(t));
460}
461
462TEST_F(StructuralEquivalenceCXXMethodTest, Static) {
463 auto t = makeNamedDecls("struct X { void foo(); };",
464 "struct X { static void foo(); };", Lang_CXX);
465 EXPECT_FALSE(testStructuralMatch(t));
466}
467
468TEST_F(StructuralEquivalenceCXXMethodTest, Ref1) {
469 auto t = makeNamedDecls("struct X { void foo(); };",
470 "struct X { void foo() &&; };", Lang_CXX11);
471 EXPECT_FALSE(testStructuralMatch(t));
472}
473
474TEST_F(StructuralEquivalenceCXXMethodTest, Ref2) {
475 auto t = makeNamedDecls("struct X { void foo() &; };",
476 "struct X { void foo() &&; };", Lang_CXX11);
477 EXPECT_FALSE(testStructuralMatch(t));
478}
479
480TEST_F(StructuralEquivalenceCXXMethodTest, AccessSpecifier) {
481 auto t = makeDecls<CXXMethodDecl>(
482 "struct X { public: void foo(); };",
483 "struct X { private: void foo(); };", Lang_CXX,
484 cxxMethodDecl(hasName("foo")));
485 EXPECT_FALSE(testStructuralMatch(t));
486}
487
488TEST_F(StructuralEquivalenceCXXMethodTest, Delete) {
489 auto t = makeNamedDecls("struct X { void foo(); };",
490 "struct X { void foo() = delete; };", Lang_CXX11);
491 EXPECT_FALSE(testStructuralMatch(t));
492}
493
494TEST_F(StructuralEquivalenceCXXMethodTest, Constructor) {
495 auto t = makeDecls<FunctionDecl>(
496 "void foo();", "struct foo { foo(); };", Lang_CXX,
Balazs Keri36883d32018-07-11 15:26:26 +0000497 functionDecl(hasName("foo")), cxxConstructorDecl(hasName("foo")));
Balazs Keric7797c42018-07-11 09:37:24 +0000498 EXPECT_FALSE(testStructuralMatch(t));
499}
500
501TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorParam) {
502 auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
503 "struct X { X(int); };", Lang_CXX,
Balazs Keri36883d32018-07-11 15:26:26 +0000504 cxxConstructorDecl(hasName("X")));
Balazs Keric7797c42018-07-11 09:37:24 +0000505 EXPECT_FALSE(testStructuralMatch(t));
506}
507
508TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorExplicit) {
509 auto t = makeDecls<CXXConstructorDecl>("struct X { X(int); };",
510 "struct X { explicit X(int); };",
511 Lang_CXX11,
Balazs Keri36883d32018-07-11 15:26:26 +0000512 cxxConstructorDecl(hasName("X")));
Balazs Keric7797c42018-07-11 09:37:24 +0000513 EXPECT_FALSE(testStructuralMatch(t));
514}
515
516TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorDefault) {
517 auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
518 "struct X { X() = default; };",
519 Lang_CXX11,
Balazs Keri36883d32018-07-11 15:26:26 +0000520 cxxConstructorDecl(hasName("X")));
Balazs Keric7797c42018-07-11 09:37:24 +0000521 EXPECT_FALSE(testStructuralMatch(t));
522}
523
524TEST_F(StructuralEquivalenceCXXMethodTest, Conversion) {
525 auto t = makeDecls<CXXConversionDecl>("struct X { operator bool(); };",
526 "struct X { operator char(); };",
527 Lang_CXX11,
528 cxxConversionDecl());
529 EXPECT_FALSE(testStructuralMatch(t));
530}
531
532TEST_F(StructuralEquivalenceCXXMethodTest, Operator) {
533 auto t = makeDecls<FunctionDecl>(
534 "struct X { int operator +(int); };",
535 "struct X { int operator -(int); };", Lang_CXX,
536 functionDecl(hasOverloadedOperatorName("+")),
537 functionDecl(hasOverloadedOperatorName("-")));
538 EXPECT_FALSE(testStructuralMatch(t));
539}
540
541TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass1) {
542 auto t = makeDecls<FunctionDecl>(
543 "struct X { virtual void f(); }; void X::f() { }",
544 "struct X { virtual void f() { }; };",
545 Lang_CXX,
546 functionDecl(allOf(hasName("f"), isDefinition())));
547 EXPECT_TRUE(testStructuralMatch(t));
548}
549
550TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass2) {
551 auto t = makeDecls<FunctionDecl>(
552 "struct X { virtual void f(); }; void X::f() { }",
553 "struct X { void f(); }; void X::f() { }",
554 Lang_CXX,
555 functionDecl(allOf(hasName("f"), isDefinition())));
556 EXPECT_FALSE(testStructuralMatch(t));
557}
558
559struct StructuralEquivalenceRecordTest : StructuralEquivalenceTest {
Gabor Martonf086fa82018-07-17 12:06:36 +0000560 // FIXME Use a common getRecordDecl with ASTImporterTest.cpp!
561 RecordDecl *getRecordDecl(FieldDecl *FD) {
562 auto *ET = cast<ElaboratedType>(FD->getType().getTypePtr());
563 return cast<RecordType>(ET->getNamedType().getTypePtr())->getDecl();
564 };
Balazs Keric7797c42018-07-11 09:37:24 +0000565};
566
567TEST_F(StructuralEquivalenceRecordTest, Name) {
568 auto t = makeDecls<CXXRecordDecl>(
569 "struct A{ };",
570 "struct B{ };",
571 Lang_CXX,
Balazs Keri36883d32018-07-11 15:26:26 +0000572 cxxRecordDecl(hasName("A")),
573 cxxRecordDecl(hasName("B")));
Balazs Keric7797c42018-07-11 09:37:24 +0000574 EXPECT_FALSE(testStructuralMatch(t));
575}
576
577TEST_F(StructuralEquivalenceRecordTest, Fields) {
578 auto t = makeNamedDecls(
579 "struct foo{ int x; };",
580 "struct foo{ char x; };",
581 Lang_CXX);
582 EXPECT_FALSE(testStructuralMatch(t));
583}
584
585TEST_F(StructuralEquivalenceRecordTest, DISABLED_Methods) {
586 // Currently, methods of a class are not checked at class equivalence.
587 auto t = makeNamedDecls(
588 "struct foo{ int x(); };",
589 "struct foo{ char x(); };",
590 Lang_CXX);
591 EXPECT_FALSE(testStructuralMatch(t));
592}
593
594TEST_F(StructuralEquivalenceRecordTest, Bases) {
595 auto t = makeNamedDecls(
596 "struct A{ }; struct foo: A { };",
597 "struct B{ }; struct foo: B { };",
598 Lang_CXX);
599 EXPECT_FALSE(testStructuralMatch(t));
600}
601
602TEST_F(StructuralEquivalenceRecordTest, InheritanceVirtual) {
603 auto t = makeNamedDecls(
604 "struct A{ }; struct foo: A { };",
605 "struct A{ }; struct foo: virtual A { };",
606 Lang_CXX);
607 EXPECT_FALSE(testStructuralMatch(t));
608}
609
610TEST_F(StructuralEquivalenceRecordTest, DISABLED_InheritanceType) {
611 // Access specifier in inheritance is not checked yet.
612 auto t = makeNamedDecls(
613 "struct A{ }; struct foo: public A { };",
614 "struct A{ }; struct foo: private A { };",
615 Lang_CXX);
616 EXPECT_FALSE(testStructuralMatch(t));
617}
618
619TEST_F(StructuralEquivalenceRecordTest, Match) {
620 auto Code = R"(
621 struct A{ };
622 struct B{ };
623 struct foo: A, virtual B {
624 void x();
625 int a;
626 };
627 )";
628 auto t = makeNamedDecls(Code, Code, Lang_CXX);
629 EXPECT_TRUE(testStructuralMatch(t));
630}
631
Gabor Martonf086fa82018-07-17 12:06:36 +0000632TEST_F(StructuralEquivalenceRecordTest, UnnamedRecordsShouldBeInequivalent) {
633 auto t = makeTuDecls(
634 R"(
635 struct A {
636 struct {
637 struct A *next;
638 } entry0;
639 struct {
640 struct A *next;
641 } entry1;
642 };
643 )",
644 "", Lang_C);
645 auto *TU = get<0>(t);
646 auto *Entry0 =
647 FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry0")));
648 auto *Entry1 =
649 FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry1")));
650 auto *R0 = getRecordDecl(Entry0);
651 auto *R1 = getRecordDecl(Entry1);
652
653 ASSERT_NE(R0, R1);
654 EXPECT_TRUE(testStructuralMatch(R0, R0));
655 EXPECT_TRUE(testStructuralMatch(R1, R1));
656 EXPECT_FALSE(testStructuralMatch(R0, R1));
657}
658
Gabor Marton7df342a2018-12-17 12:42:12 +0000659TEST_F(StructuralEquivalenceRecordTest, AnonymousRecordsShouldBeInequivalent) {
660 auto t = makeTuDecls(
661 R"(
662 struct X {
663 struct {
664 int a;
665 };
666 struct {
667 int b;
668 };
669 };
670 )",
671 "", Lang_C);
672 auto *TU = get<0>(t);
673 auto *A = FirstDeclMatcher<IndirectFieldDecl>().match(
674 TU, indirectFieldDecl(hasName("a")));
675 auto *FA = cast<FieldDecl>(A->chain().front());
676 RecordDecl *RA = cast<RecordType>(FA->getType().getTypePtr())->getDecl();
677 auto *B = FirstDeclMatcher<IndirectFieldDecl>().match(
678 TU, indirectFieldDecl(hasName("b")));
679 auto *FB = cast<FieldDecl>(B->chain().front());
680 RecordDecl *RB = cast<RecordType>(FB->getType().getTypePtr())->getDecl();
681
682 ASSERT_NE(RA, RB);
683 EXPECT_TRUE(testStructuralMatch(RA, RA));
684 EXPECT_TRUE(testStructuralMatch(RB, RB));
685 EXPECT_FALSE(testStructuralMatch(RA, RB));
686}
687
688TEST_F(StructuralEquivalenceRecordTest,
689 RecordsAreInequivalentIfOrderOfAnonRecordsIsDifferent) {
690 auto t = makeTuDecls(
691 R"(
692 struct X {
693 struct { int a; };
694 struct { int b; };
695 };
696 )",
697 R"(
698 struct X { // The order is reversed.
699 struct { int b; };
700 struct { int a; };
701 };
702 )",
703 Lang_C);
704
705 auto *TU = get<0>(t);
706 auto *A = FirstDeclMatcher<IndirectFieldDecl>().match(
707 TU, indirectFieldDecl(hasName("a")));
708 auto *FA = cast<FieldDecl>(A->chain().front());
709 RecordDecl *RA = cast<RecordType>(FA->getType().getTypePtr())->getDecl();
710
711 auto *TU1 = get<1>(t);
712 auto *A1 = FirstDeclMatcher<IndirectFieldDecl>().match(
713 TU1, indirectFieldDecl(hasName("a")));
714 auto *FA1 = cast<FieldDecl>(A1->chain().front());
715 RecordDecl *RA1 = cast<RecordType>(FA1->getType().getTypePtr())->getDecl();
716
717 RecordDecl *X =
718 FirstDeclMatcher<RecordDecl>().match(TU, recordDecl(hasName("X")));
719 RecordDecl *X1 =
720 FirstDeclMatcher<RecordDecl>().match(TU1, recordDecl(hasName("X")));
721 ASSERT_NE(X, X1);
722 EXPECT_FALSE(testStructuralMatch(X, X1));
723
724 ASSERT_NE(RA, RA1);
725 EXPECT_TRUE(testStructuralMatch(RA, RA));
726 EXPECT_TRUE(testStructuralMatch(RA1, RA1));
727 EXPECT_FALSE(testStructuralMatch(RA1, RA));
728}
729
Gabor Martonf086fa82018-07-17 12:06:36 +0000730TEST_F(StructuralEquivalenceRecordTest,
731 UnnamedRecordsShouldBeInequivalentEvenIfTheSecondIsBeingDefined) {
732 auto Code =
733 R"(
734 struct A {
735 struct {
736 struct A *next;
737 } entry0;
738 struct {
739 struct A *next;
740 } entry1;
741 };
742 )";
743 auto t = makeTuDecls(Code, Code, Lang_C);
744
745 auto *FromTU = get<0>(t);
746 auto *Entry1 =
747 FirstDeclMatcher<FieldDecl>().match(FromTU, fieldDecl(hasName("entry1")));
748
749 auto *ToTU = get<1>(t);
750 auto *Entry0 =
751 FirstDeclMatcher<FieldDecl>().match(ToTU, fieldDecl(hasName("entry0")));
752 auto *A =
753 FirstDeclMatcher<RecordDecl>().match(ToTU, recordDecl(hasName("A")));
754 A->startDefinition(); // Set isBeingDefined, getDefinition() will return a
755 // nullptr. This may be the case during ASTImport.
756
757 auto *R0 = getRecordDecl(Entry0);
758 auto *R1 = getRecordDecl(Entry1);
759
760 ASSERT_NE(R0, R1);
761 EXPECT_TRUE(testStructuralMatch(R0, R0));
762 EXPECT_TRUE(testStructuralMatch(R1, R1));
763 EXPECT_FALSE(testStructuralMatch(R0, R1));
764}
765
Balazs Keria0a81b12018-08-08 15:04:27 +0000766TEST_F(StructuralEquivalenceRecordTest, TemplateVsNonTemplate) {
767 auto t = makeDecls<CXXRecordDecl>(
768 "struct A { };",
769 "template<class T> struct A { };",
770 Lang_CXX,
771 cxxRecordDecl(hasName("A")));
772 EXPECT_FALSE(testStructuralMatch(t));
773}
Gabor Martonf086fa82018-07-17 12:06:36 +0000774
Gabor Marton6b01e1c2018-08-09 12:36:25 +0000775TEST_F(StructuralEquivalenceRecordTest,
776 FwdDeclRecordShouldBeEqualWithFwdDeclRecord) {
777 auto t = makeNamedDecls("class foo;", "class foo;", Lang_CXX11);
778 EXPECT_TRUE(testStructuralMatch(t));
779}
780
781TEST_F(StructuralEquivalenceRecordTest,
782 FwdDeclRecordShouldBeEqualWithRecordWhichHasDefinition) {
783 auto t =
784 makeNamedDecls("class foo;", "class foo { int A; };", Lang_CXX11);
785 EXPECT_TRUE(testStructuralMatch(t));
786}
787
788TEST_F(StructuralEquivalenceRecordTest,
789 RecordShouldBeEqualWithRecordWhichHasDefinition) {
790 auto t = makeNamedDecls("class foo { int A; };", "class foo { int A; };",
791 Lang_CXX11);
792 EXPECT_TRUE(testStructuralMatch(t));
793}
794
795TEST_F(StructuralEquivalenceRecordTest, RecordsWithDifferentBody) {
796 auto t = makeNamedDecls("class foo { int B; };", "class foo { int A; };",
797 Lang_CXX11);
798 EXPECT_FALSE(testStructuralMatch(t));
799}
800
Gabor Martonae512b82019-07-17 14:40:09 +0000801struct StructuralEquivalenceLambdaTest : StructuralEquivalenceTest {};
802
803TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithDifferentMethods) {
804 // Get the LambdaExprs, unfortunately we can't match directly the underlying
805 // implicit CXXRecordDecl of the Lambda classes.
806 auto t = makeDecls<LambdaExpr>(
807 "void f() { auto L0 = [](int){}; }",
808 "void f() { auto L1 = [](){}; }",
809 Lang_CXX11,
810 lambdaExpr(),
811 lambdaExpr());
812 CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
813 CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
814 EXPECT_FALSE(testStructuralMatch(L0, L1));
815}
816
817TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithEqMethods) {
818 auto t = makeDecls<LambdaExpr>(
819 "void f() { auto L0 = [](int){}; }",
820 "void f() { auto L1 = [](int){}; }",
821 Lang_CXX11,
822 lambdaExpr(),
823 lambdaExpr());
824 CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
825 CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
826 EXPECT_TRUE(testStructuralMatch(L0, L1));
827}
828
829TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithDifferentFields) {
830 auto t = makeDecls<LambdaExpr>(
831 "void f() { char* X; auto L0 = [X](){}; }",
832 "void f() { float X; auto L1 = [X](){}; }",
833 Lang_CXX11,
834 lambdaExpr(),
835 lambdaExpr());
836 CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
837 CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
838 EXPECT_FALSE(testStructuralMatch(L0, L1));
839}
840
841TEST_F(StructuralEquivalenceLambdaTest, LambdaClassesWithEqFields) {
842 auto t = makeDecls<LambdaExpr>(
843 "void f() { float X; auto L0 = [X](){}; }",
844 "void f() { float X; auto L1 = [X](){}; }",
845 Lang_CXX11,
846 lambdaExpr(),
847 lambdaExpr());
848 CXXRecordDecl *L0 = get<0>(t)->getLambdaClass();
849 CXXRecordDecl *L1 = get<1>(t)->getLambdaClass();
850 EXPECT_TRUE(testStructuralMatch(L0, L1));
851}
852
Balazs Keric7797c42018-07-11 09:37:24 +0000853TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
854 auto t = makeNamedDecls(
855 "struct A{ }; struct B{ }; void foo(A a, A b);",
856 "struct A{ }; struct B{ }; void foo(A a, B b);",
857 Lang_CXX);
858 EXPECT_FALSE(testStructuralMatch(t));
859}
860
Richard Smith76b90272019-05-09 03:59:21 +0000861TEST_F(StructuralEquivalenceTest, ExplicitBoolDifferent) {
862 auto Decls = makeNamedDecls("struct foo {explicit(false) foo(int);};",
863 "struct foo {explicit(true) foo(int);};", Lang_CXX2a);
864 CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
865 get<0>(Decls), cxxConstructorDecl(hasName("foo")));
866 CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
867 get<1>(Decls), cxxConstructorDecl(hasName("foo")));
868 EXPECT_FALSE(testStructuralMatch(First, Second));
869}
870
871TEST_F(StructuralEquivalenceTest, ExplicitBoolSame) {
872 auto Decls = makeNamedDecls("struct foo {explicit(true) foo(int);};",
873 "struct foo {explicit(true) foo(int);};", Lang_CXX2a);
874 CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
875 get<0>(Decls), cxxConstructorDecl(hasName("foo")));
876 CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
877 get<1>(Decls), cxxConstructorDecl(hasName("foo")));
878 EXPECT_TRUE(testStructuralMatch(First, Second));
879}
880
Gabor Marton6b01e1c2018-08-09 12:36:25 +0000881struct StructuralEquivalenceEnumTest : StructuralEquivalenceTest {};
882
883TEST_F(StructuralEquivalenceEnumTest, FwdDeclEnumShouldBeEqualWithFwdDeclEnum) {
884 auto t = makeNamedDecls("enum class foo;", "enum class foo;", Lang_CXX11);
885 EXPECT_TRUE(testStructuralMatch(t));
886}
887
888TEST_F(StructuralEquivalenceEnumTest,
889 FwdDeclEnumShouldBeEqualWithEnumWhichHasDefinition) {
890 auto t =
891 makeNamedDecls("enum class foo;", "enum class foo { A };", Lang_CXX11);
892 EXPECT_TRUE(testStructuralMatch(t));
893}
894
895TEST_F(StructuralEquivalenceEnumTest,
896 EnumShouldBeEqualWithEnumWhichHasDefinition) {
897 auto t = makeNamedDecls("enum class foo { A };", "enum class foo { A };",
898 Lang_CXX11);
899 EXPECT_TRUE(testStructuralMatch(t));
900}
901
902TEST_F(StructuralEquivalenceEnumTest, EnumsWithDifferentBody) {
903 auto t = makeNamedDecls("enum class foo { B };", "enum class foo { A };",
904 Lang_CXX11);
905 EXPECT_FALSE(testStructuralMatch(t));
906}
907
Gabor Marton059c1d82019-01-28 10:01:11 +0000908struct StructuralEquivalenceTemplateTest : StructuralEquivalenceTest {};
909
910TEST_F(StructuralEquivalenceTemplateTest, ExactlySameTemplates) {
911 auto t = makeNamedDecls("template <class T> struct foo;",
912 "template <class T> struct foo;", Lang_CXX);
913 EXPECT_TRUE(testStructuralMatch(t));
914}
915
916TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgName) {
917 auto t = makeNamedDecls("template <class T> struct foo;",
918 "template <class U> struct foo;", Lang_CXX);
919 EXPECT_TRUE(testStructuralMatch(t));
920}
921
922TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgKind) {
923 auto t = makeNamedDecls("template <class T> struct foo;",
924 "template <int T> struct foo;", Lang_CXX);
925 EXPECT_FALSE(testStructuralMatch(t));
926}
Gabor Marton6b01e1c2018-08-09 12:36:25 +0000927
Richard Smith76b90272019-05-09 03:59:21 +0000928TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolSame) {
929 auto Decls = makeNamedDecls("template <bool b> struct foo {explicit(b) foo(int);};",
930 "template <bool b> struct foo {explicit(b) foo(int);};", Lang_CXX2a);
931 CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
932 get<0>(Decls), cxxConstructorDecl(hasName("foo<b>")));
933 CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
934 get<1>(Decls), cxxConstructorDecl(hasName("foo<b>")));
935 EXPECT_TRUE(testStructuralMatch(First, Second));
936}
937
938TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolDifference) {
939 auto Decls = makeNamedDecls("template <bool b> struct foo {explicit(b) foo(int);};",
940 "template <bool b> struct foo {explicit(!b) foo(int);};", Lang_CXX2a);
941 CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
942 get<0>(Decls), cxxConstructorDecl(hasName("foo<b>")));
943 CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
944 get<1>(Decls), cxxConstructorDecl(hasName("foo<b>")));
945 EXPECT_FALSE(testStructuralMatch(First, Second));
946}
947
Gabor Marton123f6ff2019-07-23 15:46:38 +0000948TEST_F(StructuralEquivalenceTemplateTest,
949 TemplateVsSubstTemplateTemplateParmInArgEq) {
950 auto t = makeDecls<ClassTemplateSpecializationDecl>(
951 R"(
952template <typename P1> class Arg { };
953template <template <typename PP1> class P1> class Primary { };
954
955void f() {
956 // Make specialization with simple template.
957 Primary <Arg> A;
958}
959 )",
960 R"(
961template <typename P1> class Arg { };
962template <template <typename PP1> class P1> class Primary { };
963
964template <template <typename PP1> class P1> class Templ {
965 void f() {
966 // Make specialization with substituted template template param.
967 Primary <P1> A;
968 };
969};
970
971// Instantiate with substitution Arg into P1.
972template class Templ <Arg>;
973 )",
974 Lang_CXX, classTemplateSpecializationDecl(hasName("Primary")));
975 EXPECT_TRUE(testStructuralMatch(t));
976}
977
978TEST_F(StructuralEquivalenceTemplateTest,
979 TemplateVsSubstTemplateTemplateParmInArgNotEq) {
980 auto t = makeDecls<ClassTemplateSpecializationDecl>(
981 R"(
982template <typename P1> class Arg { };
983template <template <typename PP1> class P1> class Primary { };
984
985void f() {
986 // Make specialization with simple template.
987 Primary <Arg> A;
988}
989 )",
990 R"(
991// Arg is different from the other, this should cause non-equivalence.
992template <typename P1> class Arg { int X; };
993template <template <typename PP1> class P1> class Primary { };
994
995template <template <typename PP1> class P1> class Templ {
996 void f() {
997 // Make specialization with substituted template template param.
998 Primary <P1> A;
999 };
1000};
1001
1002// Instantiate with substitution Arg into P1.
1003template class Templ <Arg>;
1004 )",
1005 Lang_CXX, classTemplateSpecializationDecl(hasName("Primary")));
1006 EXPECT_FALSE(testStructuralMatch(t));
1007}
1008
Gabor Marton4f883f12019-07-02 07:36:39 +00001009struct StructuralEquivalenceDependentTemplateArgsTest
1010 : StructuralEquivalenceTemplateTest {};
1011
1012TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
1013 SameStructsInDependentArgs) {
1014 std::string Code =
1015 R"(
1016 template <typename>
1017 struct S1;
1018
1019 template <typename>
1020 struct enable_if;
1021
1022 struct S
1023 {
1024 template <typename T, typename enable_if<S1<T>>::type>
1025 void f();
1026 };
1027 )";
1028 auto t = makeDecls<FunctionTemplateDecl>(Code, Code, Lang_CXX11,
1029 functionTemplateDecl(hasName("f")));
1030 EXPECT_TRUE(testStructuralMatch(t));
1031}
1032
1033TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
1034 DifferentStructsInDependentArgs) {
1035 std::string Code =
1036 R"(
1037 template <typename>
1038 struct S1;
1039
1040 template <typename>
1041 struct S2;
1042
1043 template <typename>
1044 struct enable_if;
1045 )";
1046 auto t = makeDecls<FunctionTemplateDecl>(Code + R"(
1047 struct S
1048 {
1049 template <typename T, typename enable_if<S1<T>>::type>
1050 void f();
1051 };
1052 )",
1053 Code + R"(
1054 struct S
1055 {
1056 template <typename T, typename enable_if<S2<T>>::type>
1057 void f();
1058 };
1059 )",
1060 Lang_CXX11,
1061 functionTemplateDecl(hasName("f")));
1062 EXPECT_FALSE(testStructuralMatch(t));
1063}
1064
1065TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
1066 SameStructsInDependentScopeDeclRefExpr) {
1067 std::string Code =
1068 R"(
1069 template <typename>
1070 struct S1;
1071
1072 template <bool>
1073 struct enable_if;
1074
1075 struct S
1076 {
1077 template <typename T, typename enable_if<S1<T>::value>::type>
1078 void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^
1079 };
1080 )";
1081 auto t = makeDecls<FunctionTemplateDecl>(Code, Code, Lang_CXX11,
1082 functionTemplateDecl(hasName("f")));
1083 EXPECT_TRUE(testStructuralMatch(t));
1084}
1085
1086TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
1087 DifferentStructsInDependentScopeDeclRefExpr) {
1088 std::string Code =
1089 R"(
1090 template <typename>
1091 struct S1;
1092
1093 template <typename>
1094 struct S2;
1095
1096 template <bool>
1097 struct enable_if;
1098 )";
1099 auto t = makeDecls<FunctionTemplateDecl>(Code + R"(
1100 struct S
1101 {
1102 template <typename T, typename enable_if<S1<T>::value>::type>
1103 void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^
1104 };
1105 )",
1106 Code + R"(
1107 struct S
1108 {
1109 template <typename T, typename enable_if<S2<T>::value>::type>
1110 void f();
1111 };
1112 )",
1113 Lang_CXX,
1114 functionTemplateDecl(hasName("f")));
1115 EXPECT_FALSE(testStructuralMatch(t));
1116}
1117
1118TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
1119 DifferentValueInDependentScopeDeclRefExpr) {
1120 std::string Code =
1121 R"(
1122 template <typename>
1123 struct S1;
1124
1125 template <bool>
1126 struct enable_if;
1127 )";
1128 auto t = makeDecls<FunctionTemplateDecl>(Code + R"(
1129 struct S
1130 {
1131 template <typename T, typename enable_if<S1<T>::value1>::type>
1132 void f(); // DependentScopeDeclRefExpr:^^^^^^^^^^^^
1133 };
1134 )",
1135 Code + R"(
1136 struct S
1137 {
1138 template <typename T, typename enable_if<S1<T>::value2>::type>
1139 void f();
1140 };
1141 )",
1142 Lang_CXX,
1143 functionTemplateDecl(hasName("f")));
1144 EXPECT_FALSE(testStructuralMatch(t));
1145}
1146
Gabor Marton123f6ff2019-07-23 15:46:38 +00001147TEST_F(
1148 StructuralEquivalenceTemplateTest,
1149 ClassTemplSpecWithQualifiedAndNonQualifiedTypeArgsShouldBeEqual) {
1150 auto t = makeDecls<ClassTemplateSpecializationDecl>(
1151 R"(
1152 template <class T> struct Primary {};
1153 namespace N {
1154 struct Arg;
1155 }
1156 // Explicit instantiation with qualified name.
1157 template struct Primary<N::Arg>;
1158 )",
1159 R"(
1160 template <class T> struct Primary {};
1161 namespace N {
1162 struct Arg;
1163 }
1164 using namespace N;
1165 // Explicit instantiation with UNqualified name.
1166 template struct Primary<Arg>;
1167 )",
1168 Lang_CXX,
1169 classTemplateSpecializationDecl(hasName("Primary")));
1170 EXPECT_TRUE(testStructuralMatch(t));
1171}
1172
1173TEST_F(
1174 StructuralEquivalenceTemplateTest,
1175 ClassTemplSpecWithInequivalentQualifiedAndNonQualifiedTypeArgs) {
1176 auto t = makeDecls<ClassTemplateSpecializationDecl>(
1177 R"(
1178 template <class T> struct Primary {};
1179 namespace N {
1180 struct Arg { int a; };
1181 }
1182 // Explicit instantiation with qualified name.
1183 template struct Primary<N::Arg>;
1184 )",
1185 R"(
1186 template <class T> struct Primary {};
1187 namespace N {
1188 // This struct is not equivalent with the other in the prev TU.
1189 struct Arg { double b; }; // -- Field mismatch.
1190 }
1191 using namespace N;
1192 // Explicit instantiation with UNqualified name.
1193 template struct Primary<Arg>;
1194 )",
1195 Lang_CXX,
1196 classTemplateSpecializationDecl(hasName("Primary")));
1197 EXPECT_FALSE(testStructuralMatch(t));
1198}
1199
1200TEST_F(
1201 StructuralEquivalenceTemplateTest,
1202 ClassTemplSpecWithQualifiedAndNonQualifiedTemplArgsShouldBeEqual) {
1203 auto t = makeDecls<ClassTemplateSpecializationDecl>(
1204 R"(
1205 template <template <class> class T> struct Primary {};
1206 namespace N {
1207 template <class T> struct Arg;
1208 }
1209 // Explicit instantiation with qualified name.
1210 template struct Primary<N::Arg>;
1211 )",
1212 R"(
1213 template <template <class> class T> struct Primary {};
1214 namespace N {
1215 template <class T> struct Arg;
1216 }
1217 using namespace N;
1218 // Explicit instantiation with UNqualified name.
1219 template struct Primary<Arg>;
1220 )",
1221 Lang_CXX,
1222 classTemplateSpecializationDecl(hasName("Primary")));
1223 EXPECT_TRUE(testStructuralMatch(t));
1224}
1225
1226TEST_F(
1227 StructuralEquivalenceTemplateTest,
1228 ClassTemplSpecWithInequivalentQualifiedAndNonQualifiedTemplArgs) {
1229 auto t = makeDecls<ClassTemplateSpecializationDecl>(
1230 R"(
1231 template <template <class> class T> struct Primary {};
1232 namespace N {
1233 template <class T> struct Arg { int a; };
1234 }
1235 // Explicit instantiation with qualified name.
1236 template struct Primary<N::Arg>;
1237 )",
1238 R"(
1239 template <template <class> class T> struct Primary {};
1240 namespace N {
1241 // This template is not equivalent with the other in the prev TU.
1242 template <class T> struct Arg { double b; }; // -- Field mismatch.
1243 }
1244 using namespace N;
1245 // Explicit instantiation with UNqualified name.
1246 template struct Primary<Arg>;
1247 )",
1248 Lang_CXX,
1249 classTemplateSpecializationDecl(hasName("Primary")));
1250 EXPECT_FALSE(testStructuralMatch(t));
1251}
1252
1253TEST_F(
1254 StructuralEquivalenceTemplateTest,
1255 ClassTemplSpecWithInequivalentShadowedTemplArg) {
1256 auto t = makeDecls<ClassTemplateSpecializationDecl>(
1257 R"(
1258 template <template <class> class T> struct Primary {};
1259 template <class T> struct Arg { int a; };
1260 // Explicit instantiation with ::Arg
1261 template struct Primary<Arg>;
1262 )",
1263 R"(
1264 template <template <class> class T> struct Primary {};
1265 template <class T> struct Arg { int a; };
1266 namespace N {
1267 // This template is not equivalent with the other in the global scope.
1268 template <class T> struct Arg { double b; }; // -- Field mismatch.
1269 // Explicit instantiation with N::Arg which shadows ::Arg
1270 template struct Primary<Arg>;
1271 }
1272 )",
1273 Lang_CXX,
1274 classTemplateSpecializationDecl(hasName("Primary")));
1275 EXPECT_FALSE(testStructuralMatch(t));
1276}
Balazs Kerib06b14b2019-09-02 11:01:09 +00001277struct StructuralEquivalenceCacheTest : public StructuralEquivalenceTest {
1278 llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls;
1279
1280 template <typename NodeType, typename MatcherType>
1281 std::pair<NodeType *, NodeType *>
1282 findDeclPair(std::tuple<TranslationUnitDecl *, TranslationUnitDecl *> TU,
1283 MatcherType M) {
1284 NodeType *D0 = FirstDeclMatcher<NodeType>().match(get<0>(TU), M);
1285 NodeType *D1 = FirstDeclMatcher<NodeType>().match(get<1>(TU), M);
1286 return {D0, D1};
1287 }
1288
1289 template <typename NodeType>
1290 bool isInNonEqCache(std::pair<NodeType *, NodeType *> D) {
1291 return NonEquivalentDecls.count(D) > 0;
1292 }
1293};
1294
1295TEST_F(StructuralEquivalenceCacheTest, SimpleNonEq) {
1296 auto TU = makeTuDecls(
1297 R"(
1298 class A {};
1299 class B {};
1300 void x(A, A);
1301 )",
1302 R"(
1303 class A {};
1304 class B {};
1305 void x(A, B);
1306 )",
1307 Lang_CXX);
1308
1309 StructuralEquivalenceContext Ctx(
1310 get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(),
1311 NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false);
1312
1313 auto X = findDeclPair<FunctionDecl>(TU, functionDecl(hasName("x")));
1314 EXPECT_FALSE(Ctx.IsEquivalent(X.first, X.second));
1315
1316 EXPECT_FALSE(isInNonEqCache(findDeclPair<CXXRecordDecl>(
1317 TU, cxxRecordDecl(hasName("A"), unless(isImplicit())))));
1318 EXPECT_FALSE(isInNonEqCache(findDeclPair<CXXRecordDecl>(
1319 TU, cxxRecordDecl(hasName("B"), unless(isImplicit())))));
1320}
1321
1322TEST_F(StructuralEquivalenceCacheTest, SpecialNonEq) {
1323 auto TU = makeTuDecls(
1324 R"(
1325 class A {};
1326 class B { int i; };
1327 void x(A *);
1328 void y(A *);
1329 class C {
1330 friend void x(A *);
1331 friend void y(A *);
1332 };
1333 )",
1334 R"(
1335 class A {};
1336 class B { int i; };
1337 void x(A *);
1338 void y(B *);
1339 class C {
1340 friend void x(A *);
1341 friend void y(B *);
1342 };
1343 )",
1344 Lang_CXX);
1345
1346 StructuralEquivalenceContext Ctx(
1347 get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(),
1348 NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false);
1349
1350 auto C = findDeclPair<CXXRecordDecl>(
1351 TU, cxxRecordDecl(hasName("C"), unless(isImplicit())));
1352 EXPECT_FALSE(Ctx.IsEquivalent(C.first, C.second));
1353
1354 EXPECT_FALSE(isInNonEqCache(C));
1355 EXPECT_FALSE(isInNonEqCache(findDeclPair<CXXRecordDecl>(
1356 TU, cxxRecordDecl(hasName("A"), unless(isImplicit())))));
1357 EXPECT_FALSE(isInNonEqCache(findDeclPair<CXXRecordDecl>(
1358 TU, cxxRecordDecl(hasName("B"), unless(isImplicit())))));
1359 EXPECT_FALSE(isInNonEqCache(
1360 findDeclPair<FunctionDecl>(TU, functionDecl(hasName("x")))));
1361 EXPECT_FALSE(isInNonEqCache(
1362 findDeclPair<FunctionDecl>(TU, functionDecl(hasName("y")))));
1363}
1364
1365TEST_F(StructuralEquivalenceCacheTest, Cycle) {
1366 auto TU = makeTuDecls(
1367 R"(
1368 class C;
1369 class A { C *c; };
1370 void x(A *);
1371 class C {
1372 friend void x(A *);
1373 };
1374 )",
1375 R"(
1376 class C;
1377 class A { C *c; };
1378 void x(A *);
1379 class C {
1380 friend void x(A *);
1381 };
1382 )",
1383 Lang_CXX);
1384
1385 StructuralEquivalenceContext Ctx(
1386 get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(),
1387 NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false);
1388
1389 auto C = findDeclPair<CXXRecordDecl>(
1390 TU, cxxRecordDecl(hasName("C"), unless(isImplicit())));
1391 EXPECT_TRUE(Ctx.IsEquivalent(C.first, C.second));
1392
1393 EXPECT_FALSE(isInNonEqCache(C));
1394 EXPECT_FALSE(isInNonEqCache(findDeclPair<CXXRecordDecl>(
1395 TU, cxxRecordDecl(hasName("A"), unless(isImplicit())))));
1396 EXPECT_FALSE(isInNonEqCache(
1397 findDeclPair<FunctionDecl>(TU, functionDecl(hasName("x")))));
1398}
Gabor Marton123f6ff2019-07-23 15:46:38 +00001399
Gabor Marton1f667532018-05-24 08:41:07 +00001400} // end namespace ast_matchers
1401} // end namespace clang