/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Analysis/FlowSensitive/Transfer.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- Transfer.cpp --------------------------------------------*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | // This file defines transfer functions that evaluate program statements and |
10 | | // update an environment accordingly. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #include "clang/Analysis/FlowSensitive/Transfer.h" |
15 | | #include "clang/AST/Decl.h" |
16 | | #include "clang/AST/DeclBase.h" |
17 | | #include "clang/AST/DeclCXX.h" |
18 | | #include "clang/AST/Expr.h" |
19 | | #include "clang/AST/ExprCXX.h" |
20 | | #include "clang/AST/OperationKinds.h" |
21 | | #include "clang/AST/Stmt.h" |
22 | | #include "clang/AST/StmtVisitor.h" |
23 | | #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" |
24 | | #include "clang/Analysis/FlowSensitive/Value.h" |
25 | | #include "clang/Basic/Builtins.h" |
26 | | #include "clang/Basic/OperatorKinds.h" |
27 | | #include "llvm/ADT/STLExtras.h" |
28 | | #include "llvm/Support/Casting.h" |
29 | | #include <cassert> |
30 | | #include <memory> |
31 | | #include <tuple> |
32 | | |
33 | | namespace clang { |
34 | | namespace dataflow { |
35 | | |
36 | | static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS, |
37 | 22 | Environment &Env) { |
38 | 22 | if (auto *LHSValue = |
39 | 22 | dyn_cast_or_null<BoolValue>(Env.getValue(LHS, SkipPast::Reference))) |
40 | 4 | if (auto *RHSValue = |
41 | 4 | dyn_cast_or_null<BoolValue>(Env.getValue(RHS, SkipPast::Reference))) |
42 | 4 | return Env.makeIff(*LHSValue, *RHSValue); |
43 | | |
44 | 18 | return Env.makeAtomicBoolValue(); |
45 | 22 | } |
46 | | |
47 | | class TransferVisitor : public ConstStmtVisitor<TransferVisitor> { |
48 | | public: |
49 | | TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env) |
50 | 5.80k | : StmtToEnv(StmtToEnv), Env(Env) {} |
51 | | |
52 | 136 | void VisitBinaryOperator(const BinaryOperator *S) { |
53 | 136 | const Expr *LHS = S->getLHS(); |
54 | 136 | assert(LHS != nullptr); |
55 | | |
56 | 0 | const Expr *RHS = S->getRHS(); |
57 | 136 | assert(RHS != nullptr); |
58 | | |
59 | 0 | switch (S->getOpcode()) { |
60 | 82 | case BO_Assign: { |
61 | 82 | auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference); |
62 | 82 | if (LHSLoc == nullptr) |
63 | 2 | break; |
64 | | |
65 | 80 | auto *RHSVal = Env.getValue(*RHS, SkipPast::Reference); |
66 | 80 | if (RHSVal == nullptr) |
67 | 52 | break; |
68 | | |
69 | | // Assign a value to the storage location of the left-hand side. |
70 | 28 | Env.setValue(*LHSLoc, *RHSVal); |
71 | | |
72 | | // Assign a storage location for the whole expression. |
73 | 28 | Env.setStorageLocation(*S, *LHSLoc); |
74 | 28 | break; |
75 | 80 | } |
76 | 14 | case BO_LAnd: |
77 | 24 | case BO_LOr: { |
78 | 24 | BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS); |
79 | 24 | BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS); |
80 | | |
81 | 24 | auto &Loc = Env.createStorageLocation(*S); |
82 | 24 | Env.setStorageLocation(*S, Loc); |
83 | 24 | if (S->getOpcode() == BO_LAnd) |
84 | 14 | Env.setValue(Loc, Env.makeAnd(LHSVal, RHSVal)); |
85 | 10 | else |
86 | 10 | Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal)); |
87 | 24 | break; |
88 | 14 | } |
89 | 20 | case BO_NE: |
90 | 22 | case BO_EQ: { |
91 | 22 | auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env); |
92 | 22 | auto &Loc = Env.createStorageLocation(*S); |
93 | 22 | Env.setStorageLocation(*S, Loc); |
94 | 22 | Env.setValue(Loc, S->getOpcode() == BO_EQ ? LHSEqRHSValue2 |
95 | 22 | : Env.makeNot(LHSEqRHSValue)20 ); |
96 | 22 | break; |
97 | 20 | } |
98 | 8 | default: |
99 | 8 | break; |
100 | 136 | } |
101 | 136 | } |
102 | | |
103 | 1.32k | void VisitDeclRefExpr(const DeclRefExpr *S) { |
104 | 1.32k | assert(S->getDecl() != nullptr); |
105 | 0 | auto *DeclLoc = Env.getStorageLocation(*S->getDecl(), SkipPast::None); |
106 | 1.32k | if (DeclLoc == nullptr) |
107 | 298 | return; |
108 | | |
109 | 1.02k | if (S->getDecl()->getType()->isReferenceType()) { |
110 | 31 | Env.setStorageLocation(*S, *DeclLoc); |
111 | 993 | } else { |
112 | 993 | auto &Loc = Env.createStorageLocation(*S); |
113 | 993 | auto &Val = Env.takeOwnership(std::make_unique<ReferenceValue>(*DeclLoc)); |
114 | 993 | Env.setStorageLocation(*S, Loc); |
115 | 993 | Env.setValue(Loc, Val); |
116 | 993 | } |
117 | 1.02k | } |
118 | | |
119 | 583 | void VisitDeclStmt(const DeclStmt *S) { |
120 | | // Group decls are converted into single decls in the CFG so the cast below |
121 | | // is safe. |
122 | 583 | const auto &D = *cast<VarDecl>(S->getSingleDecl()); |
123 | | |
124 | | // Static local vars are already initialized in `Environment`. |
125 | 583 | if (D.hasGlobalStorage()) |
126 | 6 | return; |
127 | | |
128 | 577 | auto &Loc = Env.createStorageLocation(D); |
129 | 577 | Env.setStorageLocation(D, Loc); |
130 | | |
131 | 577 | const Expr *InitExpr = D.getInit(); |
132 | 577 | if (InitExpr == nullptr) { |
133 | | // No initializer expression - associate `Loc` with a new value. |
134 | 64 | if (Value *Val = Env.createValue(D.getType())) |
135 | 64 | Env.setValue(Loc, *Val); |
136 | 64 | return; |
137 | 64 | } |
138 | | |
139 | 513 | InitExpr = D.getInit(); |
140 | 513 | assert(InitExpr != nullptr); |
141 | | |
142 | 513 | if (D.getType()->isReferenceType()) { |
143 | | // Initializing a reference variable - do not create a reference to |
144 | | // reference. |
145 | 15 | if (auto *InitExprLoc = |
146 | 15 | Env.getStorageLocation(*InitExpr, SkipPast::Reference)) { |
147 | 8 | auto &Val = |
148 | 8 | Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc)); |
149 | 8 | Env.setValue(Loc, Val); |
150 | 8 | return; |
151 | 8 | } |
152 | 498 | } else if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) { |
153 | 447 | Env.setValue(Loc, *InitExprVal); |
154 | 447 | return; |
155 | 447 | } |
156 | | |
157 | | // We arrive here in (the few) cases where an expression is intentionally |
158 | | // "uninterpreted". There are two ways to handle this situation: propagate |
159 | | // the status, so that uninterpreted initializers result in uninterpreted |
160 | | // variables, or provide a default value. We choose the latter so that later |
161 | | // refinements of the variable can be used for reasoning about the |
162 | | // surrounding code. |
163 | | // |
164 | | // FIXME. If and when we interpret all language cases, change this to assert |
165 | | // that `InitExpr` is interpreted, rather than supplying a default value |
166 | | // (assuming we don't update the environment API to return references). |
167 | 58 | if (Value *Val = Env.createValue(D.getType())) |
168 | 56 | Env.setValue(Loc, *Val); |
169 | 58 | } |
170 | | |
171 | 854 | void VisitImplicitCastExpr(const ImplicitCastExpr *S) { |
172 | 854 | const Expr *SubExpr = S->getSubExpr(); |
173 | 854 | assert(SubExpr != nullptr); |
174 | | |
175 | 0 | switch (S->getCastKind()) { |
176 | 6 | case CK_IntegralToBoolean: { |
177 | | // This cast creates a new, boolean value from the integral value. We |
178 | | // model that with a fresh value in the environment, unless it's already a |
179 | | // boolean. |
180 | 6 | auto &Loc = Env.createStorageLocation(*S); |
181 | 6 | Env.setStorageLocation(*S, Loc); |
182 | 6 | if (auto *SubExprVal = dyn_cast_or_null<BoolValue>( |
183 | 6 | Env.getValue(*SubExpr, SkipPast::Reference))) |
184 | 4 | Env.setValue(Loc, *SubExprVal); |
185 | 2 | else |
186 | | // FIXME: If integer modeling is added, then update this code to create |
187 | | // the boolean based on the integer model. |
188 | 2 | Env.setValue(Loc, Env.makeAtomicBoolValue()); |
189 | 6 | break; |
190 | 0 | } |
191 | | |
192 | 280 | case CK_LValueToRValue: { |
193 | 280 | auto *SubExprVal = Env.getValue(*SubExpr, SkipPast::Reference); |
194 | 280 | if (SubExprVal == nullptr) |
195 | 5 | break; |
196 | | |
197 | 275 | auto &ExprLoc = Env.createStorageLocation(*S); |
198 | 275 | Env.setStorageLocation(*S, ExprLoc); |
199 | 275 | Env.setValue(ExprLoc, *SubExprVal); |
200 | 275 | break; |
201 | 280 | } |
202 | | |
203 | 18 | case CK_IntegralCast: |
204 | | // FIXME: This cast creates a new integral value from the |
205 | | // subexpression. But, because we don't model integers, we don't |
206 | | // distinguish between this new value and the underlying one. If integer |
207 | | // modeling is added, then update this code to create a fresh location and |
208 | | // value. |
209 | 28 | case CK_UncheckedDerivedToBase: |
210 | 112 | case CK_ConstructorConversion: |
211 | 118 | case CK_UserDefinedConversion: |
212 | | // FIXME: Add tests that excercise CK_UncheckedDerivedToBase, |
213 | | // CK_ConstructorConversion, and CK_UserDefinedConversion. |
214 | 226 | case CK_NoOp: { |
215 | | // FIXME: Consider making `Environment::getStorageLocation` skip noop |
216 | | // expressions (this and other similar expressions in the file) instead of |
217 | | // assigning them storage locations. |
218 | 226 | auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); |
219 | 226 | if (SubExprLoc == nullptr) |
220 | 6 | break; |
221 | | |
222 | 220 | Env.setStorageLocation(*S, *SubExprLoc); |
223 | 220 | break; |
224 | 226 | } |
225 | 342 | default: |
226 | 342 | break; |
227 | 854 | } |
228 | 854 | } |
229 | | |
230 | 65 | void VisitUnaryOperator(const UnaryOperator *S) { |
231 | 65 | const Expr *SubExpr = S->getSubExpr(); |
232 | 65 | assert(SubExpr != nullptr); |
233 | | |
234 | 0 | switch (S->getOpcode()) { |
235 | 11 | case UO_Deref: { |
236 | | // Skip past a reference to handle dereference of a dependent pointer. |
237 | 11 | const auto *SubExprVal = cast_or_null<PointerValue>( |
238 | 11 | Env.getValue(*SubExpr, SkipPast::Reference)); |
239 | 11 | if (SubExprVal == nullptr) |
240 | 0 | break; |
241 | | |
242 | 11 | auto &Loc = Env.createStorageLocation(*S); |
243 | 11 | Env.setStorageLocation(*S, Loc); |
244 | 11 | Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>( |
245 | 11 | SubExprVal->getPointeeLoc()))); |
246 | 11 | break; |
247 | 11 | } |
248 | 14 | case UO_AddrOf: { |
249 | | // Do not form a pointer to a reference. If `SubExpr` is assigned a |
250 | | // `ReferenceValue` then form a value that points to the location of its |
251 | | // pointee. |
252 | 14 | StorageLocation *PointeeLoc = |
253 | 14 | Env.getStorageLocation(*SubExpr, SkipPast::Reference); |
254 | 14 | if (PointeeLoc == nullptr) |
255 | 0 | break; |
256 | | |
257 | 14 | auto &PointerLoc = Env.createStorageLocation(*S); |
258 | 14 | auto &PointerVal = |
259 | 14 | Env.takeOwnership(std::make_unique<PointerValue>(*PointeeLoc)); |
260 | 14 | Env.setStorageLocation(*S, PointerLoc); |
261 | 14 | Env.setValue(PointerLoc, PointerVal); |
262 | 14 | break; |
263 | 14 | } |
264 | 40 | case UO_LNot: { |
265 | 40 | auto *SubExprVal = |
266 | 40 | dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr, SkipPast::None)); |
267 | 40 | if (SubExprVal == nullptr) |
268 | 0 | break; |
269 | | |
270 | 40 | auto &ExprLoc = Env.createStorageLocation(*S); |
271 | 40 | Env.setStorageLocation(*S, ExprLoc); |
272 | 40 | Env.setValue(ExprLoc, Env.makeNot(*SubExprVal)); |
273 | 40 | break; |
274 | 40 | } |
275 | 0 | default: |
276 | 0 | break; |
277 | 65 | } |
278 | 65 | } |
279 | | |
280 | 18 | void VisitCXXThisExpr(const CXXThisExpr *S) { |
281 | 18 | auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation(); |
282 | 18 | assert(ThisPointeeLoc != nullptr); |
283 | | |
284 | 0 | auto &Loc = Env.createStorageLocation(*S); |
285 | 18 | Env.setStorageLocation(*S, Loc); |
286 | 18 | Env.setValue(Loc, Env.takeOwnership( |
287 | 18 | std::make_unique<PointerValue>(*ThisPointeeLoc))); |
288 | 18 | } |
289 | | |
290 | 540 | void VisitMemberExpr(const MemberExpr *S) { |
291 | 540 | ValueDecl *Member = S->getMemberDecl(); |
292 | 540 | assert(Member != nullptr); |
293 | | |
294 | | // FIXME: Consider assigning pointer values to function member expressions. |
295 | 540 | if (Member->isFunctionOrFunctionTemplate()) |
296 | 482 | return; |
297 | | |
298 | 58 | if (auto *D = dyn_cast<VarDecl>(Member)) { |
299 | 8 | if (D->hasGlobalStorage()) { |
300 | 8 | auto *VarDeclLoc = Env.getStorageLocation(*D, SkipPast::None); |
301 | 8 | if (VarDeclLoc == nullptr) |
302 | 0 | return; |
303 | | |
304 | 8 | if (VarDeclLoc->getType()->isReferenceType()) { |
305 | 4 | Env.setStorageLocation(*S, *VarDeclLoc); |
306 | 4 | } else { |
307 | 4 | auto &Loc = Env.createStorageLocation(*S); |
308 | 4 | Env.setStorageLocation(*S, Loc); |
309 | 4 | Env.setValue(Loc, Env.takeOwnership( |
310 | 4 | std::make_unique<ReferenceValue>(*VarDeclLoc))); |
311 | 4 | } |
312 | 8 | return; |
313 | 8 | } |
314 | 8 | } |
315 | | |
316 | | // The receiver can be either a value or a pointer to a value. Skip past the |
317 | | // indirection to handle both cases. |
318 | 50 | auto *BaseLoc = cast_or_null<AggregateStorageLocation>( |
319 | 50 | Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer)); |
320 | 50 | if (BaseLoc == nullptr) |
321 | 12 | return; |
322 | | |
323 | | // FIXME: Add support for union types. |
324 | 38 | if (BaseLoc->getType()->isUnionType()) |
325 | 2 | return; |
326 | | |
327 | 36 | auto &MemberLoc = BaseLoc->getChild(*Member); |
328 | 36 | if (MemberLoc.getType()->isReferenceType()) { |
329 | 6 | Env.setStorageLocation(*S, MemberLoc); |
330 | 30 | } else { |
331 | 30 | auto &Loc = Env.createStorageLocation(*S); |
332 | 30 | Env.setStorageLocation(*S, Loc); |
333 | 30 | Env.setValue( |
334 | 30 | Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(MemberLoc))); |
335 | 30 | } |
336 | 36 | } |
337 | | |
338 | 4 | void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { |
339 | 4 | const Expr *InitExpr = S->getExpr(); |
340 | 4 | assert(InitExpr != nullptr); |
341 | | |
342 | 0 | Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None); |
343 | 4 | if (InitExprVal == nullptr) |
344 | 0 | return; |
345 | | |
346 | 4 | const FieldDecl *Field = S->getField(); |
347 | 4 | assert(Field != nullptr); |
348 | | |
349 | 0 | auto &ThisLoc = |
350 | 4 | *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation()); |
351 | 4 | auto &FieldLoc = ThisLoc.getChild(*Field); |
352 | 4 | Env.setValue(FieldLoc, *InitExprVal); |
353 | 4 | } |
354 | | |
355 | 380 | void VisitCXXConstructExpr(const CXXConstructExpr *S) { |
356 | 380 | const CXXConstructorDecl *ConstructorDecl = S->getConstructor(); |
357 | 380 | assert(ConstructorDecl != nullptr); |
358 | | |
359 | 380 | if (ConstructorDecl->isCopyOrMoveConstructor()) { |
360 | 82 | assert(S->getNumArgs() == 1); |
361 | | |
362 | 0 | const Expr *Arg = S->getArg(0); |
363 | 82 | assert(Arg != nullptr); |
364 | | |
365 | 82 | if (S->isElidable()) { |
366 | 2 | auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference); |
367 | 2 | if (ArgLoc == nullptr) |
368 | 0 | return; |
369 | | |
370 | 2 | Env.setStorageLocation(*S, *ArgLoc); |
371 | 80 | } else if (auto *ArgVal = Env.getValue(*Arg, SkipPast::Reference)) { |
372 | 80 | auto &Loc = Env.createStorageLocation(*S); |
373 | 80 | Env.setStorageLocation(*S, Loc); |
374 | 80 | Env.setValue(Loc, *ArgVal); |
375 | 80 | } |
376 | 82 | return; |
377 | 82 | } |
378 | | |
379 | 298 | auto &Loc = Env.createStorageLocation(*S); |
380 | 298 | Env.setStorageLocation(*S, Loc); |
381 | 298 | if (Value *Val = Env.createValue(S->getType())) |
382 | 296 | Env.setValue(Loc, *Val); |
383 | 298 | } |
384 | | |
385 | 132 | void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) { |
386 | 132 | if (S->getOperator() == OO_Equal) { |
387 | 70 | assert(S->getNumArgs() == 2); |
388 | | |
389 | 0 | const Expr *Arg0 = S->getArg(0); |
390 | 70 | assert(Arg0 != nullptr); |
391 | | |
392 | 0 | const Expr *Arg1 = S->getArg(1); |
393 | 70 | assert(Arg1 != nullptr); |
394 | | |
395 | | // Evaluate only copy and move assignment operators. |
396 | 0 | auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType(); |
397 | 70 | auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType(); |
398 | 70 | if (Arg0Type != Arg1Type) |
399 | 58 | return; |
400 | | |
401 | 12 | auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference); |
402 | 12 | if (ObjectLoc == nullptr) |
403 | 0 | return; |
404 | | |
405 | 12 | auto *Val = Env.getValue(*Arg1, SkipPast::Reference); |
406 | 12 | if (Val == nullptr) |
407 | 0 | return; |
408 | | |
409 | | // Assign a value to the storage location of the object. |
410 | 12 | Env.setValue(*ObjectLoc, *Val); |
411 | | |
412 | | // FIXME: Add a test for the value of the whole expression. |
413 | | // Assign a storage location for the whole expression. |
414 | 12 | Env.setStorageLocation(*S, *ObjectLoc); |
415 | 12 | } |
416 | 132 | } |
417 | | |
418 | 10 | void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) { |
419 | 10 | if (S->getCastKind() == CK_ConstructorConversion) { |
420 | 10 | const Expr *SubExpr = S->getSubExpr(); |
421 | 10 | assert(SubExpr != nullptr); |
422 | | |
423 | 0 | auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); |
424 | 10 | if (SubExprLoc == nullptr) |
425 | 0 | return; |
426 | | |
427 | 10 | Env.setStorageLocation(*S, *SubExprLoc); |
428 | 10 | } |
429 | 10 | } |
430 | | |
431 | 50 | void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) { |
432 | 50 | auto &Loc = Env.createStorageLocation(*S); |
433 | 50 | Env.setStorageLocation(*S, Loc); |
434 | 50 | if (Value *Val = Env.createValue(S->getType())) |
435 | 50 | Env.setValue(Loc, *Val); |
436 | 50 | } |
437 | | |
438 | 656 | void VisitCallExpr(const CallExpr *S) { |
439 | | // Of clang's builtins, only `__builtin_expect` is handled explicitly, since |
440 | | // others (like trap, debugtrap, and unreachable) are handled by CFG |
441 | | // construction. |
442 | 656 | if (S->isCallToStdMove()) { |
443 | 26 | assert(S->getNumArgs() == 1); |
444 | | |
445 | 0 | const Expr *Arg = S->getArg(0); |
446 | 26 | assert(Arg != nullptr); |
447 | | |
448 | 0 | auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None); |
449 | 26 | if (ArgLoc == nullptr) |
450 | 0 | return; |
451 | | |
452 | 26 | Env.setStorageLocation(*S, *ArgLoc); |
453 | 630 | } else if (S->getDirectCallee() != nullptr && |
454 | 630 | S->getDirectCallee()->getBuiltinID() == |
455 | 630 | Builtin::BI__builtin_expect) { |
456 | 4 | assert(S->getNumArgs() > 0); |
457 | 0 | assert(S->getArg(0) != nullptr); |
458 | | // `__builtin_expect` returns by-value, so strip away any potential |
459 | | // references in the argument. |
460 | 0 | auto *ArgLoc = Env.getStorageLocation(*S->getArg(0), SkipPast::Reference); |
461 | 4 | if (ArgLoc == nullptr) |
462 | 0 | return; |
463 | 4 | Env.setStorageLocation(*S, *ArgLoc); |
464 | 4 | } |
465 | 656 | } |
466 | | |
467 | 262 | void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) { |
468 | 262 | const Expr *SubExpr = S->getSubExpr(); |
469 | 262 | assert(SubExpr != nullptr); |
470 | | |
471 | 0 | auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); |
472 | 262 | if (SubExprLoc == nullptr) |
473 | 188 | return; |
474 | | |
475 | 74 | Env.setStorageLocation(*S, *SubExprLoc); |
476 | 74 | } |
477 | | |
478 | 36 | void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) { |
479 | 36 | const Expr *SubExpr = S->getSubExpr(); |
480 | 36 | assert(SubExpr != nullptr); |
481 | | |
482 | 0 | auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); |
483 | 36 | if (SubExprLoc == nullptr) |
484 | 20 | return; |
485 | | |
486 | 16 | Env.setStorageLocation(*S, *SubExprLoc); |
487 | 16 | } |
488 | | |
489 | 2 | void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) { |
490 | 2 | if (S->getCastKind() == CK_NoOp) { |
491 | 2 | const Expr *SubExpr = S->getSubExpr(); |
492 | 2 | assert(SubExpr != nullptr); |
493 | | |
494 | 0 | auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None); |
495 | 2 | if (SubExprLoc == nullptr) |
496 | 0 | return; |
497 | | |
498 | 2 | Env.setStorageLocation(*S, *SubExprLoc); |
499 | 2 | } |
500 | 2 | } |
501 | | |
502 | 24 | void VisitConditionalOperator(const ConditionalOperator *S) { |
503 | | // FIXME: Revisit this once flow conditions are added to the framework. For |
504 | | // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow |
505 | | // condition. |
506 | 24 | auto &Loc = Env.createStorageLocation(*S); |
507 | 24 | Env.setStorageLocation(*S, Loc); |
508 | 24 | if (Value *Val = Env.createValue(S->getType())) |
509 | 16 | Env.setValue(Loc, *Val); |
510 | 24 | } |
511 | | |
512 | 20 | void VisitInitListExpr(const InitListExpr *S) { |
513 | 20 | QualType Type = S->getType(); |
514 | | |
515 | 20 | auto &Loc = Env.createStorageLocation(*S); |
516 | 20 | Env.setStorageLocation(*S, Loc); |
517 | | |
518 | 20 | auto *Val = Env.createValue(Type); |
519 | 20 | if (Val == nullptr) |
520 | 12 | return; |
521 | | |
522 | 8 | Env.setValue(Loc, *Val); |
523 | | |
524 | 8 | if (Type->isStructureOrClassType()) { |
525 | 16 | for (auto IT : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) { |
526 | 16 | const FieldDecl *Field = std::get<0>(IT); |
527 | 16 | assert(Field != nullptr); |
528 | | |
529 | 0 | const Expr *Init = std::get<1>(IT); |
530 | 16 | assert(Init != nullptr); |
531 | | |
532 | 16 | if (Value *InitVal = Env.getValue(*Init, SkipPast::None)) |
533 | 16 | cast<StructValue>(Val)->setChild(*Field, *InitVal); |
534 | 16 | } |
535 | 8 | } |
536 | | // FIXME: Implement array initialization. |
537 | 8 | } |
538 | | |
539 | 60 | void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) { |
540 | 60 | auto &Loc = Env.createStorageLocation(*S); |
541 | 60 | Env.setStorageLocation(*S, Loc); |
542 | 60 | Env.setValue(Loc, Env.getBoolLiteralValue(S->getValue())); |
543 | 60 | } |
544 | | |
545 | 8 | void VisitParenExpr(const ParenExpr *S) { |
546 | | // The CFG does not contain `ParenExpr` as top-level statements in basic |
547 | | // blocks, however manual traversal to sub-expressions may encounter them. |
548 | | // Redirect to the sub-expression. |
549 | 8 | auto *SubExpr = S->getSubExpr(); |
550 | 8 | assert(SubExpr != nullptr); |
551 | 0 | Visit(SubExpr); |
552 | 8 | } |
553 | | |
554 | 0 | void VisitExprWithCleanups(const ExprWithCleanups *S) { |
555 | | // The CFG does not contain `ExprWithCleanups` as top-level statements in |
556 | | // basic blocks, however manual traversal to sub-expressions may encounter |
557 | | // them. Redirect to the sub-expression. |
558 | 0 | auto *SubExpr = S->getSubExpr(); |
559 | 0 | assert(SubExpr != nullptr); |
560 | 0 | Visit(SubExpr); |
561 | 0 | } |
562 | | |
563 | | private: |
564 | 48 | BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) { |
565 | | // `SubExpr` and its parent logic operator might be part of different basic |
566 | | // blocks. We try to access the value that is assigned to `SubExpr` in the |
567 | | // corresponding environment. |
568 | 48 | if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) { |
569 | 48 | if (auto *Val = dyn_cast_or_null<BoolValue>( |
570 | 48 | SubExprEnv->getValue(SubExpr, SkipPast::Reference))) |
571 | 44 | return *Val; |
572 | 48 | } |
573 | | |
574 | | // Sub-expressions that are logic operators are not added in basic blocks |
575 | | // (e.g. see CFG for `bool d = a && (b || c);`). If `SubExpr` is a logic |
576 | | // operator, it isn't evaluated and assigned a value yet. In that case, we |
577 | | // need to first visit `SubExpr` and then try to get the value that gets |
578 | | // assigned to it. |
579 | 4 | Visit(&SubExpr); |
580 | 4 | if (auto *Val = dyn_cast_or_null<BoolValue>( |
581 | 4 | Env.getValue(SubExpr, SkipPast::Reference))) |
582 | 4 | return *Val; |
583 | | |
584 | | // If the value of `SubExpr` is still unknown, we create a fresh symbolic |
585 | | // boolean value for it. |
586 | 0 | return Env.makeAtomicBoolValue(); |
587 | 4 | } |
588 | | |
589 | | const StmtToEnvMap &StmtToEnv; |
590 | | Environment &Env; |
591 | | }; |
592 | | |
593 | 5.80k | void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) { |
594 | 5.80k | TransferVisitor(StmtToEnv, Env).Visit(&S); |
595 | 5.80k | } |
596 | | |
597 | | } // namespace dataflow |
598 | | } // namespace clang |