[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-11 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG93fbaa46c82a: Revert Revert [clang][dataflow] 
Add framework for testing analyses. (authored by ymandel).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115341/new/

https://reviews.llvm.org/D115341

Files:
  clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h
  clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
  clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
  clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
  clang/unittests/Analysis/FlowSensitive/TestingSupport.h
  clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
  llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn

Index: llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn
===
--- llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn
+++ llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn
@@ -9,9 +9,15 @@
 "//clang/lib/Analysis/FlowSensitive",
 "//clang/lib/Basic",
 "//clang/lib/Frontend",
+"//clang/lib/Lex",
 "//clang/lib/Testing",
 "//clang/lib/Tooling",
 "//llvm/lib/Support",
+"//llvm/lib/Testing/Support",
+  ]
+  sources = [
+"TestingSupport.cpp",
+"TestingSupportTest.cpp",
+"TypeErasedDataflowAnalysisTest.cpp",
   ]
-  sources = [ "TypeErasedDataflowAnalysisTest.cpp" ]
 }
Index: clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
===
--- /dev/null
+++ clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
@@ -0,0 +1,178 @@
+#include "TestingSupport.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace dataflow;
+
+namespace {
+
+using ::clang::ast_matchers::functionDecl;
+using ::clang::ast_matchers::hasName;
+using ::clang::ast_matchers::isDefinition;
+using ::testing::_;
+using ::testing::IsEmpty;
+using ::testing::Pair;
+using ::testing::UnorderedElementsAre;
+
+class NoopLattice {
+public:
+  bool operator==(const NoopLattice &) const { return true; }
+
+  LatticeJoinEffect join(const NoopLattice &) {
+return LatticeJoinEffect::Unchanged;
+  }
+};
+
+std::ostream <<(std::ostream , const NoopLattice ) {
+  OS << "noop";
+  return OS;
+}
+
+class NoopAnalysis : public DataflowAnalysis {
+public:
+  NoopAnalysis(ASTContext )
+  : DataflowAnalysis(Context) {}
+
+  static NoopLattice initialElement() { return {}; }
+
+  NoopLattice transfer(const Stmt *S, const NoopLattice , Environment ) {
+return {};
+  }
+};
+
+template 
+const FunctionDecl *findTargetFunc(ASTContext , T FunctionMatcher) {
+  auto TargetMatcher =
+  functionDecl(FunctionMatcher, isDefinition()).bind("target");
+  for (const auto  : ast_matchers::match(TargetMatcher, Context)) {
+const auto *Func = Node.template getNodeAs("target");
+if (Func == nullptr)
+  continue;
+if (Func->isTemplated())
+  continue;
+return Func;
+  }
+  return nullptr;
+}
+
+class BuildStatementToAnnotationMappingTest : public ::testing::Test {
+public:
+  void
+  runTest(llvm::StringRef Code, llvm::StringRef TargetName,
+  std::function &)>
+  RunChecks) {
+llvm::Annotations AnnotatedCode(Code);
+auto Unit = tooling::buildASTFromCodeWithArgs(
+AnnotatedCode.code(), {"-fsyntax-only", "-std=c++17"});
+auto  = Unit->getASTContext();
+const FunctionDecl *Func = findTargetFunc(Context, hasName(TargetName));
+ASSERT_NE(Func, nullptr);
+
+llvm::Expected> Mapping =
+test::buildStatementToAnnotationMapping(Func, AnnotatedCode);
+ASSERT_TRUE(static_cast(Mapping));
+
+RunChecks(Mapping.get());
+  }
+};
+
+TEST_F(BuildStatementToAnnotationMappingTest, ReturnStmt) {
+  runTest(R"(
+int target() {
+  return 42;
+  /*[[ok]]*/
+}
+  )",
+  "target",
+  [](const llvm::DenseMap ) {
+ASSERT_EQ(Annotations.size(), static_cast(1));
+EXPECT_TRUE(isa(Annotations.begin()->first));
+EXPECT_EQ(Annotations.begin()->second, "ok");
+  });
+}
+
+void checkDataflow(
+llvm::StringRef Code, llvm::StringRef Target,
+std::function>>,
+   ASTContext &)>
+Expectations) {
+  test::checkDataflow(
+  Code, Target,
+  [](ASTContext , Environment &) { return NoopAnalysis(Context); },
+  std::move(Expectations), {"-fsyntax-only", "-std=c++17"});
+}
+
+TEST(ProgramPointAnnotations, NoAnnotations) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, 

[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-11 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel updated this revision to Diff 393705.
ymandel added a comment.

rebase


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115341/new/

https://reviews.llvm.org/D115341

Files:
  clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h
  clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
  clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
  clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
  clang/unittests/Analysis/FlowSensitive/TestingSupport.h
  clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
  llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn

Index: llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn
===
--- llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn
+++ llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn
@@ -9,9 +9,15 @@
 "//clang/lib/Analysis/FlowSensitive",
 "//clang/lib/Basic",
 "//clang/lib/Frontend",
+"//clang/lib/Lex",
 "//clang/lib/Testing",
 "//clang/lib/Tooling",
 "//llvm/lib/Support",
+"//llvm/lib/Testing/Support",
+  ]
+  sources = [
+"TestingSupport.cpp",
+"TestingSupportTest.cpp",
+"TypeErasedDataflowAnalysisTest.cpp",
   ]
-  sources = [ "TypeErasedDataflowAnalysisTest.cpp" ]
 }
