1 #include "TestingSupport.h" 2 #include "NoopAnalysis.h" 3 #include "clang/AST/ASTContext.h" 4 #include "clang/ASTMatchers/ASTMatchFinder.h" 5 #include "clang/ASTMatchers/ASTMatchers.h" 6 #include "clang/Tooling/Tooling.h" 7 #include "llvm/Testing/Support/Error.h" 8 #include "gmock/gmock.h" 9 #include "gtest/gtest.h" 10 11 using namespace clang; 12 using namespace dataflow; 13 14 namespace { 15 16 using ::clang::ast_matchers::functionDecl; 17 using ::clang::ast_matchers::hasName; 18 using ::clang::ast_matchers::isDefinition; 19 using ::testing::_; 20 using ::testing::IsEmpty; 21 using ::testing::Pair; 22 using ::testing::UnorderedElementsAre; 23 24 template <typename T> 25 const FunctionDecl *findTargetFunc(ASTContext &Context, T FunctionMatcher) { 26 auto TargetMatcher = 27 functionDecl(FunctionMatcher, isDefinition()).bind("target"); 28 for (const auto &Node : ast_matchers::match(TargetMatcher, Context)) { 29 const auto *Func = Node.template getNodeAs<FunctionDecl>("target"); 30 if (Func == nullptr) 31 continue; 32 if (Func->isTemplated()) 33 continue; 34 return Func; 35 } 36 return nullptr; 37 } 38 39 class BuildStatementToAnnotationMappingTest : public ::testing::Test { 40 public: 41 void 42 runTest(llvm::StringRef Code, llvm::StringRef TargetName, 43 std::function<void(const llvm::DenseMap<const Stmt *, std::string> &)> 44 RunChecks) { 45 llvm::Annotations AnnotatedCode(Code); 46 auto Unit = tooling::buildASTFromCodeWithArgs( 47 AnnotatedCode.code(), {"-fsyntax-only", "-std=c++17"}); 48 auto &Context = Unit->getASTContext(); 49 const FunctionDecl *Func = findTargetFunc(Context, hasName(TargetName)); 50 ASSERT_NE(Func, nullptr); 51 52 llvm::Expected<llvm::DenseMap<const Stmt *, std::string>> Mapping = 53 test::buildStatementToAnnotationMapping(Func, AnnotatedCode); 54 ASSERT_TRUE(static_cast<bool>(Mapping)); 55 56 RunChecks(Mapping.get()); 57 } 58 }; 59 60 TEST_F(BuildStatementToAnnotationMappingTest, ReturnStmt) { 61 runTest(R"( 62 int target() { 63 return 42; 64 /*[[ok]]*/ 65 } 66 )", 67 "target", 68 [](const llvm::DenseMap<const Stmt *, std::string> &Annotations) { 69 ASSERT_EQ(Annotations.size(), static_cast<unsigned int>(1)); 70 EXPECT_TRUE(isa<ReturnStmt>(Annotations.begin()->first)); 71 EXPECT_EQ(Annotations.begin()->second, "ok"); 72 }); 73 } 74 75 void checkDataflow( 76 llvm::StringRef Code, llvm::StringRef Target, 77 std::function<void(llvm::ArrayRef<std::pair< 78 std::string, DataflowAnalysisState<NoopLattice>>>, 79 ASTContext &)> 80 Expectations) { 81 ASSERT_THAT_ERROR( 82 test::checkDataflow<NoopAnalysis>( 83 Code, Target, 84 [](ASTContext &Context, Environment &) { 85 return NoopAnalysis(Context, /*ApplyBuiltinTransfer=*/false); 86 }, 87 std::move(Expectations), {"-fsyntax-only", "-std=c++17"}), 88 llvm::Succeeded()); 89 } 90 91 TEST(ProgramPointAnnotations, NoAnnotations) { 92 ::testing::MockFunction<void( 93 llvm::ArrayRef< 94 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>, 95 ASTContext &)> 96 Expectations; 97 98 EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1); 99 100 checkDataflow("void target() {}", "target", Expectations.AsStdFunction()); 101 } 102 103 TEST(ProgramPointAnnotations, NoAnnotationsDifferentTarget) { 104 ::testing::MockFunction<void( 105 llvm::ArrayRef< 106 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>, 107 ASTContext &)> 108 Expectations; 109 110 EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1); 111 112 checkDataflow("void fun() {}", "fun", Expectations.AsStdFunction()); 113 } 114 115 TEST(ProgramPointAnnotations, WithCodepoint) { 116 ::testing::MockFunction<void( 117 llvm::ArrayRef< 118 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>, 119 ASTContext &)> 120 Expectations; 121 122 EXPECT_CALL(Expectations, 123 Call(UnorderedElementsAre(Pair("program-point", _)), _)) 124 .Times(1); 125 126 checkDataflow(R"cc(void target() { 127 int n; 128 // [[program-point]] 129 })cc", 130 "target", Expectations.AsStdFunction()); 131 } 132 133 TEST(ProgramPointAnnotations, MultipleCodepoints) { 134 ::testing::MockFunction<void( 135 llvm::ArrayRef< 136 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>, 137 ASTContext &)> 138 Expectations; 139 140 EXPECT_CALL(Expectations, 141 Call(UnorderedElementsAre(Pair("program-point-1", _), 142 Pair("program-point-2", _)), 143 _)) 144 .Times(1); 145 146 checkDataflow(R"cc(void target(bool b) { 147 if (b) { 148 int n; 149 // [[program-point-1]] 150 } else { 151 int m; 152 // [[program-point-2]] 153 } 154 })cc", 155 "target", Expectations.AsStdFunction()); 156 } 157 158 } // namespace 159