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