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