30#include "llvm/ADT/StringRef.h"
31#include "llvm/Support/Casting.h"
32#include "llvm/Support/ErrorHandling.h"
42 llvm::StringRef Name) {
51 if (RD.
getName() ==
"optional") {
52 if (
const auto *N = dyn_cast_or_null<NamespaceDecl>(RD.
getDeclContext()))
57 if (RD.
getName() ==
"Optional") {
59 const auto *N = dyn_cast_or_null<NamespaceDecl>(RD.
getDeclContext());
70using LatticeTransferState = TransferState<NoopLattice>;
78 hasOptionalClassNameMatcher(),
79 hasTemplateArgument(0, refersToType(
type().bind(
"T"))));
82auto optionalOrAliasType() {
83 return hasUnqualifiedDesugaredType(
88auto hasOptionalType() {
return hasType(optionalOrAliasType()); }
90auto isOptionalMemberCallWithNameMatcher(
91 ast_matchers::internal::Matcher<NamedDecl> matcher,
92 const std::optional<StatementMatcher> &Ignorable = std::nullopt) {
97 anyOf(hasOptionalType(),
98 hasType(
pointerType(pointee(optionalOrAliasType())))))),
102auto isOptionalOperatorCallWithName(
103 llvm::StringRef operator_name,
104 const std::optional<StatementMatcher> &Ignorable = std::nullopt) {
111auto isMakeOptionalCall() {
113 "std::make_optional",
"base::make_optional",
114 "absl::make_optional",
"folly::make_optional"))),
118auto nulloptTypeDecl() {
120 "base::nullopt_t",
"folly::None"));
123auto hasNulloptType() {
return hasType(nulloptTypeDecl()); }
127 "base::in_place_t",
"folly::in_place_t"));
130auto isOptionalNulloptConstructor() {
134 hasParameter(0, hasNulloptType()))));
137auto isOptionalInPlaceConstructor() {
139 hasArgument(0, hasType(inPlaceClass())));
142auto isOptionalValueOrConversionConstructor() {
147 argumentCountIs(1), hasArgument(0,
unless(hasNulloptType())));
150auto isOptionalValueOrConversionAssignment() {
155 anyOf(isCopyAssignmentOperator(), isMoveAssignmentOperator())))),
156 argumentCountIs(2), hasArgument(1,
unless(hasNulloptType())));
159auto isOptionalNulloptAssignment() {
163 hasArgument(1, hasNulloptType()));
166auto isStdSwapCall() {
168 argumentCountIs(2), hasArgument(0, hasOptionalType()),
169 hasArgument(1, hasOptionalType()));
172auto isStdForwardCall() {
174 argumentCountIs(1), hasArgument(0, hasOptionalType()));
177constexpr llvm::StringLiteral ValueOrCallID =
"ValueOrCall";
179auto isValueOrStringEmptyCall() {
183 onImplicitObjectArgument(ignoringImplicit(
186 ofClass(optionalClass()))),
188 .bind(ValueOrCallID))));
191auto isValueOrNotEqX() {
192 auto ComparesToSame = [](ast_matchers::internal::Matcher<Stmt> Arg) {
197 ofClass(optionalClass()))),
199 .bind(ValueOrCallID)),
200 ignoringImplicit(Arg));
214auto isCallReturningOptional() {
216 optionalOrAliasType(),
referenceType(pointee(optionalOrAliasType()))))));
219template <
typename L,
typename R>
220auto isComparisonOperatorCall(L lhs_arg_matcher, R rhs_arg_matcher) {
223 argumentCountIs(2), hasArgument(0, lhs_arg_matcher),
224 hasArgument(1, rhs_arg_matcher));
228const Formula &forceBoolValue(Environment &
Env,
const Expr &Expr) {
230 if (
Value !=
nullptr)
231 return Value->formula();
235 return Value->formula();
238StorageLocation &locForHasValue(
const RecordStorageLocation &OptionalLoc) {
239 return OptionalLoc.getSyntheticField(
"has_value");
242StorageLocation &locForValue(
const RecordStorageLocation &OptionalLoc) {
243 return OptionalLoc.getSyntheticField(
"value");
248void setHasValue(RecordStorageLocation &OptionalLoc, BoolValue &HasValueVal,
250 Env.
setValue(locForHasValue(OptionalLoc), HasValueVal);
256RecordValue &createOptionalValue(RecordStorageLocation &Loc,
257 BoolValue &HasValueVal, Environment &
Env) {
258 auto &OptionalVal =
Env.
create<RecordValue>(Loc);
260 setHasValue(Loc, HasValueVal,
Env);
266BoolValue *getHasValue(Environment &
Env, RecordStorageLocation *OptionalLoc) {
267 if (OptionalLoc ==
nullptr)
269 StorageLocation &HasValueLoc = locForHasValue(*OptionalLoc);
270 auto *HasValueVal = cast_or_null<BoolValue>(
Env.
getValue(HasValueLoc));
271 if (HasValueVal ==
nullptr) {
279bool isOptionalType(QualType Type) {
280 if (!
Type->isRecordType())
282 const CXXRecordDecl *D =
Type->getAsCXXRecordDecl();
290int countOptionalWrappers(
const ASTContext &ASTCtx, QualType Type) {
291 if (!isOptionalType(Type))
293 return 1 + countOptionalWrappers(
295 cast<ClassTemplateSpecializationDecl>(
Type->getAsRecordDecl())
299 .getDesugaredType(ASTCtx));
302StorageLocation *getLocBehindPossiblePointer(
const Expr &E,
303 const Environment &
Env) {
305 if (
auto *PointerVal = dyn_cast_or_null<PointerValue>(
Env.
getValue(E)))
306 return &PointerVal->getPointeeLoc();
312void transferUnwrapCall(
const Expr *UnwrapExpr,
const Expr *ObjectExpr,
313 LatticeTransferState &State) {
314 if (
auto *OptionalLoc = cast_or_null<RecordStorageLocation>(
315 getLocBehindPossiblePointer(*ObjectExpr, State.Env))) {
316 if (State.Env.getStorageLocation(*UnwrapExpr) ==
nullptr)
317 State.Env.setStorageLocation(*UnwrapExpr, locForValue(*OptionalLoc));
321void transferArrowOpCall(
const Expr *UnwrapExpr,
const Expr *ObjectExpr,
322 LatticeTransferState &State) {
323 if (
auto *OptionalLoc = cast_or_null<RecordStorageLocation>(
324 getLocBehindPossiblePointer(*ObjectExpr, State.Env)))
326 *UnwrapExpr, State.Env.create<PointerValue>(locForValue(*OptionalLoc)));
329void transferMakeOptionalCall(
const CallExpr *E,
330 const MatchFinder::MatchResult &,
331 LatticeTransferState &State) {
333 *E, createOptionalValue(State.Env.getResultObjectLocation(*E),
334 State.Env.getBoolLiteralValue(
true), State.Env));
337void transferOptionalHasValueCall(
const CXXMemberCallExpr *CallExpr,
338 const MatchFinder::MatchResult &,
339 LatticeTransferState &State) {
340 if (
auto *HasValueVal = getHasValue(
342 State.Env.setValue(*CallExpr, *HasValueVal);
348void transferValueOrImpl(
350 LatticeTransferState &State,
351 const Formula &(*ModelPred)(Environment &
Env,
const Formula &ExprVal,
352 const Formula &HasValueVal)) {
353 auto &
Env = State.Env;
360 if (HasValueVal ==
nullptr)
364 HasValueVal->formula()));
367void transferValueOrStringEmptyCall(
const clang::Expr *ComparisonExpr,
368 const MatchFinder::MatchResult &
Result,
369 LatticeTransferState &State) {
370 return transferValueOrImpl(ComparisonExpr,
Result, State,
371 [](Environment &
Env,
const Formula &ExprVal,
372 const Formula &HasValueVal) ->
const Formula & {
385void transferValueOrNotEqX(
const Expr *ComparisonExpr,
386 const MatchFinder::MatchResult &
Result,
387 LatticeTransferState &State) {
388 transferValueOrImpl(ComparisonExpr,
Result, State,
389 [](Environment &
Env,
const Formula &ExprVal,
390 const Formula &HasValueVal) ->
const Formula & {
399void transferCallReturningOptional(
const CallExpr *E,
400 const MatchFinder::MatchResult &
Result,
401 LatticeTransferState &State) {
402 if (State.Env.getValue(*E) !=
nullptr)
405 RecordStorageLocation *Loc =
nullptr;
406 if (E->isPRValue()) {
407 Loc = &State.Env.getResultObjectLocation(*E);
409 Loc = cast_or_null<RecordStorageLocation>(State.Env.getStorageLocation(*E));
410 if (Loc ==
nullptr) {
411 Loc = &cast<RecordStorageLocation>(State.Env.createStorageLocation(*E));
412 State.Env.setStorageLocation(*E, *Loc);
417 createOptionalValue(*Loc, State.Env.makeAtomicBoolValue(), State.Env);
419 State.Env.setValue(*E, Val);
422void constructOptionalValue(
const Expr &E, Environment &
Env,
423 BoolValue &HasValueVal) {
431BoolValue &valueOrConversionHasValue(
const FunctionDecl &F,
const Expr &E,
432 const MatchFinder::MatchResult &MatchRes,
433 LatticeTransferState &State) {
434 assert(F.getTemplateSpecializationArgs() !=
nullptr);
435 assert(F.getTemplateSpecializationArgs()->size() > 0);
437 const int TemplateParamOptionalWrappersCount =
438 countOptionalWrappers(*MatchRes.Context, F.getTemplateSpecializationArgs()
441 .getNonReferenceType());
442 const int ArgTypeOptionalWrappersCount = countOptionalWrappers(
443 *MatchRes.Context, E.getType().getNonReferenceType());
447 if (TemplateParamOptionalWrappersCount == ArgTypeOptionalWrappersCount)
448 return State.Env.getBoolLiteralValue(
true);
453 cast_or_null<RecordStorageLocation>(State.Env.getStorageLocation(E));
454 if (
auto *HasValueVal = getHasValue(State.Env, Loc))
456 return State.Env.makeAtomicBoolValue();
459void transferValueOrConversionConstructor(
460 const CXXConstructExpr *E,
const MatchFinder::MatchResult &MatchRes,
461 LatticeTransferState &State) {
462 assert(E->getNumArgs() > 0);
464 constructOptionalValue(*E, State.Env,
465 valueOrConversionHasValue(*E->getConstructor(),
466 *E->getArg(0), MatchRes,
470void transferAssignment(
const CXXOperatorCallExpr *E, BoolValue &HasValueVal,
471 LatticeTransferState &State) {
472 assert(E->getNumArgs() > 0);
474 if (
auto *Loc = cast_or_null<RecordStorageLocation>(
475 State.Env.getStorageLocation(*E->getArg(0)))) {
476 createOptionalValue(*Loc, HasValueVal, State.Env);
479 State.Env.setStorageLocation(*E, *Loc);
483void transferValueOrConversionAssignment(
484 const CXXOperatorCallExpr *E,
const MatchFinder::MatchResult &MatchRes,
485 LatticeTransferState &State) {
486 assert(E->getNumArgs() > 1);
487 transferAssignment(E,
488 valueOrConversionHasValue(*E->getDirectCallee(),
489 *E->getArg(1), MatchRes, State),
493void transferNulloptAssignment(
const CXXOperatorCallExpr *E,
494 const MatchFinder::MatchResult &,
495 LatticeTransferState &State) {
496 transferAssignment(E, State.Env.getBoolLiteralValue(
false), State);
499void transferSwap(RecordStorageLocation *Loc1, RecordStorageLocation *Loc2,
505 if (Loc1 ==
nullptr) {
510 if (Loc2 ==
nullptr) {
521 BoolValue *BoolVal1 = getHasValue(
Env, Loc1);
522 if (BoolVal1 ==
nullptr)
525 BoolValue *BoolVal2 = getHasValue(
Env, Loc2);
526 if (BoolVal2 ==
nullptr)
529 createOptionalValue(*Loc1, *BoolVal2,
Env);
530 createOptionalValue(*Loc2, *BoolVal1,
Env);
533void transferSwapCall(
const CXXMemberCallExpr *E,
534 const MatchFinder::MatchResult &,
535 LatticeTransferState &State) {
536 assert(E->getNumArgs() == 1);
537 auto *OtherLoc = cast_or_null<RecordStorageLocation>(
538 State.Env.getStorageLocation(*E->getArg(0)));
542void transferStdSwapCall(
const CallExpr *E,
const MatchFinder::MatchResult &,
543 LatticeTransferState &State) {
544 assert(E->getNumArgs() == 2);
545 auto *Arg0Loc = cast_or_null<RecordStorageLocation>(
546 State.Env.getStorageLocation(*E->getArg(0)));
547 auto *Arg1Loc = cast_or_null<RecordStorageLocation>(
548 State.Env.getStorageLocation(*E->getArg(1)));
549 transferSwap(Arg0Loc, Arg1Loc, State.Env);
552void transferStdForwardCall(
const CallExpr *E,
const MatchFinder::MatchResult &,
553 LatticeTransferState &State) {
554 assert(E->getNumArgs() == 1);
556 if (
auto *Loc = State.Env.getStorageLocation(*E->getArg(0)))
557 State.Env.setStorageLocation(*E, *Loc);
560const Formula &evaluateEquality(Arena &A,
const Formula &EqVal,
561 const Formula &LHS,
const Formula &RHS) {
577 A.makeImplies(EqVal, A.makeOr(A.makeAnd(LHS, RHS),
578 A.makeAnd(A.makeNot(LHS), A.makeNot(RHS)))),
579 A.makeImplies(A.makeNot(EqVal), A.makeOr(LHS, RHS)));
583 const MatchFinder::MatchResult &,
584 LatticeTransferState &State) {
585 Environment &
Env = State.Env;
587 auto *CmpValue = &forceBoolValue(
Env, *CmpExpr);
588 auto *Arg0Loc = cast_or_null<RecordStorageLocation>(
590 if (
auto *LHasVal = getHasValue(
Env, Arg0Loc)) {
591 auto *Arg1Loc = cast_or_null<RecordStorageLocation>(
593 if (
auto *RHasVal = getHasValue(
Env, Arg1Loc)) {
594 if (CmpExpr->
getOperator() == clang::OO_ExclaimEqual)
595 CmpValue = &A.makeNot(*CmpValue);
596 Env.
assume(evaluateEquality(A, *CmpValue, LHasVal->formula(),
597 RHasVal->formula()));
605 auto *CmpValue = &forceBoolValue(
Env, *CmpExpr);
607 if (
auto *HasVal = getHasValue(
Env, Loc)) {
608 if (CmpExpr->
getOperator() == clang::OO_ExclaimEqual)
609 CmpValue = &A.makeNot(*CmpValue);
611 evaluateEquality(A, *CmpValue, HasVal->formula(), A.makeLiteral(
true)));
618 auto *CmpValue = &forceBoolValue(
Env, *CmpExpr);
620 if (
auto *HasVal = getHasValue(
Env, Loc)) {
621 if (CmpExpr->
getOperator() == clang::OO_ExclaimEqual)
622 CmpValue = &A.makeNot(*CmpValue);
623 Env.
assume(evaluateEquality(A, *CmpValue, HasVal->formula(),
624 A.makeLiteral(
false)));
628std::optional<StatementMatcher>
629ignorableOptional(
const UncheckedOptionalAccessModelOptions &Options) {
630 if (Options.IgnoreSmartPointerDereference) {
633 unless(hasArgument(0,
expr(hasOptionalType()))))));
641valueCall(
const std::optional<StatementMatcher> &IgnorableOptional) {
642 return isOptionalMemberCallWithNameMatcher(
hasName(
"value"),
647valueOperatorCall(
const std::optional<StatementMatcher> &IgnorableOptional) {
648 return expr(
anyOf(isOptionalOperatorCallWithName(
"*", IgnorableOptional),
649 isOptionalOperatorCallWithName(
"->", IgnorableOptional)));
652auto buildTransferMatchSwitch() {
656 return CFGMatchSwitchBuilder<LatticeTransferState>()
658 .CaseOfCFGStmt<CallExpr>(isMakeOptionalCall(), transferMakeOptionalCall)
661 .CaseOfCFGStmt<CXXConstructExpr>(
662 isOptionalInPlaceConstructor(),
663 [](
const CXXConstructExpr *E,
const MatchFinder::MatchResult &,
664 LatticeTransferState &State) {
665 constructOptionalValue(*E, State.Env,
666 State.Env.getBoolLiteralValue(
true));
669 .CaseOfCFGStmt<CXXConstructExpr>(
670 isOptionalNulloptConstructor(),
671 [](
const CXXConstructExpr *E,
const MatchFinder::MatchResult &,
672 LatticeTransferState &State) {
673 constructOptionalValue(*E, State.Env,
674 State.Env.getBoolLiteralValue(
false));
677 .CaseOfCFGStmt<CXXConstructExpr>(isOptionalValueOrConversionConstructor(),
678 transferValueOrConversionConstructor)
681 .CaseOfCFGStmt<CXXOperatorCallExpr>(
682 isOptionalValueOrConversionAssignment(),
683 transferValueOrConversionAssignment)
684 .CaseOfCFGStmt<CXXOperatorCallExpr>(isOptionalNulloptAssignment(),
685 transferNulloptAssignment)
688 .CaseOfCFGStmt<CXXMemberCallExpr>(
689 valueCall(std::nullopt),
690 [](
const CXXMemberCallExpr *E,
const MatchFinder::MatchResult &,
691 LatticeTransferState &State) {
692 transferUnwrapCall(E, E->getImplicitObjectArgument(), State);
696 .CaseOfCFGStmt<CallExpr>(isOptionalOperatorCallWithName(
"*"),
697 [](
const CallExpr *E,
698 const MatchFinder::MatchResult &,
699 LatticeTransferState &State) {
700 transferUnwrapCall(E, E->getArg(0), State);
704 .CaseOfCFGStmt<CallExpr>(isOptionalOperatorCallWithName(
"->"),
705 [](
const CallExpr *E,
706 const MatchFinder::MatchResult &,
707 LatticeTransferState &State) {
708 transferArrowOpCall(E, E->getArg(0), State);
714 .CaseOfCFGStmt<CXXMemberCallExpr>(
715 isOptionalMemberCallWithNameMatcher(
717 transferOptionalHasValueCall)
720 .CaseOfCFGStmt<CXXMemberCallExpr>(
721 isOptionalMemberCallWithNameMatcher(
hasName(
"operator bool")),
722 transferOptionalHasValueCall)
725 .CaseOfCFGStmt<CXXMemberCallExpr>(
726 isOptionalMemberCallWithNameMatcher(
hasName(
"emplace")),
727 [](
const CXXMemberCallExpr *E,
const MatchFinder::MatchResult &,
728 LatticeTransferState &State) {
729 if (RecordStorageLocation *Loc =
731 createOptionalValue(*Loc, State.Env.getBoolLiteralValue(
true),
737 .CaseOfCFGStmt<CXXMemberCallExpr>(
738 isOptionalMemberCallWithNameMatcher(
hasName(
"reset")),
739 [](
const CXXMemberCallExpr *E,
const MatchFinder::MatchResult &,
740 LatticeTransferState &State) {
741 if (RecordStorageLocation *Loc =
743 createOptionalValue(*Loc, State.Env.getBoolLiteralValue(
false),
749 .CaseOfCFGStmt<CXXMemberCallExpr>(
750 isOptionalMemberCallWithNameMatcher(
hasName(
"swap")),
754 .CaseOfCFGStmt<CallExpr>(isStdSwapCall(), transferStdSwapCall)
757 .CaseOfCFGStmt<CallExpr>(isStdForwardCall(), transferStdForwardCall)
760 .CaseOfCFGStmt<Expr>(isValueOrStringEmptyCall(),
761 transferValueOrStringEmptyCall)
764 .CaseOfCFGStmt<Expr>(isValueOrNotEqX(), transferValueOrNotEqX)
767 .CaseOfCFGStmt<CXXOperatorCallExpr>(
768 isComparisonOperatorCall(hasOptionalType(), hasOptionalType()),
769 transferOptionalAndOptionalCmp)
770 .CaseOfCFGStmt<CXXOperatorCallExpr>(
771 isComparisonOperatorCall(hasOptionalType(), hasNulloptType()),
773 const MatchFinder::MatchResult &, LatticeTransferState &State) {
774 transferOptionalAndNulloptCmp(Cmp, Cmp->getArg(0), State.Env);
776 .CaseOfCFGStmt<CXXOperatorCallExpr>(
777 isComparisonOperatorCall(hasNulloptType(), hasOptionalType()),
779 const MatchFinder::MatchResult &, LatticeTransferState &State) {
780 transferOptionalAndNulloptCmp(Cmp, Cmp->getArg(1), State.Env);
782 .CaseOfCFGStmt<CXXOperatorCallExpr>(
783 isComparisonOperatorCall(
785 unless(
anyOf(hasOptionalType(), hasNulloptType()))),
787 const MatchFinder::MatchResult &, LatticeTransferState &State) {
788 transferOptionalAndValueCmp(Cmp, Cmp->getArg(0), State.Env);
790 .CaseOfCFGStmt<CXXOperatorCallExpr>(
791 isComparisonOperatorCall(
792 unless(
anyOf(hasOptionalType(), hasNulloptType())),
795 const MatchFinder::MatchResult &, LatticeTransferState &State) {
796 transferOptionalAndValueCmp(Cmp, Cmp->getArg(1), State.Env);
800 .CaseOfCFGStmt<CallExpr>(isCallReturningOptional(),
801 transferCallReturningOptional)
807 const Environment &
Env) {
808 if (
auto *OptionalLoc = cast_or_null<RecordStorageLocation>(
809 getLocBehindPossiblePointer(*ObjectExpr,
Env))) {
810 auto *Prop =
Env.
getValue(locForHasValue(*OptionalLoc));
811 if (
auto *HasValueVal = cast_or_null<BoolValue>(Prop)) {
820 return {ObjectExpr->getBeginLoc()};
823auto buildDiagnoseMatchSwitch(
824 const UncheckedOptionalAccessModelOptions &Options) {
828 auto IgnorableOptional = ignorableOptional(Options);
829 return CFGMatchSwitchBuilder<
const Environment,
832 .CaseOfCFGStmt<CXXMemberCallExpr>(
833 valueCall(IgnorableOptional),
834 [](
const CXXMemberCallExpr *E,
const MatchFinder::MatchResult &,
835 const Environment &
Env) {
836 return diagnoseUnwrapCall(E->getImplicitObjectArgument(),
Env);
840 .CaseOfCFGStmt<CallExpr>(valueOperatorCall(IgnorableOptional),
841 [](
const CallExpr *E,
842 const MatchFinder::MatchResult &,
843 const Environment &
Env) {
844 return diagnoseUnwrapCall(E->getArg(0),
Env);
853 return optionalClass();
859 return CTSD->getTemplateArgs()[0].getAsType();
865 TransferMatchSwitch(buildTransferMatchSwitch()) {
866 Env.getDataflowAnalysisContext().setSyntheticFieldCallback(
867 [&Ctx](
QualType Ty) -> llvm::StringMap<QualType> {
868 if (!isOptionalType(Ty))
871 {
"has_value", Ctx.
BoolTy}};
877 LatticeTransferState State(L,
Env);
883 : DiagnoseMatchSwitch(buildDiagnoseMatchSwitch(Options)) {}
Defines the clang::ASTContext interface.
#define AST_MATCHER(Type, DefineMatcher)
AST_MATCHER(Type, DefineMatcher) { ... } defines a zero parameter function named DefineMatcher() that...
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
Defines the clang::SourceLocation class and associated facilities.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Represents a top-level expression in a basic block.
Represents a call to a member function that may be written either with member call syntax (e....
A call to an overloaded operator written using operator syntax.
OverloadedOperatorKind getOperator() const
Returns the kind of overloaded operator that this expression refers to.
Represents a C++ struct/union/class.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
DeclContext * getParent()
getParent - Returns the containing DeclContext.
bool isTranslationUnit() const
DeclContext * getDeclContext()
bool isIdentifier() const
Predicate functions for querying what type of name this is.
This represents one expression.
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Represent a C++ namespace.
A (possibly-)qualified type.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
const Formula & makeImplies(const Formula &LHS, const Formula &RHS)
Returns a formula for LHS => RHS.
Base class template for dataflow analyses built on a single lattice type.
ASTContext & getASTContext() final
Holds the state of the program (store and heap) at a given program point.
StorageLocation * getStorageLocation(const ValueDecl &D) const
Returns the storage location assigned to D in the environment, or null if D isn't assigned a storage ...
BoolValue & makeAtomicBoolValue() const
Returns an atomic boolean value.
bool proves(const Formula &) const
Returns true if the formula is always true when this point is reached.
Value * getValue(const StorageLocation &Loc) const
Returns the value assigned to Loc in the environment or null if Loc isn't assigned a value in the env...
void assume(const Formula &)
Record a fact that must be true if this point in the program is reached.
RecordStorageLocation & getResultObjectLocation(const Expr &RecordPRValue)
Returns the location of the result object for a record-type prvalue.
void setValue(const StorageLocation &Loc, Value &Val)
Assigns Val as the value of Loc in the environment.
std::enable_if_t< std::is_base_of< Value, T >::value, T & > create(Args &&...args)
Creates a T (some subclass of Value), forwarding args to the constructor, and returns a reference to ...
Trivial lattice for dataflow analysis with exactly one element.
UncheckedOptionalAccessDiagnoser(UncheckedOptionalAccessModelOptions Options={})
Dataflow analysis that models whether optionals hold values or not.
UncheckedOptionalAccessModel(ASTContext &Ctx, dataflow::Environment &Env)
void transfer(const CFGElement &Elt, NoopLattice &L, Environment &Env)
static ast_matchers::DeclarationMatcher optionalClassDecl()
Returns a matcher for the optional classes covered by this model.
const internal::VariadicOperatorMatcherFunc< 1, 1 > unless
Matches if the provided matcher does not match.
internal::Matcher< Decl > DeclarationMatcher
Types of matchers for the top-level classes in the AST class hierarchy.
const internal::VariadicDynCastAllOfMatcher< Stmt, StringLiteral > stringLiteral
Matches string literals (also matches wide string literals).
const AstTypeMatcher< PointerType > pointerType
Matches pointer types, but does not match Objective-C object pointer types.
internal::Matcher< NamedDecl > hasName(StringRef Name)
Matches NamedDecl nodes that have the specified name.
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
const internal::VariadicDynCastAllOfMatcher< Decl, NamedDecl > namedDecl
Matches a declaration of anything that could have a name.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const internal::VariadicFunction< internal::Matcher< NamedDecl >, StringRef, internal::hasAnyNameFunc > hasAnyName
Matches NamedDecl nodes that have any of the specified names.
const internal::MapAnyOfMatcher< BinaryOperator, CXXOperatorCallExpr, CXXRewrittenBinaryOperator > binaryOperation
Matches nodes which can be used with binary operators.
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXMemberCallExpr > cxxMemberCallExpr
Matches member call expressions.
const internal::VariadicDynCastAllOfMatcher< Decl, CXXConstructorDecl > cxxConstructorDecl
Matches C++ constructor declarations.
internal::PolymorphicMatcher< internal::ValueEqualsMatcher, void(internal::AllNodeBaseTypes), ValueT > equals(const ValueT &Value)
Matches literals that are equal to the given value of type ValueT.
internal::Matcher< Stmt > StatementMatcher
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXConstructExpr > cxxConstructExpr
Matches constructor call expressions (including implicit ones).
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXOperatorCallExpr > cxxOperatorCallExpr
Matches overloaded operator calls.
internal::PolymorphicMatcher< internal::HasOverloadedOperatorNameMatcher, AST_POLYMORPHIC_SUPPORTED_TYPES(CXXOperatorCallExpr, FunctionDecl), std::vector< std::string > > hasOverloadedOperatorName(StringRef Name)
Matches overloaded operator names.
const internal::VariadicDynCastAllOfMatcher< Decl, ClassTemplateSpecializationDecl > classTemplateSpecializationDecl
Matches C++ class template specializations.
const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl
Matches function declarations.
const AstTypeMatcher< RecordType > recordType
Matches record types (e.g.
const internal::VariadicDynCastAllOfMatcher< Stmt, MemberExpr > memberExpr
Matches member expressions.
const AstTypeMatcher< ReferenceType > referenceType
Matches both lvalue and rvalue reference types.
const internal::VariadicDynCastAllOfMatcher< Decl, RecordDecl > recordDecl
Matches class, struct, and union declarations.
const internal::VariadicDynCastAllOfMatcher< Stmt, IntegerLiteral > integerLiteral
Matches integer literals of all sizes / encodings, e.g.
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXNullPtrLiteralExpr > cxxNullPtrLiteralExpr
Matches nullptr literal.
internal::PolymorphicMatcher< internal::HasDeclarationMatcher, void(internal::HasDeclarationSupportedTypes), internal::Matcher< Decl > > hasDeclaration(const internal::Matcher< Decl > &InnerMatcher)
Matches a node if the declaration associated with that node matches the given matcher.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
const internal::VariadicDynCastAllOfMatcher< Decl, CXXMethodDecl > cxxMethodDecl
Matches method declarations.
const internal::VariadicAllOfMatcher< QualType > qualType
Matches QualTypes in the clang AST.
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXThisExpr > cxxThisExpr
Matches implicit and explicit this expressions.
static bool hasOptionalClassName(const CXXRecordDecl &RD)
static bool isTopLevelNamespaceWithName(const NamespaceDecl &NS, llvm::StringRef Name)
static QualType valueTypeFromOptionalType(QualType OptionalTy)
RecordStorageLocation * getImplicitObjectLocation(const CXXMemberCallExpr &MCE, const Environment &Env)
Returns the storage location for the implicit object of a CXXMemberCallExpr, or null if none is defin...
@ Result
The result type of a method or function.