[analyzer] Refactoring: include/clang/Checker -> include/clang/GR
[clang.git] / include / clang / GR / PathSensitive / Checker.h
blob4e4cd5855572baad96a38f88d78b785b511c2193
1 //== Checker.h - Abstract interface for checkers -----------------*- C++ -*--=//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines Checker and CheckerVisitor, classes used for creating
11 // domain-specific checks.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_CLANG_ANALYSIS_CHECKER
16 #define LLVM_CLANG_ANALYSIS_CHECKER
18 #include "clang/Analysis/Support/SaveAndRestore.h"
19 #include "clang/GR/PathSensitive/GRExprEngine.h"
21 //===----------------------------------------------------------------------===//
22 // Checker interface.
23 //===----------------------------------------------------------------------===//
25 namespace clang {
27 class CheckerContext {
28 ExplodedNodeSet &Dst;
29 GRStmtNodeBuilder &B;
30 GRExprEngine &Eng;
31 ExplodedNode *Pred;
32 SaveAndRestore<bool> OldSink;
33 SaveAndRestore<const void*> OldTag;
34 SaveAndRestore<ProgramPoint::Kind> OldPointKind;
35 SaveOr OldHasGen;
36 const GRState *ST;
37 const Stmt *statement;
38 const unsigned size;
39 public:
40 bool *respondsToCallback;
41 public:
42 CheckerContext(ExplodedNodeSet &dst, GRStmtNodeBuilder &builder,
43 GRExprEngine &eng, ExplodedNode *pred,
44 const void *tag, ProgramPoint::Kind K,
45 bool *respondsToCB = 0,
46 const Stmt *stmt = 0, const GRState *st = 0)
47 : Dst(dst), B(builder), Eng(eng), Pred(pred),
48 OldSink(B.BuildSinks),
49 OldTag(B.Tag, tag),
50 OldPointKind(B.PointKind, K),
51 OldHasGen(B.HasGeneratedNode),
52 ST(st), statement(stmt), size(Dst.size()),
53 respondsToCallback(respondsToCB) {}
55 ~CheckerContext();
57 GRExprEngine &getEngine() {
58 return Eng;
61 AnalysisManager &getAnalysisManager() {
62 return Eng.getAnalysisManager();
65 ConstraintManager &getConstraintManager() {
66 return Eng.getConstraintManager();
69 StoreManager &getStoreManager() {
70 return Eng.getStoreManager();
73 ExplodedNodeSet &getNodeSet() { return Dst; }
74 GRStmtNodeBuilder &getNodeBuilder() { return B; }
75 ExplodedNode *&getPredecessor() { return Pred; }
76 const GRState *getState() { return ST ? ST : B.GetState(Pred); }
78 ASTContext &getASTContext() {
79 return Eng.getContext();
82 BugReporter &getBugReporter() {
83 return Eng.getBugReporter();
86 SourceManager &getSourceManager() {
87 return getBugReporter().getSourceManager();
90 SValBuilder &getSValBuilder() {
91 return Eng.getSValBuilder();
94 ExplodedNode *generateNode(bool autoTransition = true) {
95 assert(statement && "Only transitions with statements currently supported");
96 ExplodedNode *N = generateNodeImpl(statement, getState(), false);
97 if (N && autoTransition)
98 Dst.Add(N);
99 return N;
102 ExplodedNode *generateNode(const Stmt *stmt, const GRState *state,
103 bool autoTransition = true) {
104 assert(state);
105 ExplodedNode *N = generateNodeImpl(stmt, state, false);
106 if (N && autoTransition)
107 addTransition(N);
108 return N;
111 ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred,
112 bool autoTransition = true) {
113 assert(statement && "Only transitions with statements currently supported");
114 ExplodedNode *N = generateNodeImpl(statement, state, pred, false);
115 if (N && autoTransition)
116 addTransition(N);
117 return N;
120 ExplodedNode *generateNode(const GRState *state, bool autoTransition = true) {
121 assert(statement && "Only transitions with statements currently supported");
122 ExplodedNode *N = generateNodeImpl(statement, state, false);
123 if (N && autoTransition)
124 addTransition(N);
125 return N;
128 ExplodedNode *generateSink(const Stmt *stmt, const GRState *state = 0) {
129 return generateNodeImpl(stmt, state ? state : getState(), true);
132 ExplodedNode *generateSink(const GRState *state = 0) {
133 assert(statement && "Only transitions with statements currently supported");
134 return generateNodeImpl(statement, state ? state : getState(), true);
137 void addTransition(ExplodedNode *node) {
138 Dst.Add(node);
141 void addTransition(const GRState *state) {
142 assert(state);
143 // If the 'state' is not new, we need to check if the cached state 'ST'
144 // is new.
145 if (state != getState() || (ST && ST != B.GetState(Pred)))
146 // state is new or equals to ST.
147 generateNode(state, true);
148 else
149 Dst.Add(Pred);
152 // Generate a node with a new program point different from the one that will
153 // be created by the GRStmtNodeBuilder.
154 void addTransition(const GRState *state, ProgramPoint Loc) {
155 ExplodedNode *N = B.generateNode(Loc, state, Pred);
156 if (N)
157 addTransition(N);
160 void EmitReport(BugReport *R) {
161 Eng.getBugReporter().EmitReport(R);
164 AnalysisContext *getCurrentAnalysisContext() const {
165 return Pred->getLocationContext()->getAnalysisContext();
168 private:
169 ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state,
170 bool markAsSink) {
171 ExplodedNode *node = B.generateNode(stmt, state, Pred);
172 if (markAsSink && node)
173 node->markAsSink();
174 return node;
177 ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state,
178 ExplodedNode *pred, bool markAsSink) {
179 ExplodedNode *node = B.generateNode(stmt, state, pred);
180 if (markAsSink && node)
181 node->markAsSink();
182 return node;
186 class Checker {
187 private:
188 friend class GRExprEngine;
190 // FIXME: Remove the 'tag' option.
191 void GR_Visit(ExplodedNodeSet &Dst,
192 GRStmtNodeBuilder &Builder,
193 GRExprEngine &Eng,
194 const Stmt *S,
195 ExplodedNode *Pred, void *tag, bool isPrevisit,
196 bool& respondsToCallback) {
197 CheckerContext C(Dst, Builder, Eng, Pred, tag,
198 isPrevisit ? ProgramPoint::PreStmtKind :
199 ProgramPoint::PostStmtKind, &respondsToCallback, S);
200 if (isPrevisit)
201 _PreVisit(C, S);
202 else
203 _PostVisit(C, S);
206 bool GR_evalNilReceiver(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder,
207 GRExprEngine &Eng, const ObjCMessageExpr *ME,
208 ExplodedNode *Pred, const GRState *state, void *tag) {
209 CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
210 0, ME, state);
211 return evalNilReceiver(C, ME);
214 bool GR_evalCallExpr(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder,
215 GRExprEngine &Eng, const CallExpr *CE,
216 ExplodedNode *Pred, void *tag) {
217 CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
218 0, CE);
219 return evalCallExpr(C, CE);
222 // FIXME: Remove the 'tag' option.
223 void GR_VisitBind(ExplodedNodeSet &Dst,
224 GRStmtNodeBuilder &Builder, GRExprEngine &Eng,
225 const Stmt *StoreE, ExplodedNode *Pred, void *tag,
226 SVal location, SVal val,
227 bool isPrevisit) {
228 CheckerContext C(Dst, Builder, Eng, Pred, tag,
229 isPrevisit ? ProgramPoint::PreStmtKind :
230 ProgramPoint::PostStmtKind, 0, StoreE);
231 assert(isPrevisit && "Only previsit supported for now.");
232 PreVisitBind(C, StoreE, location, val);
235 // FIXME: Remove the 'tag' option.
236 void GR_visitLocation(ExplodedNodeSet &Dst,
237 GRStmtNodeBuilder &Builder,
238 GRExprEngine &Eng,
239 const Stmt *S,
240 ExplodedNode *Pred, const GRState *state,
241 SVal location,
242 void *tag, bool isLoad) {
243 CheckerContext C(Dst, Builder, Eng, Pred, tag,
244 isLoad ? ProgramPoint::PreLoadKind :
245 ProgramPoint::PreStoreKind, 0, S, state);
246 visitLocation(C, S, location);
249 void GR_evalDeadSymbols(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder,
250 GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred,
251 SymbolReaper &SymReaper, void *tag) {
252 CheckerContext C(Dst, Builder, Eng, Pred, tag,
253 ProgramPoint::PostPurgeDeadSymbolsKind, 0, S);
254 evalDeadSymbols(C, SymReaper);
257 public:
258 virtual ~Checker();
259 virtual void _PreVisit(CheckerContext &C, const Stmt *S) {}
260 virtual void _PostVisit(CheckerContext &C, const Stmt *S) {}
261 virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location) {}
262 virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
263 SVal location, SVal val) {}
264 virtual void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper) {}
265 virtual void evalEndPath(GREndPathNodeBuilder &B, void *tag,
266 GRExprEngine &Eng) {}
268 virtual void MarkLiveSymbols(const GRState *state, SymbolReaper &SymReaper) {}
270 virtual void VisitBranchCondition(GRBranchNodeBuilder &Builder,
271 GRExprEngine &Eng,
272 const Stmt *Condition, void *tag) {}
274 virtual bool evalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME) {
275 return false;
278 virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE) {
279 return false;
282 virtual const GRState *evalAssume(const GRState *state, SVal Cond,
283 bool Assumption, bool *respondsToCallback) {
284 *respondsToCallback = false;
285 return state;
288 virtual bool WantsRegionChangeUpdate(const GRState *state) { return false; }
290 virtual const GRState *EvalRegionChanges(const GRState *state,
291 const MemRegion * const *Begin,
292 const MemRegion * const *End,
293 bool *respondsToCallback) {
294 *respondsToCallback = false;
295 return state;
298 virtual void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B,
299 GRExprEngine &Eng) {}
301 } // end clang namespace
303 #endif