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   // FIXME: Add support for:
168   // - CallExpr
169   // - CXXBindTemporaryExpr
170   // - CXXBoolLiteralExpr
171   // - CXXConstructExpr
172   // - CXXFunctionalCastExpr
173   // - CXXOperatorCallExpr
174   // - CXXStaticCastExpr
175   // - MaterializeTemporaryExpr
176 
177 private:
178   void visitVarDecl(const VarDecl &D) {
179     auto &Loc = Env.createStorageLocation(D);
180     Env.setStorageLocation(D, Loc);
181 
182     const Expr *InitExpr = D.getInit();
183     if (InitExpr == nullptr) {
184       // No initializer expression - associate `Loc` with a new value.
185       Env.initValueInStorageLocation(Loc, D.getType());
186       return;
187     }
188 
189     if (D.getType()->isReferenceType()) {
190       // Initializing a reference variable - do not create a reference to
191       // reference.
192       if (auto *InitExprLoc =
193               Env.getStorageLocation(*InitExpr, SkipPast::Reference)) {
194         auto &Val =
195             Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc));
196         Env.setValue(Loc, Val);
197       } else {
198         // FIXME: The initializer expression must always be assigned a value.
199         // Replace this with an assert when we have sufficient coverage of
200         // language features.
201         Env.initValueInStorageLocation(Loc, D.getType());
202       }
203       return;
204     }
205 
206     if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) {
207       Env.setValue(Loc, *InitExprVal);
208     } else {
209       // FIXME: The initializer expression must always be assigned a value.
210       // Replace this with an assert when we have sufficient coverage of
211       // language features.
212       Env.initValueInStorageLocation(Loc, D.getType());
213     }
214   }
215 
216   Environment &Env;
217 };
218 
219 void transfer(const Stmt &S, Environment &Env) {
220   assert(!isa<ParenExpr>(&S));
221   TransferVisitor(Env).Visit(&S);
222 }
223 
224 } // namespace dataflow
225 } // namespace clang
226