173 lines · 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-exception6//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 the12// 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 *S, ASTContext &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 namespace51 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 namespace71 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<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 "88 "(found "89 << Hasher.NumFound << ")";90 return testing::AssertionSuccess();91}92 93static testing::AssertionResult94isStmtHashEqual(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