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