1b000b770SStanislav Gatev //===-- UncheckedOptionalAccessModel.cpp ------------------------*- C++ -*-===// 2b000b770SStanislav Gatev // 3b000b770SStanislav Gatev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4b000b770SStanislav Gatev // See https://llvm.org/LICENSE.txt for license information. 5b000b770SStanislav Gatev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6b000b770SStanislav Gatev // 7b000b770SStanislav Gatev //===----------------------------------------------------------------------===// 8b000b770SStanislav Gatev // 9b000b770SStanislav Gatev // This file defines a dataflow analysis that detects unsafe uses of optional 10b000b770SStanislav Gatev // values. 11b000b770SStanislav Gatev // 12b000b770SStanislav Gatev //===----------------------------------------------------------------------===// 13b000b770SStanislav Gatev 14af98b0afSStanislav Gatev #include "clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h" 15af98b0afSStanislav Gatev #include "clang/AST/ASTContext.h" 16af98b0afSStanislav Gatev #include "clang/AST/Expr.h" 17af98b0afSStanislav Gatev #include "clang/AST/ExprCXX.h" 18af98b0afSStanislav Gatev #include "clang/AST/Stmt.h" 19af98b0afSStanislav Gatev #include "clang/ASTMatchers/ASTMatchers.h" 20af98b0afSStanislav Gatev #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 21af98b0afSStanislav Gatev #include "clang/Analysis/FlowSensitive/MatchSwitch.h" 22af98b0afSStanislav Gatev #include "clang/Analysis/FlowSensitive/SourceLocationsLattice.h" 23af98b0afSStanislav Gatev #include "clang/Analysis/FlowSensitive/Value.h" 24af98b0afSStanislav Gatev #include "llvm/ADT/StringRef.h" 25af98b0afSStanislav Gatev #include "llvm/Support/Casting.h" 26af98b0afSStanislav Gatev #include <cassert> 279e0fc676SStanislav Gatev #include <memory> 289e0fc676SStanislav Gatev #include <utility> 29af98b0afSStanislav Gatev 30af98b0afSStanislav Gatev namespace clang { 31af98b0afSStanislav Gatev namespace dataflow { 32af98b0afSStanislav Gatev namespace { 33af98b0afSStanislav Gatev 34af98b0afSStanislav Gatev using namespace ::clang::ast_matchers; 35af98b0afSStanislav Gatev 36af98b0afSStanislav Gatev using LatticeTransferState = TransferState<SourceLocationsLattice>; 37af98b0afSStanislav Gatev 38092a530cSStanislav Gatev auto optionalClass() { 39af98b0afSStanislav Gatev return classTemplateSpecializationDecl( 40af98b0afSStanislav Gatev anyOf(hasName("std::optional"), hasName("std::__optional_storage_base"), 41af98b0afSStanislav Gatev hasName("__optional_destruct_base"), hasName("absl::optional"), 42af98b0afSStanislav Gatev hasName("base::Optional")), 43af98b0afSStanislav Gatev hasTemplateArgument(0, refersToType(type().bind("T")))); 44af98b0afSStanislav Gatev } 45af98b0afSStanislav Gatev 46092a530cSStanislav Gatev auto hasOptionalType() { return hasType(optionalClass()); } 47af98b0afSStanislav Gatev 48092a530cSStanislav Gatev auto isOptionalMemberCallWithName(llvm::StringRef MemberName) { 49af98b0afSStanislav Gatev return cxxMemberCallExpr( 50af98b0afSStanislav Gatev on(expr(unless(cxxThisExpr()))), 51af98b0afSStanislav Gatev callee(cxxMethodDecl(hasName(MemberName), ofClass(optionalClass())))); 52af98b0afSStanislav Gatev } 53af98b0afSStanislav Gatev 54092a530cSStanislav Gatev auto isOptionalOperatorCallWithName(llvm::StringRef OperatorName) { 55af98b0afSStanislav Gatev return cxxOperatorCallExpr(hasOverloadedOperatorName(OperatorName), 56af98b0afSStanislav Gatev callee(cxxMethodDecl(ofClass(optionalClass())))); 57af98b0afSStanislav Gatev } 58af98b0afSStanislav Gatev 59092a530cSStanislav Gatev auto isMakeOptionalCall() { 609e0fc676SStanislav Gatev return callExpr( 619e0fc676SStanislav Gatev callee(functionDecl(hasAnyName( 629e0fc676SStanislav Gatev "std::make_optional", "base::make_optional", "absl::make_optional"))), 639e0fc676SStanislav Gatev hasOptionalType()); 649e0fc676SStanislav Gatev } 659e0fc676SStanislav Gatev 66092a530cSStanislav Gatev auto hasNulloptType() { 67092a530cSStanislav Gatev return hasType(namedDecl( 68092a530cSStanislav Gatev hasAnyName("std::nullopt_t", "absl::nullopt_t", "base::nullopt_t"))); 69092a530cSStanislav Gatev } 70092a530cSStanislav Gatev 71092a530cSStanislav Gatev auto inPlaceClass() { 72092a530cSStanislav Gatev return recordDecl( 73092a530cSStanislav Gatev hasAnyName("std::in_place_t", "absl::in_place_t", "base::in_place_t")); 74092a530cSStanislav Gatev } 75092a530cSStanislav Gatev 76092a530cSStanislav Gatev auto isOptionalNulloptConstructor() { 77092a530cSStanislav Gatev return cxxConstructExpr(hasOptionalType(), argumentCountIs(1), 78092a530cSStanislav Gatev hasArgument(0, hasNulloptType())); 79092a530cSStanislav Gatev } 80092a530cSStanislav Gatev 81092a530cSStanislav Gatev auto isOptionalInPlaceConstructor() { 82092a530cSStanislav Gatev return cxxConstructExpr(hasOptionalType(), 83092a530cSStanislav Gatev hasArgument(0, hasType(inPlaceClass()))); 84092a530cSStanislav Gatev } 85092a530cSStanislav Gatev 86092a530cSStanislav Gatev auto isOptionalValueOrConversionConstructor() { 87092a530cSStanislav Gatev return cxxConstructExpr( 88092a530cSStanislav Gatev hasOptionalType(), 89092a530cSStanislav Gatev unless(hasDeclaration( 90092a530cSStanislav Gatev cxxConstructorDecl(anyOf(isCopyConstructor(), isMoveConstructor())))), 91092a530cSStanislav Gatev argumentCountIs(1), hasArgument(0, unless(hasNulloptType()))); 92092a530cSStanislav Gatev } 93092a530cSStanislav Gatev 94b000b770SStanislav Gatev auto isOptionalValueOrConversionAssignment() { 95b000b770SStanislav Gatev return cxxOperatorCallExpr( 96b000b770SStanislav Gatev hasOverloadedOperatorName("="), 97b000b770SStanislav Gatev callee(cxxMethodDecl(ofClass(optionalClass()))), 98b000b770SStanislav Gatev unless(hasDeclaration(cxxMethodDecl( 99b000b770SStanislav Gatev anyOf(isCopyAssignmentOperator(), isMoveAssignmentOperator())))), 100b000b770SStanislav Gatev argumentCountIs(2), hasArgument(1, unless(hasNulloptType()))); 101b000b770SStanislav Gatev } 102b000b770SStanislav Gatev 103b000b770SStanislav Gatev auto isOptionalNulloptAssignment() { 104b000b770SStanislav Gatev return cxxOperatorCallExpr(hasOverloadedOperatorName("="), 105b000b770SStanislav Gatev callee(cxxMethodDecl(ofClass(optionalClass()))), 106b000b770SStanislav Gatev argumentCountIs(2), 107b000b770SStanislav Gatev hasArgument(1, hasNulloptType())); 108b000b770SStanislav Gatev } 109b000b770SStanislav Gatev 110*2ddd57aeSStanislav Gatev auto isStdSwapCall() { 111*2ddd57aeSStanislav Gatev return callExpr(callee(functionDecl(hasName("std::swap"))), 112*2ddd57aeSStanislav Gatev argumentCountIs(2), hasArgument(0, hasOptionalType()), 113*2ddd57aeSStanislav Gatev hasArgument(1, hasOptionalType())); 114*2ddd57aeSStanislav Gatev } 115*2ddd57aeSStanislav Gatev 1169e0fc676SStanislav Gatev /// Creates a symbolic value for an `optional` value using `HasValueVal` as the 1179e0fc676SStanislav Gatev /// symbolic value of its "has_value" property. 1189e0fc676SStanislav Gatev StructValue &createOptionalValue(Environment &Env, BoolValue &HasValueVal) { 1199e0fc676SStanislav Gatev auto OptionalVal = std::make_unique<StructValue>(); 1209e0fc676SStanislav Gatev OptionalVal->setProperty("has_value", HasValueVal); 1219e0fc676SStanislav Gatev return Env.takeOwnership(std::move(OptionalVal)); 1229e0fc676SStanislav Gatev } 1239e0fc676SStanislav Gatev 124af98b0afSStanislav Gatev /// Returns the symbolic value that represents the "has_value" property of the 125af98b0afSStanislav Gatev /// optional value `Val`. Returns null if `Val` is null. 126092a530cSStanislav Gatev BoolValue *getHasValue(Value *Val) { 127af98b0afSStanislav Gatev if (auto *OptionalVal = cast_or_null<StructValue>(Val)) { 128af98b0afSStanislav Gatev return cast<BoolValue>(OptionalVal->getProperty("has_value")); 129af98b0afSStanislav Gatev } 130af98b0afSStanislav Gatev return nullptr; 131af98b0afSStanislav Gatev } 132af98b0afSStanislav Gatev 133092a530cSStanislav Gatev /// If `Type` is a reference type, returns the type of its pointee. Otherwise, 134092a530cSStanislav Gatev /// returns `Type` itself. 135092a530cSStanislav Gatev QualType stripReference(QualType Type) { 136092a530cSStanislav Gatev return Type->isReferenceType() ? Type->getPointeeType() : Type; 137092a530cSStanislav Gatev } 138092a530cSStanislav Gatev 139092a530cSStanislav Gatev /// Returns true if and only if `Type` is an optional type. 140092a530cSStanislav Gatev bool IsOptionalType(QualType Type) { 141092a530cSStanislav Gatev if (!Type->isRecordType()) 142092a530cSStanislav Gatev return false; 143092a530cSStanislav Gatev // FIXME: Optimize this by avoiding the `getQualifiedNameAsString` call. 144092a530cSStanislav Gatev auto TypeName = Type->getAsCXXRecordDecl()->getQualifiedNameAsString(); 145092a530cSStanislav Gatev return TypeName == "std::optional" || TypeName == "absl::optional" || 146092a530cSStanislav Gatev TypeName == "base::Optional"; 147092a530cSStanislav Gatev } 148092a530cSStanislav Gatev 149092a530cSStanislav Gatev /// Returns the number of optional wrappers in `Type`. 150092a530cSStanislav Gatev /// 151092a530cSStanislav Gatev /// For example, if `Type` is `optional<optional<int>>`, the result of this 152092a530cSStanislav Gatev /// function will be 2. 153092a530cSStanislav Gatev int countOptionalWrappers(const ASTContext &ASTCtx, QualType Type) { 154092a530cSStanislav Gatev if (!IsOptionalType(Type)) 155092a530cSStanislav Gatev return 0; 156092a530cSStanislav Gatev return 1 + countOptionalWrappers( 157092a530cSStanislav Gatev ASTCtx, 158092a530cSStanislav Gatev cast<ClassTemplateSpecializationDecl>(Type->getAsRecordDecl()) 159092a530cSStanislav Gatev ->getTemplateArgs() 160092a530cSStanislav Gatev .get(0) 161092a530cSStanislav Gatev .getAsType() 162092a530cSStanislav Gatev .getDesugaredType(ASTCtx)); 163092a530cSStanislav Gatev } 164092a530cSStanislav Gatev 165092a530cSStanislav Gatev void initializeOptionalReference(const Expr *OptionalExpr, 166092a530cSStanislav Gatev const MatchFinder::MatchResult &, 167af98b0afSStanislav Gatev LatticeTransferState &State) { 168af98b0afSStanislav Gatev if (auto *OptionalVal = cast_or_null<StructValue>( 169af98b0afSStanislav Gatev State.Env.getValue(*OptionalExpr, SkipPast::Reference))) { 170af98b0afSStanislav Gatev if (OptionalVal->getProperty("has_value") == nullptr) { 171af98b0afSStanislav Gatev OptionalVal->setProperty("has_value", State.Env.makeAtomicBoolValue()); 172af98b0afSStanislav Gatev } 173af98b0afSStanislav Gatev } 174af98b0afSStanislav Gatev } 175af98b0afSStanislav Gatev 176092a530cSStanislav Gatev void transferUnwrapCall(const Expr *UnwrapExpr, const Expr *ObjectExpr, 177af98b0afSStanislav Gatev LatticeTransferState &State) { 178af98b0afSStanislav Gatev if (auto *OptionalVal = cast_or_null<StructValue>( 179af98b0afSStanislav Gatev State.Env.getValue(*ObjectExpr, SkipPast::ReferenceThenPointer))) { 180af98b0afSStanislav Gatev auto *HasValueVal = getHasValue(OptionalVal); 181af98b0afSStanislav Gatev assert(HasValueVal != nullptr); 182af98b0afSStanislav Gatev 183af98b0afSStanislav Gatev if (State.Env.flowConditionImplies(*HasValueVal)) 184af98b0afSStanislav Gatev return; 185af98b0afSStanislav Gatev } 186af98b0afSStanislav Gatev 187af98b0afSStanislav Gatev // Record that this unwrap is *not* provably safe. 188af98b0afSStanislav Gatev State.Lattice.getSourceLocations().insert(ObjectExpr->getBeginLoc()); 189af98b0afSStanislav Gatev } 190af98b0afSStanislav Gatev 191092a530cSStanislav Gatev void transferMakeOptionalCall(const CallExpr *E, 192092a530cSStanislav Gatev const MatchFinder::MatchResult &, 193092a530cSStanislav Gatev LatticeTransferState &State) { 1949e0fc676SStanislav Gatev auto &Loc = State.Env.createStorageLocation(*E); 1959e0fc676SStanislav Gatev State.Env.setStorageLocation(*E, Loc); 1969e0fc676SStanislav Gatev State.Env.setValue( 1979e0fc676SStanislav Gatev Loc, createOptionalValue(State.Env, State.Env.getBoolLiteralValue(true))); 1989e0fc676SStanislav Gatev } 1999e0fc676SStanislav Gatev 200092a530cSStanislav Gatev void transferOptionalHasValueCall(const CXXMemberCallExpr *CallExpr, 201092a530cSStanislav Gatev const MatchFinder::MatchResult &, 202af98b0afSStanislav Gatev LatticeTransferState &State) { 203af98b0afSStanislav Gatev if (auto *OptionalVal = cast_or_null<StructValue>( 204af98b0afSStanislav Gatev State.Env.getValue(*CallExpr->getImplicitObjectArgument(), 205af98b0afSStanislav Gatev SkipPast::ReferenceThenPointer))) { 206af98b0afSStanislav Gatev auto *HasValueVal = getHasValue(OptionalVal); 207af98b0afSStanislav Gatev assert(HasValueVal != nullptr); 208af98b0afSStanislav Gatev 209af98b0afSStanislav Gatev auto &CallExprLoc = State.Env.createStorageLocation(*CallExpr); 210af98b0afSStanislav Gatev State.Env.setValue(CallExprLoc, *HasValueVal); 211af98b0afSStanislav Gatev State.Env.setStorageLocation(*CallExpr, CallExprLoc); 212af98b0afSStanislav Gatev } 213af98b0afSStanislav Gatev } 214af98b0afSStanislav Gatev 215092a530cSStanislav Gatev void assignOptionalValue(const Expr &E, LatticeTransferState &State, 216092a530cSStanislav Gatev BoolValue &HasValueVal) { 217092a530cSStanislav Gatev if (auto *OptionalLoc = 218092a530cSStanislav Gatev State.Env.getStorageLocation(E, SkipPast::ReferenceThenPointer)) { 219092a530cSStanislav Gatev State.Env.setValue(*OptionalLoc, 220092a530cSStanislav Gatev createOptionalValue(State.Env, HasValueVal)); 2219e0fc676SStanislav Gatev } 2229e0fc676SStanislav Gatev } 2239e0fc676SStanislav Gatev 224b000b770SStanislav Gatev /// Returns a symbolic value for the "has_value" property of an `optional<T>` 225b000b770SStanislav Gatev /// value that is constructed/assigned from a value of type `U` or `optional<U>` 226b000b770SStanislav Gatev /// where `T` is constructible from `U`. 227b000b770SStanislav Gatev BoolValue & 228b000b770SStanislav Gatev getValueOrConversionHasValue(const FunctionDecl &F, const Expr &E, 229b000b770SStanislav Gatev const MatchFinder::MatchResult &MatchRes, 230b000b770SStanislav Gatev LatticeTransferState &State) { 231b000b770SStanislav Gatev assert(F.getTemplateSpecializationArgs()->size() > 0); 232b000b770SStanislav Gatev 233b000b770SStanislav Gatev const int TemplateParamOptionalWrappersCount = countOptionalWrappers( 234b000b770SStanislav Gatev *MatchRes.Context, 235b000b770SStanislav Gatev stripReference(F.getTemplateSpecializationArgs()->get(0).getAsType())); 236b000b770SStanislav Gatev const int ArgTypeOptionalWrappersCount = 237b000b770SStanislav Gatev countOptionalWrappers(*MatchRes.Context, stripReference(E.getType())); 238b000b770SStanislav Gatev 239b000b770SStanislav Gatev // Check if this is a constructor/assignment call for `optional<T>` with 240b000b770SStanislav Gatev // argument of type `U` such that `T` is constructible from `U`. 241b000b770SStanislav Gatev if (TemplateParamOptionalWrappersCount == ArgTypeOptionalWrappersCount) 242b000b770SStanislav Gatev return State.Env.getBoolLiteralValue(true); 243b000b770SStanislav Gatev 244b000b770SStanislav Gatev // This is a constructor/assignment call for `optional<T>` with argument of 245b000b770SStanislav Gatev // type `optional<U>` such that `T` is constructible from `U`. 246b000b770SStanislav Gatev if (BoolValue *Val = getHasValue(State.Env.getValue(E, SkipPast::Reference))) 247b000b770SStanislav Gatev return *Val; 248b000b770SStanislav Gatev return State.Env.makeAtomicBoolValue(); 249b000b770SStanislav Gatev } 250b000b770SStanislav Gatev 251092a530cSStanislav Gatev void transferValueOrConversionConstructor( 252092a530cSStanislav Gatev const CXXConstructExpr *E, const MatchFinder::MatchResult &MatchRes, 2539e0fc676SStanislav Gatev LatticeTransferState &State) { 254092a530cSStanislav Gatev assert(E->getNumArgs() > 0); 255092a530cSStanislav Gatev 256b000b770SStanislav Gatev assignOptionalValue(*E, State, 257b000b770SStanislav Gatev getValueOrConversionHasValue(*E->getConstructor(), 258b000b770SStanislav Gatev *E->getArg(0), MatchRes, 259b000b770SStanislav Gatev State)); 260b000b770SStanislav Gatev } 261092a530cSStanislav Gatev 262b000b770SStanislav Gatev void transferAssignment(const CXXOperatorCallExpr *E, BoolValue &HasValueVal, 263b000b770SStanislav Gatev LatticeTransferState &State) { 264b000b770SStanislav Gatev assert(E->getNumArgs() > 0); 265b000b770SStanislav Gatev 266b000b770SStanislav Gatev auto *OptionalLoc = 267b000b770SStanislav Gatev State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference); 268b000b770SStanislav Gatev assert(OptionalLoc != nullptr); 269b000b770SStanislav Gatev 270b000b770SStanislav Gatev State.Env.setValue(*OptionalLoc, createOptionalValue(State.Env, HasValueVal)); 271b000b770SStanislav Gatev 272b000b770SStanislav Gatev // Assign a storage location for the whole expression. 273b000b770SStanislav Gatev State.Env.setStorageLocation(*E, *OptionalLoc); 274b000b770SStanislav Gatev } 275b000b770SStanislav Gatev 276b000b770SStanislav Gatev void transferValueOrConversionAssignment( 277b000b770SStanislav Gatev const CXXOperatorCallExpr *E, const MatchFinder::MatchResult &MatchRes, 278b000b770SStanislav Gatev LatticeTransferState &State) { 279b000b770SStanislav Gatev assert(E->getNumArgs() > 1); 280b000b770SStanislav Gatev transferAssignment(E, 281b000b770SStanislav Gatev getValueOrConversionHasValue( 282b000b770SStanislav Gatev *E->getDirectCallee(), *E->getArg(1), MatchRes, State), 283b000b770SStanislav Gatev State); 284b000b770SStanislav Gatev } 285b000b770SStanislav Gatev 286b000b770SStanislav Gatev void transferNulloptAssignment(const CXXOperatorCallExpr *E, 287b000b770SStanislav Gatev const MatchFinder::MatchResult &, 288b000b770SStanislav Gatev LatticeTransferState &State) { 289b000b770SStanislav Gatev transferAssignment(E, State.Env.getBoolLiteralValue(false), State); 2909e0fc676SStanislav Gatev } 2919e0fc676SStanislav Gatev 292*2ddd57aeSStanislav Gatev void transferSwap(const StorageLocation &OptionalLoc1, 293*2ddd57aeSStanislav Gatev const StorageLocation &OptionalLoc2, 294*2ddd57aeSStanislav Gatev LatticeTransferState &State) { 295*2ddd57aeSStanislav Gatev auto *OptionalVal1 = State.Env.getValue(OptionalLoc1); 296*2ddd57aeSStanislav Gatev assert(OptionalVal1 != nullptr); 297*2ddd57aeSStanislav Gatev 298*2ddd57aeSStanislav Gatev auto *OptionalVal2 = State.Env.getValue(OptionalLoc2); 299*2ddd57aeSStanislav Gatev assert(OptionalVal2 != nullptr); 300*2ddd57aeSStanislav Gatev 301*2ddd57aeSStanislav Gatev State.Env.setValue(OptionalLoc1, *OptionalVal2); 302*2ddd57aeSStanislav Gatev State.Env.setValue(OptionalLoc2, *OptionalVal1); 303*2ddd57aeSStanislav Gatev } 304*2ddd57aeSStanislav Gatev 305*2ddd57aeSStanislav Gatev void transferSwapCall(const CXXMemberCallExpr *E, 306*2ddd57aeSStanislav Gatev const MatchFinder::MatchResult &, 307*2ddd57aeSStanislav Gatev LatticeTransferState &State) { 308*2ddd57aeSStanislav Gatev assert(E->getNumArgs() == 1); 309*2ddd57aeSStanislav Gatev 310*2ddd57aeSStanislav Gatev auto *OptionalLoc1 = State.Env.getStorageLocation( 311*2ddd57aeSStanislav Gatev *E->getImplicitObjectArgument(), SkipPast::ReferenceThenPointer); 312*2ddd57aeSStanislav Gatev assert(OptionalLoc1 != nullptr); 313*2ddd57aeSStanislav Gatev 314*2ddd57aeSStanislav Gatev auto *OptionalLoc2 = 315*2ddd57aeSStanislav Gatev State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference); 316*2ddd57aeSStanislav Gatev assert(OptionalLoc2 != nullptr); 317*2ddd57aeSStanislav Gatev 318*2ddd57aeSStanislav Gatev transferSwap(*OptionalLoc1, *OptionalLoc2, State); 319*2ddd57aeSStanislav Gatev } 320*2ddd57aeSStanislav Gatev 321*2ddd57aeSStanislav Gatev void transferStdSwapCall(const CallExpr *E, const MatchFinder::MatchResult &, 322*2ddd57aeSStanislav Gatev LatticeTransferState &State) { 323*2ddd57aeSStanislav Gatev assert(E->getNumArgs() == 2); 324*2ddd57aeSStanislav Gatev 325*2ddd57aeSStanislav Gatev auto *OptionalLoc1 = 326*2ddd57aeSStanislav Gatev State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference); 327*2ddd57aeSStanislav Gatev assert(OptionalLoc1 != nullptr); 328*2ddd57aeSStanislav Gatev 329*2ddd57aeSStanislav Gatev auto *OptionalLoc2 = 330*2ddd57aeSStanislav Gatev State.Env.getStorageLocation(*E->getArg(1), SkipPast::Reference); 331*2ddd57aeSStanislav Gatev assert(OptionalLoc2 != nullptr); 332*2ddd57aeSStanislav Gatev 333*2ddd57aeSStanislav Gatev transferSwap(*OptionalLoc1, *OptionalLoc2, State); 334*2ddd57aeSStanislav Gatev } 335*2ddd57aeSStanislav Gatev 336092a530cSStanislav Gatev auto buildTransferMatchSwitch() { 337b000b770SStanislav Gatev // FIXME: Evaluate the efficiency of matchers. If using matchers results in a 338b000b770SStanislav Gatev // lot of duplicated work (e.g. string comparisons), consider providing APIs 339b000b770SStanislav Gatev // that avoid it through memoization. 340af98b0afSStanislav Gatev return MatchSwitchBuilder<LatticeTransferState>() 341af98b0afSStanislav Gatev // Attach a symbolic "has_value" state to optional values that we see for 342af98b0afSStanislav Gatev // the first time. 343092a530cSStanislav Gatev .CaseOf<Expr>(expr(anyOf(declRefExpr(), memberExpr()), hasOptionalType()), 344af98b0afSStanislav Gatev initializeOptionalReference) 345af98b0afSStanislav Gatev 3469e0fc676SStanislav Gatev // make_optional 347092a530cSStanislav Gatev .CaseOf<CallExpr>(isMakeOptionalCall(), transferMakeOptionalCall) 348092a530cSStanislav Gatev 349b000b770SStanislav Gatev // optional::optional 350092a530cSStanislav Gatev .CaseOf<CXXConstructExpr>( 351092a530cSStanislav Gatev isOptionalInPlaceConstructor(), 352092a530cSStanislav Gatev [](const CXXConstructExpr *E, const MatchFinder::MatchResult &, 353092a530cSStanislav Gatev LatticeTransferState &State) { 354092a530cSStanislav Gatev assignOptionalValue(*E, State, State.Env.getBoolLiteralValue(true)); 355092a530cSStanislav Gatev }) 356092a530cSStanislav Gatev .CaseOf<CXXConstructExpr>( 357092a530cSStanislav Gatev isOptionalNulloptConstructor(), 358092a530cSStanislav Gatev [](const CXXConstructExpr *E, const MatchFinder::MatchResult &, 359092a530cSStanislav Gatev LatticeTransferState &State) { 360092a530cSStanislav Gatev assignOptionalValue(*E, State, 361092a530cSStanislav Gatev State.Env.getBoolLiteralValue(false)); 362092a530cSStanislav Gatev }) 363092a530cSStanislav Gatev .CaseOf<CXXConstructExpr>(isOptionalValueOrConversionConstructor(), 364092a530cSStanislav Gatev transferValueOrConversionConstructor) 3659e0fc676SStanislav Gatev 366b000b770SStanislav Gatev // optional::operator= 367b000b770SStanislav Gatev .CaseOf<CXXOperatorCallExpr>(isOptionalValueOrConversionAssignment(), 368b000b770SStanislav Gatev transferValueOrConversionAssignment) 369b000b770SStanislav Gatev .CaseOf<CXXOperatorCallExpr>(isOptionalNulloptAssignment(), 370b000b770SStanislav Gatev transferNulloptAssignment) 371b000b770SStanislav Gatev 372af98b0afSStanislav Gatev // optional::value 373092a530cSStanislav Gatev .CaseOf<CXXMemberCallExpr>( 374af98b0afSStanislav Gatev isOptionalMemberCallWithName("value"), 375092a530cSStanislav Gatev [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &, 376092a530cSStanislav Gatev LatticeTransferState &State) { 377af98b0afSStanislav Gatev transferUnwrapCall(E, E->getImplicitObjectArgument(), State); 378af98b0afSStanislav Gatev }) 379af98b0afSStanislav Gatev 380af98b0afSStanislav Gatev // optional::operator*, optional::operator-> 381092a530cSStanislav Gatev .CaseOf<CallExpr>(expr(anyOf(isOptionalOperatorCallWithName("*"), 382af98b0afSStanislav Gatev isOptionalOperatorCallWithName("->"))), 383092a530cSStanislav Gatev [](const CallExpr *E, const MatchFinder::MatchResult &, 384092a530cSStanislav Gatev LatticeTransferState &State) { 385af98b0afSStanislav Gatev transferUnwrapCall(E, E->getArg(0), State); 386af98b0afSStanislav Gatev }) 387af98b0afSStanislav Gatev 388af98b0afSStanislav Gatev // optional::has_value 389092a530cSStanislav Gatev .CaseOf<CXXMemberCallExpr>(isOptionalMemberCallWithName("has_value"), 390af98b0afSStanislav Gatev transferOptionalHasValueCall) 391af98b0afSStanislav Gatev 3929e0fc676SStanislav Gatev // optional::operator bool 393092a530cSStanislav Gatev .CaseOf<CXXMemberCallExpr>(isOptionalMemberCallWithName("operator bool"), 3949e0fc676SStanislav Gatev transferOptionalHasValueCall) 3959e0fc676SStanislav Gatev 3969e0fc676SStanislav Gatev // optional::emplace 397092a530cSStanislav Gatev .CaseOf<CXXMemberCallExpr>( 398092a530cSStanislav Gatev isOptionalMemberCallWithName("emplace"), 399092a530cSStanislav Gatev [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &, 400092a530cSStanislav Gatev LatticeTransferState &State) { 401092a530cSStanislav Gatev assignOptionalValue(*E->getImplicitObjectArgument(), State, 402092a530cSStanislav Gatev State.Env.getBoolLiteralValue(true)); 403092a530cSStanislav Gatev }) 4049e0fc676SStanislav Gatev 4059e0fc676SStanislav Gatev // optional::reset 406092a530cSStanislav Gatev .CaseOf<CXXMemberCallExpr>( 407092a530cSStanislav Gatev isOptionalMemberCallWithName("reset"), 408092a530cSStanislav Gatev [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &, 409092a530cSStanislav Gatev LatticeTransferState &State) { 410092a530cSStanislav Gatev assignOptionalValue(*E->getImplicitObjectArgument(), State, 411092a530cSStanislav Gatev State.Env.getBoolLiteralValue(false)); 412092a530cSStanislav Gatev }) 4139e0fc676SStanislav Gatev 414*2ddd57aeSStanislav Gatev // optional::swap 415*2ddd57aeSStanislav Gatev .CaseOf<CXXMemberCallExpr>(isOptionalMemberCallWithName("swap"), 416*2ddd57aeSStanislav Gatev transferSwapCall) 417*2ddd57aeSStanislav Gatev 418*2ddd57aeSStanislav Gatev // std::swap 419*2ddd57aeSStanislav Gatev .CaseOf<CallExpr>(isStdSwapCall(), transferStdSwapCall) 420*2ddd57aeSStanislav Gatev 421af98b0afSStanislav Gatev .Build(); 422af98b0afSStanislav Gatev } 423af98b0afSStanislav Gatev 424af98b0afSStanislav Gatev } // namespace 425af98b0afSStanislav Gatev 426af98b0afSStanislav Gatev UncheckedOptionalAccessModel::UncheckedOptionalAccessModel(ASTContext &Ctx) 427af98b0afSStanislav Gatev : DataflowAnalysis<UncheckedOptionalAccessModel, SourceLocationsLattice>( 428af98b0afSStanislav Gatev Ctx), 429af98b0afSStanislav Gatev TransferMatchSwitch(buildTransferMatchSwitch()) {} 430af98b0afSStanislav Gatev 431af98b0afSStanislav Gatev void UncheckedOptionalAccessModel::transfer(const Stmt *S, 432af98b0afSStanislav Gatev SourceLocationsLattice &L, 433af98b0afSStanislav Gatev Environment &Env) { 434af98b0afSStanislav Gatev LatticeTransferState State(L, Env); 435af98b0afSStanislav Gatev TransferMatchSwitch(*S, getASTContext(), State); 436af98b0afSStanislav Gatev } 437af98b0afSStanislav Gatev 438af98b0afSStanislav Gatev } // namespace dataflow 439af98b0afSStanislav Gatev } // namespace clang 440