xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/Transfer.cpp (revision d5b0e70f7e04d971691517ce1304d86a1e367e2e)
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/Basic/OperatorKinds.h"
25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/Support/Casting.h"
27 #include <cassert>
28 #include <memory>
29 #include <tuple>
30 
31 namespace clang {
32 namespace dataflow {
33 
34 static const Expr *skipExprWithCleanups(const Expr *E) {
35   if (auto *C = dyn_cast_or_null<ExprWithCleanups>(E))
36     return C->getSubExpr();
37   return E;
38 }
39 
40 class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
41 public:
42   TransferVisitor(Environment &Env) : Env(Env) {}
43 
44   void VisitBinaryOperator(const BinaryOperator *S) {
45     if (S->getOpcode() == BO_Assign) {
46       // The CFG does not contain `ParenExpr` as top-level statements in basic
47       // blocks, however sub-expressions can still be of that type.
48       assert(S->getLHS() != nullptr);
49       const Expr *LHS = S->getLHS()->IgnoreParens();
50 
51       assert(LHS != nullptr);
52       auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference);
53       if (LHSLoc == nullptr)
54         return;
55 
56       // The CFG does not contain `ParenExpr` as top-level statements in basic
57       // blocks, however sub-expressions can still be of that type.
58       assert(S->getRHS() != nullptr);
59       const Expr *RHS = S->getRHS()->IgnoreParens();
60 
61       assert(RHS != nullptr);
62       Value *RHSVal = Env.getValue(*RHS, SkipPast::Reference);
63       if (RHSVal == nullptr)
64         return;
65 
66       // Assign a value to the storage location of the left-hand side.
67       Env.setValue(*LHSLoc, *RHSVal);
68 
69       // Assign a storage location for the whole expression.
70       Env.setStorageLocation(*S, *LHSLoc);
71     }
72     // FIXME: Add support for BO_EQ, BO_NE.
73   }
74 
75   void VisitDeclRefExpr(const DeclRefExpr *S) {
76     assert(S->getDecl() != nullptr);
77     auto *DeclLoc = Env.getStorageLocation(*S->getDecl(), SkipPast::None);
78     if (DeclLoc == nullptr)
79       return;
80 
81     if (S->getDecl()->getType()->isReferenceType()) {
82       Env.setStorageLocation(*S, *DeclLoc);
83     } else {
84       auto &Loc = Env.createStorageLocation(*S);
85       auto &Val = Env.takeOwnership(std::make_unique<ReferenceValue>(*DeclLoc));
86       Env.setStorageLocation(*S, Loc);
87       Env.setValue(Loc, Val);
88     }
89   }
90 
91   void VisitDeclStmt(const DeclStmt *S) {
92     // Group decls are converted into single decls in the CFG so the cast below
93     // is safe.
94     const auto &D = *cast<VarDecl>(S->getSingleDecl());
95     auto &Loc = Env.createStorageLocation(D);
96     Env.setStorageLocation(D, Loc);
97 
98     const Expr *InitExpr = D.getInit();
99     if (InitExpr == nullptr) {
100       // No initializer expression - associate `Loc` with a new value.
101       if (Value *Val = Env.createValue(D.getType()))
102         Env.setValue(Loc, *Val);
103       return;
104     }
105 
106     // The CFG does not contain `ParenExpr` as top-level statements in basic
107     // blocks, however sub-expressions can still be of that type.
108     InitExpr = skipExprWithCleanups(D.getInit()->IgnoreParens());
109     assert(InitExpr != nullptr);
110 
111     if (D.getType()->isReferenceType()) {
112       // Initializing a reference variable - do not create a reference to
113       // reference.
114       if (auto *InitExprLoc =
115               Env.getStorageLocation(*InitExpr, SkipPast::Reference)) {
116         auto &Val =
117             Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc));
118         Env.setValue(Loc, Val);
119       } else {
120         // FIXME: The initializer expression must always be assigned a value.
121         // Replace this with an assert when we have sufficient coverage of
122         // language features.
123         if (Value *Val = Env.createValue(D.getType()))
124           Env.setValue(Loc, *Val);
125       }
126       return;
127     }
128 
129     if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) {
130       Env.setValue(Loc, *InitExprVal);
131     } else if (!D.getType()->isStructureOrClassType()) {
132       // FIXME: The initializer expression must always be assigned a value.
133       // Replace this with an assert when we have sufficient coverage of
134       // language features.
135       if (Value *Val = Env.createValue(D.getType()))
136         Env.setValue(Loc, *Val);
137     } else {
138       llvm_unreachable("structs and classes must always be assigned values");
139     }
140   }
141 
142   void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
143     // The CFG does not contain `ParenExpr` as top-level statements in basic
144     // blocks, however sub-expressions can still be of that type.
145     assert(S->getSubExpr() != nullptr);
146     const Expr *SubExpr = S->getSubExpr()->IgnoreParens();
147     assert(SubExpr != nullptr);
148 
149     switch (S->getCastKind()) {
150     case CK_LValueToRValue: {
151       auto *SubExprVal = Env.getValue(*SubExpr, SkipPast::Reference);
152       if (SubExprVal == nullptr)
153         break;
154 
155       auto &ExprLoc = Env.createStorageLocation(*S);
156       Env.setStorageLocation(*S, ExprLoc);
157       Env.setValue(ExprLoc, *SubExprVal);
158       break;
159     }
160     case CK_NoOp: {
161       // FIXME: Consider making `Environment::getStorageLocation` skip noop
162       // expressions (this and other similar expressions in the file) instead of
163       // assigning them storage locations.
164       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
165       if (SubExprLoc == nullptr)
166         break;
167 
168       Env.setStorageLocation(*S, *SubExprLoc);
169       break;
170     }
171     default:
172       // FIXME: Add support for CK_UserDefinedConversion,
173       // CK_ConstructorConversion, CK_UncheckedDerivedToBase.
174       break;
175     }
176   }
177 
178   void VisitUnaryOperator(const UnaryOperator *S) {
179     // The CFG does not contain `ParenExpr` as top-level statements in basic
180     // blocks, however sub-expressions can still be of that type.
181     assert(S->getSubExpr() != nullptr);
182     const Expr *SubExpr = S->getSubExpr()->IgnoreParens();
183     assert(SubExpr != nullptr);
184 
185     switch (S->getOpcode()) {
186     case UO_Deref: {
187       // Skip past a reference to handle dereference of a dependent pointer.
188       const auto *SubExprVal = cast_or_null<PointerValue>(
189           Env.getValue(*SubExpr, SkipPast::Reference));
190       if (SubExprVal == nullptr)
191         break;
192 
193       auto &Loc = Env.createStorageLocation(*S);
194       Env.setStorageLocation(*S, Loc);
195       Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(
196                             SubExprVal->getPointeeLoc())));
197       break;
198     }
199     case UO_AddrOf: {
200       // Do not form a pointer to a reference. If `SubExpr` is assigned a
201       // `ReferenceValue` then form a value that points to the location of its
202       // pointee.
203       StorageLocation *PointeeLoc =
204           Env.getStorageLocation(*SubExpr, SkipPast::Reference);
205       if (PointeeLoc == nullptr)
206         break;
207 
208       auto &PointerLoc = Env.createStorageLocation(*S);
209       auto &PointerVal =
210           Env.takeOwnership(std::make_unique<PointerValue>(*PointeeLoc));
211       Env.setStorageLocation(*S, PointerLoc);
212       Env.setValue(PointerLoc, PointerVal);
213       break;
214     }
215     default:
216       // FIXME: Add support for UO_LNot.
217       break;
218     }
219   }
220 
221   void VisitCXXThisExpr(const CXXThisExpr *S) {
222     auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
223     assert(ThisPointeeLoc != nullptr);
224 
225     auto &Loc = Env.createStorageLocation(*S);
226     Env.setStorageLocation(*S, Loc);
227     Env.setValue(Loc, Env.takeOwnership(
228                           std::make_unique<PointerValue>(*ThisPointeeLoc)));
229   }
230 
231   void VisitMemberExpr(const MemberExpr *S) {
232     ValueDecl *Member = S->getMemberDecl();
233     assert(Member != nullptr);
234 
235     // FIXME: Consider assigning pointer values to function member expressions.
236     if (Member->isFunctionOrFunctionTemplate())
237       return;
238 
239     // The receiver can be either a value or a pointer to a value. Skip past the
240     // indirection to handle both cases.
241     auto *BaseLoc = cast_or_null<AggregateStorageLocation>(
242         Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer));
243     if (BaseLoc == nullptr)
244       return;
245 
246     // FIXME: Add support for union types.
247     if (BaseLoc->getType()->isUnionType())
248       return;
249 
250     auto &MemberLoc = BaseLoc->getChild(*Member);
251     if (MemberLoc.getType()->isReferenceType()) {
252       Env.setStorageLocation(*S, MemberLoc);
253     } else {
254       auto &Loc = Env.createStorageLocation(*S);
255       Env.setStorageLocation(*S, Loc);
256       Env.setValue(
257           Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(MemberLoc)));
258     }
259   }
260 
261   void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
262     const Expr *InitExpr = S->getExpr();
263     assert(InitExpr != nullptr);
264 
265     Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None);
266     if (InitExprVal == nullptr)
267       return;
268 
269     const FieldDecl *Field = S->getField();
270     assert(Field != nullptr);
271 
272     auto &ThisLoc =
273         *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
274     auto &FieldLoc = ThisLoc.getChild(*Field);
275     Env.setValue(FieldLoc, *InitExprVal);
276   }
277 
278   void VisitCXXConstructExpr(const CXXConstructExpr *S) {
279     const CXXConstructorDecl *ConstructorDecl = S->getConstructor();
280     assert(ConstructorDecl != nullptr);
281 
282     if (ConstructorDecl->isCopyOrMoveConstructor()) {
283       assert(S->getNumArgs() == 1);
284 
285       const Expr *Arg = S->getArg(0);
286       assert(Arg != nullptr);
287 
288       if (S->isElidable()) {
289         auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
290         if (ArgLoc == nullptr)
291           return;
292 
293         Env.setStorageLocation(*S, *ArgLoc);
294       } else if (auto *ArgVal = Env.getValue(*Arg, SkipPast::Reference)) {
295         auto &Loc = Env.createStorageLocation(*S);
296         Env.setStorageLocation(*S, Loc);
297         Env.setValue(Loc, *ArgVal);
298       }
299       return;
300     }
301 
302     auto &Loc = Env.createStorageLocation(*S);
303     Env.setStorageLocation(*S, Loc);
304     if (Value *Val = Env.createValue(S->getType()))
305       Env.setValue(Loc, *Val);
306   }
307 
308   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
309     if (S->getOperator() == OO_Equal) {
310       assert(S->getNumArgs() == 2);
311 
312       const Expr *Arg0 = S->getArg(0);
313       assert(Arg0 != nullptr);
314 
315       const Expr *Arg1 = S->getArg(1);
316       assert(Arg1 != nullptr);
317 
318       // Evaluate only copy and move assignment operators.
319       auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType();
320       auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType();
321       if (Arg0Type != Arg1Type)
322         return;
323 
324       auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference);
325       if (ObjectLoc == nullptr)
326         return;
327 
328       auto *Val = Env.getValue(*Arg1, SkipPast::Reference);
329       if (Val == nullptr)
330         return;
331 
332       Env.setValue(*ObjectLoc, *Val);
333     }
334   }
335 
336   void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
337     if (S->getCastKind() == CK_ConstructorConversion) {
338       // The CFG does not contain `ParenExpr` as top-level statements in basic
339       // blocks, however sub-expressions can still be of that type.
340       assert(S->getSubExpr() != nullptr);
341       const Expr *SubExpr = S->getSubExpr();
342       assert(SubExpr != nullptr);
343 
344       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
345       if (SubExprLoc == nullptr)
346         return;
347 
348       Env.setStorageLocation(*S, *SubExprLoc);
349     }
350   }
351 
352   void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
353     auto &Loc = Env.createStorageLocation(*S);
354     Env.setStorageLocation(*S, Loc);
355     if (Value *Val = Env.createValue(S->getType()))
356       Env.setValue(Loc, *Val);
357   }
358 
359   void VisitCallExpr(const CallExpr *S) {
360     if (S->isCallToStdMove()) {
361       assert(S->getNumArgs() == 1);
362 
363       const Expr *Arg = S->getArg(0);
364       assert(Arg != nullptr);
365 
366       auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None);
367       if (ArgLoc == nullptr)
368         return;
369 
370       Env.setStorageLocation(*S, *ArgLoc);
371     }
372   }
373 
374   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
375     const Expr *SubExpr = S->getSubExpr();
376     assert(SubExpr != nullptr);
377 
378     auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
379     if (SubExprLoc == nullptr)
380       return;
381 
382     Env.setStorageLocation(*S, *SubExprLoc);
383   }
384 
385   void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {
386     const Expr *SubExpr = S->getSubExpr();
387     assert(SubExpr != nullptr);
388 
389     auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
390     if (SubExprLoc == nullptr)
391       return;
392 
393     Env.setStorageLocation(*S, *SubExprLoc);
394   }
395 
396   void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
397     if (S->getCastKind() == CK_NoOp) {
398       const Expr *SubExpr = S->getSubExpr();
399       assert(SubExpr != nullptr);
400 
401       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
402       if (SubExprLoc == nullptr)
403         return;
404 
405       Env.setStorageLocation(*S, *SubExprLoc);
406     }
407   }
408 
409   void VisitConditionalOperator(const ConditionalOperator *S) {
410     // FIXME: Revisit this once flow conditions are added to the framework. For
411     // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow
412     // condition.
413     auto &Loc = Env.createStorageLocation(*S);
414     Env.setStorageLocation(*S, Loc);
415     if (Value *Val = Env.createValue(S->getType()))
416       Env.setValue(Loc, *Val);
417   }
418 
419   void VisitInitListExpr(const InitListExpr *S) {
420     QualType Type = S->getType();
421 
422     auto &Loc = Env.createStorageLocation(*S);
423     Env.setStorageLocation(*S, Loc);
424 
425     auto *Val = Env.createValue(Type);
426     if (Val == nullptr)
427       return;
428 
429     Env.setValue(Loc, *Val);
430 
431     if (Type->isStructureOrClassType()) {
432       for (auto IT : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
433         const FieldDecl *Field = std::get<0>(IT);
434         assert(Field != nullptr);
435 
436         const Expr *Init = std::get<1>(IT);
437         assert(Init != nullptr);
438 
439         if (Value *InitVal = Env.getValue(*Init, SkipPast::None))
440           cast<StructValue>(Val)->setChild(*Field, *InitVal);
441       }
442     }
443     // FIXME: Implement array initialization.
444   }
445 
446   void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
447     auto &Loc = Env.createStorageLocation(*S);
448     Env.setStorageLocation(*S, Loc);
449     Env.setValue(Loc, Env.getBoolLiteralValue(S->getValue()));
450   }
451 
452 private:
453   Environment &Env;
454 };
455 
456 void transfer(const Stmt &S, Environment &Env) {
457   assert(!isa<ParenExpr>(&S));
458   TransferVisitor(Env).Visit(&S);
459 }
460 
461 } // namespace dataflow
462 } // namespace clang
463