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/Expr.h"
18 #include "clang/AST/ExprCXX.h"
19 #include "clang/AST/OperationKinds.h"
20 #include "clang/AST/Stmt.h"
21 #include "clang/AST/StmtVisitor.h"
22 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
23 #include "clang/Basic/OperatorKinds.h"
24 #include "llvm/Support/Casting.h"
25 #include <cassert>
26 #include <memory>
27 
28 namespace clang {
29 namespace dataflow {
30 
31 class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
32 public:
33   TransferVisitor(Environment &Env) : Env(Env) {}
34 
35   void VisitBinaryOperator(const BinaryOperator *S) {
36     if (S->getOpcode() == BO_Assign) {
37       // The CFG does not contain `ParenExpr` as top-level statements in basic
38       // blocks, however sub-expressions can still be of that type.
39       assert(S->getLHS() != nullptr);
40       const Expr *LHS = S->getLHS()->IgnoreParens();
41 
42       assert(LHS != nullptr);
43       auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference);
44       if (LHSLoc == nullptr)
45         return;
46 
47       // The CFG does not contain `ParenExpr` as top-level statements in basic
48       // blocks, however sub-expressions can still be of that type.
49       assert(S->getRHS() != nullptr);
50       const Expr *RHS = S->getRHS()->IgnoreParens();
51 
52       assert(RHS != nullptr);
53       Value *RHSVal = Env.getValue(*RHS, SkipPast::Reference);
54       if (RHSVal == nullptr)
55         return;
56 
57       // Assign a value to the storage location of the left-hand side.
58       Env.setValue(*LHSLoc, *RHSVal);
59 
60       // Assign a storage location for the whole expression.
61       Env.setStorageLocation(*S, *LHSLoc);
62     }
63     // FIXME: Add support for BO_EQ, BO_NE.
64   }
65 
66   void VisitDeclRefExpr(const DeclRefExpr *S) {
67     assert(S->getDecl() != nullptr);
68     auto *DeclLoc = Env.getStorageLocation(*S->getDecl(), SkipPast::None);
69     if (DeclLoc == nullptr)
70       return;
71 
72     if (S->getDecl()->getType()->isReferenceType()) {
73       Env.setStorageLocation(*S, *DeclLoc);
74     } else {
75       auto &Loc = Env.createStorageLocation(*S);
76       auto &Val = Env.takeOwnership(std::make_unique<ReferenceValue>(*DeclLoc));
77       Env.setStorageLocation(*S, Loc);
78       Env.setValue(Loc, Val);
79     }
80   }
81 
82   void VisitDeclStmt(const DeclStmt *S) {
83     // FIXME: Add support for group decls, e.g: `int a, b;`
84     if (S->isSingleDecl()) {
85       if (const auto *D = dyn_cast<VarDecl>(S->getSingleDecl())) {
86         visitVarDecl(*D);
87       }
88     }
89   }
90 
91   void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
92     if (S->getCastKind() == CK_LValueToRValue) {
93       // The CFG does not contain `ParenExpr` as top-level statements in basic
94       // blocks, however sub-expressions can still be of that type.
95       assert(S->getSubExpr() != nullptr);
96       const Expr *SubExpr = S->getSubExpr()->IgnoreParens();
97 
98       assert(SubExpr != nullptr);
99       auto *SubExprVal = Env.getValue(*SubExpr, SkipPast::Reference);
100       if (SubExprVal == nullptr)
101         return;
102 
103       auto &ExprLoc = Env.createStorageLocation(*S);
104       Env.setStorageLocation(*S, ExprLoc);
105       Env.setValue(ExprLoc, *SubExprVal);
106     }
107     // FIXME: Add support for CK_NoOp, CK_UserDefinedConversion,
108     // CK_ConstructorConversion, CK_UncheckedDerivedToBase.
109   }
110 
111   void VisitUnaryOperator(const UnaryOperator *S) {
112     if (S->getOpcode() == UO_Deref) {
113       assert(S->getSubExpr() != nullptr);
114       const auto *SubExprVal = cast_or_null<PointerValue>(
115           Env.getValue(*S->getSubExpr(), SkipPast::Reference));
116       if (SubExprVal == nullptr)
117         return;
118 
119       auto &Loc = Env.createStorageLocation(*S);
120       Env.setStorageLocation(*S, Loc);
121       Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(
122                             SubExprVal->getPointeeLoc())));
123     }
124     // FIXME: Add support for UO_AddrOf, UO_LNot.
125   }
126 
127   void VisitCXXThisExpr(const CXXThisExpr *S) {
128     auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
129     assert(ThisPointeeLoc != nullptr);
130 
131     auto &Loc = Env.createStorageLocation(*S);
132     Env.setStorageLocation(*S, Loc);
133     Env.setValue(Loc, Env.takeOwnership(
134                           std::make_unique<PointerValue>(*ThisPointeeLoc)));
135   }
136 
137   void VisitMemberExpr(const MemberExpr *S) {
138     ValueDecl *Member = S->getMemberDecl();
139     assert(Member != nullptr);
140 
141     // FIXME: Consider assigning pointer values to function member expressions.
142     if (Member->isFunctionOrFunctionTemplate())
143       return;
144 
145     // The receiver can be either a value or a pointer to a value. Skip past the
146     // indirection to handle both cases.
147     auto *BaseLoc = cast_or_null<AggregateStorageLocation>(
148         Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer));
149     if (BaseLoc == nullptr)
150       return;
151 
152     // FIXME: Add support for union types.
153     if (BaseLoc->getType()->isUnionType())
154       return;
155 
156     auto &MemberLoc = BaseLoc->getChild(*Member);
157     if (MemberLoc.getType()->isReferenceType()) {
158       Env.setStorageLocation(*S, MemberLoc);
159     } else {
160       auto &Loc = Env.createStorageLocation(*S);
161       Env.setStorageLocation(*S, Loc);
162       Env.setValue(
163           Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(MemberLoc)));
164     }
165   }
166 
167   void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
168     const Expr *InitExpr = S->getExpr();
169     assert(InitExpr != nullptr);
170 
171     Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None);
172     if (InitExprVal == nullptr)
173       return;
174 
175     const FieldDecl *Field = S->getField();
176     assert(Field != nullptr);
177 
178     auto &ThisLoc =
179         *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
180     auto &FieldLoc = ThisLoc.getChild(*Field);
181     Env.setValue(FieldLoc, *InitExprVal);
182   }
183 
184   // FIXME: Add support for:
185   // - CallExpr
186   // - CXXBindTemporaryExpr
187   // - CXXBoolLiteralExpr
188   // - CXXConstructExpr
189   // - CXXFunctionalCastExpr
190   // - CXXOperatorCallExpr
191   // - CXXStaticCastExpr
192   // - MaterializeTemporaryExpr
193 
194 private:
195   void visitVarDecl(const VarDecl &D) {
196     auto &Loc = Env.createStorageLocation(D);
197     Env.setStorageLocation(D, Loc);
198 
199     const Expr *InitExpr = D.getInit();
200     if (InitExpr == nullptr) {
201       // No initializer expression - associate `Loc` with a new value.
202       Env.initValueInStorageLocation(Loc, D.getType());
203       return;
204     }
205 
206     if (D.getType()->isReferenceType()) {
207       // Initializing a reference variable - do not create a reference to
208       // reference.
209       if (auto *InitExprLoc =
210               Env.getStorageLocation(*InitExpr, SkipPast::Reference)) {
211         auto &Val =
212             Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc));
213         Env.setValue(Loc, Val);
214       } else {
215         // FIXME: The initializer expression must always be assigned a value.
216         // Replace this with an assert when we have sufficient coverage of
217         // language features.
218         Env.initValueInStorageLocation(Loc, D.getType());
219       }
220       return;
221     }
222 
223     if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) {
224       Env.setValue(Loc, *InitExprVal);
225     } else {
226       // FIXME: The initializer expression must always be assigned a value.
227       // Replace this with an assert when we have sufficient coverage of
228       // language features.
229       Env.initValueInStorageLocation(Loc, D.getType());
230     }
231   }
232 
233   Environment &Env;
234 };
235 
236 void transfer(const Stmt &S, Environment &Env) {
237   assert(!isa<ParenExpr>(&S));
238   TransferVisitor(Env).Visit(&S);
239 }
240 
241 } // namespace dataflow
242 } // namespace clang
243