blob: 5bb4f7e1225b0d6c10b605a4bfed36197633f824 [file] [log] [blame]
Gabor Marton1f667532018-05-24 08:41:07 +00001#include "clang/AST/ASTContext.h"
2#include "clang/ASTMatchers/ASTMatchers.h"
3#include "clang/AST/ASTStructuralEquivalence.h"
4#include "clang/Frontend/ASTUnit.h"
5#include "clang/Tooling/Tooling.h"
6
7#include "Language.h"
8#include "DeclMatcher.h"
9
10#include "gtest/gtest.h"
11
12namespace clang {
13namespace ast_matchers {
14
15using std::get;
16
17struct StructuralEquivalenceTest : ::testing::Test {
18 std::unique_ptr<ASTUnit> AST0, AST1;
19 std::string Code0, Code1; // Buffers for SourceManager
20
Balazs Keric7797c42018-07-11 09:37:24 +000021 // Get a pair of node pointers into the synthesized AST from the given code
22 // snippets. To determine the returned node, a separate matcher is specified
23 // for both snippets. The first matching node is returned.
24 template <typename NodeType, typename MatcherType>
25 std::tuple<NodeType *, NodeType *> makeDecls(
26 const std::string &SrcCode0, const std::string &SrcCode1, Language Lang,
27 const MatcherType &Matcher0, const MatcherType &Matcher1) {
Gabor Marton1f667532018-05-24 08:41:07 +000028 this->Code0 = SrcCode0;
29 this->Code1 = SrcCode1;
30 ArgVector Args = getBasicRunOptionsForLanguage(Lang);
31
32 const char *const InputFileName = "input.cc";
33
34 AST0 = tooling::buildASTFromCodeWithArgs(Code0, Args, InputFileName);
35 AST1 = tooling::buildASTFromCodeWithArgs(Code1, Args, InputFileName);
36
Balazs Keric7797c42018-07-11 09:37:24 +000037 NodeType *D0 = FirstDeclMatcher<NodeType>().match(
38 AST0->getASTContext().getTranslationUnitDecl(), Matcher0);
39 NodeType *D1 = FirstDeclMatcher<NodeType>().match(
40 AST1->getASTContext().getTranslationUnitDecl(), Matcher1);
Gabor Marton1f667532018-05-24 08:41:07 +000041
Gabor Marton1f667532018-05-24 08:41:07 +000042 return std::make_tuple(D0, D1);
43 }
44
Gabor Martonf086fa82018-07-17 12:06:36 +000045 std::tuple<TranslationUnitDecl *, TranslationUnitDecl *> makeTuDecls(
46 const std::string &SrcCode0, const std::string &SrcCode1, Language Lang) {
47 this->Code0 = SrcCode0;
48 this->Code1 = SrcCode1;
49 ArgVector Args = getBasicRunOptionsForLanguage(Lang);
50
51 const char *const InputFileName = "input.cc";
52
53 AST0 = tooling::buildASTFromCodeWithArgs(Code0, Args, InputFileName);
54 AST1 = tooling::buildASTFromCodeWithArgs(Code1, Args, InputFileName);
55
56 return std::make_tuple(AST0->getASTContext().getTranslationUnitDecl(),
57 AST1->getASTContext().getTranslationUnitDecl());
58 }
59
Balazs Keric7797c42018-07-11 09:37:24 +000060 // Get a pair of node pointers into the synthesized AST from the given code
61 // snippets. The same matcher is used for both snippets.
62 template <typename NodeType, typename MatcherType>
63 std::tuple<NodeType *, NodeType *> makeDecls(
64 const std::string &SrcCode0, const std::string &SrcCode1, Language Lang,
65 const MatcherType &AMatcher) {
66 return makeDecls<NodeType, MatcherType>(
67 SrcCode0, SrcCode1, Lang, AMatcher, AMatcher);
68 }
69
70 // Get a pair of Decl pointers to the synthesized declarations from the given
71 // code snippets. We search for the first NamedDecl with given name in both
72 // snippets.
73 std::tuple<NamedDecl *, NamedDecl *> makeNamedDecls(
74 const std::string &SrcCode0, const std::string &SrcCode1,
75 Language Lang, const char *const Identifier = "foo") {
76 auto Matcher = namedDecl(hasName(Identifier));
77 return makeDecls<NamedDecl>(SrcCode0, SrcCode1, Lang, Matcher);
78 }
79
Gabor Martonf086fa82018-07-17 12:06:36 +000080 bool testStructuralMatch(Decl *D0, Decl *D1) {
Balazs Keria0a81b12018-08-08 15:04:27 +000081 llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls01;
82 llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls10;
83 StructuralEquivalenceContext Ctx01(
84 D0->getASTContext(), D1->getASTContext(),
85 NonEquivalentDecls01, StructuralEquivalenceKind::Default, false, false);
86 StructuralEquivalenceContext Ctx10(
87 D1->getASTContext(), D0->getASTContext(),
88 NonEquivalentDecls10, StructuralEquivalenceKind::Default, false, false);
89 bool Eq01 = Ctx01.IsEquivalent(D0, D1);
90 bool Eq10 = Ctx10.IsEquivalent(D1, D0);
91 EXPECT_EQ(Eq01, Eq10);
92 return Eq01;
Gabor Marton1f667532018-05-24 08:41:07 +000093 }
94
Gabor Martonf086fa82018-07-17 12:06:36 +000095 bool testStructuralMatch(std::tuple<Decl *, Decl *> t) {
Gabor Marton1f667532018-05-24 08:41:07 +000096 return testStructuralMatch(get<0>(t), get<1>(t));
97 }
98};
99
100TEST_F(StructuralEquivalenceTest, Int) {
101 auto Decls = makeNamedDecls("int foo;", "int foo;", Lang_CXX);
102 EXPECT_TRUE(testStructuralMatch(Decls));
103}
104
105TEST_F(StructuralEquivalenceTest, IntVsSignedInt) {
106 auto Decls = makeNamedDecls("int foo;", "signed int foo;", Lang_CXX);
107 EXPECT_TRUE(testStructuralMatch(Decls));
108}
109
110TEST_F(StructuralEquivalenceTest, Char) {
111 auto Decls = makeNamedDecls("char foo;", "char foo;", Lang_CXX);
112 EXPECT_TRUE(testStructuralMatch(Decls));
113}
114
115// This test is disabled for now.
116// FIXME Whether this is equivalent is dependendant on the target.
117TEST_F(StructuralEquivalenceTest, DISABLED_CharVsSignedChar) {
118 auto Decls = makeNamedDecls("char foo;", "signed char foo;", Lang_CXX);
119 EXPECT_FALSE(testStructuralMatch(Decls));
120}
121
122TEST_F(StructuralEquivalenceTest, ForwardRecordDecl) {
123 auto Decls = makeNamedDecls("struct foo;", "struct foo;", Lang_CXX);
124 EXPECT_TRUE(testStructuralMatch(Decls));
125}
126
127TEST_F(StructuralEquivalenceTest, IntVsSignedIntInStruct) {
128 auto Decls = makeNamedDecls("struct foo { int x; };",
129 "struct foo { signed int x; };", Lang_CXX);
130 EXPECT_TRUE(testStructuralMatch(Decls));
131}
132
133TEST_F(StructuralEquivalenceTest, CharVsSignedCharInStruct) {
134 auto Decls = makeNamedDecls("struct foo { char x; };",
135 "struct foo { signed char x; };", Lang_CXX);
136 EXPECT_FALSE(testStructuralMatch(Decls));
137}
138
139TEST_F(StructuralEquivalenceTest, IntVsSignedIntTemplateSpec) {
Balazs Keric7797c42018-07-11 09:37:24 +0000140 auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
141 R"(template <class T> struct foo; template<> struct foo<int>{};)",
142 R"(template <class T> struct foo; template<> struct foo<signed int>{};)",
143 Lang_CXX,
144 classTemplateSpecializationDecl());
145 auto Spec0 = get<0>(Decls);
146 auto Spec1 = get<1>(Decls);
Gabor Marton1f667532018-05-24 08:41:07 +0000147 EXPECT_TRUE(testStructuralMatch(Spec0, Spec1));
148}
149
150TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpec) {
Balazs Keric7797c42018-07-11 09:37:24 +0000151 auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
152 R"(template <class T> struct foo; template<> struct foo<char>{};)",
153 R"(template <class T> struct foo; template<> struct foo<signed char>{};)",
154 Lang_CXX,
155 classTemplateSpecializationDecl());
156 auto Spec0 = get<0>(Decls);
157 auto Spec1 = get<1>(Decls);
Gabor Marton1f667532018-05-24 08:41:07 +0000158 EXPECT_FALSE(testStructuralMatch(Spec0, Spec1));
159}
160
161TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpecWithInheritance) {
Balazs Keric7797c42018-07-11 09:37:24 +0000162 auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
Gabor Marton1f667532018-05-24 08:41:07 +0000163 R"(
164 struct true_type{};
165 template <class T> struct foo;
166 template<> struct foo<char> : true_type {};
167 )",
168 R"(
169 struct true_type{};
170 template <class T> struct foo;
171 template<> struct foo<signed char> : true_type {};
172 )",
Balazs Keric7797c42018-07-11 09:37:24 +0000173 Lang_CXX,
174 classTemplateSpecializationDecl());
175 EXPECT_FALSE(testStructuralMatch(Decls));
Gabor Marton1f667532018-05-24 08:41:07 +0000176}
177
178// This test is disabled for now.
179// FIXME Enable it, once the check is implemented.
180TEST_F(StructuralEquivalenceTest, DISABLED_WrongOrderInNamespace) {
181 auto Code =
182 R"(
183 namespace NS {
184 template <class T> class Base {
185 int a;
186 };
187 class Derived : Base<Derived> {
188 };
189 }
190 void foo(NS::Derived &);
191 )";
192 auto Decls = makeNamedDecls(Code, Code, Lang_CXX);
193
194 NamespaceDecl *NS =
195 LastDeclMatcher<NamespaceDecl>().match(get<1>(Decls), namespaceDecl());
196 ClassTemplateDecl *TD = LastDeclMatcher<ClassTemplateDecl>().match(
197 get<1>(Decls), classTemplateDecl(hasName("Base")));
198
199 // Reorder the decls, move the TD to the last place in the DC.
200 NS->removeDecl(TD);
201 NS->addDeclInternal(TD);
202
203 EXPECT_FALSE(testStructuralMatch(Decls));
204}
205
206TEST_F(StructuralEquivalenceTest, WrongOrderOfFieldsInClass) {
207 auto Code = "class X { int a; int b; };";
208 auto Decls = makeNamedDecls(Code, Code, Lang_CXX, "X");
209
210 CXXRecordDecl *RD = FirstDeclMatcher<CXXRecordDecl>().match(
211 get<1>(Decls), cxxRecordDecl(hasName("X")));
212 FieldDecl *FD =
213 FirstDeclMatcher<FieldDecl>().match(get<1>(Decls), fieldDecl(hasName("a")));
214
215 // Reorder the FieldDecls
216 RD->removeDecl(FD);
217 RD->addDeclInternal(FD);
218
219 EXPECT_FALSE(testStructuralMatch(Decls));
220}
221
Balazs Keric7797c42018-07-11 09:37:24 +0000222struct StructuralEquivalenceFunctionTest : StructuralEquivalenceTest {
223};
224
Balazs Keria0a81b12018-08-08 15:04:27 +0000225TEST_F(StructuralEquivalenceFunctionTest, TemplateVsNonTemplate) {
226 auto t = makeNamedDecls(
227 "void foo();",
228 "template<class T> void foo();",
229 Lang_CXX);
230 EXPECT_FALSE(testStructuralMatch(t));
231}
232
Gabor Martonfc638d62019-02-08 08:55:32 +0000233TEST_F(StructuralEquivalenceFunctionTest, DifferentOperators) {
234 auto t = makeDecls<FunctionDecl>(
235 "struct X{}; bool operator<(X, X);",
236 "struct X{}; bool operator==(X, X);", Lang_CXX,
237 functionDecl(hasOverloadedOperatorName("<")),
238 functionDecl(hasOverloadedOperatorName("==")));
239 EXPECT_FALSE(testStructuralMatch(t));
240}
241
242TEST_F(StructuralEquivalenceFunctionTest, SameOperators) {
243 auto t = makeDecls<FunctionDecl>(
244 "struct X{}; bool operator<(X, X);",
245 "struct X{}; bool operator<(X, X);", Lang_CXX,
246 functionDecl(hasOverloadedOperatorName("<")),
247 functionDecl(hasOverloadedOperatorName("<")));
248 EXPECT_TRUE(testStructuralMatch(t));
249}
250
251TEST_F(StructuralEquivalenceFunctionTest, CtorVsDtor) {
252 auto t = makeDecls<FunctionDecl>(
253 "struct X{ X(); };",
254 "struct X{ ~X(); };", Lang_CXX,
255 cxxConstructorDecl(),
256 cxxDestructorDecl());
257 EXPECT_FALSE(testStructuralMatch(t));
258}
259
Balazs Keric7797c42018-07-11 09:37:24 +0000260TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) {
261 auto t = makeNamedDecls("void foo(int&);",
262 "void foo(const int&);", Lang_CXX);
263 EXPECT_FALSE(testStructuralMatch(t));
264}
265
266TEST_F(StructuralEquivalenceFunctionTest, ParamConstSimple) {
267 auto t = makeNamedDecls("void foo(int);",
268 "void foo(const int);", Lang_CXX);
269 EXPECT_TRUE(testStructuralMatch(t));
270 // consider this OK
271}
272
273TEST_F(StructuralEquivalenceFunctionTest, Throw) {
274 auto t = makeNamedDecls("void foo();",
275 "void foo() throw();", Lang_CXX);
276 EXPECT_FALSE(testStructuralMatch(t));
277}
278
279TEST_F(StructuralEquivalenceFunctionTest, Noexcept) {
280 auto t = makeNamedDecls("void foo();",
281 "void foo() noexcept;", Lang_CXX11);
282 EXPECT_FALSE(testStructuralMatch(t));
283}
284
285TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexcept) {
286 auto t = makeNamedDecls("void foo() throw();",
287 "void foo() noexcept;", Lang_CXX11);
288 EXPECT_FALSE(testStructuralMatch(t));
289}
290
291TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptFalse) {
292 auto t = makeNamedDecls("void foo() throw();",
293 "void foo() noexcept(false);", Lang_CXX11);
294 EXPECT_FALSE(testStructuralMatch(t));
295}
296
297TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptTrue) {
298 auto t = makeNamedDecls("void foo() throw();",
299 "void foo() noexcept(true);", Lang_CXX11);
300 EXPECT_FALSE(testStructuralMatch(t));
301}
302
303TEST_F(StructuralEquivalenceFunctionTest, DISABLED_NoexceptNonMatch) {
304 // The expression is not checked yet.
305 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
Balazs Keric7797c42018-07-11 09:37:24 +0000801TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
802 auto t = makeNamedDecls(
803 "struct A{ }; struct B{ }; void foo(A a, A b);",
804 "struct A{ }; struct B{ }; void foo(A a, B b);",
805 Lang_CXX);
806 EXPECT_FALSE(testStructuralMatch(t));
807}
808
Richard Smith76b90272019-05-09 03:59:21 +0000809TEST_F(StructuralEquivalenceTest, ExplicitBoolDifferent) {
810 auto Decls = makeNamedDecls("struct foo {explicit(false) foo(int);};",
811 "struct foo {explicit(true) foo(int);};", Lang_CXX2a);
812 CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
813 get<0>(Decls), cxxConstructorDecl(hasName("foo")));
814 CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
815 get<1>(Decls), cxxConstructorDecl(hasName("foo")));
816 EXPECT_FALSE(testStructuralMatch(First, Second));
817}
818
819TEST_F(StructuralEquivalenceTest, ExplicitBoolSame) {
820 auto Decls = makeNamedDecls("struct foo {explicit(true) foo(int);};",
821 "struct foo {explicit(true) foo(int);};", Lang_CXX2a);
822 CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
823 get<0>(Decls), cxxConstructorDecl(hasName("foo")));
824 CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
825 get<1>(Decls), cxxConstructorDecl(hasName("foo")));
826 EXPECT_TRUE(testStructuralMatch(First, Second));
827}
828
Gabor Marton6b01e1c2018-08-09 12:36:25 +0000829struct StructuralEquivalenceEnumTest : StructuralEquivalenceTest {};
830
831TEST_F(StructuralEquivalenceEnumTest, FwdDeclEnumShouldBeEqualWithFwdDeclEnum) {
832 auto t = makeNamedDecls("enum class foo;", "enum class foo;", Lang_CXX11);
833 EXPECT_TRUE(testStructuralMatch(t));
834}
835
836TEST_F(StructuralEquivalenceEnumTest,
837 FwdDeclEnumShouldBeEqualWithEnumWhichHasDefinition) {
838 auto t =
839 makeNamedDecls("enum class foo;", "enum class foo { A };", Lang_CXX11);
840 EXPECT_TRUE(testStructuralMatch(t));
841}
842
843TEST_F(StructuralEquivalenceEnumTest,
844 EnumShouldBeEqualWithEnumWhichHasDefinition) {
845 auto t = makeNamedDecls("enum class foo { A };", "enum class foo { A };",
846 Lang_CXX11);
847 EXPECT_TRUE(testStructuralMatch(t));
848}
849
850TEST_F(StructuralEquivalenceEnumTest, EnumsWithDifferentBody) {
851 auto t = makeNamedDecls("enum class foo { B };", "enum class foo { A };",
852 Lang_CXX11);
853 EXPECT_FALSE(testStructuralMatch(t));
854}
855
Gabor Marton059c1d82019-01-28 10:01:11 +0000856struct StructuralEquivalenceTemplateTest : StructuralEquivalenceTest {};
857
858TEST_F(StructuralEquivalenceTemplateTest, ExactlySameTemplates) {
859 auto t = makeNamedDecls("template <class T> struct foo;",
860 "template <class T> struct foo;", Lang_CXX);
861 EXPECT_TRUE(testStructuralMatch(t));
862}
863
864TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgName) {
865 auto t = makeNamedDecls("template <class T> struct foo;",
866 "template <class U> struct foo;", Lang_CXX);
867 EXPECT_TRUE(testStructuralMatch(t));
868}
869
870TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgKind) {
871 auto t = makeNamedDecls("template <class T> struct foo;",
872 "template <int T> struct foo;", Lang_CXX);
873 EXPECT_FALSE(testStructuralMatch(t));
874}
Gabor Marton6b01e1c2018-08-09 12:36:25 +0000875
Richard Smith76b90272019-05-09 03:59:21 +0000876TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolSame) {
877 auto Decls = makeNamedDecls("template <bool b> struct foo {explicit(b) foo(int);};",
878 "template <bool b> struct foo {explicit(b) foo(int);};", Lang_CXX2a);
879 CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
880 get<0>(Decls), cxxConstructorDecl(hasName("foo<b>")));
881 CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
882 get<1>(Decls), cxxConstructorDecl(hasName("foo<b>")));
883 EXPECT_TRUE(testStructuralMatch(First, Second));
884}
885
886TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolDifference) {
887 auto Decls = makeNamedDecls("template <bool b> struct foo {explicit(b) foo(int);};",
888 "template <bool b> struct foo {explicit(!b) foo(int);};", Lang_CXX2a);
889 CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
890 get<0>(Decls), cxxConstructorDecl(hasName("foo<b>")));
891 CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
892 get<1>(Decls), cxxConstructorDecl(hasName("foo<b>")));
893 EXPECT_FALSE(testStructuralMatch(First, Second));
894}
895
Gabor Marton1f667532018-05-24 08:41:07 +0000896} // end namespace ast_matchers
897} // end namespace clang