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 <functional> 24 #include <memory> 25 #include <string> 26 #include <system_error> 27 #include <utility> 28 #include <vector> 29 30 using namespace clang; 31 using namespace dataflow; 32 33 static bool 34 isAnnotationDirectlyAfterStatement(const Stmt *Stmt, unsigned AnnotationBegin, 35 const SourceManager &SourceManager, 36 const LangOptions &LangOptions) { 37 auto NextToken = 38 Lexer::findNextToken(Stmt->getEndLoc(), SourceManager, LangOptions); 39 40 while (NextToken.hasValue() && 41 SourceManager.getFileOffset(NextToken->getLocation()) < 42 AnnotationBegin) { 43 if (NextToken->isNot(tok::semi)) 44 return false; 45 46 NextToken = Lexer::findNextToken(NextToken->getEndLoc(), SourceManager, 47 LangOptions); 48 } 49 50 return true; 51 } 52 53 llvm::Expected<llvm::DenseMap<const Stmt *, std::string>> 54 test::buildStatementToAnnotationMapping(const FunctionDecl *Func, 55 llvm::Annotations AnnotatedCode) { 56 llvm::DenseMap<const Stmt *, std::string> Result; 57 58 using namespace ast_matchers; // NOLINT: Too many names 59 auto StmtMatcher = 60 findAll(stmt(unless(anyOf(hasParent(expr()), hasParent(returnStmt())))) 61 .bind("stmt")); 62 63 // This map should stay sorted because the binding algorithm relies on the 64 // ordering of statement offsets 65 std::map<unsigned, const Stmt *> Stmts; 66 auto &Context = Func->getASTContext(); 67 auto &SourceManager = Context.getSourceManager(); 68 69 for (auto &Match : match(StmtMatcher, *Func->getBody(), Context)) { 70 const auto *S = Match.getNodeAs<Stmt>("stmt"); 71 unsigned Offset = SourceManager.getFileOffset(S->getEndLoc()); 72 Stmts[Offset] = S; 73 } 74 75 unsigned I = 0; 76 auto Annotations = AnnotatedCode.ranges(); 77 std::reverse(Annotations.begin(), Annotations.end()); 78 auto Code = AnnotatedCode.code(); 79 80 for (auto OffsetAndStmt = Stmts.rbegin(); OffsetAndStmt != Stmts.rend(); 81 OffsetAndStmt++) { 82 unsigned Offset = OffsetAndStmt->first; 83 const Stmt *Stmt = OffsetAndStmt->second; 84 85 if (I < Annotations.size() && Annotations[I].Begin >= Offset) { 86 auto Range = Annotations[I]; 87 88 if (!isAnnotationDirectlyAfterStatement(Stmt, Range.Begin, SourceManager, 89 Context.getLangOpts())) { 90 return llvm::createStringError( 91 std::make_error_code(std::errc::invalid_argument), 92 "Annotation is not placed after a statement: %s", 93 SourceManager.getLocForStartOfFile(SourceManager.getMainFileID()) 94 .getLocWithOffset(Offset) 95 .printToString(SourceManager) 96 .data()); 97 } 98 99 Result[Stmt] = Code.slice(Range.Begin, Range.End).str(); 100 I++; 101 102 if (I < Annotations.size() && Annotations[I].Begin >= Offset) { 103 return llvm::createStringError( 104 std::make_error_code(std::errc::invalid_argument), 105 "Multiple annotations bound to the statement at the location: %s", 106 Stmt->getBeginLoc().printToString(SourceManager).data()); 107 } 108 } 109 } 110 111 if (I < Annotations.size()) { 112 return llvm::createStringError( 113 std::make_error_code(std::errc::invalid_argument), 114 "Not all annotations were bound to statements. Unbound annotation at: " 115 "%s", 116 SourceManager.getLocForStartOfFile(SourceManager.getMainFileID()) 117 .getLocWithOffset(Annotations[I].Begin) 118 .printToString(SourceManager) 119 .data()); 120 } 121 122 return Result; 123 } 124