1 | #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 | |
12 | namespace clang { |
13 | namespace ast_matchers { |
14 | |
15 | using std::get; |
16 | |
17 | struct StructuralEquivalenceTest : ::testing::Test { |
18 | std::unique_ptr<ASTUnit> AST0, AST1; |
19 | std::string Code0, Code1; |
20 | |
21 | |
22 | |
23 | |
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) { |
28 | 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 | |
37 | NodeType *D0 = FirstDeclMatcher<NodeType>().match( |
38 | AST0->getASTContext().getTranslationUnitDecl(), Matcher0); |
39 | NodeType *D1 = FirstDeclMatcher<NodeType>().match( |
40 | AST1->getASTContext().getTranslationUnitDecl(), Matcher1); |
41 | |
42 | return std::make_tuple(D0, D1); |
43 | } |
44 | |
45 | 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 | |
60 | |
61 | |
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 | |
71 | |
72 | |
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 | |
80 | bool testStructuralMatch(Decl *D0, Decl *D1) { |
81 | 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; |
93 | } |
94 | |
95 | bool testStructuralMatch(std::tuple<Decl *, Decl *> t) { |
96 | return testStructuralMatch(get<0>(t), get<1>(t)); |
97 | } |
98 | }; |
99 | |
100 | TEST_F(StructuralEquivalenceTest, Int) { |
101 | auto Decls = makeNamedDecls("int foo;", "int foo;", Lang_CXX); |
102 | EXPECT_TRUE(testStructuralMatch(Decls)); |
103 | } |
104 | |
105 | TEST_F(StructuralEquivalenceTest, IntVsSignedInt) { |
106 | auto Decls = makeNamedDecls("int foo;", "signed int foo;", Lang_CXX); |
107 | EXPECT_TRUE(testStructuralMatch(Decls)); |
108 | } |
109 | |
110 | TEST_F(StructuralEquivalenceTest, Char) { |
111 | auto Decls = makeNamedDecls("char foo;", "char foo;", Lang_CXX); |
112 | EXPECT_TRUE(testStructuralMatch(Decls)); |
113 | } |
114 | |
115 | |
116 | |
117 | TEST_F(StructuralEquivalenceTest, DISABLED_CharVsSignedChar) { |
118 | auto Decls = makeNamedDecls("char foo;", "signed char foo;", Lang_CXX); |
119 | EXPECT_FALSE(testStructuralMatch(Decls)); |
120 | } |
121 | |
122 | TEST_F(StructuralEquivalenceTest, ForwardRecordDecl) { |
123 | auto Decls = makeNamedDecls("struct foo;", "struct foo;", Lang_CXX); |
124 | EXPECT_TRUE(testStructuralMatch(Decls)); |
125 | } |
126 | |
127 | TEST_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 | |
133 | TEST_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 | |
139 | TEST_F(StructuralEquivalenceTest, IntVsSignedIntTemplateSpec) { |
140 | 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); |
147 | EXPECT_TRUE(testStructuralMatch(Spec0, Spec1)); |
148 | } |
149 | |
150 | TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpec) { |
151 | 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); |
158 | EXPECT_FALSE(testStructuralMatch(Spec0, Spec1)); |
159 | } |
160 | |
161 | TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpecWithInheritance) { |
162 | auto Decls = makeDecls<ClassTemplateSpecializationDecl>( |
163 | 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 | )", |
173 | Lang_CXX, |
174 | classTemplateSpecializationDecl()); |
175 | EXPECT_FALSE(testStructuralMatch(Decls)); |
176 | } |
177 | |
178 | |
179 | |
180 | TEST_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 | |
200 | NS->removeDecl(TD); |
201 | NS->addDeclInternal(TD); |
202 | |
203 | EXPECT_FALSE(testStructuralMatch(Decls)); |
204 | } |
205 | |
206 | TEST_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 | |
216 | RD->removeDecl(FD); |
217 | RD->addDeclInternal(FD); |
218 | |
219 | EXPECT_FALSE(testStructuralMatch(Decls)); |
220 | } |
221 | |
222 | struct StructuralEquivalenceFunctionTest : StructuralEquivalenceTest { |
223 | }; |
224 | |
225 | TEST_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 | |
233 | TEST_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 | |
242 | TEST_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 | |
251 | TEST_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 | |
260 | TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) { |
261 | auto t = makeNamedDecls("void foo(int&);", |
262 | "void foo(const int&);", Lang_CXX); |
263 | EXPECT_FALSE(testStructuralMatch(t)); |
264 | } |
265 | |
266 | TEST_F(StructuralEquivalenceFunctionTest, ParamConstSimple) { |
267 | auto t = makeNamedDecls("void foo(int);", |
268 | "void foo(const int);", Lang_CXX); |
269 | EXPECT_TRUE(testStructuralMatch(t)); |
270 | |
271 | } |
272 | |
273 | TEST_F(StructuralEquivalenceFunctionTest, Throw) { |
274 | auto t = makeNamedDecls("void foo();", |
275 | "void foo() throw();", Lang_CXX); |
276 | EXPECT_FALSE(testStructuralMatch(t)); |
277 | } |
278 | |
279 | TEST_F(StructuralEquivalenceFunctionTest, Noexcept) { |
280 | auto t = makeNamedDecls("void foo();", |
281 | "void foo() noexcept;", Lang_CXX11); |
282 | EXPECT_FALSE(testStructuralMatch(t)); |
283 | } |
284 | |
285 | TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexcept) { |
286 | auto t = makeNamedDecls("void foo() throw();", |
287 | "void foo() noexcept;", Lang_CXX11); |
288 | EXPECT_FALSE(testStructuralMatch(t)); |
289 | } |
290 | |
291 | TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptFalse) { |
292 | auto t = makeNamedDecls("void foo() throw();", |
293 | "void foo() noexcept(false);", Lang_CXX11); |
294 | EXPECT_FALSE(testStructuralMatch(t)); |
295 | } |
296 | |
297 | TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptTrue) { |
298 | auto t = makeNamedDecls("void foo() throw();", |
299 | "void foo() noexcept(true);", Lang_CXX11); |
300 | EXPECT_FALSE(testStructuralMatch(t)); |
301 | } |
302 | |
303 | TEST_F(StructuralEquivalenceFunctionTest, DISABLED_NoexceptNonMatch) { |
304 | |
305 | auto t = makeNamedDecls("void foo() noexcept(false);", |
306 | "void foo() noexcept(true);", Lang_CXX11); |
307 | EXPECT_FALSE(testStructuralMatch(t)); |
308 | } |
309 | |
310 | TEST_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 | |
316 | TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptFalse) { |
317 | auto t = makeNamedDecls("void foo() noexcept;", |
318 | "void foo() noexcept(false);", Lang_CXX11); |
319 | EXPECT_FALSE(testStructuralMatch(t)); |
320 | } |
321 | |
322 | TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptTrue) { |
323 | auto t = makeNamedDecls("void foo() noexcept;", |
324 | "void foo() noexcept(true);", Lang_CXX11); |
325 | EXPECT_FALSE(testStructuralMatch(t)); |
326 | } |
327 | |
328 | TEST_F(StructuralEquivalenceFunctionTest, ReturnType) { |
329 | auto t = makeNamedDecls("char foo();", |
330 | "int foo();", Lang_CXX); |
331 | EXPECT_FALSE(testStructuralMatch(t)); |
332 | } |
333 | |
334 | TEST_F(StructuralEquivalenceFunctionTest, ReturnConst) { |
335 | auto t = makeNamedDecls("char foo();", |
336 | "const char foo();", Lang_CXX); |
337 | EXPECT_FALSE(testStructuralMatch(t)); |
338 | } |
339 | |
340 | TEST_F(StructuralEquivalenceFunctionTest, ReturnRef) { |
341 | auto t = makeNamedDecls("char &foo();", |
342 | "char &&foo();", Lang_CXX11); |
343 | EXPECT_FALSE(testStructuralMatch(t)); |
344 | } |
345 | |
346 | TEST_F(StructuralEquivalenceFunctionTest, ParamCount) { |
347 | auto t = makeNamedDecls("void foo(int);", |
348 | "void foo(int, int);", Lang_CXX); |
349 | EXPECT_FALSE(testStructuralMatch(t)); |
350 | } |
351 | |
352 | TEST_F(StructuralEquivalenceFunctionTest, ParamType) { |
353 | auto t = makeNamedDecls("void foo(int);", |
354 | "void foo(char);", Lang_CXX); |
355 | EXPECT_FALSE(testStructuralMatch(t)); |
356 | } |
357 | |
358 | TEST_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 | |
364 | TEST_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 | |
370 | TEST_F(StructuralEquivalenceFunctionTest, ParamPtr) { |
371 | auto t = makeNamedDecls("void foo(int *);", |
372 | "void foo(int);", Lang_CXX); |
373 | EXPECT_FALSE(testStructuralMatch(t)); |
374 | } |
375 | |
376 | TEST_F(StructuralEquivalenceFunctionTest, NameInParen) { |
377 | auto t = makeNamedDecls( |
378 | "void ((foo))();", |
379 | "void foo();", |
380 | Lang_CXX); |
381 | EXPECT_TRUE(testStructuralMatch(t)); |
382 | } |
383 | |
384 | TEST_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 | |
392 | TEST_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 | |
400 | TEST_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 | |
408 | TEST_F(StructuralEquivalenceFunctionTest, |
409 | FunctionsWithDifferentCallingConventions) { |
410 | |
411 | if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getArch() != |
412 | llvm::Triple::x86_64) |
413 | return; |
414 | auto t = makeNamedDecls( |
415 | "__attribute__((preserve_all)) void foo();", |
416 | "__attribute__((ms_abi)) void foo();", |
417 | Lang_C); |
418 | EXPECT_FALSE(testStructuralMatch(t)); |
419 | } |
420 | |
421 | TEST_F(StructuralEquivalenceFunctionTest, FunctionsWithDifferentSavedRegsAttr) { |
422 | if (llvm::Triple(llvm::sys::getDefaultTargetTriple()).getArch() != |
423 | llvm::Triple::x86_64) |
424 | return; |
425 | auto t = makeNamedDecls( |
426 | "__attribute__((no_caller_saved_registers)) void foo();", |
427 | " void foo();", |
428 | Lang_C); |
429 | EXPECT_FALSE(testStructuralMatch(t)); |
430 | } |
431 | |
432 | struct StructuralEquivalenceCXXMethodTest : StructuralEquivalenceTest { |
433 | }; |
434 | |
435 | TEST_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 | |
443 | TEST_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 | |
449 | TEST_F(StructuralEquivalenceCXXMethodTest, DISABLED_Final) { |
450 | |
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 | |
456 | TEST_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 | |
462 | TEST_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 | |
468 | TEST_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 | |
474 | TEST_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 | |
480 | TEST_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 | |
488 | TEST_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 | |
494 | TEST_F(StructuralEquivalenceCXXMethodTest, Constructor) { |
495 | auto t = makeDecls<FunctionDecl>( |
496 | "void foo();", "struct foo { foo(); };", Lang_CXX, |
497 | functionDecl(hasName("foo")), cxxConstructorDecl(hasName("foo"))); |
498 | EXPECT_FALSE(testStructuralMatch(t)); |
499 | } |
500 | |
501 | TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorParam) { |
502 | auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };", |
503 | "struct X { X(int); };", Lang_CXX, |
504 | cxxConstructorDecl(hasName("X"))); |
505 | EXPECT_FALSE(testStructuralMatch(t)); |
506 | } |
507 | |
508 | TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorExplicit) { |
509 | auto t = makeDecls<CXXConstructorDecl>("struct X { X(int); };", |
510 | "struct X { explicit X(int); };", |
511 | Lang_CXX11, |
512 | cxxConstructorDecl(hasName("X"))); |
513 | EXPECT_FALSE(testStructuralMatch(t)); |
514 | } |
515 | |
516 | TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorDefault) { |
517 | auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };", |
518 | "struct X { X() = default; };", |
519 | Lang_CXX11, |
520 | cxxConstructorDecl(hasName("X"))); |
521 | EXPECT_FALSE(testStructuralMatch(t)); |
522 | } |
523 | |
524 | TEST_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 | |
532 | TEST_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 | |
541 | TEST_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 | |
550 | TEST_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 | |
559 | struct StructuralEquivalenceRecordTest : StructuralEquivalenceTest { |
560 | |
561 | RecordDecl *getRecordDecl(FieldDecl *FD) { |
562 | auto *ET = cast<ElaboratedType>(FD->getType().getTypePtr()); |
563 | return cast<RecordType>(ET->getNamedType().getTypePtr())->getDecl(); |
564 | }; |
565 | }; |
566 | |
567 | TEST_F(StructuralEquivalenceRecordTest, Name) { |
568 | auto t = makeDecls<CXXRecordDecl>( |
569 | "struct A{ };", |
570 | "struct B{ };", |
571 | Lang_CXX, |
572 | cxxRecordDecl(hasName("A")), |
573 | cxxRecordDecl(hasName("B"))); |
574 | EXPECT_FALSE(testStructuralMatch(t)); |
575 | } |
576 | |
577 | TEST_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 | |
585 | TEST_F(StructuralEquivalenceRecordTest, DISABLED_Methods) { |
586 | |
587 | auto t = makeNamedDecls( |
588 | "struct foo{ int x(); };", |
589 | "struct foo{ char x(); };", |
590 | Lang_CXX); |
591 | EXPECT_FALSE(testStructuralMatch(t)); |
592 | } |
593 | |
594 | TEST_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 | |
602 | TEST_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 | |
610 | TEST_F(StructuralEquivalenceRecordTest, DISABLED_InheritanceType) { |
611 | |
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 | |
619 | TEST_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 | |
632 | TEST_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 | |
659 | TEST_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 | |
688 | TEST_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 | |
730 | TEST_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(); |
755 | |
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 | |
766 | TEST_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 | } |
774 | |
775 | TEST_F(StructuralEquivalenceRecordTest, |
776 | FwdDeclRecordShouldBeEqualWithFwdDeclRecord) { |
777 | auto t = makeNamedDecls("class foo;", "class foo;", Lang_CXX11); |
778 | EXPECT_TRUE(testStructuralMatch(t)); |
779 | } |
780 | |
781 | TEST_F(StructuralEquivalenceRecordTest, |
782 | FwdDeclRecordShouldBeEqualWithRecordWhichHasDefinition) { |
783 | auto t = |
784 | makeNamedDecls("class foo;", "class foo { int A; };", Lang_CXX11); |
785 | EXPECT_TRUE(testStructuralMatch(t)); |
786 | } |
787 | |
788 | TEST_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 | |
795 | TEST_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 | |
801 | TEST_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 | |
809 | struct StructuralEquivalenceEnumTest : StructuralEquivalenceTest {}; |
810 | |
811 | TEST_F(StructuralEquivalenceEnumTest, FwdDeclEnumShouldBeEqualWithFwdDeclEnum) { |
812 | auto t = makeNamedDecls("enum class foo;", "enum class foo;", Lang_CXX11); |
813 | EXPECT_TRUE(testStructuralMatch(t)); |
814 | } |
815 | |
816 | TEST_F(StructuralEquivalenceEnumTest, |
817 | FwdDeclEnumShouldBeEqualWithEnumWhichHasDefinition) { |
818 | auto t = |
819 | makeNamedDecls("enum class foo;", "enum class foo { A };", Lang_CXX11); |
820 | EXPECT_TRUE(testStructuralMatch(t)); |
821 | } |
822 | |
823 | TEST_F(StructuralEquivalenceEnumTest, |
824 | EnumShouldBeEqualWithEnumWhichHasDefinition) { |
825 | auto t = makeNamedDecls("enum class foo { A };", "enum class foo { A };", |
826 | Lang_CXX11); |
827 | EXPECT_TRUE(testStructuralMatch(t)); |
828 | } |
829 | |
830 | TEST_F(StructuralEquivalenceEnumTest, EnumsWithDifferentBody) { |
831 | auto t = makeNamedDecls("enum class foo { B };", "enum class foo { A };", |
832 | Lang_CXX11); |
833 | EXPECT_FALSE(testStructuralMatch(t)); |
834 | } |
835 | |
836 | struct StructuralEquivalenceTemplateTest : StructuralEquivalenceTest {}; |
837 | |
838 | TEST_F(StructuralEquivalenceTemplateTest, ExactlySameTemplates) { |
839 | auto t = makeNamedDecls("template <class T> struct foo;", |
840 | "template <class T> struct foo;", Lang_CXX); |
841 | EXPECT_TRUE(testStructuralMatch(t)); |
842 | } |
843 | |
844 | TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgName) { |
845 | auto t = makeNamedDecls("template <class T> struct foo;", |
846 | "template <class U> struct foo;", Lang_CXX); |
847 | EXPECT_TRUE(testStructuralMatch(t)); |
848 | } |
849 | |
850 | TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgKind) { |
851 | auto t = makeNamedDecls("template <class T> struct foo;", |
852 | "template <int T> struct foo;", Lang_CXX); |
853 | EXPECT_FALSE(testStructuralMatch(t)); |
854 | } |
855 | |
856 | } |
857 | } |
858 | |