blob: d6bb9cbfcb8efd76dcbe714722aedf7aa50b7546 [file] [log] [blame]
Johannes Altmanninger1a267692017-08-23 16:28:26 +00001//===- 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
24using namespace clang;
25using namespace tooling;
26using namespace ast_matchers;
27
28namespace {
29class 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
37public:
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
53namespace {
54struct 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
73static 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
94static testing::AssertionResult
95isStmtHashEqual(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
107TEST(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
116TEST(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
131TEST(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
140TEST(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
151TEST(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
158TEST(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
165TEST(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}