Index: clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
===
--- /dev/null
+++ clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
@@ -0,0 +1,178 @@
+#include "TestingSupport.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace dataflow;
+
+namespace {
+
+using ::clang::ast_matchers::functionDecl;
+using ::clang::ast_matchers::hasName;
+using ::clang::ast_matchers::isDefinition;
+using ::testing::_;
+using ::testing::IsEmpty;
+using ::testing::Pair;
+using ::testing::UnorderedElementsAre;
+
+class NoopLattice {
+public:
+  bool operator==(const NoopLattice &) const { return true; }
+
+  LatticeJoinEffect join(const NoopLattice &) {
+return LatticeJoinEffect::Unchanged;
+  }
+};
+
+std::ostream <<(std::ostream , const NoopLattice ) {
+  OS << "noop";
+  return OS;
+}
+
+class NoopAnalysis : public DataflowAnalysis {
+public:
+  NoopAnalysis(ASTContext )
+  : DataflowAnalysis(Context) {}
+
+  static NoopLattice initialElement() { return {}; }
+
+  NoopLattice transfer(const Stmt *S, const NoopLattice , Environment ) {
+return {};
+  }
+};
+
+template 
+const FunctionDecl *findTargetFunc(ASTContext , T FunctionMatcher) {
+  auto TargetMatcher =
+  functionDecl(FunctionMatcher, isDefinition()).bind("target");
+  for (const auto  : ast_matchers::match(TargetMatcher, Context)) {
+const auto *Func = Node.template getNodeAs("target");
+if (Func == nullptr)
+  continue;
+if (Func->isTemplated())
+  continue;
+return Func;
+  }
+  return nullptr;
+}
+
+class BuildStatementToAnnotationMappingTest : public ::testing::Test {
+public:
+  void
+  runTest(llvm::StringRef Code, llvm::StringRef TargetName,
+  std::function &)>
+  RunChecks) {
+llvm::Annotations AnnotatedCode(Code);
+auto Unit = tooling::buildASTFromCodeWithArgs(
+AnnotatedCode.code(), {"-fsyntax-only", "-std=c++17"});
+auto  = Unit->getASTContext();
+const FunctionDecl *Func = findTargetFunc(Context, hasName(TargetName));
+ASSERT_NE(Func, nullptr);
+
+llvm::Expected> Mapping =
+test::buildStatementToAnnotationMapping(Func, AnnotatedCode);
+ASSERT_TRUE(static_cast(Mapping));
+
+RunChecks(Mapping.get());
+  }
+};
+
+TEST_F(BuildStatementToAnnotationMappingTest, ReturnStmt) {
+  runTest(R"(
+int target() {
+  return 42;
+  /*[[ok]]*/
+}
+  )",
+  "target",
+  [](const llvm::DenseMap ) {
+ASSERT_EQ(Annotations.size(), static_cast(1));
+EXPECT_TRUE(isa(Annotations.begin()->first));
+EXPECT_EQ(Annotations.begin()->second, "ok");
+  });
+}
+
+void checkDataflow(
+llvm::StringRef Code, llvm::StringRef Target,
+std::function>>,
+   ASTContext &)>
+Expectations) {
+  test::checkDataflow(
+  Code, Target,
+  [](ASTContext , Environment &) { return NoopAnalysis(Context); },
+  std::move(Expectations), {"-fsyntax-only", "-std=c++17"});
+}
+
+TEST(ProgramPointAnnotations, NoAnnotations) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  checkDataflow("void target() {}", "target", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, NoAnnotationsDifferentTarget) 

[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-10 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel updated this revision to Diff 393513.
ymandel added a comment.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

renames the `testing` namespace to `test`

cleans up the code the implementation of `operator<<` for dataflow state.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115341/new/

https://reviews.llvm.org/D115341

Files:
  clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h
  clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
  clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
  clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
  clang/unittests/Analysis/FlowSensitive/TestingSupport.h
  clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
  llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn

Index: llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn
===
--- llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn
+++ llvm/utils/gn/secondary/clang/unittests/Analysis/FlowSensitive/BUILD.gn
@@ -9,9 +9,15 @@
 "//clang/lib/Analysis/FlowSensitive",
 "//clang/lib/Basic",
 "//clang/lib/Frontend",
+"//clang/lib/Lex",
 "//clang/lib/Testing",
 "//clang/lib/Tooling",
 "//llvm/lib/Support",
+"//llvm/lib/Testing/Support",
+  ]
+  sources = [
+"TestingSupport.cpp",
+"TestingSupportTest.cpp",
+"TypeErasedDataflowAnalysisTest.cpp",
   ]
-  sources = [ "TypeErasedDataflowAnalysisTest.cpp" ]
 }
Index: clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
===
--- /dev/null
+++ clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
@@ -0,0 +1,178 @@
+#include "TestingSupport.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace dataflow;
+
+namespace {
+
+using ::clang::ast_matchers::functionDecl;
+using ::clang::ast_matchers::hasName;
+using ::clang::ast_matchers::isDefinition;
+using ::testing::_;
+using ::testing::IsEmpty;
+using ::testing::Pair;
+using ::testing::UnorderedElementsAre;
+
+class NoopLattice {
+public:
+  bool operator==(const NoopLattice &) const { return true; }
+
+  LatticeJoinEffect join(const NoopLattice &) {
+return LatticeJoinEffect::Unchanged;
+  }
+};
+
+std::ostream <<(std::ostream , const NoopLattice ) {
+  OS << "noop";
+  return OS;
+}
+
+class NoopAnalysis : public DataflowAnalysis {
+public:
+  NoopAnalysis(ASTContext )
+  : DataflowAnalysis(Context) {}
+
+  static NoopLattice initialElement() { return {}; }
+
+  NoopLattice transfer(const Stmt *S, const NoopLattice , Environment ) {
+return {};
+  }
+};
+
+template 
+const FunctionDecl *findTargetFunc(ASTContext , T FunctionMatcher) {
+  auto TargetMatcher =
+  functionDecl(FunctionMatcher, isDefinition()).bind("target");
+  for (const auto  : ast_matchers::match(TargetMatcher, Context)) {
+const auto *Func = Node.template getNodeAs("target");
+if (Func == nullptr)
+  continue;
+if (Func->isTemplated())
+  continue;
+return Func;
+  }
+  return nullptr;
+}
+
+class BuildStatementToAnnotationMappingTest : public ::testing::Test {
+public:
+  void
+  runTest(llvm::StringRef Code, llvm::StringRef TargetName,
+  std::function &)>
+  RunChecks) {
+llvm::Annotations AnnotatedCode(Code);
+auto Unit = tooling::buildASTFromCodeWithArgs(
+AnnotatedCode.code(), {"-fsyntax-only", "-std=c++17"});
+auto  = Unit->getASTContext();
+const FunctionDecl *Func = findTargetFunc(Context, hasName(TargetName));
+ASSERT_NE(Func, nullptr);
+
+llvm::Expected> Mapping =
+test::buildStatementToAnnotationMapping(Func, AnnotatedCode);
+ASSERT_TRUE(static_cast(Mapping));
+
+RunChecks(Mapping.get());
+  }
+};
+
+TEST_F(BuildStatementToAnnotationMappingTest, ReturnStmt) {
+  runTest(R"(
+int target() {
+  return 42;
+  /*[[ok]]*/
+}
+  )",
+  "target",
+  [](const llvm::DenseMap ) {
+ASSERT_EQ(Annotations.size(), static_cast(1));
+EXPECT_TRUE(isa(Annotations.begin()->first));
+EXPECT_EQ(Annotations.begin()->second, "ok");
+  });
+}
+
+void checkDataflow(
+llvm::StringRef Code, llvm::StringRef Target,
+std::function>>,
+   ASTContext &)>
+Expectations) {
+  test::checkDataflow(
+  Code, Target,
+  [](ASTContext , Environment &) { return NoopAnalysis(Context); },
+  std::move(Expectations), {"-fsyntax-only", "-std=c++17"});
+}
+
+TEST(ProgramPointAnnotations, NoAnnotations) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  

