173 lines
6.7 KiB
C++
173 lines
6.7 KiB
C++
//===- unittests/AST/DataCollectionTest.cpp -------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file contains tests for the DataCollection module.
|
|
//
|
|
// They work by hashing the collected data of two nodes and asserting that the
|
|
// hash values are equal iff the nodes are considered equal.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/AST/DataCollection.h"
|
|
#include "clang/AST/DeclTemplate.h"
|
|
#include "clang/AST/StmtVisitor.h"
|
|
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
|
#include "clang/Tooling/Tooling.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace clang;
|
|
using namespace tooling;
|
|
using namespace ast_matchers;
|
|
|
|
namespace {
|
|
class StmtDataCollector : public ConstStmtVisitor<StmtDataCollector> {
|
|
ASTContext &Context;
|
|
llvm::MD5 &DataConsumer;
|
|
|
|
template <class T> void addData(const T &Data) {
|
|
data_collection::addDataToConsumer(DataConsumer, Data);
|
|
}
|
|
|
|
public:
|
|
StmtDataCollector(const Stmt *S, ASTContext &Context, llvm::MD5 &DataConsumer)
|
|
: Context(Context), DataConsumer(DataConsumer) {
|
|
this->Visit(S);
|
|
}
|
|
|
|
#define DEF_ADD_DATA(CLASS, CODE) \
|
|
template <class Dummy = void> Dummy Visit##CLASS(const CLASS *S) { \
|
|
CODE; \
|
|
ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S); \
|
|
}
|
|
|
|
#include "clang/AST/StmtDataCollectors.inc"
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
namespace {
|
|
struct StmtHashMatch : public MatchFinder::MatchCallback {
|
|
unsigned NumFound;
|
|
llvm::MD5::MD5Result &Hash;
|
|
StmtHashMatch(llvm::MD5::MD5Result &Hash) : NumFound(0), Hash(Hash) {}
|
|
|
|
void run(const MatchFinder::MatchResult &Result) override {
|
|
const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id");
|
|
if (!S)
|
|
return;
|
|
++NumFound;
|
|
if (NumFound > 1)
|
|
return;
|
|
llvm::MD5 MD5;
|
|
StmtDataCollector(S, *Result.Context, MD5);
|
|
MD5.final(Hash);
|
|
}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
static testing::AssertionResult hashStmt(llvm::MD5::MD5Result &Hash,
|
|
const StatementMatcher &StmtMatch,
|
|
StringRef Code) {
|
|
StmtHashMatch Hasher(Hash);
|
|
MatchFinder Finder;
|
|
Finder.addMatcher(StmtMatch, &Hasher);
|
|
std::unique_ptr<FrontendActionFactory> Factory(
|
|
newFrontendActionFactory(&Finder));
|
|
if (!runToolOnCode(Factory->create(), Code))
|
|
return testing::AssertionFailure()
|
|
<< "Parsing error in \"" << Code.str() << "\"";
|
|
if (Hasher.NumFound == 0)
|
|
return testing::AssertionFailure() << "Matcher didn't find any statements";
|
|
if (Hasher.NumFound > 1)
|
|
return testing::AssertionFailure()
|
|
<< "Matcher should match only one statement "
|
|
"(found "
|
|
<< Hasher.NumFound << ")";
|
|
return testing::AssertionSuccess();
|
|
}
|
|
|
|
static testing::AssertionResult
|
|
isStmtHashEqual(const StatementMatcher &StmtMatch, StringRef Code1,
|
|
StringRef Code2) {
|
|
llvm::MD5::MD5Result Hash1, Hash2;
|
|
testing::AssertionResult Result = hashStmt(Hash1, StmtMatch, Code1);
|
|
if (!Result)
|
|
return Result;
|
|
if (!(Result = hashStmt(Hash2, StmtMatch, Code2)))
|
|
return Result;
|
|
|
|
return testing::AssertionResult(Hash1 == Hash2);
|
|
}
|
|
|
|
TEST(StmtDataCollector, TestDeclRefExpr) {
|
|
ASSERT_TRUE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
|
|
"int x, r = x;"));
|
|
ASSERT_FALSE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
|
|
"int y, r = y;"));
|
|
ASSERT_FALSE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
|
|
"namespace n { int x, r = x; };"));
|
|
}
|
|
|
|
TEST(StmtDataCollector, TestMemberExpr) {
|
|
ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
|
|
"struct { int x; } X; int r = X.x;",
|
|
"struct { int x; } X; int r = (&X)->x;"));
|
|
ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
|
|
"struct { int x; } X; int r = X.x;",
|
|
"struct { int x; } Y; int r = Y.x;"));
|
|
ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
|
|
"struct { int x; } X; int r = X.x;",
|
|
"struct C { int x; } X; int r = X.C::x;"));
|
|
ASSERT_FALSE(isStmtHashEqual(memberExpr().bind("id"),
|
|
"struct { int x; } X; int r = X.x;",
|
|
"struct { int y; } X; int r = X.y;"));
|
|
}
|
|
|
|
TEST(StmtDataCollector, TestIntegerLiteral) {
|
|
ASSERT_TRUE(
|
|
isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x = 0;"));
|
|
ASSERT_TRUE(
|
|
isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x =00;"));
|
|
ASSERT_FALSE(
|
|
isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x = 1;"));
|
|
}
|
|
|
|
TEST(StmtDataCollector, TestFloatingLiteral) {
|
|
ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .0;",
|
|
"double x = .0;"));
|
|
ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .10;",
|
|
"double x = .1;"));
|
|
ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .1;",
|
|
"double x = 1e-1;"));
|
|
ASSERT_FALSE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .0;",
|
|
"double x = .1;"));
|
|
}
|
|
|
|
TEST(StmtDataCollector, TestStringLiteral) {
|
|
ASSERT_TRUE(isStmtHashEqual(stringLiteral().bind("id"), R"(char x[] = "0";)",
|
|
R"(char x[] = "0";)"));
|
|
ASSERT_FALSE(isStmtHashEqual(stringLiteral().bind("id"), R"(char x[] = "0";)",
|
|
R"(char x[] = "1";)"));
|
|
}
|
|
|
|
TEST(StmtDataCollector, TestCXXBoolLiteral) {
|
|
ASSERT_TRUE(isStmtHashEqual(cxxBoolLiteral().bind("id"), "bool x = false;",
|
|
"bool x = false;"));
|
|
ASSERT_FALSE(isStmtHashEqual(cxxBoolLiteral().bind("id"), "bool x = false;",
|
|
"bool x = true;"));
|
|
}
|
|
|
|
TEST(StmtDataCollector, TestCharacterLiteral) {
|
|
ASSERT_TRUE(isStmtHashEqual(characterLiteral().bind("id"), "char x = '0';",
|
|
"char x = '0';"));
|
|
ASSERT_TRUE(isStmtHashEqual(characterLiteral().bind("id"),
|
|
R"(char x = '\0';)",
|
|
R"(char x = '\x00';)"));
|
|
ASSERT_FALSE(isStmtHashEqual(characterLiteral().bind("id"), "char x = '0';",
|
|
"char x = '1';"));
|
|
}
|