DataCollectionTest.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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. #include "clang/AST/DataCollection.h"
  16. #include "clang/AST/DeclTemplate.h"
  17. #include "clang/AST/StmtVisitor.h"
  18. #include "clang/ASTMatchers/ASTMatchFinder.h"
  19. #include "clang/Tooling/Tooling.h"
  20. #include "gtest/gtest.h"
  21. using namespace clang;
  22. using namespace tooling;
  23. using namespace ast_matchers;
  24. namespace {
  25. class StmtDataCollector : public ConstStmtVisitor<StmtDataCollector> {
  26. ASTContext &Context;
  27. llvm::MD5 &DataConsumer;
  28. template <class T> void addData(const T &Data) {
  29. data_collection::addDataToConsumer(DataConsumer, Data);
  30. }
  31. public:
  32. StmtDataCollector(const Stmt *S, ASTContext &Context, llvm::MD5 &DataConsumer)
  33. : Context(Context), DataConsumer(DataConsumer) {
  34. this->Visit(S);
  35. }
  36. #define DEF_ADD_DATA(CLASS, CODE) \
  37. template <class Dummy = void> Dummy Visit##CLASS(const CLASS *S) { \
  38. CODE; \
  39. ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S); \
  40. }
  41. #include "clang/AST/StmtDataCollectors.inc"
  42. };
  43. } // end anonymous namespace
  44. namespace {
  45. struct StmtHashMatch : public MatchFinder::MatchCallback {
  46. unsigned NumFound;
  47. llvm::MD5::MD5Result &Hash;
  48. StmtHashMatch(llvm::MD5::MD5Result &Hash) : NumFound(0), Hash(Hash) {}
  49. void run(const MatchFinder::MatchResult &Result) override {
  50. const Stmt *S = Result.Nodes.getNodeAs<Stmt>("id");
  51. if (!S)
  52. return;
  53. ++NumFound;
  54. if (NumFound > 1)
  55. return;
  56. llvm::MD5 MD5;
  57. StmtDataCollector(S, *Result.Context, MD5);
  58. MD5.final(Hash);
  59. }
  60. };
  61. } // end anonymous namespace
  62. static testing::AssertionResult hashStmt(llvm::MD5::MD5Result &Hash,
  63. const StatementMatcher &StmtMatch,
  64. StringRef Code) {
  65. StmtHashMatch Hasher(Hash);
  66. MatchFinder Finder;
  67. Finder.addMatcher(StmtMatch, &Hasher);
  68. std::unique_ptr<FrontendActionFactory> Factory(
  69. newFrontendActionFactory(&Finder));
  70. if (!runToolOnCode(Factory->create(), Code))
  71. return testing::AssertionFailure()
  72. << "Parsing error in \"" << Code.str() << "\"";
  73. if (Hasher.NumFound == 0)
  74. return testing::AssertionFailure() << "Matcher didn't find any statements";
  75. if (Hasher.NumFound > 1)
  76. return testing::AssertionFailure()
  77. << "Matcher should match only one statement "
  78. "(found "
  79. << Hasher.NumFound << ")";
  80. return testing::AssertionSuccess();
  81. }
  82. static testing::AssertionResult
  83. isStmtHashEqual(const StatementMatcher &StmtMatch, StringRef Code1,
  84. StringRef Code2) {
  85. llvm::MD5::MD5Result Hash1, Hash2;
  86. testing::AssertionResult Result = hashStmt(Hash1, StmtMatch, Code1);
  87. if (!Result)
  88. return Result;
  89. if (!(Result = hashStmt(Hash2, StmtMatch, Code2)))
  90. return Result;
  91. return testing::AssertionResult(Hash1 == Hash2);
  92. }
  93. TEST(StmtDataCollector, TestDeclRefExpr) {
  94. ASSERT_TRUE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
  95. "int x, r = x;"));
  96. ASSERT_FALSE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
  97. "int y, r = y;"));
  98. ASSERT_FALSE(isStmtHashEqual(declRefExpr().bind("id"), "int x, r = x;",
  99. "namespace n { int x, r = x; };"));
  100. }
  101. TEST(StmtDataCollector, TestMemberExpr) {
  102. ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
  103. "struct { int x; } X; int r = X.x;",
  104. "struct { int x; } X; int r = (&X)->x;"));
  105. ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
  106. "struct { int x; } X; int r = X.x;",
  107. "struct { int x; } Y; int r = Y.x;"));
  108. ASSERT_TRUE(isStmtHashEqual(memberExpr().bind("id"),
  109. "struct { int x; } X; int r = X.x;",
  110. "struct C { int x; } X; int r = X.C::x;"));
  111. ASSERT_FALSE(isStmtHashEqual(memberExpr().bind("id"),
  112. "struct { int x; } X; int r = X.x;",
  113. "struct { int y; } X; int r = X.y;"));
  114. }
  115. TEST(StmtDataCollector, TestIntegerLiteral) {
  116. ASSERT_TRUE(
  117. isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x = 0;"));
  118. ASSERT_TRUE(
  119. isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x =00;"));
  120. ASSERT_FALSE(
  121. isStmtHashEqual(integerLiteral().bind("id"), "int x = 0;", "int x = 1;"));
  122. }
  123. TEST(StmtDataCollector, TestFloatingLiteral) {
  124. ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .0;",
  125. "double x = .0;"));
  126. ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .10;",
  127. "double x = .1;"));
  128. ASSERT_TRUE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .1;",
  129. "double x = 1e-1;"));
  130. ASSERT_FALSE(isStmtHashEqual(floatLiteral().bind("id"), "double x = .0;",
  131. "double x = .1;"));
  132. }
  133. TEST(StmtDataCollector, TestStringLiteral) {
  134. ASSERT_TRUE(isStmtHashEqual(stringLiteral().bind("id"), R"(char x[] = "0";)",
  135. R"(char x[] = "0";)"));
  136. ASSERT_FALSE(isStmtHashEqual(stringLiteral().bind("id"), R"(char x[] = "0";)",
  137. R"(char x[] = "1";)"));
  138. }
  139. TEST(StmtDataCollector, TestCXXBoolLiteral) {
  140. ASSERT_TRUE(isStmtHashEqual(cxxBoolLiteral().bind("id"), "bool x = false;",
  141. "bool x = false;"));
  142. ASSERT_FALSE(isStmtHashEqual(cxxBoolLiteral().bind("id"), "bool x = false;",
  143. "bool x = true;"));
  144. }
  145. TEST(StmtDataCollector, TestCharacterLiteral) {
  146. ASSERT_TRUE(isStmtHashEqual(characterLiteral().bind("id"), "char x = '0';",
  147. "char x = '0';"));
  148. ASSERT_TRUE(isStmtHashEqual(characterLiteral().bind("id"),
  149. R"(char x = '\0';)",
  150. R"(char x = '\x00';)"));
  151. ASSERT_FALSE(isStmtHashEqual(characterLiteral().bind("id"), "char x = '0';",
  152. "char x = '1';"));
  153. }