[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-10 Thread Nico Weber via Phabricator via cfe-commits
thakis added a comment.

Looks like this breaks building on Windows: 
http://45.33.8.238/win/50614/step_4.txt

Please take a look!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115341/new/

https://reviews.llvm.org/D115341

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-10 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG5a40df638181: [clang][dataflow] Add framework for testing 
analyses. (authored by ymandel).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115341/new/

https://reviews.llvm.org/D115341

Files:
  clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h
  clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
  clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
  clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
  clang/unittests/Analysis/FlowSensitive/TestingSupport.h
  clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp

Index: clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
===
--- /dev/null
+++ clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
@@ -0,0 +1,179 @@
+#include "TestingSupport.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace dataflow;
+
+namespace {
+
+using ::clang::ast_matchers::functionDecl;
+using ::clang::ast_matchers::hasName;
+using ::clang::ast_matchers::isDefinition;
+using ::testing::_;
+using ::testing::IsEmpty;
+using ::testing::Pair;
+using ::testing::UnorderedElementsAre;
+
+class NoopLattice {
+public:
+  bool operator==(const NoopLattice &) const { return true; }
+
+  LatticeJoinEffect join(const NoopLattice &) {
+return LatticeJoinEffect::Unchanged;
+  }
+};
+
+std::ostream <<(std::ostream , const NoopLattice ) {
+  OS << "noop";
+  return OS;
+}
+
+class NoopAnalysis : public DataflowAnalysis {
+public:
+  NoopAnalysis(ASTContext )
+  : DataflowAnalysis(Context) {}
+
+  static NoopLattice initialElement() { return {}; }
+
+  NoopLattice transfer(const Stmt *S, const NoopLattice , Environment ) {
+return {};
+  }
+};
+
+template 
+const FunctionDecl *findTargetFunc(ASTContext , T FunctionMatcher) {
+  auto TargetMatcher =
+  functionDecl(FunctionMatcher, isDefinition()).bind("target");
+  for (const auto  : ast_matchers::match(TargetMatcher, Context)) {
+const auto *Func = Node.template getNodeAs("target");
+if (Func == nullptr)
+  continue;
+if (Func->isTemplated())
+  continue;
+return Func;
+  }
+  return nullptr;
+}
+
+class BuildStatementToAnnotationMappingTest : public ::testing::Test {
+public:
+  void
+  runTest(llvm::StringRef Code, llvm::StringRef TargetName,
+  std::function &)>
+  RunChecks) {
+llvm::Annotations AnnotatedCode(Code);
+auto Unit = tooling::buildASTFromCodeWithArgs(
+AnnotatedCode.code(), {"-fsyntax-only", "-std=c++17"});
+auto  = Unit->getASTContext();
+const FunctionDecl *Func = findTargetFunc(Context, hasName(TargetName));
+ASSERT_NE(Func, nullptr);
+
+llvm::Expected> Mapping =
+clang::dataflow::testing::buildStatementToAnnotationMapping(
+Func, AnnotatedCode);
+ASSERT_TRUE(static_cast(Mapping));
+
+RunChecks(Mapping.get());
+  }
+};
+
+TEST_F(BuildStatementToAnnotationMappingTest, ReturnStmt) {
+  runTest(R"(
+int target() {
+  return 42;
+  /*[[ok]]*/
+}
+  )",
+  "target",
+  [](const llvm::DenseMap ) {
+ASSERT_EQ(Annotations.size(), static_cast(1));
+EXPECT_TRUE(isa(Annotations.begin()->first));
+EXPECT_EQ(Annotations.begin()->second, "ok");
+  });
+}
+
+void checkDataflow(
+llvm::StringRef Code, llvm::StringRef Target,
+std::function>>,
+   ASTContext &)>
+Expectations) {
+  clang::dataflow::testing::checkDataflow(
+  Code, Target,
+  [](ASTContext , Environment &) { return NoopAnalysis(Context); },
+  std::move(Expectations), {"-fsyntax-only", "-std=c++17"});
+}
+
+TEST(ProgramPointAnnotations, NoAnnotations) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  checkDataflow("void target() {}", "target", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, NoAnnotationsDifferentTarget) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  checkDataflow("void fun() {}", "fun", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, WithCodepoint) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations,
+  Call(UnorderedElementsAre(Pair("program-point", _)), _))
+  .Times(1);
+
+  checkDataflow(R"cc(void target() {
+ int n;
+ // [[program-point]]
+   })cc",
+ 

