forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			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';"));
 | 
						|
}
 |