1 #include "TestingSupport.h" 2 #include "clang/AST/ASTContext.h" 3 #include "clang/AST/Decl.h" 4 #include "clang/AST/Stmt.h" 5 #include "clang/ASTMatchers/ASTMatchFinder.h" 6 #include "clang/ASTMatchers/ASTMatchers.h" 7 #include "clang/Analysis/CFG.h" 8 #include "clang/Analysis/FlowSensitive/DataflowAnalysis.h" 9 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 10 #include "clang/Basic/LLVM.h" 11 #include "clang/Basic/LangOptions.h" 12 #include "clang/Basic/SourceManager.h" 13 #include "clang/Basic/TokenKinds.h" 14 #include "clang/Lex/Lexer.h" 15 #include "clang/Serialization/PCHContainerOperations.h" 16 #include "clang/Tooling/ArgumentsAdjusters.h" 17 #include "clang/Tooling/Tooling.h" 18 #include "llvm/ADT/ArrayRef.h" 19 #include "llvm/ADT/DenseMap.h" 20 #include "llvm/ADT/Optional.h" 21 #include "llvm/Support/Error.h" 22 #include "llvm/Testing/Support/Annotations.h" 23 #include "gtest/gtest.h" 24 #include <functional> 25 #include <memory> 26 #include <string> 27 #include <system_error> 28 #include <utility> 29 #include <vector> 30 31 using namespace clang; 32 using namespace dataflow; 33 34 namespace { 35 using ast_matchers::MatchFinder; 36 37 class FindTranslationUnitCallback : public MatchFinder::MatchCallback { 38 public: 39 explicit FindTranslationUnitCallback( 40 std::function<void(ASTContext &)> Operation) 41 : Operation{Operation} {} 42 43 void run(const MatchFinder::MatchResult &Result) override { 44 const auto *TU = Result.Nodes.getNodeAs<TranslationUnitDecl>("tu"); 45 if (TU->getASTContext().getDiagnostics().getClient()->getNumErrors() != 0) { 46 FAIL() << "Source file has syntax or type errors, they were printed to " 47 "the test log"; 48 } 49 Operation(TU->getASTContext()); 50 } 51 52 std::function<void(ASTContext &)> Operation; 53 }; 54 } // namespace 55 56 static bool 57 isAnnotationDirectlyAfterStatement(const Stmt *Stmt, unsigned AnnotationBegin, 58 const SourceManager &SourceManager, 59 const LangOptions &LangOptions) { 60 auto NextToken = 61 Lexer::findNextToken(Stmt->getEndLoc(), SourceManager, LangOptions); 62 63 while (NextToken.hasValue() && 64 SourceManager.getFileOffset(NextToken->getLocation()) < 65 AnnotationBegin) { 66 if (NextToken->isNot(tok::semi)) 67 return false; 68 69 NextToken = Lexer::findNextToken(NextToken->getEndLoc(), SourceManager, 70 LangOptions); 71 } 72 73 return true; 74 } 75 76 llvm::Expected<llvm::DenseMap<const Stmt *, std::string>> 77 test::buildStatementToAnnotationMapping(const FunctionDecl *Func, 78 llvm::Annotations AnnotatedCode) { 79 llvm::DenseMap<const Stmt *, std::string> Result; 80 81 using namespace ast_matchers; // NOLINT: Too many names 82 auto StmtMatcher = 83 findAll(stmt(unless(anyOf(hasParent(expr()), hasParent(returnStmt())))) 84 .bind("stmt")); 85 86 // This map should stay sorted because the binding algorithm relies on the 87 // ordering of statement offsets 88 std::map<unsigned, const Stmt *> Stmts; 89 auto &Context = Func->getASTContext(); 90 auto &SourceManager = Context.getSourceManager(); 91 92 for (auto &Match : match(StmtMatcher, *Func->getBody(), Context)) { 93 const auto *S = Match.getNodeAs<Stmt>("stmt"); 94 unsigned Offset = SourceManager.getFileOffset(S->getEndLoc()); 95 Stmts[Offset] = S; 96 } 97 98 unsigned I = 0; 99 auto Annotations = AnnotatedCode.ranges(); 100 std::reverse(Annotations.begin(), Annotations.end()); 101 auto Code = AnnotatedCode.code(); 102 103 for (auto OffsetAndStmt = Stmts.rbegin(); OffsetAndStmt != Stmts.rend(); 104 OffsetAndStmt++) { 105 unsigned Offset = OffsetAndStmt->first; 106 const Stmt *Stmt = OffsetAndStmt->second; 107 108 if (I < Annotations.size() && Annotations[I].Begin >= Offset) { 109 auto Range = Annotations[I]; 110 111 if (!isAnnotationDirectlyAfterStatement(Stmt, Range.Begin, SourceManager, 112 Context.getLangOpts())) { 113 return llvm::createStringError( 114 std::make_error_code(std::errc::invalid_argument), 115 "Annotation is not placed after a statement: %s", 116 SourceManager.getLocForStartOfFile(SourceManager.getMainFileID()) 117 .getLocWithOffset(Offset) 118 .printToString(SourceManager) 119 .data()); 120 } 121 122 Result[Stmt] = Code.slice(Range.Begin, Range.End).str(); 123 I++; 124 125 if (I < Annotations.size() && Annotations[I].Begin >= Offset) { 126 return llvm::createStringError( 127 std::make_error_code(std::errc::invalid_argument), 128 "Multiple annotations bound to the statement at the location: %s", 129 Stmt->getBeginLoc().printToString(SourceManager).data()); 130 } 131 } 132 } 133 134 if (I < Annotations.size()) { 135 return llvm::createStringError( 136 std::make_error_code(std::errc::invalid_argument), 137 "Not all annotations were bound to statements. Unbound annotation at: " 138 "%s", 139 SourceManager.getLocForStartOfFile(SourceManager.getMainFileID()) 140 .getLocWithOffset(Annotations[I].Begin) 141 .printToString(SourceManager) 142 .data()); 143 } 144 145 return Result; 146 } 147 148 std::pair<const FunctionDecl *, std::unique_ptr<CFG>> 149 test::buildCFG(ASTContext &Context, 150 ast_matchers::internal::Matcher<FunctionDecl> FuncMatcher) { 151 CFG::BuildOptions Options; 152 Options.PruneTriviallyFalseEdges = false; 153 Options.AddInitializers = true; 154 Options.AddImplicitDtors = true; 155 Options.AddTemporaryDtors = true; 156 Options.setAllAlwaysAdd(); 157 158 const FunctionDecl *F = ast_matchers::selectFirst<FunctionDecl>( 159 "target", 160 ast_matchers::match( 161 ast_matchers::functionDecl(ast_matchers::isDefinition(), FuncMatcher) 162 .bind("target"), 163 Context)); 164 if (F == nullptr) 165 return std::make_pair(nullptr, nullptr); 166 167 return std::make_pair( 168 F, clang::CFG::buildCFG(F, F->getBody(), &Context, Options)); 169 } 170