[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-10 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel updated this revision to Diff 393477.
ymandel added a comment.

Remove the SFINAE guard and add `operator<<` for `NoopLattice`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115341/new/

https://reviews.llvm.org/D115341

Files:
  clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h
  clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
  clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
  clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
  clang/unittests/Analysis/FlowSensitive/TestingSupport.h
  clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp

Index: clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
===
--- /dev/null
+++ clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
@@ -0,0 +1,179 @@
+#include "TestingSupport.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace dataflow;
+
+namespace {
+
+using ::clang::ast_matchers::functionDecl;
+using ::clang::ast_matchers::hasName;
+using ::clang::ast_matchers::isDefinition;
+using ::testing::_;
+using ::testing::IsEmpty;
+using ::testing::Pair;
+using ::testing::UnorderedElementsAre;
+
+class NoopLattice {
+public:
+  bool operator==(const NoopLattice &) const { return true; }
+
+  LatticeJoinEffect join(const NoopLattice &) {
+return LatticeJoinEffect::Unchanged;
+  }
+};
+
+std::ostream <<(std::ostream , const NoopLattice ) {
+  OS << "noop";
+  return OS;
+}
+
+class NoopAnalysis : public DataflowAnalysis {
+public:
+  NoopAnalysis(ASTContext )
+  : DataflowAnalysis(Context) {}
+
+  static NoopLattice initialElement() { return {}; }
+
+  NoopLattice transfer(const Stmt *S, const NoopLattice , Environment ) {
+return {};
+  }
+};
+
+template 
+const FunctionDecl *findTargetFunc(ASTContext , T FunctionMatcher) {
+  auto TargetMatcher =
+  functionDecl(FunctionMatcher, isDefinition()).bind("target");
+  for (const auto  : ast_matchers::match(TargetMatcher, Context)) {
+const auto *Func = Node.template getNodeAs("target");
+if (Func == nullptr)
+  continue;
+if (Func->isTemplated())
+  continue;
+return Func;
+  }
+  return nullptr;
+}
+
+class BuildStatementToAnnotationMappingTest : public ::testing::Test {
+public:
+  void
+  runTest(llvm::StringRef Code, llvm::StringRef TargetName,
+  std::function &)>
+  RunChecks) {
+llvm::Annotations AnnotatedCode(Code);
+auto Unit = tooling::buildASTFromCodeWithArgs(
+AnnotatedCode.code(), {"-fsyntax-only", "-std=c++17"});
+auto  = Unit->getASTContext();
+const FunctionDecl *Func = findTargetFunc(Context, hasName(TargetName));
+ASSERT_NE(Func, nullptr);
+
+llvm::Expected> Mapping =
+clang::dataflow::testing::buildStatementToAnnotationMapping(
+Func, AnnotatedCode);
+ASSERT_TRUE(static_cast(Mapping));
+
+RunChecks(Mapping.get());
+  }
+};
+
+TEST_F(BuildStatementToAnnotationMappingTest, ReturnStmt) {
+  runTest(R"(
+int target() {
+  return 42;
+  /*[[ok]]*/
+}
+  )",
+  "target",
+  [](const llvm::DenseMap ) {
+ASSERT_EQ(Annotations.size(), static_cast(1));
+EXPECT_TRUE(isa(Annotations.begin()->first));
+EXPECT_EQ(Annotations.begin()->second, "ok");
+  });
+}
+
+void checkDataflow(
+llvm::StringRef Code, llvm::StringRef Target,
+std::function>>,
+   ASTContext &)>
+Expectations) {
+  clang::dataflow::testing::checkDataflow(
+  Code, Target,
+  [](ASTContext , Environment &) { return NoopAnalysis(Context); },
+  std::move(Expectations), {"-fsyntax-only", "-std=c++17"});
+}
+
+TEST(ProgramPointAnnotations, NoAnnotations) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  checkDataflow("void target() {}", "target", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, NoAnnotationsDifferentTarget) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  checkDataflow("void fun() {}", "fun", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, WithCodepoint) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations,
+  Call(UnorderedElementsAre(Pair("program-point", _)), _))
+  .Times(1);
+
+  checkDataflow(R"cc(void target() {
+ int n;
+ // [[program-point]]
+   })cc",
+"target", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, 

[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-10 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel added inline comments.



Comment at: clang/unittests/Analysis/FlowSensitive/TestingSupport.h:47-48
+template ()
+  << std::declval())>
+std::ostream <<(std::ostream ,

This SFINAE guard doesn't work on some platforms, as evidenced by the many 
buildbot failures after commit.

Any suggestions for 
1) what's wrong
2) how to configure my local build to replicate the breakage
would be appreciated.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115341/new/

https://reviews.llvm.org/D115341

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-10 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG47d526d67e3c: [clang][dataflow] Add framework for testing 
analyses. (authored by ymandel).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115341/new/

https://reviews.llvm.org/D115341

Files:
  clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h
  clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
  clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
  clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
  clang/unittests/Analysis/FlowSensitive/TestingSupport.h
  clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp

