Clang Project

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