1 //===- unittests/AST/DataCollectionTest.cpp -------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains tests for the DataCollection module.
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.
14 //===----------------------------------------------------------------------===//
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"
23 using namespace clang
;
24 using namespace tooling
;
25 using namespace ast_matchers
;
28 class StmtDataCollector
: public ConstStmtVisitor
<StmtDataCollector
> {
30 llvm::MD5
&DataConsumer
;
32 template <class T
> void addData(const T
&Data
) {
33 data_collection::addDataToConsumer(DataConsumer
, Data
);
37 StmtDataCollector(const Stmt
*S
, ASTContext
&Context
, llvm::MD5
&DataConsumer
)
38 : Context(Context
), DataConsumer(DataConsumer
) {
42 #define DEF_ADD_DATA(CLASS, CODE) \
43 template <class Dummy = void> Dummy Visit##CLASS(const CLASS *S) { \
45 ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S); \
48 #include "clang/AST/StmtDataCollectors.inc"
50 } // end anonymous namespace
53 struct StmtHashMatch
: public MatchFinder::MatchCallback
{
55 llvm::MD5::MD5Result
&Hash
;
56 StmtHashMatch(llvm::MD5::MD5Result
&Hash
) : NumFound(0), Hash(Hash
) {}
58 void run(const MatchFinder::MatchResult
&Result
) override
{
59 const Stmt
*S
= Result
.Nodes
.getNodeAs
<Stmt
>("id");
66 StmtDataCollector(S
, *Result
.Context
, MD5
);
70 } // end anonymous namespace
72 static testing::AssertionResult
hashStmt(llvm::MD5::MD5Result
&Hash
,
73 const StatementMatcher
&StmtMatch
,
75 StmtHashMatch
Hasher(Hash
);
77 Finder
.addMatcher(StmtMatch
, &Hasher
);
78 std::unique_ptr
<FrontendActionFactory
> Factory(
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 "
89 << Hasher
.NumFound
<< ")";
90 return testing::AssertionSuccess();
93 static testing::AssertionResult
94 isStmtHashEqual(const StatementMatcher
&StmtMatch
, StringRef Code1
,
96 llvm::MD5::MD5Result Hash1
, Hash2
;
97 testing::AssertionResult Result
= hashStmt(Hash1
, StmtMatch
, Code1
);
100 if (!(Result
= hashStmt(Hash2
, StmtMatch
, Code2
)))
103 return testing::AssertionResult(Hash1
== Hash2
);
106 TEST(StmtDataCollector
, TestDeclRefExpr
) {
107 ASSERT_TRUE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
109 ASSERT_FALSE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
111 ASSERT_FALSE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
112 "namespace n { int x, r = x; };"));
115 TEST(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;"));
130 TEST(StmtDataCollector
, TestIntegerLiteral
) {
132 isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x = 0;"));
134 isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x =00;"));
136 isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x = 1;"));
139 TEST(StmtDataCollector
, TestFloatingLiteral
) {
140 ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .0;",
142 ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .10;",
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;",
150 TEST(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";)"));
157 TEST(StmtDataCollector
, TestCXXBoolLiteral
) {
158 ASSERT_TRUE(isStmtHashEqual(cxxBoolLiteral().bind("id"), "bool x = false;",
160 ASSERT_FALSE(isStmtHashEqual(cxxBoolLiteral().bind("id"), "bool x = false;",
164 TEST(StmtDataCollector
, TestCharacterLiteral
) {
165 ASSERT_TRUE(isStmtHashEqual(characterLiteral().bind("id"), "char x = '0';",
167 ASSERT_TRUE(isStmtHashEqual(characterLiteral().bind("id"),
169 R
"(char x = '\x00';)"));
170 ASSERT_FALSE(isStmtHashEqual(characterLiteral().bind("id"), "char x = '0';",