Index: clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
===
--- /dev/null
+++ clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
@@ -0,0 +1,174 @@
+#include "TestingSupport.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace dataflow;
+
+namespace {
+
+using ::clang::ast_matchers::functionDecl;
+using ::clang::ast_matchers::hasName;
+using ::clang::ast_matchers::isDefinition;
+using ::testing::_;
+using ::testing::IsEmpty;
+using ::testing::Pair;
+using ::testing::UnorderedElementsAre;
+
+class NoopLattice {
+public:
+  bool operator==(const NoopLattice &) const { return true; }
+
+  LatticeJoinEffect join(const NoopLattice &) {
+return LatticeJoinEffect::Unchanged;
+  }
+};
+
+class NoopAnalysis : public DataflowAnalysis {
+public:
+  NoopAnalysis(ASTContext )
+  : DataflowAnalysis(Context) {}
+
+  static NoopLattice initialElement() { return {}; }
+
+  NoopLattice transfer(const Stmt *S, const NoopLattice , Environment ) {
+return {};
+  }
+};
+
+template 
+const FunctionDecl *findTargetFunc(ASTContext , T FunctionMatcher) {
+  auto TargetMatcher =
+  functionDecl(FunctionMatcher, isDefinition()).bind("target");
+  for (const auto  : ast_matchers::match(TargetMatcher, Context)) {
+const auto *Func = Node.template getNodeAs("target");
+if (Func == nullptr)
+  continue;
+if (Func->isTemplated())
+  continue;
+return Func;
+  }
+  return nullptr;
+}
+
+class BuildStatementToAnnotationMappingTest : public ::testing::Test {
+public:
+  void
+  runTest(llvm::StringRef Code, llvm::StringRef TargetName,
+  std::function &)>
+  RunChecks) {
+llvm::Annotations AnnotatedCode(Code);
+auto Unit = tooling::buildASTFromCodeWithArgs(
+AnnotatedCode.code(), {"-fsyntax-only", "-std=c++17"});
+auto  = Unit->getASTContext();
+const FunctionDecl *Func = findTargetFunc(Context, hasName(TargetName));
+ASSERT_NE(Func, nullptr);
+
+llvm::Expected> Mapping =
+clang::dataflow::testing::buildStatementToAnnotationMapping(
+Func, AnnotatedCode);
+ASSERT_TRUE(static_cast(Mapping));
+
+RunChecks(Mapping.get());
+  }
+};
+
+TEST_F(BuildStatementToAnnotationMappingTest, ReturnStmt) {
+  runTest(R"(
+int target() {
+  return 42;
+  /*[[ok]]*/
+}
+  )",
+  "target",
+  [](const llvm::DenseMap ) {
+ASSERT_EQ(Annotations.size(), static_cast(1));
+EXPECT_TRUE(isa(Annotations.begin()->first));
+EXPECT_EQ(Annotations.begin()->second, "ok");
+  });
+}
+
+void checkDataflow(
+llvm::StringRef Code, llvm::StringRef Target,
+std::function>>,
+   ASTContext &)>
+Expectations) {
+  clang::dataflow::testing::checkDataflow(
+  Code, Target,
+  [](ASTContext , Environment &) { return NoopAnalysis(Context); },
+  std::move(Expectations), {"-fsyntax-only", "-std=c++17"});
+}
+
+TEST(ProgramPointAnnotations, NoAnnotations) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  checkDataflow("void target() {}", "target", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, NoAnnotationsDifferentTarget) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  checkDataflow("void fun() {}", "fun", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, WithCodepoint) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations,
+  Call(UnorderedElementsAre(Pair("program-point", _)), _))
+  .Times(1);
+
+  checkDataflow(R"cc(void target() {
+ int n;
+ // [[program-point]]
+   })cc",
+"target", Expectations.AsStdFunction());
+}
+

[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-10 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel updated this revision to Diff 393460.
ymandel added a comment.

add missing build dependency


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115341/new/

https://reviews.llvm.org/D115341

Files:
  clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h
  clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
  clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
  clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
  clang/unittests/Analysis/FlowSensitive/TestingSupport.h
  clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp

Index: clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
===
--- /dev/null
+++ clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
@@ -0,0 +1,174 @@
+#include "TestingSupport.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace dataflow;
+
+namespace {
+
+using ::clang::ast_matchers::functionDecl;
+using ::clang::ast_matchers::hasName;
+using ::clang::ast_matchers::isDefinition;
+using ::testing::_;
+using ::testing::IsEmpty;
+using ::testing::Pair;
+using ::testing::UnorderedElementsAre;
+
+class NoopLattice {
+public:
+  bool operator==(const NoopLattice &) const { return true; }
+
+  LatticeJoinEffect join(const NoopLattice &) {
+return LatticeJoinEffect::Unchanged;
+  }
+};
+
+class NoopAnalysis : public DataflowAnalysis {
+public:
+  NoopAnalysis(ASTContext )
+  : DataflowAnalysis(Context) {}
+
+  static NoopLattice initialElement() { return {}; }
+
+  NoopLattice transfer(const Stmt *S, const NoopLattice , Environment ) {
+return {};
+  }
+};
+
+template 
+const FunctionDecl *findTargetFunc(ASTContext , T FunctionMatcher) {
+  auto TargetMatcher =
+  functionDecl(FunctionMatcher, isDefinition()).bind("target");
+  for (const auto  : ast_matchers::match(TargetMatcher, Context)) {
+const auto *Func = Node.template getNodeAs("target");
+if (Func == nullptr)
+  continue;
+if (Func->isTemplated())
+  continue;
+return Func;
+  }
+  return nullptr;
+}
+
+class BuildStatementToAnnotationMappingTest : public ::testing::Test {
+public:
+  void
+  runTest(llvm::StringRef Code, llvm::StringRef TargetName,
+  std::function &)>
+  RunChecks) {
+llvm::Annotations AnnotatedCode(Code);
+auto Unit = tooling::buildASTFromCodeWithArgs(
+AnnotatedCode.code(), {"-fsyntax-only", "-std=c++17"});
+auto  = Unit->getASTContext();
+const FunctionDecl *Func = findTargetFunc(Context, hasName(TargetName));
+ASSERT_NE(Func, nullptr);
+
+llvm::Expected> Mapping =
+clang::dataflow::testing::buildStatementToAnnotationMapping(
+Func, AnnotatedCode);
+ASSERT_TRUE(static_cast(Mapping));
+
+RunChecks(Mapping.get());
+  }
+};
+
+TEST_F(BuildStatementToAnnotationMappingTest, ReturnStmt) {
+  runTest(R"(
+int target() {
+  return 42;
+  /*[[ok]]*/
+}
+  )",
+  "target",
+  [](const llvm::DenseMap ) {
+ASSERT_EQ(Annotations.size(), static_cast(1));
+EXPECT_TRUE(isa(Annotations.begin()->first));
+EXPECT_EQ(Annotations.begin()->second, "ok");
+  });
+}
+
+void checkDataflow(
+llvm::StringRef Code, llvm::StringRef Target,
+std::function>>,
+   ASTContext &)>
+Expectations) {
+  clang::dataflow::testing::checkDataflow(
+  Code, Target,
+  [](ASTContext , Environment &) { return NoopAnalysis(Context); },
+  std::move(Expectations), {"-fsyntax-only", "-std=c++17"});
+}
+
+TEST(ProgramPointAnnotations, NoAnnotations) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  checkDataflow("void target() {}", "target", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, NoAnnotationsDifferentTarget) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  checkDataflow("void fun() {}", "fun", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, WithCodepoint) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations,
+  Call(UnorderedElementsAre(Pair("program-point", _)), _))
+  .Times(1);
+
+  checkDataflow(R"cc(void target() {
+ int n;
+ // [[program-point]]
+   })cc",
+"target", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, MultipleCodepoints) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations,
+  

