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/Basic/LLVM.h" 8 #include "clang/Basic/LangOptions.h" 9 #include "clang/Basic/SourceLocation.h" 10 #include "clang/Basic/SourceManager.h" 11 #include "clang/Basic/TokenKinds.h" 12 #include "clang/Lex/Lexer.h" 13 #include "llvm/ADT/DenseMap.h" 14 #include "llvm/ADT/StringRef.h" 15 #include "llvm/ADT/StringSet.h" 16 #include "llvm/Support/Error.h" 17 #include "llvm/Testing/Annotations/Annotations.h" 18 #include <cassert> 19 #include <functional> 20 #include <memory> 21 #include <string> 22 #include <system_error> 23 #include <utility> 24 #include <vector> 25 26 using namespace clang; 27 using namespace dataflow; 28 using namespace ast_matchers; 29 30 static bool 31 isAnnotationDirectlyAfterStatement(const Stmt *Stmt, unsigned AnnotationBegin, 32 const SourceManager &SourceManager, 33 const LangOptions &LangOptions) { 34 auto NextToken = 35 Lexer::findNextToken(Stmt->getEndLoc(), SourceManager, LangOptions); 36 37 while (NextToken && SourceManager.getFileOffset(NextToken->getLocation()) < 38 AnnotationBegin) { 39 if (NextToken->isNot(tok::semi)) 40 return false; 41 42 NextToken = Lexer::findNextToken(NextToken->getEndLoc(), SourceManager, 43 LangOptions); 44 } 45 46 return true; 47 } 48 49 llvm::DenseMap<unsigned, std::string> test::buildLineToAnnotationMapping( 50 const SourceManager &SM, const LangOptions &LangOpts, 51 SourceRange BoundingRange, llvm::Annotations AnnotatedCode) { 52 CharSourceRange CharBoundingRange = 53 Lexer::getAsCharRange(BoundingRange, SM, LangOpts); 54 55 llvm::DenseMap<unsigned, std::string> LineNumberToContent; 56 auto Code = AnnotatedCode.code(); 57 auto Annotations = AnnotatedCode.ranges(); 58 for (auto &AnnotationRange : Annotations) { 59 SourceLocation Loc = SM.getLocForStartOfFile(SM.getMainFileID()) 60 .getLocWithOffset(AnnotationRange.Begin); 61 if (SM.isPointWithin(Loc, CharBoundingRange.getBegin(), 62 CharBoundingRange.getEnd())) { 63 LineNumberToContent[SM.getPresumedLineNumber(Loc)] = 64 Code.slice(AnnotationRange.Begin, AnnotationRange.End).str(); 65 } 66 } 67 return LineNumberToContent; 68 } 69 70 llvm::Expected<llvm::DenseMap<const Stmt *, std::string>> 71 test::buildStatementToAnnotationMapping(const FunctionDecl *Func, 72 llvm::Annotations AnnotatedCode) { 73 llvm::DenseMap<const Stmt *, std::string> Result; 74 llvm::StringSet<> ExistingAnnotations; 75 76 auto StmtMatcher = 77 findAll(stmt(unless(anyOf(hasParent(expr()), hasParent(returnStmt())))) 78 .bind("stmt")); 79 80 // This map should stay sorted because the binding algorithm relies on the 81 // ordering of statement offsets 82 std::map<unsigned, const Stmt *> Stmts; 83 auto &Context = Func->getASTContext(); 84 auto &SourceManager = Context.getSourceManager(); 85 86 for (auto &Match : match(StmtMatcher, *Func->getBody(), Context)) { 87 const auto *S = Match.getNodeAs<Stmt>("stmt"); 88 unsigned Offset = SourceManager.getFileOffset(S->getEndLoc()); 89 Stmts[Offset] = S; 90 } 91 92 unsigned FunctionBeginOffset = 93 SourceManager.getFileOffset(Func->getBeginLoc()); 94 unsigned FunctionEndOffset = SourceManager.getFileOffset(Func->getEndLoc()); 95 96 std::vector<llvm::Annotations::Range> Annotations = AnnotatedCode.ranges(); 97 llvm::erase_if(Annotations, [=](llvm::Annotations::Range R) { 98 return R.Begin < FunctionBeginOffset || R.End >= FunctionEndOffset; 99 }); 100 std::reverse(Annotations.begin(), Annotations.end()); 101 auto Code = AnnotatedCode.code(); 102 103 unsigned I = 0; 104 for (auto OffsetAndStmt = Stmts.rbegin(); OffsetAndStmt != Stmts.rend(); 105 OffsetAndStmt++) { 106 unsigned Offset = OffsetAndStmt->first; 107 const Stmt *Stmt = OffsetAndStmt->second; 108 109 if (I < Annotations.size() && Annotations[I].Begin >= Offset) { 110 auto Range = Annotations[I]; 111 112 if (!isAnnotationDirectlyAfterStatement(Stmt, Range.Begin, SourceManager, 113 Context.getLangOpts())) { 114 return llvm::createStringError( 115 std::make_error_code(std::errc::invalid_argument), 116 "Annotation is not placed after a statement: %s", 117 SourceManager.getLocForStartOfFile(SourceManager.getMainFileID()) 118 .getLocWithOffset(Offset) 119 .printToString(SourceManager) 120 .data()); 121 } 122 123 auto Annotation = Code.slice(Range.Begin, Range.End).str(); 124 if (!ExistingAnnotations.insert(Annotation).second) { 125 return llvm::createStringError( 126 std::make_error_code(std::errc::invalid_argument), 127 "Repeated use of annotation: %s", Annotation.data()); 128 } 129 Result[Stmt] = std::move(Annotation); 130 131 I++; 132 133 if (I < Annotations.size() && Annotations[I].Begin >= Offset) { 134 return llvm::createStringError( 135 std::make_error_code(std::errc::invalid_argument), 136 "Multiple annotations bound to the statement at the location: %s", 137 Stmt->getBeginLoc().printToString(SourceManager).data()); 138 } 139 } 140 } 141 142 if (I < Annotations.size()) { 143 return llvm::createStringError( 144 std::make_error_code(std::errc::invalid_argument), 145 "Not all annotations were bound to statements. Unbound annotation at: " 146 "%s", 147 SourceManager.getLocForStartOfFile(SourceManager.getMainFileID()) 148 .getLocWithOffset(Annotations[I].Begin) 149 .printToString(SourceManager) 150 .data()); 151 } 152 153 return Result; 154 } 155 156 const ValueDecl *test::findValueDecl(ASTContext &ASTCtx, llvm::StringRef Name) { 157 auto TargetNodes = match(valueDecl(hasName(Name)).bind("v"), ASTCtx); 158 assert(TargetNodes.size() == 1 && "Name must be unique"); 159 auto *const Result = selectFirst<ValueDecl>("v", TargetNodes); 160 assert(Result != nullptr); 161 return Result; 162 } 163