blob: d5f545a397f7e22c011cb2790bdcb871b0b4b7cc [file] [log] [blame]
Zhongxing Xucb7464a2010-04-19 12:51:02 +00001//===- GRCXXExprEngine.cpp - C++ expr evaluation engine ---------*- 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 the C++ expression evaluation engine.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Checker/PathSensitive/AnalysisManager.h"
15#include "clang/Checker/PathSensitive/GRExprEngine.h"
16#include "clang/AST/DeclCXX.h"
17
18using namespace clang;
19
20const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D,
21 const StackFrameContext *SFC) {
22 Type *T = D->getParent()->getTypeForDecl();
23 QualType PT = getContext().getPointerType(QualType(T,0));
24 return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC);
25}
26
27void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
28 ExplodedNodeSet &Dst) {
29 ExplodedNodeSet Tmp;
30 Visit(Ex, Pred, Tmp);
31 for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
32 const GRState *state = GetState(*I);
33
34 // Bind the temporary object to the value of the expression. Then bind
35 // the expression to the location of the object.
36 SVal V = state->getSVal(Ex);
37
38 const MemRegion *R =
39 ValMgr.getRegionManager().getCXXObjectRegion(Ex,
40 Pred->getLocationContext());
41
42 state = state->bindLoc(loc::MemRegionVal(R), V);
43 MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R)));
44 }
45}
46
47void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
48 ExplodedNode *Pred,
49 ExplodedNodeSet &Dst) {
50 if (E->isElidable()) {
51 VisitAggExpr(E->getArg(0), Dest, Pred, Dst);
52 return;
53 }
54
55 const CXXConstructorDecl *CD = E->getConstructor();
56 assert(CD);
57
58 if (!CD->isThisDeclarationADefinition())
59 // FIXME: invalidate the object.
60 return;
61
62
63 // Evaluate other arguments.
64 CXXConstructExpr::arg_iterator AB
65 = const_cast<CXXConstructExpr*>(E)->arg_begin();
66 CXXConstructExpr::arg_iterator AE
67 = const_cast<CXXConstructExpr*>(E)->arg_end();
68 llvm::SmallVector<CallExprWLItem, 20> WorkList;
69 WorkList.reserve(AE - AB);
70 WorkList.push_back(CallExprWLItem(AB, Pred));
71 ExplodedNodeSet ArgsEvaluated;
72 const FunctionProtoType *Proto = CD->getType()->getAs<FunctionProtoType>();
73
74 while (!WorkList.empty()) {
75 CallExprWLItem Item = WorkList.back();
76 WorkList.pop_back();
77
78 if (Item.I == AE) {
79 ArgsEvaluated.insert(Item.N);
80 continue;
81 }
82
83 // Evaluate the argument.
84 ExplodedNodeSet Tmp;
85 const unsigned ParamIdx = Item.I - AB;
86
87 bool VisitAsLvalue = false;
88
89 if (ParamIdx < Proto->getNumArgs())
90 VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
91
92 if (VisitAsLvalue)
93 VisitLValue(*Item.I, Item.N, Tmp);
94 else
95 Visit(*Item.I, Item.N, Tmp);
96
97 ++(Item.I);
98
99 for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
100 WorkList.push_back(CallExprWLItem(Item.I, *NI));
101 }
102 // The callee stack frame context used to create the 'this' parameter region.
103 const StackFrameContext *SFC = AMgr.getStackFrame(CD,
104 Pred->getLocationContext(),
105 E, Builder->getBlock(), Builder->getIndex());
106
107 const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC);
108
109 CallEnter Loc(E, CD, Pred->getLocationContext());
110 for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(),
111 NE = ArgsEvaluated.end(); NI != NE; ++NI) {
112 const GRState *state = GetState(*NI);
113 // Setup 'this' region.
114 state = state->bindLoc(loc::MemRegionVal(ThisR), Dest);
115 ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
116 if (N)
117 Dst.Add(N);
118 }
119}
120
121void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE,
122 ExplodedNode *Pred,
123 ExplodedNodeSet &Dst) {
124 // Get the method type.
125 const FunctionProtoType *FnType =
126 MCE->getCallee()->getType()->getAs<FunctionProtoType>();
127 assert(FnType && "Method type not available");
128
129 // Evaluate explicit arguments with a worklist.
130 CallExpr::arg_iterator AB = const_cast<CXXMemberCallExpr*>(MCE)->arg_begin(),
131 AE = const_cast<CXXMemberCallExpr*>(MCE)->arg_end();
132 llvm::SmallVector<CallExprWLItem, 20> WorkList;
133 WorkList.reserve(AE - AB);
134 WorkList.push_back(CallExprWLItem(AB, Pred));
135 ExplodedNodeSet ArgsEvaluated;
136
137 while (!WorkList.empty()) {
138 CallExprWLItem Item = WorkList.back();
139 WorkList.pop_back();
140
141 if (Item.I == AE) {
142 ArgsEvaluated.insert(Item.N);
143 continue;
144 }
145
146 ExplodedNodeSet Tmp;
147 const unsigned ParamIdx = Item.I - AB;
148 bool VisitAsLvalue = FnType->getArgType(ParamIdx)->isReferenceType();
149
150 if (VisitAsLvalue)
151 VisitLValue(*Item.I, Item.N, Tmp);
152 else
153 Visit(*Item.I, Item.N, Tmp);
154
155 ++(Item.I);
156 for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI)
157 WorkList.push_back(CallExprWLItem(Item.I, *NI));
158 }
159 // Evaluate the implicit object argument.
160 ExplodedNodeSet AllArgsEvaluated;
161 const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens());
162 if (!ME)
163 return;
164 Expr *ObjArgExpr = ME->getBase();
165 for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(),
166 E = ArgsEvaluated.end(); I != E; ++I) {
167 if (ME->isArrow())
168 Visit(ObjArgExpr, *I, AllArgsEvaluated);
169 else
170 VisitLValue(ObjArgExpr, *I, AllArgsEvaluated);
171 }
172
173 const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
174 assert(MD && "not a CXXMethodDecl?");
175
176 if (!MD->isThisDeclarationADefinition())
177 // FIXME: conservative method call evaluation.
178 return;
179
180 const StackFrameContext *SFC = AMgr.getStackFrame(MD,
181 Pred->getLocationContext(),
182 MCE,
183 Builder->getBlock(),
184 Builder->getIndex());
185 const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC);
186 CallEnter Loc(MCE, MD, Pred->getLocationContext());
187 for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(),
188 E = AllArgsEvaluated.end(); I != E; ++I) {
189 // Set up 'this' region.
190 const GRState *state = GetState(*I);
191 state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr));
192 ExplodedNode *N = Builder->generateNode(Loc, state, *I);
193 if (N)
194 Dst.Add(N);
195 }
196}
197
198void GRExprEngine::VisitCXXNewExpr(CXXNewExpr *CNE, ExplodedNode *Pred,
199 ExplodedNodeSet &Dst) {
200 if (CNE->isArray()) {
201 // FIXME: allocating an array has not been handled.
202 return;
203 }
204
205 unsigned Count = Builder->getCurrentBlockCount();
206 DefinedOrUnknownSVal SymVal = getValueManager().getConjuredSymbolVal(NULL,CNE,
207 CNE->getType(), Count);
208 const MemRegion *NewReg = cast<loc::MemRegionVal>(SymVal).getRegion();
209
210 QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
211
212 const ElementRegion *EleReg =
213 getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
214
215 const GRState *state = Pred->getState();
216
217 Store store = state->getStore();
218 StoreManager::InvalidatedSymbols IS;
219 store = getStoreManager().InvalidateRegion(store, EleReg, CNE, Count, &IS);
220 state = state->makeWithStore(store);
221 state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
222 MakeNode(Dst, CNE, Pred, state);
223}
224
225
226void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
227 ExplodedNodeSet & Dst) {
228 // Get the this object region from StoreManager.
229 const MemRegion *R =
230 ValMgr.getRegionManager().getCXXThisRegion(
231 getContext().getCanonicalType(TE->getType()),
232 Pred->getLocationContext());
233
234 const GRState *state = GetState(Pred);
235 SVal V = state->getSVal(loc::MemRegionVal(R));
236 MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
237}