[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-09 Thread Gábor Horváth via Phabricator via cfe-commits
xazax.hun accepted this revision.
xazax.hun added a comment.
This revision is now accepted and ready to land.

Thanks!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115341/new/

https://reviews.llvm.org/D115341

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-09 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel updated this revision to Diff 393221.
ymandel marked 2 inline comments as done.
ymandel added a comment.

rebasing onto latest version of parent patch


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115341/new/

https://reviews.llvm.org/D115341

Files:
  clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h
  clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
  clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
  clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
  clang/unittests/Analysis/FlowSensitive/TestingSupport.h
  clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp

Index: clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
===
--- /dev/null
+++ clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
@@ -0,0 +1,174 @@
+#include "TestingSupport.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace dataflow;
+
+namespace {
+
+using ::clang::ast_matchers::functionDecl;
+using ::clang::ast_matchers::hasName;
+using ::clang::ast_matchers::isDefinition;
+using ::testing::_;
+using ::testing::IsEmpty;
+using ::testing::Pair;
+using ::testing::UnorderedElementsAre;
+
+class NoopLattice {
+public:
+  bool operator==(const NoopLattice &) const { return true; }
+
+  LatticeJoinEffect join(const NoopLattice &) {
+return LatticeJoinEffect::Unchanged;
+  }
+};
+
+class NoopAnalysis : public DataflowAnalysis {
+public:
+  NoopAnalysis(ASTContext )
+  : DataflowAnalysis(Context) {}
+
+  static NoopLattice initialElement() { return {}; }
+
+  NoopLattice transfer(const Stmt *S, const NoopLattice , Environment ) {
+return {};
+  }
+};
+
+template 
+const FunctionDecl *findTargetFunc(ASTContext , T FunctionMatcher) {
+  auto TargetMatcher =
+  functionDecl(FunctionMatcher, isDefinition()).bind("target");
+  for (const auto  : ast_matchers::match(TargetMatcher, Context)) {
+const auto *Func = Node.template getNodeAs("target");
+if (Func == nullptr)
+  continue;
+if (Func->isTemplated())
+  continue;
+return Func;
+  }
+  return nullptr;
+}
+
+class BuildStatementToAnnotationMappingTest : public ::testing::Test {
+public:
+  void
+  runTest(llvm::StringRef Code, llvm::StringRef TargetName,
+  std::function &)>
+  RunChecks) {
+llvm::Annotations AnnotatedCode(Code);
+auto Unit = tooling::buildASTFromCodeWithArgs(
+AnnotatedCode.code(), {"-fsyntax-only", "-std=c++17"});
+auto  = Unit->getASTContext();
+const FunctionDecl *Func = findTargetFunc(Context, hasName(TargetName));
+ASSERT_NE(Func, nullptr);
+
+llvm::Expected> Mapping =
+clang::dataflow::testing::buildStatementToAnnotationMapping(
+Func, AnnotatedCode);
+ASSERT_TRUE(static_cast(Mapping));
+
+RunChecks(Mapping.get());
+  }
+};
+
+TEST_F(BuildStatementToAnnotationMappingTest, ReturnStmt) {
+  runTest(R"(
+int target() {
+  return 42;
+  /*[[ok]]*/
+}
+  )",
+  "target",
+  [](const llvm::DenseMap ) {
+ASSERT_EQ(Annotations.size(), static_cast(1));
+EXPECT_TRUE(isa(Annotations.begin()->first));
+EXPECT_EQ(Annotations.begin()->second, "ok");
+  });
+}
+
+void checkDataflow(
+llvm::StringRef Code, llvm::StringRef Target,
+std::function>>,
+   ASTContext &)>
+Expectations) {
+  clang::dataflow::testing::checkDataflow(
+  Code, Target,
+  [](ASTContext , Environment &) { return NoopAnalysis(Context); },
+  std::move(Expectations), {"-fsyntax-only", "-std=c++17"});
+}
+
+TEST(ProgramPointAnnotations, NoAnnotations) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  checkDataflow("void target() {}", "target", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, NoAnnotationsDifferentTarget) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  checkDataflow("void fun() {}", "fun", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, WithCodepoint) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations,
+  Call(UnorderedElementsAre(Pair("program-point", _)), _))
+  .Times(1);
+
+  checkDataflow(R"cc(void target() {
+ int n;
+ // [[program-point]]
+   })cc",
+"target", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, MultipleCodepoints) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+

