blob: ae62747284108ddb5116b82e1baad678b4ca8e67 [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
Balazs Keric7797c42018-07-11 09:37:24 +0000233TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) {
234 auto t = makeNamedDecls("void foo(int&);",
235 "void foo(const int&);", Lang_CXX);
236 EXPECT_FALSE(testStructuralMatch(t));
237}
238
239TEST_F(StructuralEquivalenceFunctionTest, ParamConstSimple) {
240 auto t = makeNamedDecls("void foo(int);",
241 "void foo(const int);", Lang_CXX);
242 EXPECT_TRUE(testStructuralMatch(t));
243 // consider this OK
244}
245
246TEST_F(StructuralEquivalenceFunctionTest, Throw) {
247 auto t = makeNamedDecls("void foo();",
248 "void foo() throw();", Lang_CXX);
249 EXPECT_FALSE(testStructuralMatch(t));
250}
251
252TEST_F(StructuralEquivalenceFunctionTest, Noexcept) {
253 auto t = makeNamedDecls("void foo();",
254 "void foo() noexcept;", Lang_CXX11);
255 EXPECT_FALSE(testStructuralMatch(t));
256}
257
258TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexcept) {
259 auto t = makeNamedDecls("void foo() throw();",
260 "void foo() noexcept;", Lang_CXX11);
261 EXPECT_FALSE(testStructuralMatch(t));
262}
263
264TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptFalse) {
265 auto t = makeNamedDecls("void foo() throw();",
266 "void foo() noexcept(false);", Lang_CXX11);
267 EXPECT_FALSE(testStructuralMatch(t));
268}
269
270TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptTrue) {
271 auto t = makeNamedDecls("void foo() throw();",
272 "void foo() noexcept(true);", Lang_CXX11);
273 EXPECT_FALSE(testStructuralMatch(t));
274}
275
276TEST_F(StructuralEquivalenceFunctionTest, DISABLED_NoexceptNonMatch) {
277 // The expression is not checked yet.
278 auto t = makeNamedDecls("void foo() noexcept(false);",
279 "void foo() noexcept(true);", Lang_CXX11);
280 EXPECT_FALSE(testStructuralMatch(t));
281}
282
283TEST_F(StructuralEquivalenceFunctionTest, NoexceptMatch) {
284 auto t = makeNamedDecls("void foo() noexcept(false);",
285 "void foo() noexcept(false);", Lang_CXX11);
286 EXPECT_TRUE(testStructuralMatch(t));
287}
288
289TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptFalse) {
290 auto t = makeNamedDecls("void foo() noexcept;",
291 "void foo() noexcept(false);", Lang_CXX11);
292 EXPECT_FALSE(testStructuralMatch(t));
293}
294
295TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptTrue) {
296 auto t = makeNamedDecls("void foo() noexcept;",
297 "void foo() noexcept(true);", Lang_CXX11);
298 EXPECT_FALSE(testStructuralMatch(t));
299}
300
301TEST_F(StructuralEquivalenceFunctionTest, ReturnType) {
302 auto t = makeNamedDecls("char foo();",
303 "int foo();", Lang_CXX);
304 EXPECT_FALSE(testStructuralMatch(t));
305}
306
307TEST_F(StructuralEquivalenceFunctionTest, ReturnConst) {
308 auto t = makeNamedDecls("char foo();",
309 "const char foo();", Lang_CXX);
310 EXPECT_FALSE(testStructuralMatch(t));
311}
312
313TEST_F(StructuralEquivalenceFunctionTest, ReturnRef) {
314 auto t = makeNamedDecls("char &foo();",
315 "char &&foo();", Lang_CXX11);
316 EXPECT_FALSE(testStructuralMatch(t));
317}
318
319TEST_F(StructuralEquivalenceFunctionTest, ParamCount) {
320 auto t = makeNamedDecls("void foo(int);",
321 "void foo(int, int);", Lang_CXX);
322 EXPECT_FALSE(testStructuralMatch(t));
323}
324
325TEST_F(StructuralEquivalenceFunctionTest, ParamType) {
326 auto t = makeNamedDecls("void foo(int);",
327 "void foo(char);", Lang_CXX);
328 EXPECT_FALSE(testStructuralMatch(t));
329}
330
331TEST_F(StructuralEquivalenceFunctionTest, ParamName) {
332 auto t = makeNamedDecls("void foo(int a);",
333 "void foo(int b);", Lang_CXX);
334 EXPECT_TRUE(testStructuralMatch(t));
335}
336
337TEST_F(StructuralEquivalenceFunctionTest, Variadic) {
338 auto t = makeNamedDecls("void foo(int x...);",
339 "void foo(int x);", Lang_CXX);
340 EXPECT_FALSE(testStructuralMatch(t));
341}
342
343TEST_F(StructuralEquivalenceFunctionTest, ParamPtr) {
344 auto t = makeNamedDecls("void foo(int *);",
345 "void foo(int);", Lang_CXX);
346 EXPECT_FALSE(testStructuralMatch(t));
347}
348
349TEST_F(StructuralEquivalenceFunctionTest, NameInParen) {
350 auto t = makeNamedDecls(
351 "void ((foo))();",
352 "void foo();",
353 Lang_CXX);
354 EXPECT_TRUE(testStructuralMatch(t));
355}
356
357TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithExceptionSpec) {
358 auto t = makeNamedDecls(
359 "void (foo)() throw(int);",
360 "void (foo)() noexcept;",
361 Lang_CXX11);
362 EXPECT_FALSE(testStructuralMatch(t));
363}
364
365TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithConst) {
366 auto t = makeNamedDecls(
367 "struct A { void (foo)() const; };",
368 "struct A { void (foo)(); };",
369 Lang_CXX11);
370 EXPECT_FALSE(testStructuralMatch(t));
371}
372
Gabor Marton41f20462019-01-24 14:47:44 +0000373TEST_F(StructuralEquivalenceFunctionTest, FunctionsWithDifferentNoreturnAttr) {
374 auto t = makeNamedDecls(
375 "__attribute__((noreturn)) void foo();",
376 " void foo();",
377 Lang_C);
378 EXPECT_TRUE(testStructuralMatch(t));
379}
380
381TEST_F(StructuralEquivalenceFunctionTest,
382 FunctionsWithDifferentCallingConventions) {
David Green1be906a2019-02-02 08:31:22 +0000383 // These attributes may not be available on certain platforms.
384 if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getArch() !=
385 llvm::Triple::x86_64)
386 return;
Gabor Marton41f20462019-01-24 14:47:44 +0000387 auto t = makeNamedDecls(
Gabor Marton23a06fb2019-01-24 15:42:20 +0000388 "__attribute__((preserve_all)) void foo();",
Gabor Marton41f20462019-01-24 14:47:44 +0000389 "__attribute__((ms_abi)) void foo();",
390 Lang_C);
391 EXPECT_FALSE(testStructuralMatch(t));
392}
393
394TEST_F(StructuralEquivalenceFunctionTest, FunctionsWithDifferentSavedRegsAttr) {
David Green1be906a2019-02-02 08:31:22 +0000395 if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getArch() !=
396 llvm::Triple::x86_64)
397 return;
Gabor Marton41f20462019-01-24 14:47:44 +0000398 auto t = makeNamedDecls(
399 "__attribute__((no_caller_saved_registers)) void foo();",
400 " void foo();",
401 Lang_C);
402 EXPECT_FALSE(testStructuralMatch(t));
403}
404
Balazs Keric7797c42018-07-11 09:37:24 +0000405struct StructuralEquivalenceCXXMethodTest : StructuralEquivalenceTest {
406};
407
408TEST_F(StructuralEquivalenceCXXMethodTest, Virtual) {
409 auto t = makeDecls<CXXMethodDecl>(
410 "struct X { void foo(); };",
411 "struct X { virtual void foo(); };", Lang_CXX,
412 cxxMethodDecl(hasName("foo")));
413 EXPECT_FALSE(testStructuralMatch(t));
414}
415
416TEST_F(StructuralEquivalenceCXXMethodTest, Pure) {
417 auto t = makeNamedDecls("struct X { virtual void foo(); };",
418 "struct X { virtual void foo() = 0; };", Lang_CXX);
419 EXPECT_FALSE(testStructuralMatch(t));
420}
421
422TEST_F(StructuralEquivalenceCXXMethodTest, DISABLED_Final) {
423 // The final-ness is not checked yet.
424 auto t = makeNamedDecls("struct X { virtual void foo(); };",
425 "struct X { virtual void foo() final; };", Lang_CXX);
426 EXPECT_FALSE(testStructuralMatch(t));
427}
428
429TEST_F(StructuralEquivalenceCXXMethodTest, Const) {
430 auto t = makeNamedDecls("struct X { void foo(); };",
431 "struct X { void foo() const; };", Lang_CXX);
432 EXPECT_FALSE(testStructuralMatch(t));
433}
434
435TEST_F(StructuralEquivalenceCXXMethodTest, Static) {
436 auto t = makeNamedDecls("struct X { void foo(); };",
437 "struct X { static void foo(); };", Lang_CXX);
438 EXPECT_FALSE(testStructuralMatch(t));
439}
440
441TEST_F(StructuralEquivalenceCXXMethodTest, Ref1) {
442 auto t = makeNamedDecls("struct X { void foo(); };",
443 "struct X { void foo() &&; };", Lang_CXX11);
444 EXPECT_FALSE(testStructuralMatch(t));
445}
446
447TEST_F(StructuralEquivalenceCXXMethodTest, Ref2) {
448 auto t = makeNamedDecls("struct X { void foo() &; };",
449 "struct X { void foo() &&; };", Lang_CXX11);
450 EXPECT_FALSE(testStructuralMatch(t));
451}
452
453TEST_F(StructuralEquivalenceCXXMethodTest, AccessSpecifier) {
454 auto t = makeDecls<CXXMethodDecl>(
455 "struct X { public: void foo(); };",
456 "struct X { private: void foo(); };", Lang_CXX,
457 cxxMethodDecl(hasName("foo")));
458 EXPECT_FALSE(testStructuralMatch(t));
459}
460
461TEST_F(StructuralEquivalenceCXXMethodTest, Delete) {
462 auto t = makeNamedDecls("struct X { void foo(); };",
463 "struct X { void foo() = delete; };", Lang_CXX11);
464 EXPECT_FALSE(testStructuralMatch(t));
465}
466
467TEST_F(StructuralEquivalenceCXXMethodTest, Constructor) {
468 auto t = makeDecls<FunctionDecl>(
469 "void foo();", "struct foo { foo(); };", Lang_CXX,
Balazs Keri36883d32018-07-11 15:26:26 +0000470 functionDecl(hasName("foo")), cxxConstructorDecl(hasName("foo")));
Balazs Keric7797c42018-07-11 09:37:24 +0000471 EXPECT_FALSE(testStructuralMatch(t));
472}
473
474TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorParam) {
475 auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
476 "struct X { X(int); };", Lang_CXX,
Balazs Keri36883d32018-07-11 15:26:26 +0000477 cxxConstructorDecl(hasName("X")));
Balazs Keric7797c42018-07-11 09:37:24 +0000478 EXPECT_FALSE(testStructuralMatch(t));
479}
480
481TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorExplicit) {
482 auto t = makeDecls<CXXConstructorDecl>("struct X { X(int); };",
483 "struct X { explicit X(int); };",
484 Lang_CXX11,
Balazs Keri36883d32018-07-11 15:26:26 +0000485 cxxConstructorDecl(hasName("X")));
Balazs Keric7797c42018-07-11 09:37:24 +0000486 EXPECT_FALSE(testStructuralMatch(t));
487}
488
489TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorDefault) {
490 auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
491 "struct X { X() = default; };",
492 Lang_CXX11,
Balazs Keri36883d32018-07-11 15:26:26 +0000493 cxxConstructorDecl(hasName("X")));
Balazs Keric7797c42018-07-11 09:37:24 +0000494 EXPECT_FALSE(testStructuralMatch(t));
495}
496
497TEST_F(StructuralEquivalenceCXXMethodTest, Conversion) {
498 auto t = makeDecls<CXXConversionDecl>("struct X { operator bool(); };",
499 "struct X { operator char(); };",
500 Lang_CXX11,
501 cxxConversionDecl());
502 EXPECT_FALSE(testStructuralMatch(t));
503}
504
505TEST_F(StructuralEquivalenceCXXMethodTest, Operator) {
506 auto t = makeDecls<FunctionDecl>(
507 "struct X { int operator +(int); };",
508 "struct X { int operator -(int); };", Lang_CXX,
509 functionDecl(hasOverloadedOperatorName("+")),
510 functionDecl(hasOverloadedOperatorName("-")));
511 EXPECT_FALSE(testStructuralMatch(t));
512}
513
514TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass1) {
515 auto t = makeDecls<FunctionDecl>(
516 "struct X { virtual void f(); }; void X::f() { }",
517 "struct X { virtual void f() { }; };",
518 Lang_CXX,
519 functionDecl(allOf(hasName("f"), isDefinition())));
520 EXPECT_TRUE(testStructuralMatch(t));
521}
522
523TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass2) {
524 auto t = makeDecls<FunctionDecl>(
525 "struct X { virtual void f(); }; void X::f() { }",
526 "struct X { void f(); }; void X::f() { }",
527 Lang_CXX,
528 functionDecl(allOf(hasName("f"), isDefinition())));
529 EXPECT_FALSE(testStructuralMatch(t));
530}
531
532struct StructuralEquivalenceRecordTest : StructuralEquivalenceTest {
Gabor Martonf086fa82018-07-17 12:06:36 +0000533 // FIXME Use a common getRecordDecl with ASTImporterTest.cpp!
534 RecordDecl *getRecordDecl(FieldDecl *FD) {
535 auto *ET = cast<ElaboratedType>(FD->getType().getTypePtr());
536 return cast<RecordType>(ET->getNamedType().getTypePtr())->getDecl();
537 };
Balazs Keric7797c42018-07-11 09:37:24 +0000538};
539
540TEST_F(StructuralEquivalenceRecordTest, Name) {
541 auto t = makeDecls<CXXRecordDecl>(
542 "struct A{ };",
543 "struct B{ };",
544 Lang_CXX,
Balazs Keri36883d32018-07-11 15:26:26 +0000545 cxxRecordDecl(hasName("A")),
546 cxxRecordDecl(hasName("B")));
Balazs Keric7797c42018-07-11 09:37:24 +0000547 EXPECT_FALSE(testStructuralMatch(t));
548}
549
550TEST_F(StructuralEquivalenceRecordTest, Fields) {
551 auto t = makeNamedDecls(
552 "struct foo{ int x; };",
553 "struct foo{ char x; };",
554 Lang_CXX);
555 EXPECT_FALSE(testStructuralMatch(t));
556}
557
558TEST_F(StructuralEquivalenceRecordTest, DISABLED_Methods) {
559 // Currently, methods of a class are not checked at class equivalence.
560 auto t = makeNamedDecls(
561 "struct foo{ int x(); };",
562 "struct foo{ char x(); };",
563 Lang_CXX);
564 EXPECT_FALSE(testStructuralMatch(t));
565}
566
567TEST_F(StructuralEquivalenceRecordTest, Bases) {
568 auto t = makeNamedDecls(
569 "struct A{ }; struct foo: A { };",
570 "struct B{ }; struct foo: B { };",
571 Lang_CXX);
572 EXPECT_FALSE(testStructuralMatch(t));
573}
574
575TEST_F(StructuralEquivalenceRecordTest, InheritanceVirtual) {
576 auto t = makeNamedDecls(
577 "struct A{ }; struct foo: A { };",
578 "struct A{ }; struct foo: virtual A { };",
579 Lang_CXX);
580 EXPECT_FALSE(testStructuralMatch(t));
581}
582
583TEST_F(StructuralEquivalenceRecordTest, DISABLED_InheritanceType) {
584 // Access specifier in inheritance is not checked yet.
585 auto t = makeNamedDecls(
586 "struct A{ }; struct foo: public A { };",
587 "struct A{ }; struct foo: private A { };",
588 Lang_CXX);
589 EXPECT_FALSE(testStructuralMatch(t));
590}
591
592TEST_F(StructuralEquivalenceRecordTest, Match) {
593 auto Code = R"(
594 struct A{ };
595 struct B{ };
596 struct foo: A, virtual B {
597 void x();
598 int a;
599 };
600 )";
601 auto t = makeNamedDecls(Code, Code, Lang_CXX);
602 EXPECT_TRUE(testStructuralMatch(t));
603}
604
Gabor Martonf086fa82018-07-17 12:06:36 +0000605TEST_F(StructuralEquivalenceRecordTest, UnnamedRecordsShouldBeInequivalent) {
606 auto t = makeTuDecls(
607 R"(
608 struct A {
609 struct {
610 struct A *next;
611 } entry0;
612 struct {
613 struct A *next;
614 } entry1;
615 };
616 )",
617 "", Lang_C);
618 auto *TU = get<0>(t);
619 auto *Entry0 =
620 FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry0")));
621 auto *Entry1 =
622 FirstDeclMatcher<FieldDecl>().match(TU, fieldDecl(hasName("entry1")));
623 auto *R0 = getRecordDecl(Entry0);
624 auto *R1 = getRecordDecl(Entry1);
625
626 ASSERT_NE(R0, R1);
627 EXPECT_TRUE(testStructuralMatch(R0, R0));
628 EXPECT_TRUE(testStructuralMatch(R1, R1));
629 EXPECT_FALSE(testStructuralMatch(R0, R1));
630}
631
Gabor Marton7df342a2018-12-17 12:42:12 +0000632TEST_F(StructuralEquivalenceRecordTest, AnonymousRecordsShouldBeInequivalent) {
633 auto t = makeTuDecls(
634 R"(
635 struct X {
636 struct {
637 int a;
638 };
639 struct {
640 int b;
641 };
642 };
643 )",
644 "", Lang_C);
645 auto *TU = get<0>(t);
646 auto *A = FirstDeclMatcher<IndirectFieldDecl>().match(
647 TU, indirectFieldDecl(hasName("a")));
648 auto *FA = cast<FieldDecl>(A->chain().front());
649 RecordDecl *RA = cast<RecordType>(FA->getType().getTypePtr())->getDecl();
650 auto *B = FirstDeclMatcher<IndirectFieldDecl>().match(
651 TU, indirectFieldDecl(hasName("b")));
652 auto *FB = cast<FieldDecl>(B->chain().front());
653 RecordDecl *RB = cast<RecordType>(FB->getType().getTypePtr())->getDecl();
654
655 ASSERT_NE(RA, RB);
656 EXPECT_TRUE(testStructuralMatch(RA, RA));
657 EXPECT_TRUE(testStructuralMatch(RB, RB));
658 EXPECT_FALSE(testStructuralMatch(RA, RB));
659}
660
661TEST_F(StructuralEquivalenceRecordTest,
662 RecordsAreInequivalentIfOrderOfAnonRecordsIsDifferent) {
663 auto t = makeTuDecls(
664 R"(
665 struct X {
666 struct { int a; };
667 struct { int b; };
668 };
669 )",
670 R"(
671 struct X { // The order is reversed.
672 struct { int b; };
673 struct { int a; };
674 };
675 )",
676 Lang_C);
677
678 auto *TU = get<0>(t);
679 auto *A = FirstDeclMatcher<IndirectFieldDecl>().match(
680 TU, indirectFieldDecl(hasName("a")));
681 auto *FA = cast<FieldDecl>(A->chain().front());
682 RecordDecl *RA = cast<RecordType>(FA->getType().getTypePtr())->getDecl();
683
684 auto *TU1 = get<1>(t);
685 auto *A1 = FirstDeclMatcher<IndirectFieldDecl>().match(
686 TU1, indirectFieldDecl(hasName("a")));
687 auto *FA1 = cast<FieldDecl>(A1->chain().front());
688 RecordDecl *RA1 = cast<RecordType>(FA1->getType().getTypePtr())->getDecl();
689
690 RecordDecl *X =
691 FirstDeclMatcher<RecordDecl>().match(TU, recordDecl(hasName("X")));
692 RecordDecl *X1 =
693 FirstDeclMatcher<RecordDecl>().match(TU1, recordDecl(hasName("X")));
694 ASSERT_NE(X, X1);
695 EXPECT_FALSE(testStructuralMatch(X, X1));
696
697 ASSERT_NE(RA, RA1);
698 EXPECT_TRUE(testStructuralMatch(RA, RA));
699 EXPECT_TRUE(testStructuralMatch(RA1, RA1));
700 EXPECT_FALSE(testStructuralMatch(RA1, RA));
701}
702
Gabor Martonf086fa82018-07-17 12:06:36 +0000703TEST_F(StructuralEquivalenceRecordTest,
704 UnnamedRecordsShouldBeInequivalentEvenIfTheSecondIsBeingDefined) {
705 auto Code =
706 R"(
707 struct A {
708 struct {
709 struct A *next;
710 } entry0;
711 struct {
712 struct A *next;
713 } entry1;
714 };
715 )";
716 auto t = makeTuDecls(Code, Code, Lang_C);
717
718 auto *FromTU = get<0>(t);
719 auto *Entry1 =
720 FirstDeclMatcher<FieldDecl>().match(FromTU, fieldDecl(hasName("entry1")));
721
722 auto *ToTU = get<1>(t);
723 auto *Entry0 =
724 FirstDeclMatcher<FieldDecl>().match(ToTU, fieldDecl(hasName("entry0")));
725 auto *A =
726 FirstDeclMatcher<RecordDecl>().match(ToTU, recordDecl(hasName("A")));
727 A->startDefinition(); // Set isBeingDefined, getDefinition() will return a
728 // nullptr. This may be the case during ASTImport.
729
730 auto *R0 = getRecordDecl(Entry0);
731 auto *R1 = getRecordDecl(Entry1);
732
733 ASSERT_NE(R0, R1);
734 EXPECT_TRUE(testStructuralMatch(R0, R0));
735 EXPECT_TRUE(testStructuralMatch(R1, R1));
736 EXPECT_FALSE(testStructuralMatch(R0, R1));
737}
738
Balazs Keria0a81b12018-08-08 15:04:27 +0000739TEST_F(StructuralEquivalenceRecordTest, TemplateVsNonTemplate) {
740 auto t = makeDecls<CXXRecordDecl>(
741 "struct A { };",
742 "template<class T> struct A { };",
743 Lang_CXX,
744 cxxRecordDecl(hasName("A")));
745 EXPECT_FALSE(testStructuralMatch(t));
746}
Gabor Martonf086fa82018-07-17 12:06:36 +0000747
Gabor Marton6b01e1c2018-08-09 12:36:25 +0000748TEST_F(StructuralEquivalenceRecordTest,
749 FwdDeclRecordShouldBeEqualWithFwdDeclRecord) {
750 auto t = makeNamedDecls("class foo;", "class foo;", Lang_CXX11);
751 EXPECT_TRUE(testStructuralMatch(t));
752}
753
754TEST_F(StructuralEquivalenceRecordTest,
755 FwdDeclRecordShouldBeEqualWithRecordWhichHasDefinition) {
756 auto t =
757 makeNamedDecls("class foo;", "class foo { int A; };", Lang_CXX11);
758 EXPECT_TRUE(testStructuralMatch(t));
759}
760
761TEST_F(StructuralEquivalenceRecordTest,
762 RecordShouldBeEqualWithRecordWhichHasDefinition) {
763 auto t = makeNamedDecls("class foo { int A; };", "class foo { int A; };",
764 Lang_CXX11);
765 EXPECT_TRUE(testStructuralMatch(t));
766}
767
768TEST_F(StructuralEquivalenceRecordTest, RecordsWithDifferentBody) {
769 auto t = makeNamedDecls("class foo { int B; };", "class foo { int A; };",
770 Lang_CXX11);
771 EXPECT_FALSE(testStructuralMatch(t));
772}
773
Balazs Keric7797c42018-07-11 09:37:24 +0000774TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
775 auto t = makeNamedDecls(
776 "struct A{ }; struct B{ }; void foo(A a, A b);",
777 "struct A{ }; struct B{ }; void foo(A a, B b);",
778 Lang_CXX);
779 EXPECT_FALSE(testStructuralMatch(t));
780}
781
Gabor Marton6b01e1c2018-08-09 12:36:25 +0000782struct StructuralEquivalenceEnumTest : StructuralEquivalenceTest {};
783
784TEST_F(StructuralEquivalenceEnumTest, FwdDeclEnumShouldBeEqualWithFwdDeclEnum) {
785 auto t = makeNamedDecls("enum class foo;", "enum class foo;", Lang_CXX11);
786 EXPECT_TRUE(testStructuralMatch(t));
787}
788
789TEST_F(StructuralEquivalenceEnumTest,
790 FwdDeclEnumShouldBeEqualWithEnumWhichHasDefinition) {
791 auto t =
792 makeNamedDecls("enum class foo;", "enum class foo { A };", Lang_CXX11);
793 EXPECT_TRUE(testStructuralMatch(t));
794}
795
796TEST_F(StructuralEquivalenceEnumTest,
797 EnumShouldBeEqualWithEnumWhichHasDefinition) {
798 auto t = makeNamedDecls("enum class foo { A };", "enum class foo { A };",
799 Lang_CXX11);
800 EXPECT_TRUE(testStructuralMatch(t));
801}
802
803TEST_F(StructuralEquivalenceEnumTest, EnumsWithDifferentBody) {
804 auto t = makeNamedDecls("enum class foo { B };", "enum class foo { A };",
805 Lang_CXX11);
806 EXPECT_FALSE(testStructuralMatch(t));
807}
808
Gabor Marton059c1d82019-01-28 10:01:11 +0000809struct StructuralEquivalenceTemplateTest : StructuralEquivalenceTest {};
810
811TEST_F(StructuralEquivalenceTemplateTest, ExactlySameTemplates) {
812 auto t = makeNamedDecls("template <class T> struct foo;",
813 "template <class T> struct foo;", Lang_CXX);
814 EXPECT_TRUE(testStructuralMatch(t));
815}
816
817TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgName) {
818 auto t = makeNamedDecls("template <class T> struct foo;",
819 "template <class U> struct foo;", Lang_CXX);
820 EXPECT_TRUE(testStructuralMatch(t));
821}
822
823TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgKind) {
824 auto t = makeNamedDecls("template <class T> struct foo;",
825 "template <int T> struct foo;", Lang_CXX);
826 EXPECT_FALSE(testStructuralMatch(t));
827}
Gabor Marton6b01e1c2018-08-09 12:36:25 +0000828
Gabor Marton1f667532018-05-24 08:41:07 +0000829} // end namespace ast_matchers
830} // end namespace clang