CheckerContext.h revision 390909c89c98ab1807e15e033a72e975f866fb23
1//== CheckerContext.h - Context info for path-sensitive 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 CheckerContext that provides contextual info for 11// path-sensitive checkers. 12// 13//===----------------------------------------------------------------------===// 14 15#ifndef LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT 16#define LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT 17 18#include "clang/Analysis/Support/SaveAndRestore.h" 19#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 20 21namespace clang { 22 23namespace ento { 24 25class CheckerContext { 26 ExplodedNodeSet &Dst; 27 StmtNodeBuilder &B; 28 ExprEngine &Eng; 29 ExplodedNode *Pred; 30 SaveAndRestore<bool> OldSink; 31 const ProgramPointTag *checkerTag; 32 SaveAndRestore<ProgramPoint::Kind> OldPointKind; 33 SaveOr OldHasGen; 34 const ProgramState *ST; 35 const Stmt *statement; 36 const unsigned size; 37public: 38 bool *respondsToCallback; 39public: 40 CheckerContext(ExplodedNodeSet &dst, 41 StmtNodeBuilder &builder, 42 ExprEngine &eng, 43 ExplodedNode *pred, 44 const ProgramPointTag *tag, 45 ProgramPoint::Kind K, 46 bool *respondsToCB = 0, 47 const Stmt *stmt = 0, 48 const ProgramState *st = 0) 49 : Dst(dst), 50 B(builder), 51 Eng(eng), 52 Pred(pred), 53 OldSink(B.BuildSinks), 54 checkerTag(tag), 55 OldPointKind(B.PointKind, K), 56 OldHasGen(B.hasGeneratedNode), 57 ST(st), 58 statement(stmt), 59 size(Dst.size()), 60 respondsToCallback(respondsToCB) {} 61 62 ~CheckerContext(); 63 64 ExprEngine &getEngine() { 65 return Eng; 66 } 67 68 AnalysisManager &getAnalysisManager() { 69 return Eng.getAnalysisManager(); 70 } 71 72 ConstraintManager &getConstraintManager() { 73 return Eng.getConstraintManager(); 74 } 75 76 StoreManager &getStoreManager() { 77 return Eng.getStoreManager(); 78 } 79 80 ExplodedNodeSet &getNodeSet() { return Dst; } 81 ExplodedNode *&getPredecessor() { return Pred; } 82 const ProgramState *getState() { return ST ? ST : Pred->getState(); } 83 84 /// \brief Returns the number of times the current block has been visited 85 /// along the analyzed path. 86 unsigned getCurrentBlockCount() {return B.getCurrentBlockCount();} 87 88 ASTContext &getASTContext() { 89 return Eng.getContext(); 90 } 91 92 BugReporter &getBugReporter() { 93 return Eng.getBugReporter(); 94 } 95 96 SourceManager &getSourceManager() { 97 return getBugReporter().getSourceManager(); 98 } 99 100 SValBuilder &getSValBuilder() { 101 return Eng.getSValBuilder(); 102 } 103 104 SymbolManager &getSymbolManager() { 105 return getSValBuilder().getSymbolManager(); 106 } 107 108 bool isObjCGCEnabled() { 109 return Eng.isObjCGCEnabled(); 110 } 111 112 /// \brief Generate a default checker node (containing checker tag but no 113 /// checker state changes). 114 ExplodedNode *generateNode(bool autoTransition = true) { 115 return generateNode(getState(), autoTransition); 116 } 117 118 /// \brief Generate a new checker node with the given predecessor. 119 /// Allows checkers to generate a chain of nodes. 120 ExplodedNode *generateNode(const ProgramState *state, 121 ExplodedNode *pred, 122 const ProgramPointTag *tag = 0, 123 bool autoTransition = true) { 124 ExplodedNode *N = generateNodeImpl(state, false, pred, tag); 125 if (N && autoTransition) 126 addTransition(N); 127 return N; 128 } 129 130 /// \brief Generate a new checker node. 131 ExplodedNode *generateNode(const ProgramState *state, 132 bool autoTransition = true, 133 const ProgramPointTag *tag = 0) { 134 ExplodedNode *N = generateNodeImpl(state, false, 0, tag); 135 if (N && autoTransition) 136 addTransition(N); 137 return N; 138 } 139 140 /// \brief Generate a sink node. Generating sink stops exploration of the 141 /// given path. 142 ExplodedNode *generateSink(const ProgramState *state = 0) { 143 return generateNodeImpl(state ? state : getState(), true); 144 } 145 146 void addTransition(ExplodedNode *node) { 147 Dst.Add(node); 148 } 149 150 void addTransition(const ProgramState *state, 151 const ProgramPointTag *tag = 0) { 152 assert(state); 153 // If the 'state' is not new, we need to check if the cached state 'ST' 154 // is new. 155 if (state != getState() || (ST && ST != Pred->getState())) 156 // state is new or equals to ST. 157 generateNode(state, true, tag); 158 else 159 Dst.Add(Pred); 160 } 161 162 void EmitReport(BugReport *R) { 163 Eng.getBugReporter().EmitReport(R); 164 } 165 166 AnalysisContext *getCurrentAnalysisContext() const { 167 return Pred->getLocationContext()->getAnalysisContext(); 168 } 169 170private: 171 ExplodedNode *generateNodeImpl(const ProgramState *state, 172 bool markAsSink, 173 ExplodedNode *pred = 0, 174 const ProgramPointTag *tag = 0) { 175 assert(statement && "Only transitions with statements currently supported"); 176 ExplodedNode *node = B.generateNode(statement, state, 177 pred ? pred : Pred, 178 tag ? tag : checkerTag); 179 if (markAsSink && node) 180 node->markAsSink(); 181 return node; 182 } 183}; 184 185} // end GR namespace 186 187} // end clang namespace 188 189#endif 190