[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-09 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel marked 2 inline comments as done.
ymandel added a comment.

Thanks for the great comments and the fast response time!




Comment at: clang/unittests/Analysis/FlowSensitive/TestingSupport.h:134
+
+transferBlock(
+BlockStates, *Block, Env, Analysis,

I've inlined `buildAnnotationToOutputStateMapping`, since it is only intended 
for use here anyhow and factoring it out didn't save anything because we still 
need to translate to typed state.



Comment at: clang/unittests/Analysis/FlowSensitive/TestingSupport.h:48
+  << std::declval())>
+std::ostream <<(std::ostream ,
+ const DataflowAnalysisState ) {

xazax.hun wrote:
> This would also be useful for debugging. I wonder whether utilities not 
> strictly related to testing should be closer to the actual code, so someone 
> wanting to use this for debugging does not need to include the header that is 
> dedicated to the tests.
Agreed. Added a FIXME.



Comment at: clang/unittests/Analysis/FlowSensitive/TestingSupport.h:77
+// the files provided in `VirtualMappedFiles`.
+bool runOnCode(llvm::StringRef Code,
+   const std::function ,

xazax.hun wrote:
> I feel like some of our tests keep recreating lightweight versions of the 
> LibTooling. Not really an action item for this PR, just a rant :) I hope we 
> will have some more centralized stuff at some point. 
No, I agree! I missed this -- there's no good reason for runOnCode to exist. 
I've removed it and like the result a lot more. :)



Comment at: clang/unittests/Analysis/FlowSensitive/TestingSupport.h:94
+template 
+void runDataflow(
+llvm::StringRef Code,

xazax.hun wrote:
> Since this function is actually matching the dataflow results against 
> expectations, I wonder if something like `checkDataflow` would better 
> describe its function. But feel free to keep the current name.
Agreed.



Comment at: clang/unittests/Analysis/FlowSensitive/TestingSupport.h:137
+TypeErasedBlockStates =
+runTypeErasedDataflowAnalysis(*cfg, Analysis, Env);
+

xazax.hun wrote:
> Wouldn't users end up calling the template (not the type erased) version of 
> this function? I wonder if we should mimic how users would interact with the 
> framework in the tests.
I see your point and tried to move in that direction. However, it makes this 
code a lot messier because of the need to iterate again over each block with 
`transferBlock` to recoved statement level state. Since `transferBlock` is part 
of the type-erased engine, interacting with it would require mapping all of the 
state to untyped before using it, which somewhat defeats the whole purpose of 
using the typed version.

We should consider reporting statement level information from our 
`run...DataflowAnalysis` functions, which would make this iteration 
unnecessary, at which point moving to the typed version would make a lot of 
sense.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115341/new/

https://reviews.llvm.org/D115341

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-09 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel updated this revision to Diff 393218.
ymandel added a comment.

responding to review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115341/new/

https://reviews.llvm.org/D115341

Files:
  clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h
  clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp
  clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
  clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
  clang/unittests/Analysis/FlowSensitive/TestingSupport.h
  clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp

Index: clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
===
--- /dev/null
+++ clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
@@ -0,0 +1,174 @@
+#include "TestingSupport.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace dataflow;
+
+namespace {
+
+using ::clang::ast_matchers::functionDecl;
+using ::clang::ast_matchers::hasName;
+using ::clang::ast_matchers::isDefinition;
+using ::testing::_;
+using ::testing::IsEmpty;
+using ::testing::Pair;
+using ::testing::UnorderedElementsAre;
+
+class NoopLattice {
+public:
+  bool operator==(const NoopLattice &) const { return true; }
+
+  LatticeJoinEffect join(const NoopLattice &) {
+return LatticeJoinEffect::Unchanged;
+  }
+};
+
+class NoopAnalysis : public DataflowAnalysis {
+public:
+  NoopAnalysis(ASTContext )
+  : DataflowAnalysis(Context) {}
+
+  static NoopLattice initialElement() { return {}; }
+
+  NoopLattice transfer(const Stmt *S, const NoopLattice , Environment ) {
+return {};
+  }
+};
+
+template 
+const FunctionDecl *findTargetFunc(ASTContext , T FunctionMatcher) {
+  auto TargetMatcher =
+  functionDecl(FunctionMatcher, isDefinition()).bind("target");
+  for (const auto  : ast_matchers::match(TargetMatcher, Context)) {
+const auto *Func = Node.template getNodeAs("target");
+if (Func == nullptr)
+  continue;
+if (Func->isTemplated())
+  continue;
+return Func;
+  }
+  return nullptr;
+}
+
+class BuildStatementToAnnotationMappingTest : public ::testing::Test {
+public:
+  void
+  runTest(llvm::StringRef Code, llvm::StringRef TargetName,
+  std::function &)>
+  RunChecks) {
+llvm::Annotations AnnotatedCode(Code);
+auto Unit = tooling::buildASTFromCodeWithArgs(
+AnnotatedCode.code(), {"-fsyntax-only", "-std=c++17"});
+auto  = Unit->getASTContext();
+const FunctionDecl *Func = findTargetFunc(Context, hasName(TargetName));
+ASSERT_NE(Func, nullptr);
+
+llvm::Expected> Mapping =
+clang::dataflow::testing::buildStatementToAnnotationMapping(
+Func, AnnotatedCode);
+ASSERT_TRUE(static_cast(Mapping));
+
+RunChecks(Mapping.get());
+  }
+};
+
+TEST_F(BuildStatementToAnnotationMappingTest, ReturnStmt) {
+  runTest(R"(
+int target() {
+  return 42;
+  /*[[ok]]*/
+}
+  )",
+  "target",
+  [](const llvm::DenseMap ) {
+ASSERT_EQ(Annotations.size(), static_cast(1));
+EXPECT_TRUE(isa(Annotations.begin()->first));
+EXPECT_EQ(Annotations.begin()->second, "ok");
+  });
+}
+
+void checkDataflow(
+llvm::StringRef Code, llvm::StringRef Target,
+std::function>>,
+   ASTContext &)>
+Expectations) {
+  clang::dataflow::testing::checkDataflow(
+  Code, Target,
+  [](ASTContext , Environment &) { return NoopAnalysis(Context); },
+  std::move(Expectations), {"-fsyntax-only", "-std=c++17"});
+}
+
+TEST(ProgramPointAnnotations, NoAnnotations) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  checkDataflow("void target() {}", "target", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, NoAnnotationsDifferentTarget) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  checkDataflow("void fun() {}", "fun", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, WithCodepoint) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations,
+  Call(UnorderedElementsAre(Pair("program-point", _)), _))
+  .Times(1);
+
+  checkDataflow(R"cc(void target() {
+ int n;
+ // [[program-point]]
+   })cc",
+"target", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, MultipleCodepoints) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations,
+ 

