1 //== Checker.h - Abstract interface for checkers -----------------*- C++ -*--=//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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 //===----------------------------------------------------------------------===//
23 //===----------------------------------------------------------------------===//
27 class CheckerContext
{
32 SaveAndRestore
<bool> OldSink
;
33 SaveAndRestore
<const void*> OldTag
;
34 SaveAndRestore
<ProgramPoint::Kind
> OldPointKind
;
37 const Stmt
*statement
;
40 bool *respondsToCallback
;
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
),
50 OldPointKind(B
.PointKind
, K
),
51 OldHasGen(B
.HasGeneratedNode
),
52 ST(st
), statement(stmt
), size(Dst
.size()),
53 respondsToCallback(respondsToCB
) {}
57 GRExprEngine
&getEngine() {
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
)
102 ExplodedNode
*generateNode(const Stmt
*stmt
, const GRState
*state
,
103 bool autoTransition
= true) {
105 ExplodedNode
*N
= generateNodeImpl(stmt
, state
, false);
106 if (N
&& autoTransition
)
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
)
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
)
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
) {
141 void addTransition(const GRState
*state
) {
143 // If the 'state' is not new, we need to check if the cached state 'ST'
145 if (state
!= getState() || (ST
&& ST
!= B
.GetState(Pred
)))
146 // state is new or equals to ST.
147 generateNode(state
, true);
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
);
160 void EmitReport(BugReport
*R
) {
161 Eng
.getBugReporter().EmitReport(R
);
164 AnalysisContext
*getCurrentAnalysisContext() const {
165 return Pred
->getLocationContext()->getAnalysisContext();
169 ExplodedNode
*generateNodeImpl(const Stmt
* stmt
, const GRState
*state
,
171 ExplodedNode
*node
= B
.generateNode(stmt
, state
, Pred
);
172 if (markAsSink
&& 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
)
188 friend class GRExprEngine
;
190 // FIXME: Remove the 'tag' option.
191 void GR_Visit(ExplodedNodeSet
&Dst
,
192 GRStmtNodeBuilder
&Builder
,
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
);
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
,
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
,
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
,
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
,
240 ExplodedNode
*Pred
, const GRState
*state
,
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
);
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
,
272 const Stmt
*Condition
, void *tag
) {}
274 virtual bool evalNilReceiver(CheckerContext
&C
, const ObjCMessageExpr
*ME
) {
278 virtual bool evalCallExpr(CheckerContext
&C
, const CallExpr
*CE
) {
282 virtual const GRState
*evalAssume(const GRState
*state
, SVal Cond
,
283 bool Assumption
, bool *respondsToCallback
) {
284 *respondsToCallback
= false;
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;
298 virtual void VisitEndAnalysis(ExplodedGraph
&G
, BugReporter
&B
,
299 GRExprEngine
&Eng
) {}
301 } // end clang namespace