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 void runTest( 40 llvm::StringRef Code, llvm::StringRef TargetName, 41 std::function<void(const llvm::DenseMap<const Stmt *, std::string> &)> 42 RunChecks) { 43 llvm::Annotations AnnotatedCode(Code); 44 auto Unit = tooling::buildASTFromCodeWithArgs( 45 AnnotatedCode.code(), {"-fsyntax-only", "-std=c++17"}); 46 auto &Context = Unit->getASTContext(); 47 const FunctionDecl *Func = findTargetFunc(Context, hasName(TargetName)); 48 ASSERT_NE(Func, nullptr); 49 50 llvm::Expected<llvm::DenseMap<const Stmt *, std::string>> Mapping = 51 test::buildStatementToAnnotationMapping(Func, AnnotatedCode); 52 ASSERT_TRUE(static_cast<bool>(Mapping)); 53 54 RunChecks(Mapping.get()); 55 } 56 57 TEST(BuildStatementToAnnotationMappingTest, ReturnStmt) { 58 runTest(R"( 59 int target() { 60 return 42; 61 /*[[ok]]*/ 62 } 63 )", 64 "target", 65 [](const llvm::DenseMap<const Stmt *, std::string> &Annotations) { 66 ASSERT_EQ(Annotations.size(), static_cast<unsigned int>(1)); 67 EXPECT_TRUE(isa<ReturnStmt>(Annotations.begin()->first)); 68 EXPECT_EQ(Annotations.begin()->second, "ok"); 69 }); 70 } 71 72 void checkDataflow( 73 llvm::StringRef Code, llvm::StringRef Target, 74 std::function<void(llvm::ArrayRef<std::pair< 75 std::string, DataflowAnalysisState<NoopLattice>>>, 76 ASTContext &)> 77 Expectations) { 78 ASSERT_THAT_ERROR( 79 test::checkDataflow<NoopAnalysis>( 80 Code, Target, 81 [](ASTContext &Context, Environment &) { 82 return NoopAnalysis(Context, /*ApplyBuiltinTransfer=*/false); 83 }, 84 std::move(Expectations), {"-fsyntax-only", "-std=c++17"}), 85 llvm::Succeeded()); 86 } 87 88 TEST(ProgramPointAnnotations, NoAnnotations) { 89 ::testing::MockFunction<void( 90 llvm::ArrayRef< 91 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>, 92 ASTContext &)> 93 Expectations; 94 95 EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1); 96 97 checkDataflow("void target() {}", "target", Expectations.AsStdFunction()); 98 } 99 100 TEST(ProgramPointAnnotations, NoAnnotationsDifferentTarget) { 101 ::testing::MockFunction<void( 102 llvm::ArrayRef< 103 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>, 104 ASTContext &)> 105 Expectations; 106 107 EXPECT_CALL(Expectations, Call(IsEmpty(), _)).Times(1); 108 109 checkDataflow("void fun() {}", "fun", Expectations.AsStdFunction()); 110 } 111 112 TEST(ProgramPointAnnotations, WithCodepoint) { 113 ::testing::MockFunction<void( 114 llvm::ArrayRef< 115 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>, 116 ASTContext &)> 117 Expectations; 118 119 EXPECT_CALL(Expectations, 120 Call(UnorderedElementsAre(Pair("program-point", _)), _)) 121 .Times(1); 122 123 checkDataflow(R"cc(void target() { 124 int n; 125 // [[program-point]] 126 })cc", 127 "target", Expectations.AsStdFunction()); 128 } 129 130 TEST(ProgramPointAnnotations, MultipleCodepoints) { 131 ::testing::MockFunction<void( 132 llvm::ArrayRef< 133 std::pair<std::string, DataflowAnalysisState<NoopLattice>>>, 134 ASTContext &)> 135 Expectations; 136 137 EXPECT_CALL(Expectations, 138 Call(UnorderedElementsAre(Pair("program-point-1", _), 139 Pair("program-point-2", _)), 140 _)) 141 .Times(1); 142 143 checkDataflow(R"cc(void target(bool b) { 144 if (b) { 145 int n; 146 // [[program-point-1]] 147 } else { 148 int m; 149 // [[program-point-2]] 150 } 151 })cc", 152 "target", Expectations.AsStdFunction()); 153 } 154 155 } // namespace 156