1 //===-- UncheckedOptionalAccessModel.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 a dataflow analysis that detects unsafe uses of optional
10 //  values.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h"
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/DeclCXX.h"
17 #include "clang/AST/Expr.h"
18 #include "clang/AST/ExprCXX.h"
19 #include "clang/AST/Stmt.h"
20 #include "clang/ASTMatchers/ASTMatchers.h"
21 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
22 #include "clang/Analysis/FlowSensitive/MatchSwitch.h"
23 #include "clang/Analysis/FlowSensitive/SourceLocationsLattice.h"
24 #include "clang/Analysis/FlowSensitive/Value.h"
25 #include "llvm/ADT/StringRef.h"
26 #include "llvm/Support/Casting.h"
27 #include <cassert>
28 #include <memory>
29 #include <utility>
30 
31 namespace clang {
32 namespace dataflow {
33 namespace {
34 
35 using namespace ::clang::ast_matchers;
36 using LatticeTransferState = TransferState<SourceLocationsLattice>;
37 
38 DeclarationMatcher optionalClass() {
39   return classTemplateSpecializationDecl(
40       anyOf(hasName("std::optional"), hasName("std::__optional_storage_base"),
41             hasName("__optional_destruct_base"), hasName("absl::optional"),
42             hasName("base::Optional")),
43       hasTemplateArgument(0, refersToType(type().bind("T"))));
44 }
45 
46 auto optionalOrAliasType() {
47   return hasUnqualifiedDesugaredType(
48       recordType(hasDeclaration(optionalClass())));
49 }
50 
51 /// Matches any of the spellings of the optional types and sugar, aliases, etc.
52 auto hasOptionalType() { return hasType(optionalOrAliasType()); }
53 
54 auto isOptionalMemberCallWithName(
55     llvm::StringRef MemberName,
56     llvm::Optional<StatementMatcher> Ignorable = llvm::None) {
57   auto Exception = unless(Ignorable ? expr(anyOf(*Ignorable, cxxThisExpr()))
58                                     : cxxThisExpr());
59   return cxxMemberCallExpr(
60       on(expr(Exception)),
61       callee(cxxMethodDecl(hasName(MemberName), ofClass(optionalClass()))));
62 }
63 
64 auto isOptionalOperatorCallWithName(
65     llvm::StringRef operator_name,
66     llvm::Optional<StatementMatcher> Ignorable = llvm::None) {
67   return cxxOperatorCallExpr(
68       hasOverloadedOperatorName(operator_name),
69       callee(cxxMethodDecl(ofClass(optionalClass()))),
70       Ignorable ? callExpr(unless(hasArgument(0, *Ignorable))) : callExpr());
71 }
72 
73 auto isMakeOptionalCall() {
74   return callExpr(
75       callee(functionDecl(hasAnyName(
76           "std::make_optional", "base::make_optional", "absl::make_optional"))),
77       hasOptionalType());
78 }
79 
80 auto hasNulloptType() {
81   return hasType(namedDecl(
82       hasAnyName("std::nullopt_t", "absl::nullopt_t", "base::nullopt_t")));
83 }
84 
85 auto inPlaceClass() {
86   return recordDecl(
87       hasAnyName("std::in_place_t", "absl::in_place_t", "base::in_place_t"));
88 }
89 
90 auto isOptionalNulloptConstructor() {
91   return cxxConstructExpr(hasOptionalType(), argumentCountIs(1),
92                           hasArgument(0, hasNulloptType()));
93 }
94 
95 auto isOptionalInPlaceConstructor() {
96   return cxxConstructExpr(hasOptionalType(),
97                           hasArgument(0, hasType(inPlaceClass())));
98 }
99 
100 auto isOptionalValueOrConversionConstructor() {
101   return cxxConstructExpr(
102       hasOptionalType(),
103       unless(hasDeclaration(
104           cxxConstructorDecl(anyOf(isCopyConstructor(), isMoveConstructor())))),
105       argumentCountIs(1), hasArgument(0, unless(hasNulloptType())));
106 }
107 
108 auto isOptionalValueOrConversionAssignment() {
109   return cxxOperatorCallExpr(
110       hasOverloadedOperatorName("="),
111       callee(cxxMethodDecl(ofClass(optionalClass()))),
112       unless(hasDeclaration(cxxMethodDecl(
113           anyOf(isCopyAssignmentOperator(), isMoveAssignmentOperator())))),
114       argumentCountIs(2), hasArgument(1, unless(hasNulloptType())));
115 }
116 
117 auto isOptionalNulloptAssignment() {
118   return cxxOperatorCallExpr(hasOverloadedOperatorName("="),
119                              callee(cxxMethodDecl(ofClass(optionalClass()))),
120                              argumentCountIs(2),
121                              hasArgument(1, hasNulloptType()));
122 }
123 
124 auto isStdSwapCall() {
125   return callExpr(callee(functionDecl(hasName("std::swap"))),
126                   argumentCountIs(2), hasArgument(0, hasOptionalType()),
127                   hasArgument(1, hasOptionalType()));
128 }
129 
130 constexpr llvm::StringLiteral ValueOrCallID = "ValueOrCall";
131 
132 auto isValueOrStringEmptyCall() {
133   // `opt.value_or("").empty()`
134   return cxxMemberCallExpr(
135       callee(cxxMethodDecl(hasName("empty"))),
136       onImplicitObjectArgument(ignoringImplicit(
137           cxxMemberCallExpr(on(expr(unless(cxxThisExpr()))),
138                             callee(cxxMethodDecl(hasName("value_or"),
139                                                  ofClass(optionalClass()))),
140                             hasArgument(0, stringLiteral(hasSize(0))))
141               .bind(ValueOrCallID))));
142 }
143 
144 auto isValueOrNotEqX() {
145   auto ComparesToSame = [](ast_matchers::internal::Matcher<Stmt> Arg) {
146     return hasOperands(
147         ignoringImplicit(
148             cxxMemberCallExpr(on(expr(unless(cxxThisExpr()))),
149                               callee(cxxMethodDecl(hasName("value_or"),
150                                                    ofClass(optionalClass()))),
151                               hasArgument(0, Arg))
152                 .bind(ValueOrCallID)),
153         ignoringImplicit(Arg));
154   };
155 
156   // `opt.value_or(X) != X`, for X is `nullptr`, `""`, or `0`. Ideally, we'd
157   // support this pattern for any expression, but the AST does not have a
158   // generic expression comparison facility, so we specialize to common cases
159   // seen in practice.  FIXME: define a matcher that compares values across
160   // nodes, which would let us generalize this to any `X`.
161   return binaryOperation(hasOperatorName("!="),
162                          anyOf(ComparesToSame(cxxNullPtrLiteralExpr()),
163                                ComparesToSame(stringLiteral(hasSize(0))),
164                                ComparesToSame(integerLiteral(equals(0)))));
165 }
166 
167 auto isCallReturningOptional() {
168   return callExpr(hasType(qualType(anyOf(
169       optionalOrAliasType(), referenceType(pointee(optionalOrAliasType()))))));
170 }
171 
172 /// Sets `HasValueVal` as the symbolic value that represents the "has_value"
173 /// property of the optional value `OptionalVal`.
174 void setHasValue(Value &OptionalVal, BoolValue &HasValueVal) {
175   OptionalVal.setProperty("has_value", HasValueVal);
176 }
177 
178 /// Creates a symbolic value for an `optional` value using `HasValueVal` as the
179 /// symbolic value of its "has_value" property.
180 StructValue &createOptionalValue(Environment &Env, BoolValue &HasValueVal) {
181   auto OptionalVal = std::make_unique<StructValue>();
182   setHasValue(*OptionalVal, HasValueVal);
183   return Env.takeOwnership(std::move(OptionalVal));
184 }
185 
186 /// Returns the symbolic value that represents the "has_value" property of the
187 /// optional value `OptionalVal`. Returns null if `OptionalVal` is null.
188 BoolValue *getHasValue(Environment &Env, Value *OptionalVal) {
189   if (OptionalVal != nullptr) {
190     auto *HasValueVal =
191         cast_or_null<BoolValue>(OptionalVal->getProperty("has_value"));
192     if (HasValueVal == nullptr) {
193       HasValueVal = &Env.makeAtomicBoolValue();
194       OptionalVal->setProperty("has_value", *HasValueVal);
195     }
196     return HasValueVal;
197   }
198   return nullptr;
199 }
200 
201 /// If `Type` is a reference type, returns the type of its pointee. Otherwise,
202 /// returns `Type` itself.
203 QualType stripReference(QualType Type) {
204   return Type->isReferenceType() ? Type->getPointeeType() : Type;
205 }
206 
207 /// Returns true if and only if `Type` is an optional type.
208 bool IsOptionalType(QualType Type) {
209   if (!Type->isRecordType())
210     return false;
211   // FIXME: Optimize this by avoiding the `getQualifiedNameAsString` call.
212   auto TypeName = Type->getAsCXXRecordDecl()->getQualifiedNameAsString();
213   return TypeName == "std::optional" || TypeName == "absl::optional" ||
214          TypeName == "base::Optional";
215 }
216 
217 /// Returns the number of optional wrappers in `Type`.
218 ///
219 /// For example, if `Type` is `optional<optional<int>>`, the result of this
220 /// function will be 2.
221 int countOptionalWrappers(const ASTContext &ASTCtx, QualType Type) {
222   if (!IsOptionalType(Type))
223     return 0;
224   return 1 + countOptionalWrappers(
225                  ASTCtx,
226                  cast<ClassTemplateSpecializationDecl>(Type->getAsRecordDecl())
227                      ->getTemplateArgs()
228                      .get(0)
229                      .getAsType()
230                      .getDesugaredType(ASTCtx));
231 }
232 
233 /// Tries to initialize the `optional`'s value (that is, contents), and return
234 /// its location. Returns nullptr if the value can't be represented.
235 StorageLocation *maybeInitializeOptionalValueMember(QualType Q,
236                                                     Value &OptionalVal,
237                                                     Environment &Env) {
238   // The "value" property represents a synthetic field. As such, it needs
239   // `StorageLocation`, like normal fields (and other variables). So, we model
240   // it with a `ReferenceValue`, since that includes a storage location.  Once
241   // the property is set, it will be shared by all environments that access the
242   // `Value` representing the optional (here, `OptionalVal`).
243   if (auto *ValueProp = OptionalVal.getProperty("value")) {
244     auto *ValueRef = clang::cast<ReferenceValue>(ValueProp);
245     auto &ValueLoc = ValueRef->getReferentLoc();
246     if (Env.getValue(ValueLoc) == nullptr) {
247       // The property was previously set, but the value has been lost. This can
248       // happen, for example, because of an environment merge (where the two
249       // environments mapped the property to different values, which resulted in
250       // them both being discarded), or when two blocks in the CFG, with neither
251       // a dominator of the other, visit the same optional value, or even when a
252       // block is revisited during testing to collect per-statement state.
253       // FIXME: This situation means that the optional contents are not shared
254       // between branches and the like. Practically, this lack of sharing
255       // reduces the precision of the model when the contents are relevant to
256       // the check, like another optional or a boolean that influences control
257       // flow.
258       auto *ValueVal = Env.createValue(ValueLoc.getType());
259       if (ValueVal == nullptr)
260         return nullptr;
261       Env.setValue(ValueLoc, *ValueVal);
262     }
263     return &ValueLoc;
264   }
265 
266   auto Ty = stripReference(Q);
267   auto *ValueVal = Env.createValue(Ty);
268   if (ValueVal == nullptr)
269     return nullptr;
270   auto &ValueLoc = Env.createStorageLocation(Ty);
271   Env.setValue(ValueLoc, *ValueVal);
272   auto ValueRef = std::make_unique<ReferenceValue>(ValueLoc);
273   OptionalVal.setProperty("value", Env.takeOwnership(std::move(ValueRef)));
274   return &ValueLoc;
275 }
276 
277 void initializeOptionalReference(const Expr *OptionalExpr,
278                                  const MatchFinder::MatchResult &,
279                                  LatticeTransferState &State) {
280   if (auto *OptionalVal =
281           State.Env.getValue(*OptionalExpr, SkipPast::Reference)) {
282     if (OptionalVal->getProperty("has_value") == nullptr) {
283       setHasValue(*OptionalVal, State.Env.makeAtomicBoolValue());
284     }
285   }
286 }
287 
288 /// Returns true if and only if `OptionalVal` is initialized and known to be
289 /// empty in `Env.
290 bool isEmptyOptional(const Value &OptionalVal, const Environment &Env) {
291   auto *HasValueVal =
292       cast_or_null<BoolValue>(OptionalVal.getProperty("has_value"));
293   return HasValueVal != nullptr &&
294          Env.flowConditionImplies(Env.makeNot(*HasValueVal));
295 }
296 
297 /// Returns true if and only if `OptionalVal` is initialized and known to be
298 /// non-empty in `Env.
299 bool isNonEmptyOptional(const Value &OptionalVal, const Environment &Env) {
300   auto *HasValueVal =
301       cast_or_null<BoolValue>(OptionalVal.getProperty("has_value"));
302   return HasValueVal != nullptr && Env.flowConditionImplies(*HasValueVal);
303 }
304 
305 void transferUnwrapCall(const Expr *UnwrapExpr, const Expr *ObjectExpr,
306                         LatticeTransferState &State) {
307   if (auto *OptionalVal =
308           State.Env.getValue(*ObjectExpr, SkipPast::ReferenceThenPointer)) {
309     if (State.Env.getStorageLocation(*UnwrapExpr, SkipPast::None) == nullptr)
310       if (auto *Loc = maybeInitializeOptionalValueMember(
311               UnwrapExpr->getType(), *OptionalVal, State.Env))
312         State.Env.setStorageLocation(*UnwrapExpr, *Loc);
313 
314     auto *Prop = OptionalVal->getProperty("has_value");
315     if (auto *HasValueVal = cast_or_null<BoolValue>(Prop)) {
316       if (State.Env.flowConditionImplies(*HasValueVal))
317         return;
318     }
319   }
320 
321   // Record that this unwrap is *not* provably safe.
322   // FIXME: include either the name of the optional (if applicable) or a source
323   // range of the access for easier interpretation of the result.
324   State.Lattice.getSourceLocations().insert(ObjectExpr->getBeginLoc());
325 }
326 
327 void transferMakeOptionalCall(const CallExpr *E,
328                               const MatchFinder::MatchResult &,
329                               LatticeTransferState &State) {
330   auto &Loc = State.Env.createStorageLocation(*E);
331   State.Env.setStorageLocation(*E, Loc);
332   State.Env.setValue(
333       Loc, createOptionalValue(State.Env, State.Env.getBoolLiteralValue(true)));
334 }
335 
336 void transferOptionalHasValueCall(const CXXMemberCallExpr *CallExpr,
337                                   const MatchFinder::MatchResult &,
338                                   LatticeTransferState &State) {
339   if (auto *HasValueVal = getHasValue(
340           State.Env, State.Env.getValue(*CallExpr->getImplicitObjectArgument(),
341                                         SkipPast::ReferenceThenPointer))) {
342     auto &CallExprLoc = State.Env.createStorageLocation(*CallExpr);
343     State.Env.setValue(CallExprLoc, *HasValueVal);
344     State.Env.setStorageLocation(*CallExpr, CallExprLoc);
345   }
346 }
347 
348 /// `ModelPred` builds a logical formula relating the predicate in
349 /// `ValueOrPredExpr` to the optional's `has_value` property.
350 void transferValueOrImpl(const clang::Expr *ValueOrPredExpr,
351                          const MatchFinder::MatchResult &Result,
352                          LatticeTransferState &State,
353                          BoolValue &(*ModelPred)(Environment &Env,
354                                                  BoolValue &ExprVal,
355                                                  BoolValue &HasValueVal)) {
356   auto &Env = State.Env;
357 
358   const auto *ObjectArgumentExpr =
359       Result.Nodes.getNodeAs<clang::CXXMemberCallExpr>(ValueOrCallID)
360           ->getImplicitObjectArgument();
361 
362   auto *HasValueVal = getHasValue(
363       State.Env,
364       State.Env.getValue(*ObjectArgumentExpr, SkipPast::ReferenceThenPointer));
365   if (HasValueVal == nullptr)
366     return;
367 
368   auto *ExprValue = cast_or_null<BoolValue>(
369       State.Env.getValue(*ValueOrPredExpr, SkipPast::None));
370   if (ExprValue == nullptr) {
371     auto &ExprLoc = State.Env.createStorageLocation(*ValueOrPredExpr);
372     ExprValue = &State.Env.makeAtomicBoolValue();
373     State.Env.setValue(ExprLoc, *ExprValue);
374     State.Env.setStorageLocation(*ValueOrPredExpr, ExprLoc);
375   }
376 
377   Env.addToFlowCondition(ModelPred(Env, *ExprValue, *HasValueVal));
378 }
379 
380 void transferValueOrStringEmptyCall(const clang::Expr *ComparisonExpr,
381                                     const MatchFinder::MatchResult &Result,
382                                     LatticeTransferState &State) {
383   return transferValueOrImpl(ComparisonExpr, Result, State,
384                              [](Environment &Env, BoolValue &ExprVal,
385                                 BoolValue &HasValueVal) -> BoolValue & {
386                                // If the result is *not* empty, then we know the
387                                // optional must have been holding a value. If
388                                // `ExprVal` is true, though, we don't learn
389                                // anything definite about `has_value`, so we
390                                // don't add any corresponding implications to
391                                // the flow condition.
392                                return Env.makeImplication(Env.makeNot(ExprVal),
393                                                           HasValueVal);
394                              });
395 }
396 
397 void transferValueOrNotEqX(const Expr *ComparisonExpr,
398                            const MatchFinder::MatchResult &Result,
399                            LatticeTransferState &State) {
400   transferValueOrImpl(ComparisonExpr, Result, State,
401                       [](Environment &Env, BoolValue &ExprVal,
402                          BoolValue &HasValueVal) -> BoolValue & {
403                         // We know that if `(opt.value_or(X) != X)` then
404                         // `opt.hasValue()`, even without knowing further
405                         // details about the contents of `opt`.
406                         return Env.makeImplication(ExprVal, HasValueVal);
407                       });
408 }
409 
410 void transferCallReturningOptional(const CallExpr *E,
411                                    const MatchFinder::MatchResult &Result,
412                                    LatticeTransferState &State) {
413   if (State.Env.getStorageLocation(*E, SkipPast::None) != nullptr)
414     return;
415 
416   auto &Loc = State.Env.createStorageLocation(*E);
417   State.Env.setStorageLocation(*E, Loc);
418   State.Env.setValue(
419       Loc, createOptionalValue(State.Env, State.Env.makeAtomicBoolValue()));
420 }
421 
422 void assignOptionalValue(const Expr &E, LatticeTransferState &State,
423                          BoolValue &HasValueVal) {
424   if (auto *OptionalLoc =
425           State.Env.getStorageLocation(E, SkipPast::ReferenceThenPointer)) {
426     State.Env.setValue(*OptionalLoc,
427                        createOptionalValue(State.Env, HasValueVal));
428   }
429 }
430 
431 /// Returns a symbolic value for the "has_value" property of an `optional<T>`
432 /// value that is constructed/assigned from a value of type `U` or `optional<U>`
433 /// where `T` is constructible from `U`.
434 BoolValue &
435 getValueOrConversionHasValue(const FunctionDecl &F, const Expr &E,
436                              const MatchFinder::MatchResult &MatchRes,
437                              LatticeTransferState &State) {
438   assert(F.getTemplateSpecializationArgs()->size() > 0);
439 
440   const int TemplateParamOptionalWrappersCount = countOptionalWrappers(
441       *MatchRes.Context,
442       stripReference(F.getTemplateSpecializationArgs()->get(0).getAsType()));
443   const int ArgTypeOptionalWrappersCount =
444       countOptionalWrappers(*MatchRes.Context, stripReference(E.getType()));
445 
446   // Check if this is a constructor/assignment call for `optional<T>` with
447   // argument of type `U` such that `T` is constructible from `U`.
448   if (TemplateParamOptionalWrappersCount == ArgTypeOptionalWrappersCount)
449     return State.Env.getBoolLiteralValue(true);
450 
451   // This is a constructor/assignment call for `optional<T>` with argument of
452   // type `optional<U>` such that `T` is constructible from `U`.
453   if (auto *HasValueVal =
454           getHasValue(State.Env, State.Env.getValue(E, SkipPast::Reference)))
455     return *HasValueVal;
456   return State.Env.makeAtomicBoolValue();
457 }
458 
459 void transferValueOrConversionConstructor(
460     const CXXConstructExpr *E, const MatchFinder::MatchResult &MatchRes,
461     LatticeTransferState &State) {
462   assert(E->getNumArgs() > 0);
463 
464   assignOptionalValue(*E, State,
465                       getValueOrConversionHasValue(*E->getConstructor(),
466                                                    *E->getArg(0), MatchRes,
467                                                    State));
468 }
469 
470 void transferAssignment(const CXXOperatorCallExpr *E, BoolValue &HasValueVal,
471                         LatticeTransferState &State) {
472   assert(E->getNumArgs() > 0);
473 
474   auto *OptionalLoc =
475       State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference);
476   if (OptionalLoc == nullptr)
477     return;
478 
479   State.Env.setValue(*OptionalLoc, createOptionalValue(State.Env, HasValueVal));
480 
481   // Assign a storage location for the whole expression.
482   State.Env.setStorageLocation(*E, *OptionalLoc);
483 }
484 
485 void transferValueOrConversionAssignment(
486     const CXXOperatorCallExpr *E, const MatchFinder::MatchResult &MatchRes,
487     LatticeTransferState &State) {
488   assert(E->getNumArgs() > 1);
489   transferAssignment(E,
490                      getValueOrConversionHasValue(
491                          *E->getDirectCallee(), *E->getArg(1), MatchRes, State),
492                      State);
493 }
494 
495 void transferNulloptAssignment(const CXXOperatorCallExpr *E,
496                                const MatchFinder::MatchResult &,
497                                LatticeTransferState &State) {
498   transferAssignment(E, State.Env.getBoolLiteralValue(false), State);
499 }
500 
501 void transferSwap(const StorageLocation &OptionalLoc1,
502                   const StorageLocation &OptionalLoc2,
503                   LatticeTransferState &State) {
504   auto *OptionalVal1 = State.Env.getValue(OptionalLoc1);
505   assert(OptionalVal1 != nullptr);
506 
507   auto *OptionalVal2 = State.Env.getValue(OptionalLoc2);
508   assert(OptionalVal2 != nullptr);
509 
510   State.Env.setValue(OptionalLoc1, *OptionalVal2);
511   State.Env.setValue(OptionalLoc2, *OptionalVal1);
512 }
513 
514 void transferSwapCall(const CXXMemberCallExpr *E,
515                       const MatchFinder::MatchResult &,
516                       LatticeTransferState &State) {
517   assert(E->getNumArgs() == 1);
518 
519   auto *OptionalLoc1 = State.Env.getStorageLocation(
520       *E->getImplicitObjectArgument(), SkipPast::ReferenceThenPointer);
521   assert(OptionalLoc1 != nullptr);
522 
523   auto *OptionalLoc2 =
524       State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference);
525   assert(OptionalLoc2 != nullptr);
526 
527   transferSwap(*OptionalLoc1, *OptionalLoc2, State);
528 }
529 
530 void transferStdSwapCall(const CallExpr *E, const MatchFinder::MatchResult &,
531                          LatticeTransferState &State) {
532   assert(E->getNumArgs() == 2);
533 
534   auto *OptionalLoc1 =
535       State.Env.getStorageLocation(*E->getArg(0), SkipPast::Reference);
536   assert(OptionalLoc1 != nullptr);
537 
538   auto *OptionalLoc2 =
539       State.Env.getStorageLocation(*E->getArg(1), SkipPast::Reference);
540   assert(OptionalLoc2 != nullptr);
541 
542   transferSwap(*OptionalLoc1, *OptionalLoc2, State);
543 }
544 
545 llvm::Optional<StatementMatcher>
546 ignorableOptional(const UncheckedOptionalAccessModelOptions &Options) {
547   if (Options.IgnoreSmartPointerDereference)
548     return memberExpr(hasObjectExpression(ignoringParenImpCasts(
549         cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("->"),
550                                   hasOverloadedOperatorName("*")),
551                             unless(hasArgument(0, expr(hasOptionalType())))))));
552   return llvm::None;
553 }
554 
555 auto buildTransferMatchSwitch(
556     const UncheckedOptionalAccessModelOptions &Options) {
557   // FIXME: Evaluate the efficiency of matchers. If using matchers results in a
558   // lot of duplicated work (e.g. string comparisons), consider providing APIs
559   // that avoid it through memoization.
560   auto IgnorableOptional = ignorableOptional(Options);
561   return MatchSwitchBuilder<LatticeTransferState>()
562       // Attach a symbolic "has_value" state to optional values that we see for
563       // the first time.
564       .CaseOf<Expr>(
565           expr(anyOf(declRefExpr(), memberExpr()), hasOptionalType()),
566           initializeOptionalReference)
567 
568       // make_optional
569       .CaseOf<CallExpr>(isMakeOptionalCall(), transferMakeOptionalCall)
570 
571       // optional::optional
572       .CaseOf<CXXConstructExpr>(
573           isOptionalInPlaceConstructor(),
574           [](const CXXConstructExpr *E, const MatchFinder::MatchResult &,
575              LatticeTransferState &State) {
576             assignOptionalValue(*E, State, State.Env.getBoolLiteralValue(true));
577           })
578       .CaseOf<CXXConstructExpr>(
579           isOptionalNulloptConstructor(),
580           [](const CXXConstructExpr *E, const MatchFinder::MatchResult &,
581              LatticeTransferState &State) {
582             assignOptionalValue(*E, State,
583                                 State.Env.getBoolLiteralValue(false));
584           })
585       .CaseOf<CXXConstructExpr>(isOptionalValueOrConversionConstructor(),
586                                 transferValueOrConversionConstructor)
587 
588       // optional::operator=
589       .CaseOf<CXXOperatorCallExpr>(isOptionalValueOrConversionAssignment(),
590                                    transferValueOrConversionAssignment)
591       .CaseOf<CXXOperatorCallExpr>(isOptionalNulloptAssignment(),
592                                    transferNulloptAssignment)
593 
594       // optional::value
595       .CaseOf<CXXMemberCallExpr>(
596           isOptionalMemberCallWithName("value", IgnorableOptional),
597           [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &,
598              LatticeTransferState &State) {
599             transferUnwrapCall(E, E->getImplicitObjectArgument(), State);
600           })
601 
602       // optional::operator*, optional::operator->
603       .CaseOf<CallExpr>(
604           expr(anyOf(isOptionalOperatorCallWithName("*", IgnorableOptional),
605                      isOptionalOperatorCallWithName("->", IgnorableOptional))),
606           [](const CallExpr *E, const MatchFinder::MatchResult &,
607              LatticeTransferState &State) {
608             transferUnwrapCall(E, E->getArg(0), State);
609           })
610 
611       // optional::has_value
612       .CaseOf<CXXMemberCallExpr>(isOptionalMemberCallWithName("has_value"),
613                                  transferOptionalHasValueCall)
614 
615       // optional::operator bool
616       .CaseOf<CXXMemberCallExpr>(isOptionalMemberCallWithName("operator bool"),
617                                  transferOptionalHasValueCall)
618 
619       // optional::emplace
620       .CaseOf<CXXMemberCallExpr>(
621           isOptionalMemberCallWithName("emplace"),
622           [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &,
623              LatticeTransferState &State) {
624             assignOptionalValue(*E->getImplicitObjectArgument(), State,
625                                 State.Env.getBoolLiteralValue(true));
626           })
627 
628       // optional::reset
629       .CaseOf<CXXMemberCallExpr>(
630           isOptionalMemberCallWithName("reset"),
631           [](const CXXMemberCallExpr *E, const MatchFinder::MatchResult &,
632              LatticeTransferState &State) {
633             assignOptionalValue(*E->getImplicitObjectArgument(), State,
634                                 State.Env.getBoolLiteralValue(false));
635           })
636 
637       // optional::swap
638       .CaseOf<CXXMemberCallExpr>(isOptionalMemberCallWithName("swap"),
639                                  transferSwapCall)
640 
641       // std::swap
642       .CaseOf<CallExpr>(isStdSwapCall(), transferStdSwapCall)
643 
644       // opt.value_or("").empty()
645       .CaseOf<Expr>(isValueOrStringEmptyCall(), transferValueOrStringEmptyCall)
646 
647       // opt.value_or(X) != X
648       .CaseOf<Expr>(isValueOrNotEqX(), transferValueOrNotEqX)
649 
650       // returns optional
651       .CaseOf<CallExpr>(isCallReturningOptional(),
652                         transferCallReturningOptional)
653 
654       .Build();
655 }
656 
657 } // namespace
658 
659 ast_matchers::DeclarationMatcher
660 UncheckedOptionalAccessModel::optionalClassDecl() {
661   return optionalClass();
662 }
663 
664 UncheckedOptionalAccessModel::UncheckedOptionalAccessModel(
665     ASTContext &Ctx, UncheckedOptionalAccessModelOptions Options)
666     : DataflowAnalysis<UncheckedOptionalAccessModel, SourceLocationsLattice>(
667           Ctx),
668       TransferMatchSwitch(buildTransferMatchSwitch(Options)) {}
669 
670 void UncheckedOptionalAccessModel::transfer(const Stmt *S,
671                                             SourceLocationsLattice &L,
672                                             Environment &Env) {
673   LatticeTransferState State(L, Env);
674   TransferMatchSwitch(*S, getASTContext(), State);
675 }
676 
677 bool UncheckedOptionalAccessModel::compareEquivalent(QualType Type,
678                                                      const Value &Val1,
679                                                      const Environment &Env1,
680                                                      const Value &Val2,
681                                                      const Environment &Env2) {
682   return isNonEmptyOptional(Val1, Env1) == isNonEmptyOptional(Val2, Env2);
683 }
684 
685 bool UncheckedOptionalAccessModel::merge(QualType Type, const Value &Val1,
686                                          const Environment &Env1,
687                                          const Value &Val2,
688                                          const Environment &Env2,
689                                          Value &MergedVal,
690                                          Environment &MergedEnv) {
691   if (!IsOptionalType(Type))
692     return true;
693 
694   auto &HasValueVal = MergedEnv.makeAtomicBoolValue();
695   if (isNonEmptyOptional(Val1, Env1) && isNonEmptyOptional(Val2, Env2))
696     MergedEnv.addToFlowCondition(HasValueVal);
697   else if (isEmptyOptional(Val1, Env1) && isEmptyOptional(Val2, Env2))
698     MergedEnv.addToFlowCondition(MergedEnv.makeNot(HasValueVal));
699   setHasValue(MergedVal, HasValueVal);
700   return true;
701 }
702 
703 } // namespace dataflow
704 } // namespace clang
705