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; // Buffers for SourceManager
20 
21   // 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) {
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   // Get a pair of node pointers into the synthesized AST from the given code
46   // snippets. The same matcher is used for both snippets.
47   template <typename NodeType, typename MatcherType>
48   std::tuple<NodeType *, NodeType *> makeDecls(
49       const std::string &SrcCode0, const std::string &SrcCode1, Language Lang,
50       const MatcherType &AMatcher) {
51     return makeDecls<NodeType, MatcherType>(
52           SrcCode0, SrcCode1, Lang, AMatcher, AMatcher);
53   }
54 
55   // Get a pair of Decl pointers to the synthesized declarations from the given
56   // code snippets. We search for the first NamedDecl with given name in both
57   // snippets.
58   std::tuple<NamedDecl *, NamedDecl *> makeNamedDecls(
59       const std::string &SrcCode0, const std::string &SrcCode1,
60       Language Lang, const char *const Identifier = "foo") {
61     auto Matcher = namedDecl(hasName(Identifier));
62     return makeDecls<NamedDecl>(SrcCode0, SrcCode1, Lang, Matcher);
63   }
64 
65   bool testStructuralMatch(NamedDecl *D0, NamedDecl *D1) {
66     llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls;
67     StructuralEquivalenceContext Ctx(
68         D0->getASTContext(), D1->getASTContext(), NonEquivalentDecls,
69         StructuralEquivalenceKind::Default, false, false);
70     return Ctx.IsStructurallyEquivalent(D0, D1);
71   }
72 
73   bool testStructuralMatch(std::tuple<NamedDecl *, NamedDecl *> t) {
74     return testStructuralMatch(get<0>(t), get<1>(t));
75   }
76 };
77 
78 TEST_F(StructuralEquivalenceTest, Int) {
79   auto Decls = makeNamedDecls("int foo;", "int foo;", Lang_CXX);
80   EXPECT_TRUE(testStructuralMatch(Decls));
81 }
82 
83 TEST_F(StructuralEquivalenceTest, IntVsSignedInt) {
84   auto Decls = makeNamedDecls("int foo;", "signed int foo;", Lang_CXX);
85   EXPECT_TRUE(testStructuralMatch(Decls));
86 }
87 
88 TEST_F(StructuralEquivalenceTest, Char) {
89   auto Decls = makeNamedDecls("char foo;", "char foo;", Lang_CXX);
90   EXPECT_TRUE(testStructuralMatch(Decls));
91 }
92 
93 // This test is disabled for now.
94 // FIXME Whether this is equivalent is dependendant on the target.
95 TEST_F(StructuralEquivalenceTest, DISABLED_CharVsSignedChar) {
96   auto Decls = makeNamedDecls("char foo;", "signed char foo;", Lang_CXX);
97   EXPECT_FALSE(testStructuralMatch(Decls));
98 }
99 
100 TEST_F(StructuralEquivalenceTest, ForwardRecordDecl) {
101   auto Decls = makeNamedDecls("struct foo;", "struct foo;", Lang_CXX);
102   EXPECT_TRUE(testStructuralMatch(Decls));
103 }
104 
105 TEST_F(StructuralEquivalenceTest, IntVsSignedIntInStruct) {
106   auto Decls = makeNamedDecls("struct foo { int x; };",
107                               "struct foo { signed int x; };", Lang_CXX);
108   EXPECT_TRUE(testStructuralMatch(Decls));
109 }
110 
111 TEST_F(StructuralEquivalenceTest, CharVsSignedCharInStruct) {
112   auto Decls = makeNamedDecls("struct foo { char x; };",
113                               "struct foo { signed char x; };", Lang_CXX);
114   EXPECT_FALSE(testStructuralMatch(Decls));
115 }
116 
117 TEST_F(StructuralEquivalenceTest, IntVsSignedIntTemplateSpec) {
118   auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
119       R"(template <class T> struct foo; template<> struct foo<int>{};)",
120       R"(template <class T> struct foo; template<> struct foo<signed int>{};)",
121       Lang_CXX,
122       classTemplateSpecializationDecl());
123   auto Spec0 = get<0>(Decls);
124   auto Spec1 = get<1>(Decls);
125   EXPECT_TRUE(testStructuralMatch(Spec0, Spec1));
126 }
127 
128 TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpec) {
129   auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
130       R"(template <class T> struct foo; template<> struct foo<char>{};)",
131       R"(template <class T> struct foo; template<> struct foo<signed char>{};)",
132       Lang_CXX,
133       classTemplateSpecializationDecl());
134   auto Spec0 = get<0>(Decls);
135   auto Spec1 = get<1>(Decls);
136   EXPECT_FALSE(testStructuralMatch(Spec0, Spec1));
137 }
138 
139 TEST_F(StructuralEquivalenceTest, CharVsSignedCharTemplateSpecWithInheritance) {
140   auto Decls = makeDecls<ClassTemplateSpecializationDecl>(
141       R"(
142       struct true_type{};
143       template <class T> struct foo;
144       template<> struct foo<char> : true_type {};
145       )",
146       R"(
147       struct true_type{};
148       template <class T> struct foo;
149       template<> struct foo<signed char> : true_type {};
150       )",
151       Lang_CXX,
152       classTemplateSpecializationDecl());
153   EXPECT_FALSE(testStructuralMatch(Decls));
154 }
155 
156 // This test is disabled for now.
157 // FIXME Enable it, once the check is implemented.
158 TEST_F(StructuralEquivalenceTest, DISABLED_WrongOrderInNamespace) {
159   auto Code =
160       R"(
161       namespace NS {
162       template <class T> class Base {
163           int a;
164       };
165       class Derived : Base<Derived> {
166       };
167       }
168       void foo(NS::Derived &);
169       )";
170   auto Decls = makeNamedDecls(Code, Code, Lang_CXX);
171 
172   NamespaceDecl *NS =
173       LastDeclMatcher<NamespaceDecl>().match(get<1>(Decls), namespaceDecl());
174   ClassTemplateDecl *TD = LastDeclMatcher<ClassTemplateDecl>().match(
175       get<1>(Decls), classTemplateDecl(hasName("Base")));
176 
177   // Reorder the decls, move the TD to the last place in the DC.
178   NS->removeDecl(TD);
179   NS->addDeclInternal(TD);
180 
181   EXPECT_FALSE(testStructuralMatch(Decls));
182 }
183 
184 TEST_F(StructuralEquivalenceTest, WrongOrderOfFieldsInClass) {
185   auto Code = "class X { int a; int b; };";
186   auto Decls = makeNamedDecls(Code, Code, Lang_CXX, "X");
187 
188   CXXRecordDecl *RD = FirstDeclMatcher<CXXRecordDecl>().match(
189       get<1>(Decls), cxxRecordDecl(hasName("X")));
190   FieldDecl *FD =
191       FirstDeclMatcher<FieldDecl>().match(get<1>(Decls), fieldDecl(hasName("a")));
192 
193   // Reorder the FieldDecls
194   RD->removeDecl(FD);
195   RD->addDeclInternal(FD);
196 
197   EXPECT_FALSE(testStructuralMatch(Decls));
198 }
199 
200 struct StructuralEquivalenceFunctionTest : StructuralEquivalenceTest {
201 };
202 
203 TEST_F(StructuralEquivalenceFunctionTest, ParamConstWithRef) {
204   auto t = makeNamedDecls("void foo(int&);",
205                           "void foo(const int&);", Lang_CXX);
206   EXPECT_FALSE(testStructuralMatch(t));
207 }
208 
209 TEST_F(StructuralEquivalenceFunctionTest, ParamConstSimple) {
210   auto t = makeNamedDecls("void foo(int);",
211                           "void foo(const int);", Lang_CXX);
212   EXPECT_TRUE(testStructuralMatch(t));
213   // consider this OK
214 }
215 
216 TEST_F(StructuralEquivalenceFunctionTest, Throw) {
217   auto t = makeNamedDecls("void foo();",
218                           "void foo() throw();", Lang_CXX);
219   EXPECT_FALSE(testStructuralMatch(t));
220 }
221 
222 TEST_F(StructuralEquivalenceFunctionTest, Noexcept) {
223   auto t = makeNamedDecls("void foo();",
224                           "void foo() noexcept;", Lang_CXX11);
225   EXPECT_FALSE(testStructuralMatch(t));
226 }
227 
228 TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexcept) {
229   auto t = makeNamedDecls("void foo() throw();",
230                           "void foo() noexcept;", Lang_CXX11);
231   EXPECT_FALSE(testStructuralMatch(t));
232 }
233 
234 TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptFalse) {
235   auto t = makeNamedDecls("void foo() throw();",
236                           "void foo() noexcept(false);", Lang_CXX11);
237   EXPECT_FALSE(testStructuralMatch(t));
238 }
239 
240 TEST_F(StructuralEquivalenceFunctionTest, ThrowVsNoexceptTrue) {
241   auto t = makeNamedDecls("void foo() throw();",
242                           "void foo() noexcept(true);", Lang_CXX11);
243   EXPECT_FALSE(testStructuralMatch(t));
244 }
245 
246 TEST_F(StructuralEquivalenceFunctionTest, DISABLED_NoexceptNonMatch) {
247   // The expression is not checked yet.
248   auto t = makeNamedDecls("void foo() noexcept(false);",
249                           "void foo() noexcept(true);", Lang_CXX11);
250   EXPECT_FALSE(testStructuralMatch(t));
251 }
252 
253 TEST_F(StructuralEquivalenceFunctionTest, NoexceptMatch) {
254   auto t = makeNamedDecls("void foo() noexcept(false);",
255                           "void foo() noexcept(false);", Lang_CXX11);
256   EXPECT_TRUE(testStructuralMatch(t));
257 }
258 
259 TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptFalse) {
260   auto t = makeNamedDecls("void foo() noexcept;",
261                           "void foo() noexcept(false);", Lang_CXX11);
262   EXPECT_FALSE(testStructuralMatch(t));
263 }
264 
265 TEST_F(StructuralEquivalenceFunctionTest, NoexceptVsNoexceptTrue) {
266   auto t = makeNamedDecls("void foo() noexcept;",
267                           "void foo() noexcept(true);", Lang_CXX11);
268   EXPECT_FALSE(testStructuralMatch(t));
269 }
270 
271 TEST_F(StructuralEquivalenceFunctionTest, ReturnType) {
272   auto t = makeNamedDecls("char foo();",
273                           "int foo();", Lang_CXX);
274   EXPECT_FALSE(testStructuralMatch(t));
275 }
276 
277 TEST_F(StructuralEquivalenceFunctionTest, ReturnConst) {
278   auto t = makeNamedDecls("char foo();",
279                           "const char foo();", Lang_CXX);
280   EXPECT_FALSE(testStructuralMatch(t));
281 }
282 
283 TEST_F(StructuralEquivalenceFunctionTest, ReturnRef) {
284   auto t = makeNamedDecls("char &foo();",
285                           "char &&foo();", Lang_CXX11);
286   EXPECT_FALSE(testStructuralMatch(t));
287 }
288 
289 TEST_F(StructuralEquivalenceFunctionTest, ParamCount) {
290   auto t = makeNamedDecls("void foo(int);",
291                           "void foo(int, int);", Lang_CXX);
292   EXPECT_FALSE(testStructuralMatch(t));
293 }
294 
295 TEST_F(StructuralEquivalenceFunctionTest, ParamType) {
296   auto t = makeNamedDecls("void foo(int);",
297                           "void foo(char);", Lang_CXX);
298   EXPECT_FALSE(testStructuralMatch(t));
299 }
300 
301 TEST_F(StructuralEquivalenceFunctionTest, ParamName) {
302   auto t = makeNamedDecls("void foo(int a);",
303                           "void foo(int b);", Lang_CXX);
304   EXPECT_TRUE(testStructuralMatch(t));
305 }
306 
307 TEST_F(StructuralEquivalenceFunctionTest, Variadic) {
308   auto t = makeNamedDecls("void foo(int x...);",
309                           "void foo(int x);", Lang_CXX);
310   EXPECT_FALSE(testStructuralMatch(t));
311 }
312 
313 TEST_F(StructuralEquivalenceFunctionTest, ParamPtr) {
314   auto t = makeNamedDecls("void foo(int *);",
315                           "void foo(int);", Lang_CXX);
316   EXPECT_FALSE(testStructuralMatch(t));
317 }
318 
319 TEST_F(StructuralEquivalenceFunctionTest, NameInParen) {
320   auto t = makeNamedDecls(
321       "void ((foo))();",
322       "void foo();",
323       Lang_CXX);
324   EXPECT_TRUE(testStructuralMatch(t));
325 }
326 
327 TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithExceptionSpec) {
328   auto t = makeNamedDecls(
329       "void (foo)() throw(int);",
330       "void (foo)() noexcept;",
331       Lang_CXX11);
332   EXPECT_FALSE(testStructuralMatch(t));
333 }
334 
335 TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithConst) {
336   auto t = makeNamedDecls(
337       "struct A { void (foo)() const; };",
338       "struct A { void (foo)(); };",
339       Lang_CXX11);
340   EXPECT_FALSE(testStructuralMatch(t));
341 }
342 
343 struct StructuralEquivalenceCXXMethodTest : StructuralEquivalenceTest {
344 };
345 
346 TEST_F(StructuralEquivalenceCXXMethodTest, Virtual) {
347   auto t = makeDecls<CXXMethodDecl>(
348       "struct X { void foo(); };",
349       "struct X { virtual void foo(); };", Lang_CXX,
350       cxxMethodDecl(hasName("foo")));
351   EXPECT_FALSE(testStructuralMatch(t));
352 }
353 
354 TEST_F(StructuralEquivalenceCXXMethodTest, Pure) {
355   auto t = makeNamedDecls("struct X { virtual void foo(); };",
356                           "struct X { virtual void foo() = 0; };", Lang_CXX);
357   EXPECT_FALSE(testStructuralMatch(t));
358 }
359 
360 TEST_F(StructuralEquivalenceCXXMethodTest, DISABLED_Final) {
361   // The final-ness is not checked yet.
362   auto t = makeNamedDecls("struct X { virtual void foo(); };",
363                           "struct X { virtual void foo() final; };", Lang_CXX);
364   EXPECT_FALSE(testStructuralMatch(t));
365 }
366 
367 TEST_F(StructuralEquivalenceCXXMethodTest, Const) {
368   auto t = makeNamedDecls("struct X { void foo(); };",
369                           "struct X { void foo() const; };", Lang_CXX);
370   EXPECT_FALSE(testStructuralMatch(t));
371 }
372 
373 TEST_F(StructuralEquivalenceCXXMethodTest, Static) {
374   auto t = makeNamedDecls("struct X { void foo(); };",
375                           "struct X { static void foo(); };", Lang_CXX);
376   EXPECT_FALSE(testStructuralMatch(t));
377 }
378 
379 TEST_F(StructuralEquivalenceCXXMethodTest, Ref1) {
380   auto t = makeNamedDecls("struct X { void foo(); };",
381                           "struct X { void foo() &&; };", Lang_CXX11);
382   EXPECT_FALSE(testStructuralMatch(t));
383 }
384 
385 TEST_F(StructuralEquivalenceCXXMethodTest, Ref2) {
386   auto t = makeNamedDecls("struct X { void foo() &; };",
387                           "struct X { void foo() &&; };", Lang_CXX11);
388   EXPECT_FALSE(testStructuralMatch(t));
389 }
390 
391 TEST_F(StructuralEquivalenceCXXMethodTest, AccessSpecifier) {
392   auto t = makeDecls<CXXMethodDecl>(
393       "struct X { public: void foo(); };",
394       "struct X { private: void foo(); };", Lang_CXX,
395       cxxMethodDecl(hasName("foo")));
396   EXPECT_FALSE(testStructuralMatch(t));
397 }
398 
399 TEST_F(StructuralEquivalenceCXXMethodTest, Delete) {
400   auto t = makeNamedDecls("struct X { void foo(); };",
401                           "struct X { void foo() = delete; };", Lang_CXX11);
402   EXPECT_FALSE(testStructuralMatch(t));
403 }
404 
405 TEST_F(StructuralEquivalenceCXXMethodTest, Constructor) {
406   auto t = makeDecls<FunctionDecl>(
407       "void foo();", "struct foo { foo(); };", Lang_CXX,
408       functionDecl(hasName("foo")), cxxConstructorDecl(hasName("foo")));
409   EXPECT_FALSE(testStructuralMatch(t));
410 }
411 
412 TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorParam) {
413   auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
414                                          "struct X { X(int); };", Lang_CXX,
415                                          cxxConstructorDecl(hasName("X")));
416   EXPECT_FALSE(testStructuralMatch(t));
417 }
418 
419 TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorExplicit) {
420   auto t = makeDecls<CXXConstructorDecl>("struct X { X(int); };",
421                                          "struct X { explicit X(int); };",
422                                          Lang_CXX11,
423                                          cxxConstructorDecl(hasName("X")));
424   EXPECT_FALSE(testStructuralMatch(t));
425 }
426 
427 TEST_F(StructuralEquivalenceCXXMethodTest, ConstructorDefault) {
428   auto t = makeDecls<CXXConstructorDecl>("struct X { X(); };",
429                                          "struct X { X() = default; };",
430                                          Lang_CXX11,
431                                          cxxConstructorDecl(hasName("X")));
432   EXPECT_FALSE(testStructuralMatch(t));
433 }
434 
435 TEST_F(StructuralEquivalenceCXXMethodTest, Conversion) {
436   auto t = makeDecls<CXXConversionDecl>("struct X { operator bool(); };",
437                                         "struct X { operator char(); };",
438                                          Lang_CXX11,
439                                          cxxConversionDecl());
440   EXPECT_FALSE(testStructuralMatch(t));
441 }
442 
443 TEST_F(StructuralEquivalenceCXXMethodTest, Operator) {
444   auto t = makeDecls<FunctionDecl>(
445       "struct X { int operator +(int); };",
446       "struct X { int operator -(int); };", Lang_CXX,
447       functionDecl(hasOverloadedOperatorName("+")),
448       functionDecl(hasOverloadedOperatorName("-")));
449   EXPECT_FALSE(testStructuralMatch(t));
450 }
451 
452 TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass1) {
453   auto t = makeDecls<FunctionDecl>(
454       "struct X { virtual void f(); }; void X::f() { }",
455       "struct X { virtual void f() { }; };",
456       Lang_CXX,
457       functionDecl(allOf(hasName("f"), isDefinition())));
458   EXPECT_TRUE(testStructuralMatch(t));
459 }
460 
461 TEST_F(StructuralEquivalenceCXXMethodTest, OutOfClass2) {
462   auto t = makeDecls<FunctionDecl>(
463       "struct X { virtual void f(); }; void X::f() { }",
464       "struct X { void f(); }; void X::f() { }",
465       Lang_CXX,
466       functionDecl(allOf(hasName("f"), isDefinition())));
467   EXPECT_FALSE(testStructuralMatch(t));
468 }
469 
470 struct StructuralEquivalenceRecordTest : StructuralEquivalenceTest {
471 };
472 
473 TEST_F(StructuralEquivalenceRecordTest, Name) {
474   auto t = makeDecls<CXXRecordDecl>(
475       "struct A{ };",
476       "struct B{ };",
477       Lang_CXX,
478       cxxRecordDecl(hasName("A")),
479       cxxRecordDecl(hasName("B")));
480   EXPECT_FALSE(testStructuralMatch(t));
481 }
482 
483 TEST_F(StructuralEquivalenceRecordTest, Fields) {
484   auto t = makeNamedDecls(
485       "struct foo{ int x; };",
486       "struct foo{ char x; };",
487       Lang_CXX);
488   EXPECT_FALSE(testStructuralMatch(t));
489 }
490 
491 TEST_F(StructuralEquivalenceRecordTest, DISABLED_Methods) {
492   // Currently, methods of a class are not checked at class equivalence.
493   auto t = makeNamedDecls(
494       "struct foo{ int x(); };",
495       "struct foo{ char x(); };",
496       Lang_CXX);
497   EXPECT_FALSE(testStructuralMatch(t));
498 }
499 
500 TEST_F(StructuralEquivalenceRecordTest, Bases) {
501   auto t = makeNamedDecls(
502       "struct A{ }; struct foo: A { };",
503       "struct B{ }; struct foo: B { };",
504       Lang_CXX);
505   EXPECT_FALSE(testStructuralMatch(t));
506 }
507 
508 TEST_F(StructuralEquivalenceRecordTest, InheritanceVirtual) {
509   auto t = makeNamedDecls(
510       "struct A{ }; struct foo: A { };",
511       "struct A{ }; struct foo: virtual A { };",
512       Lang_CXX);
513   EXPECT_FALSE(testStructuralMatch(t));
514 }
515 
516 TEST_F(StructuralEquivalenceRecordTest, DISABLED_InheritanceType) {
517   // Access specifier in inheritance is not checked yet.
518   auto t = makeNamedDecls(
519       "struct A{ }; struct foo: public A { };",
520       "struct A{ }; struct foo: private A { };",
521       Lang_CXX);
522   EXPECT_FALSE(testStructuralMatch(t));
523 }
524 
525 TEST_F(StructuralEquivalenceRecordTest, Match) {
526   auto Code = R"(
527       struct A{ };
528       struct B{ };
529       struct foo: A, virtual B {
530         void x();
531         int a;
532       };
533       )";
534   auto t = makeNamedDecls(Code, Code, Lang_CXX);
535   EXPECT_TRUE(testStructuralMatch(t));
536 }
537 
538 TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
539   auto t = makeNamedDecls(
540       "struct A{ }; struct B{ }; void foo(A a, A b);",
541       "struct A{ }; struct B{ }; void foo(A a, B b);",
542       Lang_CXX);
543   EXPECT_FALSE(testStructuralMatch(t));
544 }
545 
546 } // end namespace ast_matchers
547 } // end namespace clang
548