[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-08 Thread Gábor Horváth via Phabricator via cfe-commits
xazax.hun added inline comments.



Comment at: clang/unittests/Analysis/FlowSensitive/TestingSupport.h:48
+  << std::declval())>
+std::ostream <<(std::ostream ,
+ const DataflowAnalysisState ) {

This would also be useful for debugging. I wonder whether utilities not 
strictly related to testing should be closer to the actual code, so someone 
wanting to use this for debugging does not need to include the header that is 
dedicated to the tests.



Comment at: clang/unittests/Analysis/FlowSensitive/TestingSupport.h:77
+// the files provided in `VirtualMappedFiles`.
+bool runOnCode(llvm::StringRef Code,
+   const std::function ,

I feel like some of our tests keep recreating lightweight versions of the 
LibTooling. Not really an action item for this PR, just a rant :) I hope we 
will have some more centralized stuff at some point. 



Comment at: clang/unittests/Analysis/FlowSensitive/TestingSupport.h:94
+template 
+void runDataflow(
+llvm::StringRef Code,

Since this function is actually matching the dataflow results against 
expectations, I wonder if something like `checkDataflow` would better describe 
its function. But feel free to keep the current name.



Comment at: clang/unittests/Analysis/FlowSensitive/TestingSupport.h:137
+TypeErasedBlockStates =
+runTypeErasedDataflowAnalysis(*cfg, Analysis, Env);
+

Wouldn't users end up calling the template (not the type erased) version of 
this function? I wonder if we should mimic how users would interact with the 
framework in the tests.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115341/new/

https://reviews.llvm.org/D115341

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D115341: [clang][dataflow] Add framework for testing analyses.

2021-12-08 Thread Yitzhak Mandelbaum via Phabricator via cfe-commits
ymandel created this revision.
ymandel added reviewers: gribozavr2, sgatev, xazax.hun.
Herald added subscribers: rnkovacs, mgorny.
ymandel requested review of this revision.
Herald added a project: clang.

Adds a general-purpose framework to support testing of dataflow analyses.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D115341

Files:
  clang/unittests/Analysis/FlowSensitive/CMakeLists.txt
  clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
  clang/unittests/Analysis/FlowSensitive/TestingSupport.h
  clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp

Index: clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
===
--- /dev/null
+++ clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
@@ -0,0 +1,174 @@
+#include "TestingSupport.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace dataflow;
+
+namespace {
+
+using ::clang::ast_matchers::functionDecl;
+using ::clang::ast_matchers::hasName;
+using ::clang::ast_matchers::isDefinition;
+using ::testing::_;
+using ::testing::IsEmpty;
+using ::testing::Pair;
+using ::testing::UnorderedElementsAre;
+
+class NoopLattice {
+public:
+  bool operator==(const NoopLattice &) const { return true; }
+
+  LatticeJoinEffect join(const NoopLattice &) {
+return LatticeJoinEffect::Unchanged;
+  }
+};
+
+class NoopAnalysis : public DataflowAnalysis {
+public:
+  NoopAnalysis(ASTContext )
+  : DataflowAnalysis(Context) {}
+
+  static NoopLattice initialElement() { return {}; }
+
+  NoopLattice transfer(const Stmt *S, const NoopLattice , Environment ) {
+return {};
+  }
+};
+
+template 
+const FunctionDecl *findTargetFunc(ASTContext , T FunctionMatcher) {
+  auto TargetMatcher =
+  functionDecl(FunctionMatcher, isDefinition()).bind("target");
+  for (const auto  : ast_matchers::match(TargetMatcher, Context)) {
+const auto *Func = Node.template getNodeAs("target");
+if (Func == nullptr)
+  continue;
+if (Func->isTemplated())
+  continue;
+return Func;
+  }
+  return nullptr;
+}
+
+class BuildStatementToAnnotationMappingTest : public ::testing::Test {
+public:
+  void
+  runTest(llvm::StringRef SourceCode, llvm::StringRef TargetName,
+  std::function &)>
+  RunChecks) {
+llvm::Annotations AnnotatedCode(SourceCode);
+
+auto Test = [, TargetName, ](ASTContext ) {
+  const FunctionDecl *Func = findTargetFunc(Context, hasName(TargetName));
+  ASSERT_NE(Func, nullptr);
+
+  llvm::Expected> Mapping =
+  buildStatementToAnnotationMapping(Func, AnnotatedCode);
+  ASSERT_TRUE(static_cast(Mapping));
+  RunChecks(Mapping.get());
+};
+
+ASSERT_TRUE(
+runOnCode(AnnotatedCode.code(), Test, {"-fsyntax-only", "-std=c++17"}));
+  }
+};
+
+TEST_F(BuildStatementToAnnotationMappingTest, ReturnStmt) {
+  runTest(R"(
+int target() {
+  return 42;
+  /*[[ok]]*/
+}
+  )",
+  "target",
+  [](const llvm::DenseMap ) {
+ASSERT_EQ(Annotations.size(), 1);
+EXPECT_TRUE(isa(Annotations.begin()->first));
+EXPECT_EQ(Annotations.begin()->second, "ok");
+  });
+}
+
+void runDataflow(
+llvm::StringRef Code, llvm::StringRef Target,
+std::function>>,
+   ASTContext &)>
+Expectations) {
+  clang::dataflow::testing::runDataflow(
+  Code, Target,
+  [](ASTContext , Environment &) { return NoopAnalysis(Context); },
+  std::move(Expectations), {"-fsyntax-only", "-std=c++17"});
+}
+
+TEST(ProgramPointAnnotations, NoAnnotations) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  runDataflow("void target() {}", "target", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, NoAnnotationsDifferentTarget) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1);
+
+  runDataflow("void fun() {}", "fun", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, WithCodepoint) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations,
+  Call(UnorderedElementsAre(Pair("program-point", _)), _))
+  .Times(1);
+
+  runDataflow(R"cc(void target() {
+ int n;
+ // [[program-point]]
+   })cc",
+  "target", Expectations.AsStdFunction());
+}
+
+TEST(ProgramPointAnnotations, MultipleCodepoints) {
+  ::testing::MockFunction>>,
+  ASTContext &)>
+  Expectations;
+
+  EXPECT_CALL(Expectations,
+  Call(UnorderedElementsAre(Pair("program-point-1", _),
+