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" 167e63a0d4SYitzhak Mandelbaum #include "clang/AST/DeclCXX.h" 17af98b0afSStanislav Gatev #include "clang/AST/Expr.h" 18af98b0afSStanislav Gatev #include "clang/AST/ExprCXX.h" 19af98b0afSStanislav Gatev #include "clang/AST/Stmt.h" 20af98b0afSStanislav Gatev #include "clang/ASTMatchers/ASTMatchers.h" 21af98b0afSStanislav Gatev #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 22af98b0afSStanislav Gatev #include "clang/Analysis/FlowSensitive/MatchSwitch.h" 23af98b0afSStanislav Gatev #include "clang/Analysis/FlowSensitive/SourceLocationsLattice.h" 24af98b0afSStanislav Gatev #include "clang/Analysis/FlowSensitive/Value.h" 25af98b0afSStanislav Gatev #include "llvm/ADT/StringRef.h" 26af98b0afSStanislav Gatev #include "llvm/Support/Casting.h" 27af98b0afSStanislav Gatev #include <cassert> 289e0fc676SStanislav Gatev #include <memory> 299e0fc676SStanislav Gatev #include <utility> 30af98b0afSStanislav Gatev 31af98b0afSStanislav Gatev namespace clang { 32af98b0afSStanislav Gatev namespace dataflow { 33af98b0afSStanislav Gatev namespace { 34af98b0afSStanislav Gatev 35af98b0afSStanislav Gatev using namespace ::clang::ast_matchers; 36af98b0afSStanislav Gatev using LatticeTransferState = TransferState<SourceLocationsLattice>; 37af98b0afSStanislav Gatev 387e63a0d4SYitzhak Mandelbaum DeclarationMatcher 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 466adfc64eSYitzhak Mandelbaum auto optionalOrAliasType() { 4765e710c3SStanislav Gatev return hasUnqualifiedDesugaredType( 4865e710c3SStanislav Gatev recordType(hasDeclaration(optionalClass()))); 4965e710c3SStanislav Gatev } 5065e710c3SStanislav Gatev 516adfc64eSYitzhak Mandelbaum /// Matches any of the spellings of the optional types and sugar, aliases, etc. 526adfc64eSYitzhak Mandelbaum auto hasOptionalType() { return hasType(optionalOrAliasType()); } 536adfc64eSYitzhak Mandelbaum 54a184a0d8SYitzhak Mandelbaum auto isOptionalMemberCallWithName( 55a184a0d8SYitzhak Mandelbaum llvm::StringRef MemberName, 56a184a0d8SYitzhak Mandelbaum llvm::Optional<StatementMatcher> Ignorable = llvm::None) { 57a184a0d8SYitzhak Mandelbaum auto Exception = unless(Ignorable ? expr(anyOf(*Ignorable, cxxThisExpr())) 58a184a0d8SYitzhak Mandelbaum : cxxThisExpr()); 59af98b0afSStanislav Gatev return cxxMemberCallExpr( 60a184a0d8SYitzhak Mandelbaum on(expr(Exception)), 61af98b0afSStanislav Gatev callee(cxxMethodDecl(hasName(MemberName), ofClass(optionalClass())))); 62af98b0afSStanislav Gatev } 63af98b0afSStanislav Gatev 64a184a0d8SYitzhak Mandelbaum auto isOptionalOperatorCallWithName( 65a184a0d8SYitzhak Mandelbaum llvm::StringRef operator_name, 66a184a0d8SYitzhak Mandelbaum llvm::Optional<StatementMatcher> Ignorable = llvm::None) { 67a184a0d8SYitzhak Mandelbaum return cxxOperatorCallExpr( 68a184a0d8SYitzhak Mandelbaum hasOverloadedOperatorName(operator_name), 69a184a0d8SYitzhak Mandelbaum callee(cxxMethodDecl(ofClass(optionalClass()))), 70a184a0d8SYitzhak Mandelbaum Ignorable ? callExpr(unless(hasArgument(0, *Ignorable))) : callExpr()); 71af98b0afSStanislav Gatev } 72af98b0afSStanislav Gatev 73092a530cSStanislav Gatev auto isMakeOptionalCall() { 749e0fc676SStanislav Gatev return callExpr( 759e0fc676SStanislav Gatev callee(functionDecl(hasAnyName( 769e0fc676SStanislav Gatev "std::make_optional", "base::make_optional", "absl::make_optional"))), 779e0fc676SStanislav Gatev hasOptionalType()); 789e0fc676SStanislav Gatev } 799e0fc676SStanislav Gatev 80092a530cSStanislav Gatev auto hasNulloptType() { 81092a530cSStanislav Gatev return hasType(namedDecl( 82092a530cSStanislav Gatev hasAnyName("std::nullopt_t", "absl::nullopt_t", "base::nullopt_t"))); 83092a530cSStanislav Gatev } 84092a530cSStanislav Gatev 85092a530cSStanislav Gatev auto inPlaceClass() { 86092a530cSStanislav Gatev return recordDecl( 87092a530cSStanislav Gatev hasAnyName("std::in_place_t", "absl::in_place_t", "base::in_place_t")); 88092a530cSStanislav Gatev } 89092a530cSStanislav Gatev 90092a530cSStanislav Gatev auto isOptionalNulloptConstructor() { 91092a530cSStanislav Gatev return cxxConstructExpr(hasOptionalType(), argumentCountIs(1), 92092a530cSStanislav Gatev hasArgument(0, hasNulloptType())); 93092a530cSStanislav Gatev } 94092a530cSStanislav Gatev 95092a530cSStanislav Gatev auto isOptionalInPlaceConstructor() { 96092a530cSStanislav Gatev return cxxConstructExpr(hasOptionalType(), 97092a530cSStanislav Gatev hasArgument(0, hasType(inPlaceClass()))); 98092a530cSStanislav Gatev } 99092a530cSStanislav Gatev 100092a530cSStanislav Gatev auto isOptionalValueOrConversionConstructor() { 101092a530cSStanislav Gatev return cxxConstructExpr( 102092a530cSStanislav Gatev hasOptionalType(), 103092a530cSStanislav Gatev unless(hasDeclaration( 104092a530cSStanislav Gatev cxxConstructorDecl(anyOf(isCopyConstructor(), isMoveConstructor())))), 105092a530cSStanislav Gatev argumentCountIs(1), hasArgument(0, unless(hasNulloptType()))); 106092a530cSStanislav Gatev } 107092a530cSStanislav Gatev 108b000b770SStanislav Gatev auto isOptionalValueOrConversionAssignment() { 109b000b770SStanislav Gatev return cxxOperatorCallExpr( 110b000b770SStanislav Gatev hasOverloadedOperatorName("="), 111b000b770SStanislav Gatev callee(cxxMethodDecl(ofClass(optionalClass()))), 112b000b770SStanislav Gatev unless(hasDeclaration(cxxMethodDecl( 113b000b770SStanislav Gatev anyOf(isCopyAssignmentOperator(), isMoveAssignmentOperator())))), 114b000b770SStanislav Gatev argumentCountIs(2), hasArgument(1, unless(hasNulloptType()))); 115b000b770SStanislav Gatev } 116b000b770SStanislav Gatev 117b000b770SStanislav Gatev auto isOptionalNulloptAssignment() { 118b000b770SStanislav Gatev return cxxOperatorCallExpr(hasOverloadedOperatorName("="), 119b000b770SStanislav Gatev callee(cxxMethodDecl(ofClass(optionalClass()))), 120b000b770SStanislav Gatev argumentCountIs(2), 121b000b770SStanislav Gatev hasArgument(1, hasNulloptType())); 122b000b770SStanislav Gatev } 123b000b770SStanislav Gatev 1242ddd57aeSStanislav Gatev auto isStdSwapCall() { 1252ddd57aeSStanislav Gatev return callExpr(callee(functionDecl(hasName("std::swap"))), 1262ddd57aeSStanislav Gatev argumentCountIs(2), hasArgument(0, hasOptionalType()), 1272ddd57aeSStanislav Gatev hasArgument(1, hasOptionalType())); 1282ddd57aeSStanislav Gatev } 1292ddd57aeSStanislav Gatev 1307f076004SYitzhak Mandelbaum constexpr llvm::StringLiteral ValueOrCallID = "ValueOrCall"; 1317f076004SYitzhak Mandelbaum 1327f076004SYitzhak Mandelbaum auto isValueOrStringEmptyCall() { 1337f076004SYitzhak Mandelbaum // `opt.value_or("").empty()` 1347f076004SYitzhak Mandelbaum return cxxMemberCallExpr( 1357f076004SYitzhak Mandelbaum callee(cxxMethodDecl(hasName("empty"))), 1367f076004SYitzhak Mandelbaum onImplicitObjectArgument(ignoringImplicit( 1377f076004SYitzhak Mandelbaum cxxMemberCallExpr(on(expr(unless(cxxThisExpr()))), 1387f076004SYitzhak Mandelbaum callee(cxxMethodDecl(hasName("value_or"), 1397f076004SYitzhak Mandelbaum ofClass(optionalClass()))), 1407f076004SYitzhak Mandelbaum hasArgument(0, stringLiteral(hasSize(0)))) 1417f076004SYitzhak Mandelbaum .bind(ValueOrCallID)))); 1427f076004SYitzhak Mandelbaum } 1437f076004SYitzhak Mandelbaum 1447f076004SYitzhak Mandelbaum auto isValueOrNotEqX() { 1457f076004SYitzhak Mandelbaum auto ComparesToSame = [](ast_matchers::internal::Matcher<Stmt> Arg) { 1467f076004SYitzhak Mandelbaum return hasOperands( 1477f076004SYitzhak Mandelbaum ignoringImplicit( 1487f076004SYitzhak Mandelbaum cxxMemberCallExpr(on(expr(unless(cxxThisExpr()))), 1497f076004SYitzhak Mandelbaum callee(cxxMethodDecl(hasName("value_or"), 1507f076004SYitzhak Mandelbaum ofClass(optionalClass()))), 1517f076004SYitzhak Mandelbaum hasArgument(0, Arg)) 1527f076004SYitzhak Mandelbaum .bind(ValueOrCallID)), 1537f076004SYitzhak Mandelbaum ignoringImplicit(Arg)); 1547f076004SYitzhak Mandelbaum }; 1557f076004SYitzhak Mandelbaum 1567f076004SYitzhak Mandelbaum // `opt.value_or(X) != X`, for X is `nullptr`, `""`, or `0`. Ideally, we'd 1577f076004SYitzhak Mandelbaum // support this pattern for any expression, but the AST does not have a 1587f076004SYitzhak Mandelbaum // generic expression comparison facility, so we specialize to common cases 1597f076004SYitzhak Mandelbaum // seen in practice. FIXME: define a matcher that compares values across 1607f076004SYitzhak Mandelbaum // nodes, which would let us generalize this to any `X`. 1617f076004SYitzhak Mandelbaum return binaryOperation(hasOperatorName("!="), 1627f076004SYitzhak Mandelbaum anyOf(ComparesToSame(cxxNullPtrLiteralExpr()), 1637f076004SYitzhak Mandelbaum ComparesToSame(stringLiteral(hasSize(0))), 1647f076004SYitzhak Mandelbaum ComparesToSame(integerLiteral(equals(0))))); 1657f076004SYitzhak Mandelbaum } 1667f076004SYitzhak Mandelbaum 16765e710c3SStanislav Gatev auto isCallReturningOptional() { 168cd0d5261SSam Estep return callExpr(hasType(qualType(anyOf( 169cd0d5261SSam Estep optionalOrAliasType(), referenceType(pointee(optionalOrAliasType())))))); 17065e710c3SStanislav Gatev } 17165e710c3SStanislav Gatev 1729e0fc676SStanislav Gatev /// Creates a symbolic value for an `optional` value using `HasValueVal` as the 1739e0fc676SStanislav Gatev /// symbolic value of its "has_value" property. 1749e0fc676SStanislav Gatev StructValue &createOptionalValue(Environment &Env, BoolValue &HasValueVal) { 1759e0fc676SStanislav Gatev auto OptionalVal = std::make_unique<StructValue>(); 1769e0fc676SStanislav Gatev OptionalVal->setProperty("has_value", HasValueVal); 1779e0fc676SStanislav Gatev return Env.takeOwnership(std::move(OptionalVal)); 1789e0fc676SStanislav Gatev } 1799e0fc676SStanislav Gatev 180af98b0afSStanislav Gatev /// Returns the symbolic value that represents the "has_value" property of the 18149ed5bf5SWei Yi Tee /// optional value `OptionalVal`. Returns null if `OptionalVal` is null. 182dd38caf3SYitzhak Mandelbaum BoolValue *getHasValue(Environment &Env, Value *OptionalVal) { 183dd38caf3SYitzhak Mandelbaum if (OptionalVal != nullptr) { 184dd38caf3SYitzhak Mandelbaum auto *HasValueVal = 185dd38caf3SYitzhak Mandelbaum cast_or_null<BoolValue>(OptionalVal->getProperty("has_value")); 186dd38caf3SYitzhak Mandelbaum if (HasValueVal == nullptr) { 187dd38caf3SYitzhak Mandelbaum HasValueVal = &Env.makeAtomicBoolValue(); 188dd38caf3SYitzhak Mandelbaum OptionalVal->setProperty("has_value", *HasValueVal); 189dd38caf3SYitzhak Mandelbaum } 190dd38caf3SYitzhak Mandelbaum return HasValueVal; 191af98b0afSStanislav Gatev } 192af98b0afSStanislav Gatev return nullptr; 193af98b0afSStanislav Gatev } 194af98b0afSStanislav Gatev 195092a530cSStanislav Gatev /// If `Type` is a reference type, returns the type of its pointee. Otherwise, 196092a530cSStanislav Gatev /// returns `Type` itself. 197092a530cSStanislav Gatev QualType stripReference(QualType Type) { 198092a530cSStanislav Gatev return Type->isReferenceType() ? Type->getPointeeType() : Type; 199092a530cSStanislav Gatev } 200092a530cSStanislav Gatev 201092a530cSStanislav Gatev /// Returns true if and only if `Type` is an optional type. 202092a530cSStanislav Gatev bool IsOptionalType(QualType Type) { 203092a530cSStanislav Gatev if (!Type->isRecordType()) 204092a530cSStanislav Gatev return false; 205092a530cSStanislav Gatev // FIXME: Optimize this by avoiding the `getQualifiedNameAsString` call. 206092a530cSStanislav Gatev auto TypeName = Type->getAsCXXRecordDecl()->getQualifiedNameAsString(); 207092a530cSStanislav Gatev return TypeName == "std::optional" || TypeName == "absl::optional" || 208092a530cSStanislav Gatev TypeName == "base::Optional"; 209092a530cSStanislav Gatev } 210092a530cSStanislav Gatev 211092a530cSStanislav Gatev /// Returns the number of optional wrappers in `Type`. 212092a530cSStanislav Gatev /// 213092a530cSStanislav Gatev /// For example, if `Type` is `optional<optional<int>>`, the result of this 214092a530cSStanislav Gatev /// function will be 2. 215092a530cSStanislav Gatev int countOptionalWrappers(const ASTContext &ASTCtx, QualType Type) { 216092a530cSStanislav Gatev if (!IsOptionalType(Type)) 217092a530cSStanislav Gatev return 0; 218092a530cSStanislav Gatev return 1 + countOptionalWrappers( 219092a530cSStanislav Gatev ASTCtx, 220092a530cSStanislav Gatev cast<ClassTemplateSpecializationDecl>(Type->getAsRecordDecl()) 221092a530cSStanislav Gatev ->getTemplateArgs() 222092a530cSStanislav Gatev .get(0) 223092a530cSStanislav Gatev .getAsType() 224092a530cSStanislav Gatev .getDesugaredType(ASTCtx)); 225092a530cSStanislav Gatev } 226092a530cSStanislav Gatev 227dd38caf3SYitzhak Mandelbaum /// Tries to initialize the `optional`'s value (that is, contents), and return 228dd38caf3SYitzhak Mandelbaum /// its location. Returns nullptr if the value can't be represented. 229dd38caf3SYitzhak Mandelbaum StorageLocation *maybeInitializeOptionalValueMember(QualType Q, 230dd38caf3SYitzhak Mandelbaum Value &OptionalVal, 231dd38caf3SYitzhak Mandelbaum Environment &Env) { 232dd38caf3SYitzhak Mandelbaum // The "value" property represents a synthetic field. As such, it needs 233dd38caf3SYitzhak Mandelbaum // `StorageLocation`, like normal fields (and other variables). So, we model 234dd38caf3SYitzhak Mandelbaum // it with a `ReferenceValue`, since that includes a storage location. Once 235dd38caf3SYitzhak Mandelbaum // the property is set, it will be shared by all environments that access the 236dd38caf3SYitzhak Mandelbaum // `Value` representing the optional (here, `OptionalVal`). 237dd38caf3SYitzhak Mandelbaum if (auto *ValueProp = OptionalVal.getProperty("value")) { 238dd38caf3SYitzhak Mandelbaum auto *ValueRef = clang::cast<ReferenceValue>(ValueProp); 239dd38caf3SYitzhak Mandelbaum auto &ValueLoc = ValueRef->getPointeeLoc(); 240dd38caf3SYitzhak Mandelbaum if (Env.getValue(ValueLoc) == nullptr) { 241dd38caf3SYitzhak Mandelbaum // The property was previously set, but the value has been lost. This can 242dd38caf3SYitzhak Mandelbaum // happen, for example, because of an environment merge (where the two 243dd38caf3SYitzhak Mandelbaum // environments mapped the property to different values, which resulted in 244dd38caf3SYitzhak Mandelbaum // them both being discarded), or when two blocks in the CFG, with neither 245dd38caf3SYitzhak Mandelbaum // a dominator of the other, visit the same optional value, or even when a 246dd38caf3SYitzhak Mandelbaum // block is revisited during testing to collect per-statement state. 247dd38caf3SYitzhak Mandelbaum // FIXME: This situation means that the optional contents are not shared 248dd38caf3SYitzhak Mandelbaum // between branches and the like. Practically, this lack of sharing 249dd38caf3SYitzhak Mandelbaum // reduces the precision of the model when the contents are relevant to 250dd38caf3SYitzhak Mandelbaum // the check, like another optional or a boolean that influences control 251dd38caf3SYitzhak Mandelbaum // flow. 252dd38caf3SYitzhak Mandelbaum auto *ValueVal = Env.createValue(ValueLoc.getType()); 253dd38caf3SYitzhak Mandelbaum if (ValueVal == nullptr) 254dd38caf3SYitzhak Mandelbaum return nullptr; 255dd38caf3SYitzhak Mandelbaum Env.setValue(ValueLoc, *ValueVal); 256dd38caf3SYitzhak Mandelbaum } 257dd38caf3SYitzhak Mandelbaum return &ValueLoc; 258dd38caf3SYitzhak Mandelbaum } 259dd38caf3SYitzhak Mandelbaum 260dd38caf3SYitzhak Mandelbaum auto Ty = stripReference(Q); 261dd38caf3SYitzhak Mandelbaum auto *ValueVal = Env.createValue(Ty); 262dd38caf3SYitzhak Mandelbaum if (ValueVal == nullptr) 263dd38caf3SYitzhak Mandelbaum return nullptr; 264dd38caf3SYitzhak Mandelbaum auto &ValueLoc = Env.createStorageLocation(Ty); 265dd38caf3SYitzhak Mandelbaum Env.setValue(ValueLoc, *ValueVal); 266dd38caf3SYitzhak Mandelbaum auto ValueRef = std::make_unique<ReferenceValue>(ValueLoc); 267dd38caf3SYitzhak Mandelbaum OptionalVal.setProperty("value", Env.takeOwnership(std::move(ValueRef))); 268dd38caf3SYitzhak Mandelbaum return &ValueLoc; 269dd38caf3SYitzhak Mandelbaum } 270dd38caf3SYitzhak Mandelbaum 271092a530cSStanislav Gatev void initializeOptionalReference(const Expr *OptionalExpr, 272092a530cSStanislav Gatev const MatchFinder::MatchResult &, 273af98b0afSStanislav Gatev LatticeTransferState &State) { 27449ed5bf5SWei Yi Tee if (auto *OptionalVal = 27549ed5bf5SWei Yi Tee State.Env.getValue(*OptionalExpr, SkipPast::Reference)) { 276af98b0afSStanislav Gatev if (OptionalVal->getProperty("has_value") == nullptr) { 277af98b0afSStanislav Gatev OptionalVal->setProperty("has_value", State.Env.makeAtomicBoolValue()); 278af98b0afSStanislav Gatev } 279af98b0afSStanislav Gatev } 280af98b0afSStanislav Gatev } 281af98b0afSStanislav Gatev 282092a530cSStanislav Gatev void transferUnwrapCall(const Expr *UnwrapExpr, const Expr *ObjectExpr, 283af98b0afSStanislav Gatev LatticeTransferState &State) { 28449ed5bf5SWei Yi Tee if (auto *OptionalVal = 28549ed5bf5SWei Yi Tee State.Env.getValue(*ObjectExpr, SkipPast::ReferenceThenPointer)) { 286dd38caf3SYitzhak Mandelbaum if (State.Env.getStorageLocation(*UnwrapExpr, SkipPast::None) == nullptr) 287dd38caf3SYitzhak Mandelbaum if (auto *Loc = maybeInitializeOptionalValueMember( 288dd38caf3SYitzhak Mandelbaum UnwrapExpr->getType(), *OptionalVal, State.Env)) 289dd38caf3SYitzhak Mandelbaum State.Env.setStorageLocation(*UnwrapExpr, *Loc); 290af98b0afSStanislav Gatev 291dd38caf3SYitzhak Mandelbaum auto *Prop = OptionalVal->getProperty("has_value"); 292dd38caf3SYitzhak Mandelbaum if (auto *HasValueVal = cast_or_null<BoolValue>(Prop)) { 293af98b0afSStanislav Gatev if (State.Env.flowConditionImplies(*HasValueVal)) 294af98b0afSStanislav Gatev return; 295af98b0afSStanislav Gatev } 296dd38caf3SYitzhak Mandelbaum } 297af98b0afSStanislav Gatev 298af98b0afSStanislav Gatev // Record that this unwrap is *not* provably safe. 2997e63a0d4SYitzhak Mandelbaum // FIXME: include either the name of the optional (if applicable) or a source 3007e63a0d4SYitzhak Mandelbaum // range of the access for easier interpretation of the result. 301af98b0afSStanislav Gatev State.Lattice.getSourceLocations().insert(ObjectExpr->getBeginLoc()); 302af98b0afSStanislav Gatev } 303af98b0afSStanislav Gatev 304092a530cSStanislav Gatev void transferMakeOptionalCall(const CallExpr *E, 305092a530cSStanislav Gatev const MatchFinder::MatchResult &, 306092a530cSStanislav Gatev LatticeTransferState &State) { 3079e0fc676SStanislav Gatev auto &Loc = State.Env.createStorageLocation(*E); 3089e0fc676SStanislav Gatev State.Env.setStorageLocation(*E, Loc); 3099e0fc676SStanislav Gatev State.Env.setValue( 3109e0fc676SStanislav Gatev Loc, createOptionalValue(State.Env, State.Env.getBoolLiteralValue(true))); 3119e0fc676SStanislav Gatev } 3129e0fc676SStanislav Gatev 313092a530cSStanislav Gatev void transferOptionalHasValueCall(const CXXMemberCallExpr *CallExpr, 314092a530cSStanislav Gatev const MatchFinder::MatchResult &, 315af98b0afSStanislav Gatev LatticeTransferState &State) { 316dd38caf3SYitzhak Mandelbaum if (auto *HasValueVal = getHasValue( 317dd38caf3SYitzhak Mandelbaum State.Env, State.Env.getValue(*CallExpr->getImplicitObjectArgument(), 318af98b0afSStanislav Gatev SkipPast::ReferenceThenPointer))) { 319af98b0afSStanislav Gatev auto &CallExprLoc = State.Env.createStorageLocation(*CallExpr); 320af98b0afSStanislav Gatev State.Env.setValue(CallExprLoc, *HasValueVal); 321af98b0afSStanislav Gatev State.Env.setStorageLocation(*CallExpr, CallExprLoc); 322af98b0afSStanislav Gatev } 323af98b0afSStanislav Gatev } 324af98b0afSStanislav Gatev 3257f076004SYitzhak Mandelbaum /// `ModelPred` builds a logical formula relating the predicate in 3267f076004SYitzhak Mandelbaum /// `ValueOrPredExpr` to the optional's `has_value` property. 3277f076004SYitzhak Mandelbaum void transferValueOrImpl(const clang::Expr *ValueOrPredExpr, 3287f076004SYitzhak Mandelbaum const MatchFinder::MatchResult &Result, 3297f076004SYitzhak Mandelbaum LatticeTransferState &State, 3307f076004SYitzhak Mandelbaum BoolValue &(*ModelPred)(Environment &Env, 3317f076004SYitzhak Mandelbaum BoolValue &ExprVal, 3327f076004SYitzhak Mandelbaum BoolValue &HasValueVal)) { 3337f076004SYitzhak Mandelbaum auto &Env = State.Env; 3347f076004SYitzhak Mandelbaum 3357f076004SYitzhak Mandelbaum const auto *ObjectArgumentExpr = 3367f076004SYitzhak Mandelbaum Result.Nodes.getNodeAs<clang::CXXMemberCallExpr>(ValueOrCallID) 3377f076004SYitzhak Mandelbaum ->getImplicitObjectArgument(); 3387f076004SYitzhak Mandelbaum 339dd38caf3SYitzhak Mandelbaum auto *HasValueVal = getHasValue( 340dd38caf3SYitzhak Mandelbaum State.Env, 341dd38caf3SYitzhak Mandelbaum State.Env.getValue(*ObjectArgumentExpr, SkipPast::ReferenceThenPointer)); 342dd38caf3SYitzhak Mandelbaum if (HasValueVal == nullptr) 3437f076004SYitzhak Mandelbaum return; 3447f076004SYitzhak Mandelbaum 3457f076004SYitzhak Mandelbaum auto *ExprValue = cast_or_null<BoolValue>( 3467f076004SYitzhak Mandelbaum State.Env.getValue(*ValueOrPredExpr, SkipPast::None)); 3477f076004SYitzhak Mandelbaum if (ExprValue == nullptr) { 3487f076004SYitzhak Mandelbaum auto &ExprLoc = State.Env.createStorageLocation(*ValueOrPredExpr); 3497f076004SYitzhak Mandelbaum ExprValue = &State.Env.makeAtomicBoolValue(); 3507f076004SYitzhak Mandelbaum State.Env.setValue(ExprLoc, *ExprValue); 3517f076004SYitzhak Mandelbaum State.Env.setStorageLocation(*ValueOrPredExpr, ExprLoc); 3527f076004SYitzhak Mandelbaum } 3537f076004SYitzhak Mandelbaum 3547f076004SYitzhak Mandelbaum Env.addToFlowCondition(ModelPred(Env, *ExprValue, *HasValueVal)); 3557f076004SYitzhak Mandelbaum } 3567f076004SYitzhak Mandelbaum 3577f076004SYitzhak Mandelbaum void transferValueOrStringEmptyCall(const clang::Expr *ComparisonExpr, 3587f076004SYitzhak Mandelbaum const MatchFinder::MatchResult &Result, 3597f076004SYitzhak Mandelbaum LatticeTransferState &State) { 3607f076004SYitzhak Mandelbaum return transferValueOrImpl(ComparisonExpr, Result, State, 3617f076004SYitzhak Mandelbaum [](Environment &Env, BoolValue &ExprVal, 3627f076004SYitzhak Mandelbaum BoolValue &HasValueVal) -> BoolValue & { 3637f076004SYitzhak Mandelbaum // If the result is *not* empty, then we know the 3647f076004SYitzhak Mandelbaum // optional must have been holding a value. If 3657f076004SYitzhak Mandelbaum // `ExprVal` is true, though, we don't learn 3667f076004SYitzhak Mandelbaum // anything definite about `has_value`, so we 3677f076004SYitzhak Mandelbaum // don't add any corresponding implications to 3687f076004SYitzhak Mandelbaum // the flow condition. 3697f076004SYitzhak Mandelbaum return Env.makeImplication(Env.makeNot(ExprVal), 3707f076004SYitzhak Mandelbaum HasValueVal); 3717f076004SYitzhak Mandelbaum }); 3727f076004SYitzhak Mandelbaum } 3737f076004SYitzhak Mandelbaum 3747f076004SYitzhak Mandelbaum void transferValueOrNotEqX(const Expr *ComparisonExpr, 3757f076004SYitzhak Mandelbaum const MatchFinder::MatchResult &Result, 3767f076004SYitzhak Mandelbaum LatticeTransferState &State) { 3777f076004SYitzhak Mandelbaum transferValueOrImpl(ComparisonExpr, Result, State, 3787f076004SYitzhak Mandelbaum [](Environment &Env, BoolValue &ExprVal, 3797f076004SYitzhak Mandelbaum BoolValue &HasValueVal) -> BoolValue & { 3807f076004SYitzhak Mandelbaum // We know that if `(opt.value_or(X) != X)` then 3817f076004SYitzhak Mandelbaum // `opt.hasValue()`, even without knowing further 3827f076004SYitzhak Mandelbaum // details about the contents of `opt`. 3837f076004SYitzhak Mandelbaum return Env.makeImplication(ExprVal, HasValueVal); 3847f076004SYitzhak Mandelbaum }); 3857f076004SYitzhak Mandelbaum } 3867f076004SYitzhak Mandelbaum 38765e710c3SStanislav Gatev void transferCallReturningOptional(const CallExpr *E, 38865e710c3SStanislav Gatev const MatchFinder::MatchResult &Result, 38965e710c3SStanislav Gatev LatticeTransferState &State) { 39065e710c3SStanislav Gatev if (State.Env.getStorageLocation(*E, SkipPast::None) != nullptr) 39165e710c3SStanislav Gatev return; 39265e710c3SStanislav Gatev 39365e710c3SStanislav Gatev auto &Loc = State.Env.createStorageLocation(*E); 39465e710c3SStanislav Gatev State.Env.setStorageLocation(*E, Loc); 39565e710c3SStanislav Gatev State.Env.setValue( 39665e710c3SStanislav Gatev Loc, createOptionalValue(State.Env, State.Env.makeAtomicBoolValue())); 39765e710c3SStanislav Gatev } 39865e710c3SStanislav Gatev 399092a530cSStanislav Gatev void assignOptionalValue(const Expr &E, LatticeTransferState &State, 400092a530cSStanislav Gatev BoolValue &HasValueVal) { 401092a530cSStanislav Gatev if (auto *OptionalLoc = 402092a530cSStanislav Gatev State.Env.getStorageLocation(E, SkipPast::ReferenceThenPointer)) { 403092a530cSStanislav Gatev State.Env.setValue(*OptionalLoc, 404092a530cSStanislav Gatev createOptionalValue(State.Env, HasValueVal)); 4059e0fc676SStanislav Gatev } 4069e0fc676SStanislav Gatev } 4079e0fc676SStanislav Gatev 408b000b770SStanislav Gatev /// Returns a symbolic value for the "has_value" property of an `optional<T>` 409b000b770SStanislav Gatev /// value that is constructed/assigned from a value of type `U` or `optional<U>` 410b000b770SStanislav Gatev /// where `T` is constructible from `U`. 411b000b770SStanislav Gatev BoolValue & 412b000b770SStanislav Gatev getValueOrConversionHasValue(const FunctionDecl &F, const Expr &E, 413b000b770SStanislav Gatev const MatchFinder::MatchResult &MatchRes, 414b000b770SStanislav Gatev LatticeTransferState &State) { 415b000b770SStanislav Gatev assert(F.getTemplateSpecializationArgs()->size() > 0); 416b000b770SStanislav Gatev 417b000b770SStanislav Gatev const int TemplateParamOptionalWrappersCount = countOptionalWrappers( 418b000b770SStanislav Gatev *MatchRes.Context, 419b000b770SStanislav Gatev stripReference(F.getTemplateSpecializationArgs()->get(0).getAsType())); 420b000b770SStanislav Gatev const int ArgTypeOptionalWrappersCount = 421b000b770SStanislav Gatev countOptionalWrappers(*MatchRes.Context, stripReference(E.getType())); 422b000b770SStanislav Gatev 423b000b770SStanislav Gatev // Check if this is a constructor/assignment call for `optional<T>` with 424b000b770SStanislav Gatev // argument of type `U` such that `T` is constructible from `U`. 425b000b770SStanislav Gatev if (TemplateParamOptionalWrappersCount == ArgTypeOptionalWrappersCount) 426b000b770SStanislav Gatev return State.Env.getBoolLiteralValue(true); 427b000b770SStanislav Gatev 428b000b770SStanislav Gatev // This is a constructor/assignment call for `optional<T>` with argument of 429b000b770SStanislav Gatev // type `optional<U>` such that `T` is constructible from `U`. 430dd38caf3SYitzhak Mandelbaum if (auto *HasValueVal = 431dd38caf3SYitzhak Mandelbaum getHasValue(State.Env, State.Env.getValue(E, SkipPast::Reference))) 432dd38caf3SYitzhak Mandelbaum return *HasValueVal; 433b000b770SStanislav Gatev return State.Env.makeAtomicBoolValue(); 434b000b770SStanislav Gatev } 435b000b770SStanislav Gatev 436092a530cSStanislav Gatev void transferValueOrConversionConstructor( 437092a530cSStanislav Gatev const CXXConstructExpr *E, const MatchFinder::MatchResult &MatchRes, 4389e0fc676SStanislav Gatev LatticeTransferState &State) { 439092a530cSStanislav Gatev assert(E->getNumArgs() > 0); 440092a530cSStanislav Gatev 441b000b770SStanislav Gatev assignOptionalValue(*E, State, 442b000b770SStanislav Gatev getValueOrConversionHasValue(*E->getConstructor(), 443b000b770SStanislav Gatev *E->getArg(0), MatchRes, 444b000b770SStanislav Gatev State)); 445b000b770SStanislav Gatev } 446092a530cSStanislav Gatev 447b000b770SStanislav Gatev void transferAssignment(const CXXOperatorCallExpr *E, BoolValue &HasValueVal, 448b000b770SStanislav Gatev LatticeTransferState &State) { 449b000b770SStanislav Gatev assert(E->getNumArgs() > 0); 450b000b770SStanislav Gatev 451b000b770SStanislav Gatev auto *OptionalLoc = 452b000b770SStanislav Gatev State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference); 453*a9ad689eSSam Estep if (OptionalLoc == nullptr) 454*a9ad689eSSam Estep return; 455b000b770SStanislav Gatev 456b000b770SStanislav Gatev State.Env.setValue(*OptionalLoc, createOptionalValue(State.Env, HasValueVal)); 457b000b770SStanislav Gatev 458b000b770SStanislav Gatev // Assign a storage location for the whole expression. 459b000b770SStanislav Gatev State.Env.setStorageLocation(*E, *OptionalLoc); 460b000b770SStanislav Gatev } 461b000b770SStanislav Gatev 462b000b770SStanislav Gatev void transferValueOrConversionAssignment( 463b000b770SStanislav Gatev const CXXOperatorCallExpr *E, const MatchFinder::MatchResult &MatchRes, 464b000b770SStanislav Gatev LatticeTransferState &State) { 465b000b770SStanislav Gatev assert(E->getNumArgs() > 1); 466b000b770SStanislav Gatev transferAssignment(E, 467b000b770SStanislav Gatev getValueOrConversionHasValue( 468b000b770SStanislav Gatev *E->getDirectCallee(), *E->getArg(1), MatchRes, State), 469b000b770SStanislav Gatev State); 470b000b770SStanislav Gatev } 471b000b770SStanislav Gatev 472b000b770SStanislav Gatev void transferNulloptAssignment(const CXXOperatorCallExpr *E, 473b000b770SStanislav Gatev const MatchFinder::MatchResult &, 474b000b770SStanislav Gatev LatticeTransferState &State) { 475b000b770SStanislav Gatev transferAssignment(E, State.Env.getBoolLiteralValue(false), State); 4769e0fc676SStanislav Gatev } 4779e0fc676SStanislav Gatev 4782ddd57aeSStanislav Gatev void transferSwap(const StorageLocation &OptionalLoc1, 4792ddd57aeSStanislav Gatev const StorageLocation &OptionalLoc2, 4802ddd57aeSStanislav Gatev LatticeTransferState &State) { 4812ddd57aeSStanislav Gatev auto *OptionalVal1 = State.Env.getValue(OptionalLoc1); 4822ddd57aeSStanislav Gatev assert(OptionalVal1 != nullptr); 4832ddd57aeSStanislav Gatev 4842ddd57aeSStanislav Gatev auto *OptionalVal2 = State.Env.getValue(OptionalLoc2); 4852ddd57aeSStanislav Gatev assert(OptionalVal2 != nullptr); 4862ddd57aeSStanislav Gatev 4872ddd57aeSStanislav Gatev State.Env.setValue(OptionalLoc1, *OptionalVal2); 4882ddd57aeSStanislav Gatev State.Env.setValue(OptionalLoc2, *OptionalVal1); 4892ddd57aeSStanislav Gatev } 4902ddd57aeSStanislav Gatev 4912ddd57aeSStanislav Gatev void transferSwapCall(const CXXMemberCallExpr *E, 4922ddd57aeSStanislav Gatev const MatchFinder::MatchResult &, 4932ddd57aeSStanislav Gatev LatticeTransferState &State) { 4942ddd57aeSStanislav Gatev assert(E->getNumArgs() == 1); 4952ddd57aeSStanislav Gatev 4962ddd57aeSStanislav Gatev auto *OptionalLoc1 = State.Env.getStorageLocation( 4972ddd57aeSStanislav Gatev *E->getImplicitObjectArgument(), SkipPast::ReferenceThenPointer); 4982ddd57aeSStanislav Gatev assert(OptionalLoc1 != nullptr); 4992ddd57aeSStanislav Gatev 5002ddd57aeSStanislav Gatev auto *OptionalLoc2 = 5012ddd57aeSStanislav Gatev State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference); 5022ddd57aeSStanislav Gatev assert(OptionalLoc2 != nullptr); 5032ddd57aeSStanislav Gatev 5042ddd57aeSStanislav Gatev transferSwap(*OptionalLoc1, *OptionalLoc2, State); 5052ddd57aeSStanislav Gatev } 5062ddd57aeSStanislav Gatev 5072ddd57aeSStanislav Gatev void transferStdSwapCall(const CallExpr *E, const MatchFinder::MatchResult &, 5082ddd57aeSStanislav Gatev LatticeTransferState &State) { 5092ddd57aeSStanislav Gatev assert(E->getNumArgs() == 2); 5102ddd57aeSStanislav Gatev 5112ddd57aeSStanislav Gatev auto *OptionalLoc1 = 5122ddd57aeSStanislav Gatev State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference); 5132ddd57aeSStanislav Gatev assert(OptionalLoc1 != nullptr); 5142ddd57aeSStanislav Gatev 5152ddd57aeSStanislav Gatev auto *OptionalLoc2 = 5162ddd57aeSStanislav Gatev State.Env.getStorageLocation(*E->getArg(1), SkipPast::Reference); 5172ddd57aeSStanislav Gatev assert(OptionalLoc2 != nullptr); 5182ddd57aeSStanislav Gatev 5192ddd57aeSStanislav Gatev transferSwap(*OptionalLoc1, *OptionalLoc2, State); 5202ddd57aeSStanislav Gatev } 5212ddd57aeSStanislav Gatev 522a184a0d8SYitzhak Mandelbaum llvm::Optional<StatementMatcher> 523a184a0d8SYitzhak Mandelbaum ignorableOptional(const UncheckedOptionalAccessModelOptions &Options) { 524a184a0d8SYitzhak Mandelbaum if (Options.IgnoreSmartPointerDereference) 525a184a0d8SYitzhak Mandelbaum return memberExpr(hasObjectExpression(ignoringParenImpCasts( 526a184a0d8SYitzhak Mandelbaum cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("->"), 527a184a0d8SYitzhak Mandelbaum hasOverloadedOperatorName("*")), 528a184a0d8SYitzhak Mandelbaum unless(hasArgument(0, expr(hasOptionalType()))))))); 529a184a0d8SYitzhak Mandelbaum return llvm::None; 530a184a0d8SYitzhak Mandelbaum } 531a184a0d8SYitzhak Mandelbaum 532a184a0d8SYitzhak Mandelbaum auto buildTransferMatchSwitch( 533a184a0d8SYitzhak Mandelbaum const UncheckedOptionalAccessModelOptions &Options) { 534b000b770SStanislav Gatev // FIXME: Evaluate the efficiency of matchers. If using matchers results in a 535b000b770SStanislav Gatev // lot of duplicated work (e.g. string comparisons), consider providing APIs 536b000b770SStanislav Gatev // that avoid it through memoization. 537a184a0d8SYitzhak Mandelbaum auto IgnorableOptional = ignorableOptional(Options); 538af98b0afSStanislav Gatev return MatchSwitchBuilder<LatticeTransferState>() 539af98b0afSStanislav Gatev // Attach a symbolic "has_value" state to optional values that we see for 540af98b0afSStanislav Gatev // the first time. 5416adfc64eSYitzhak Mandelbaum .CaseOf<Expr>( 5426adfc64eSYitzhak Mandelbaum expr(anyOf(declRefExpr(), memberExpr()), hasOptionalType()), 543af98b0afSStanislav Gatev initializeOptionalReference) 544af98b0afSStanislav Gatev 5459e0fc676SStanislav Gatev // make_optional 546092a530cSStanislav Gatev .CaseOf<CallExpr>(isMakeOptionalCall(), transferMakeOptionalCall) 547092a530cSStanislav Gatev 548b000b770SStanislav Gatev // optional::optional 549092a530cSStanislav Gatev .CaseOf<CXXConstructExpr>( 550092a530cSStanislav Gatev isOptionalInPlaceConstructor(), 551092a530cSStanislav Gatev [](const CXXConstructExpr *E, const MatchFinder::MatchResult &, 552092a530cSStanislav Gatev LatticeTransferState &State) { 553092a530cSStanislav Gatev assignOptionalValue(*E, State, State.Env.getBoolLiteralValue(true)); 554092a530cSStanislav Gatev }) 555092a530cSStanislav Gatev .CaseOf<CXXConstructExpr>( 556092a530cSStanislav Gatev isOptionalNulloptConstructor(), 557092a530cSStanislav Gatev [](const CXXConstructExpr *E, const MatchFinder::MatchResult &, 558092a530cSStanislav Gatev LatticeTransferState &State) { 559092a530cSStanislav Gatev assignOptionalValue(*E, State, 560092a530cSStanislav Gatev State.Env.getBoolLiteralValue(false)); 561092a530cSStanislav Gatev }) 562092a530cSStanislav Gatev .CaseOf<CXXConstructExpr>(isOptionalValueOrConversionConstructor(), 563092a530cSStanislav Gatev transferValueOrConversionConstructor) 5649e0fc676SStanislav Gatev 565b000b770SStanislav Gatev // optional::operator= 566b000b770SStanislav Gatev .CaseOf<CXXOperatorCallExpr>(isOptionalValueOrConversionAssignment(), 567b000b770SStanislav Gatev transferValueOrConversionAssignment) 568b000b770SStanislav Gatev .CaseOf<CXXOperatorCallExpr>(isOptionalNulloptAssignment(), 569b000b770SStanislav Gatev transferNulloptAssignment) 570b000b770SStanislav Gatev 571af98b0afSStanislav Gatev // optional::value 572092a530cSStanislav Gatev .CaseOf<CXXMemberCallExpr>( 573a184a0d8SYitzhak Mandelbaum isOptionalMemberCallWithName("value", IgnorableOptional), 574092a530cSStanislav Gatev [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &, 575092a530cSStanislav Gatev LatticeTransferState &State) { 576af98b0afSStanislav Gatev transferUnwrapCall(E, E->getImplicitObjectArgument(), State); 577af98b0afSStanislav Gatev }) 578af98b0afSStanislav Gatev 579af98b0afSStanislav Gatev // optional::operator*, optional::operator-> 580a184a0d8SYitzhak Mandelbaum .CaseOf<CallExpr>( 581a184a0d8SYitzhak Mandelbaum expr(anyOf(isOptionalOperatorCallWithName("*", IgnorableOptional), 582a184a0d8SYitzhak Mandelbaum isOptionalOperatorCallWithName("->", IgnorableOptional))), 583092a530cSStanislav Gatev [](const CallExpr *E, const MatchFinder::MatchResult &, 584092a530cSStanislav Gatev LatticeTransferState &State) { 585af98b0afSStanislav Gatev transferUnwrapCall(E, E->getArg(0), State); 586af98b0afSStanislav Gatev }) 587af98b0afSStanislav Gatev 588af98b0afSStanislav Gatev // optional::has_value 589092a530cSStanislav Gatev .CaseOf<CXXMemberCallExpr>(isOptionalMemberCallWithName("has_value"), 590af98b0afSStanislav Gatev transferOptionalHasValueCall) 591af98b0afSStanislav Gatev 5929e0fc676SStanislav Gatev // optional::operator bool 593092a530cSStanislav Gatev .CaseOf<CXXMemberCallExpr>(isOptionalMemberCallWithName("operator bool"), 5949e0fc676SStanislav Gatev transferOptionalHasValueCall) 5959e0fc676SStanislav Gatev 5969e0fc676SStanislav Gatev // optional::emplace 597092a530cSStanislav Gatev .CaseOf<CXXMemberCallExpr>( 598092a530cSStanislav Gatev isOptionalMemberCallWithName("emplace"), 599092a530cSStanislav Gatev [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &, 600092a530cSStanislav Gatev LatticeTransferState &State) { 601092a530cSStanislav Gatev assignOptionalValue(*E->getImplicitObjectArgument(), State, 602092a530cSStanislav Gatev State.Env.getBoolLiteralValue(true)); 603092a530cSStanislav Gatev }) 6049e0fc676SStanislav Gatev 6059e0fc676SStanislav Gatev // optional::reset 606092a530cSStanislav Gatev .CaseOf<CXXMemberCallExpr>( 607092a530cSStanislav Gatev isOptionalMemberCallWithName("reset"), 608092a530cSStanislav Gatev [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &, 609092a530cSStanislav Gatev LatticeTransferState &State) { 610092a530cSStanislav Gatev assignOptionalValue(*E->getImplicitObjectArgument(), State, 611092a530cSStanislav Gatev State.Env.getBoolLiteralValue(false)); 612092a530cSStanislav Gatev }) 6139e0fc676SStanislav Gatev 6142ddd57aeSStanislav Gatev // optional::swap 6152ddd57aeSStanislav Gatev .CaseOf<CXXMemberCallExpr>(isOptionalMemberCallWithName("swap"), 6162ddd57aeSStanislav Gatev transferSwapCall) 6172ddd57aeSStanislav Gatev 6182ddd57aeSStanislav Gatev // std::swap 6192ddd57aeSStanislav Gatev .CaseOf<CallExpr>(isStdSwapCall(), transferStdSwapCall) 6202ddd57aeSStanislav Gatev 6217f076004SYitzhak Mandelbaum // opt.value_or("").empty() 6227f076004SYitzhak Mandelbaum .CaseOf<Expr>(isValueOrStringEmptyCall(), transferValueOrStringEmptyCall) 6237f076004SYitzhak Mandelbaum 6247f076004SYitzhak Mandelbaum // opt.value_or(X) != X 6257f076004SYitzhak Mandelbaum .CaseOf<Expr>(isValueOrNotEqX(), transferValueOrNotEqX) 6267f076004SYitzhak Mandelbaum 62765e710c3SStanislav Gatev // returns optional 62865e710c3SStanislav Gatev .CaseOf<CallExpr>(isCallReturningOptional(), 62965e710c3SStanislav Gatev transferCallReturningOptional) 63065e710c3SStanislav Gatev 631af98b0afSStanislav Gatev .Build(); 632af98b0afSStanislav Gatev } 633af98b0afSStanislav Gatev 634af98b0afSStanislav Gatev } // namespace 635af98b0afSStanislav Gatev 6367e63a0d4SYitzhak Mandelbaum ast_matchers::DeclarationMatcher 6377e63a0d4SYitzhak Mandelbaum UncheckedOptionalAccessModel::optionalClassDecl() { 6387e63a0d4SYitzhak Mandelbaum return optionalClass(); 6397e63a0d4SYitzhak Mandelbaum } 6407e63a0d4SYitzhak Mandelbaum 641a184a0d8SYitzhak Mandelbaum UncheckedOptionalAccessModel::UncheckedOptionalAccessModel( 642a184a0d8SYitzhak Mandelbaum ASTContext &Ctx, UncheckedOptionalAccessModelOptions Options) 643af98b0afSStanislav Gatev : DataflowAnalysis<UncheckedOptionalAccessModel, SourceLocationsLattice>( 644af98b0afSStanislav Gatev Ctx), 645a184a0d8SYitzhak Mandelbaum TransferMatchSwitch(buildTransferMatchSwitch(Options)) {} 646af98b0afSStanislav Gatev 647af98b0afSStanislav Gatev void UncheckedOptionalAccessModel::transfer(const Stmt *S, 648af98b0afSStanislav Gatev SourceLocationsLattice &L, 649af98b0afSStanislav Gatev Environment &Env) { 650af98b0afSStanislav Gatev LatticeTransferState State(L, Env); 651af98b0afSStanislav Gatev TransferMatchSwitch(*S, getASTContext(), State); 652af98b0afSStanislav Gatev } 653af98b0afSStanislav Gatev 654af98b0afSStanislav Gatev } // namespace dataflow 655af98b0afSStanislav Gatev } // namespace clang 656