xref: /llvm-project/clang/unittests/AST/DataCollectionTest.cpp (revision 1a2676924a4da482ec0b60d3d74c8c42d5719d70)
1 //===- unittests/AST/DataCollectionTest.cpp -------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains tests for the DataCollection module.
11 //
12 // They work by hashing the collected data of two nodes and asserting that the
13 // hash values are equal iff the nodes are considered equal.
14 //
15 //===----------------------------------------------------------------------===//
16 
17 #include "clang/AST/DataCollection.h"
18 #include "clang/AST/DeclTemplate.h"
19 #include "clang/AST/StmtVisitor.h"
20 #include "clang/ASTMatchers/ASTMatchFinder.h"
21 #include "clang/Tooling/Tooling.h"
22 #include "gtest/gtest.h"
23 
24 using namespace clang;
25 using namespace tooling;
26 using namespace ast_matchers;
27 
28 namespace {
29 class StmtDataCollector : public ConstStmtVisitor<StmtDataCollector> {
30   ASTContext &Context;
31   llvm::MD5 &DataConsumer;
32 
33   template <class T> void addData(const T &Data) {
34     data_collection::addDataToConsumer(DataConsumer, Data);
35   }
36 
37 public:
38   StmtDataCollector(const Stmt *S, ASTContext &Context, llvm::MD5 &DataConsumer)
39       : Context(Context), DataConsumer(DataConsumer) {
40     this->Visit(S);
41   }
42 
43 #define DEF_ADD_DATA(CLASS, CODE)                                              \
44   template <class Dummy = void> Dummy Visit##CLASS(const CLASS *S) {           \
45     CODE;                                                                      \
46     ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S);                      \
47   }
48 
49 #include "../../lib/AST/StmtDataCollectors.inc"
50 };
51 } // end anonymous namespace
52 
53 namespace {
54 struct StmtHashMatch : public MatchFinder::MatchCallback {
55   unsigned NumFound;
56   llvm::MD5::MD5Result &Hash;
57   StmtHashMatch(llvm::MD5::MD5Result &Hash) : NumFound(0), Hash(Hash) {}
58 
59   void run(const MatchFinder::MatchResult &Result) override {
60     const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id");
61     if (!S)
62       return;
63     ++NumFound;
64     if (NumFound > 1)
65       return;
66     llvm::MD5 MD5;
67     StmtDataCollector(S, *Result.Context, MD5);
68     MD5.final(Hash);
69   }
70 };
71 } // end anonymous namespace
72 
73 static testing::AssertionResult hashStmt(llvm::MD5::MD5Result &Hash,
74                                          const StatementMatcher &StmtMatch,
75                                          StringRef Code) {
76   StmtHashMatch Hasher(Hash);
77   MatchFinder Finder;
78   Finder.addMatcher(StmtMatch, &Hasher);
79   std::unique_ptr<FrontendActionFactory> Factory(
80       newFrontendActionFactory(&Finder));
81   if (!runToolOnCode(Factory->create(), Code))
82     return testing::AssertionFailure()
83            << "Parsing error in \"" << Code.str() << "\"";
84   if (Hasher.NumFound == 0)
85     return testing::AssertionFailure() << "Matcher didn't find any statements";
86   if (Hasher.NumFound > 1)
87     return testing::AssertionFailure()
88            << "Matcher should match only one statement "
89               "(found "
90            << Hasher.NumFound << ")";
91   return testing::AssertionSuccess();
92 }
93 
94 static testing::AssertionResult
95 isStmtHashEqual(const StatementMatcher &StmtMatch, StringRef Code1,
96                 StringRef Code2) {
97   llvm::MD5::MD5Result Hash1, Hash2;
98   testing::AssertionResult Result = hashStmt(Hash1, StmtMatch, Code1);
99   if (!Result)
100     return Result;
101   if (!(Result = hashStmt(Hash2, StmtMatch, Code2)))
102     return Result;
103 
104   return testing::AssertionResult(Hash1 == Hash2);
105 }
106 
107 TEST(StmtDataCollector, TestDeclRefExpr) {
108   ASSERT_TRUE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
109                               "int x, r = x;"));
110   ASSERT_FALSE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
111                                "int y, r = y;"));
112   ASSERT_FALSE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
113                                "namespace n { int x, r = x; };"));
114 }
115 
116 TEST(StmtDataCollector, TestMemberExpr) {
117   ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
118                               "struct { int x; } X; int r = X.x;",
119                               "struct { int x; } X; int r = (&X)->x;"));
120   ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
121                               "struct { int x; } X; int r = X.x;",
122                               "struct { int x; } Y; int r = Y.x;"));
123   ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
124                               "struct { int x; } X; int r = X.x;",
125                               "struct C { int x; } X; int r = X.C::x;"));
126   ASSERT_FALSE(isStmtHashEqual(memberExpr().bind("id"),
127                                "struct { int x; } X; int r = X.x;",
128                                "struct { int y; } X; int r = X.y;"));
129 }
130 
131 TEST(StmtDataCollector, TestIntegerLiteral) {
132   ASSERT_TRUE(
133       isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x = 0;"));
134   ASSERT_TRUE(
135       isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x =00;"));
136   ASSERT_FALSE(
137       isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x = 1;"));
138 }
139 
140 TEST(StmtDataCollector, TestFloatingLiteral) {
141   ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .0;",
142                               "double x = .0;"));
143   ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .10;",
144                               "double x = .1;"));
145   ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .1;",
146                               "double x = 1e-1;"));
147   ASSERT_FALSE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .0;",
148                                "double x = .1;"));
149 }
150 
151 TEST(StmtDataCollector, TestStringLiteral) {
152   ASSERT_TRUE(isStmtHashEqual(stringLiteral().bind("id"), R"(char x[] = "0";)",
153                               R"(char x[] = "0";)"));
154   ASSERT_FALSE(isStmtHashEqual(stringLiteral().bind("id"), R"(char x[] = "0";)",
155                                R"(char x[] = "1";)"));
156 }
157 
158 TEST(StmtDataCollector, TestCXXBoolLiteral) {
159   ASSERT_TRUE(isStmtHashEqual(cxxBoolLiteral().bind("id"), "bool x = false;",
160                               "bool x = false;"));
161   ASSERT_FALSE(isStmtHashEqual(cxxBoolLiteral().bind("id"), "bool x = false;",
162                                "bool x = true;"));
163 }
164 
165 TEST(StmtDataCollector, TestCharacterLiteral) {
166   ASSERT_TRUE(isStmtHashEqual(characterLiteral().bind("id"), "char x = '0';",
167                               "char x = '0';"));
168   ASSERT_TRUE(isStmtHashEqual(characterLiteral().bind("id"),
169                               R"(char x = '\0';)",
170                               R"(char x = '\x00';)"));
171   ASSERT_FALSE(isStmtHashEqual(characterLiteral().bind("id"), "char x = '0';",
172                                "char x = '1';"));
173 }
174