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());
87using LatticeTransferState = TransferState<NoopLattice>;
95auto desugarsToOptionalType() {
96 return hasUnqualifiedDesugaredType(
100auto desugarsToOptionalOrDerivedType() {
101 return hasUnqualifiedDesugaredType(
105auto hasOptionalType() {
return hasType(desugarsToOptionalType()); }
109auto hasOptionalOrDerivedType() {
110 return hasType(desugarsToOptionalOrDerivedType());
113QualType getPublicType(
const Expr *
E) {
114 auto *
Cast = dyn_cast<ImplicitCastExpr>(
E->IgnoreParens());
115 if (Cast ==
nullptr ||
Cast->getCastKind() != CK_UncheckedDerivedToBase) {
116 QualType Ty =
E->getType();
117 if (Ty->isPointerType())
118 return Ty->getPointeeType();
125 bool CastingFromThis = isa<CXXThisExpr>(
Cast->getSubExpr());
129 const CXXBaseSpecifier *PublicBase =
nullptr;
130 for (
const CXXBaseSpecifier *
Base :
Cast->path()) {
131 if (
Base->getAccessSpecifier() !=
AS_public && !CastingFromThis)
134 CastingFromThis =
false;
137 if (PublicBase !=
nullptr)
138 return PublicBase->getType();
143 return getPublicType(
Cast->getSubExpr());
170QualType getPublicReceiverType(
const CXXMemberCallExpr &MCE) {
171 return getPublicType(MCE.getImplicitObjectArgument());
175 ast_matchers::internal::Matcher<QualType>, InnerMatcher) {
176 return InnerMatcher.matches(getPublicReceiverType(
Node), Finder, Builder);
179auto isOptionalMemberCallWithNameMatcher(
180 ast_matchers::internal::Matcher<NamedDecl> matcher,
181 const std::optional<StatementMatcher> &Ignorable = std::nullopt) {
184 publicReceiverType(desugarsToOptionalType()),
188auto isOptionalOperatorCallWithName(
189 llvm::StringRef operator_name,
190 const std::optional<StatementMatcher> &Ignorable = std::nullopt) {
197auto isMakeOptionalCall() {
199 "std::make_optional",
"base::make_optional",
200 "absl::make_optional",
"folly::make_optional"))),
204auto nulloptTypeDecl() {
206 "base::nullopt_t",
"folly::None"));
209auto hasNulloptType() {
return hasType(nulloptTypeDecl()); }
213 "base::in_place_t",
"folly::in_place_t"));
216auto isOptionalNulloptConstructor() {
219 hasParameter(0, hasNulloptType()))),
220 hasOptionalOrDerivedType());
223auto isOptionalInPlaceConstructor() {
225 hasOptionalOrDerivedType());
228auto isOptionalValueOrConversionConstructor() {
232 argumentCountIs(1), hasArgument(0,
unless(hasNulloptType())),
233 hasOptionalOrDerivedType());
236auto isOptionalValueOrConversionAssignment() {
241 anyOf(isCopyAssignmentOperator(), isMoveAssignmentOperator())))),
242 argumentCountIs(2), hasArgument(1,
unless(hasNulloptType())));
245auto isOptionalNulloptAssignment() {
249 argumentCountIs(2), hasArgument(1, hasNulloptType()));
252auto isStdSwapCall() {
255 hasArgument(0, hasOptionalOrDerivedType()),
256 hasArgument(1, hasOptionalOrDerivedType()));
259auto isStdForwardCall() {
262 hasArgument(0, hasOptionalOrDerivedType()));
265constexpr llvm::StringLiteral ValueOrCallID =
"ValueOrCall";
267auto isValueOrStringEmptyCall() {
271 onImplicitObjectArgument(ignoringImplicit(
274 ofClass(optionalClass()))),
276 .bind(ValueOrCallID))));
279auto isValueOrNotEqX() {
280 auto ComparesToSame = [](ast_matchers::internal::Matcher<Stmt> Arg) {
285 ofClass(optionalClass()))),
287 .bind(ValueOrCallID)),
288 ignoringImplicit(Arg));
302auto isCallReturningOptional() {
304 anyOf(desugarsToOptionalOrDerivedType(),
305 referenceType(pointee(desugarsToOptionalOrDerivedType()))))));
308template <
typename L,
typename R>
309auto isComparisonOperatorCall(L lhs_arg_matcher, R rhs_arg_matcher) {
312 argumentCountIs(2), hasArgument(0, lhs_arg_matcher),
313 hasArgument(1, rhs_arg_matcher));
317const Formula &forceBoolValue(Environment &
Env,
const Expr &Expr) {
319 if (
Value !=
nullptr)
320 return Value->formula();
324 return Value->formula();
327StorageLocation &locForHasValue(
const RecordStorageLocation &OptionalLoc) {
328 return OptionalLoc.getSyntheticField(
"has_value");
331StorageLocation &locForValue(
const RecordStorageLocation &OptionalLoc) {
332 return OptionalLoc.getSyntheticField(
"value");
337void setHasValue(RecordStorageLocation &OptionalLoc, BoolValue &HasValueVal,
339 Env.
setValue(locForHasValue(OptionalLoc), HasValueVal);
344BoolValue *getHasValue(Environment &
Env, RecordStorageLocation *OptionalLoc) {
345 if (OptionalLoc ==
nullptr)
347 StorageLocation &HasValueLoc = locForHasValue(*OptionalLoc);
348 auto *HasValueVal =
Env.
get<BoolValue>(HasValueLoc);
349 if (HasValueVal ==
nullptr) {
356QualType valueTypeFromOptionalDecl(
const CXXRecordDecl &RD) {
357 auto &CTSD = cast<ClassTemplateSpecializationDecl>(RD);
358 return CTSD.getTemplateArgs()[0].getAsType();
365int countOptionalWrappers(
const ASTContext &ASTCtx, QualType Type) {
370 return 1 + countOptionalWrappers(
372 valueTypeFromOptionalDecl(*Optional).getDesugaredType(ASTCtx));
375StorageLocation *getLocBehindPossiblePointer(
const Expr &
E,
376 const Environment &
Env) {
378 if (
auto *PointerVal = dyn_cast_or_null<PointerValue>(
Env.
getValue(
E)))
379 return &PointerVal->getPointeeLoc();
385void transferUnwrapCall(
const Expr *UnwrapExpr,
const Expr *ObjectExpr,
386 LatticeTransferState &State) {
387 if (
auto *OptionalLoc = cast_or_null<RecordStorageLocation>(
388 getLocBehindPossiblePointer(*ObjectExpr, State.Env))) {
389 if (State.Env.getStorageLocation(*UnwrapExpr) ==
nullptr)
390 State.Env.setStorageLocation(*UnwrapExpr, locForValue(*OptionalLoc));
394void transferArrowOpCall(
const Expr *UnwrapExpr,
const Expr *ObjectExpr,
395 LatticeTransferState &State) {
396 if (
auto *OptionalLoc = cast_or_null<RecordStorageLocation>(
397 getLocBehindPossiblePointer(*ObjectExpr, State.Env)))
399 *UnwrapExpr, State.Env.create<PointerValue>(locForValue(*OptionalLoc)));
402void transferMakeOptionalCall(
const CallExpr *
E,
403 const MatchFinder::MatchResult &,
404 LatticeTransferState &State) {
405 setHasValue(State.Env.getResultObjectLocation(*
E),
406 State.Env.getBoolLiteralValue(
true), State.Env);
409void transferOptionalHasValueCall(
const CXXMemberCallExpr *CallExpr,
410 const MatchFinder::MatchResult &,
411 LatticeTransferState &State) {
412 if (
auto *HasValueVal = getHasValue(
414 State.Env.setValue(*CallExpr, *HasValueVal);
420void transferValueOrImpl(
422 LatticeTransferState &State,
423 const Formula &(*ModelPred)(Environment &
Env,
const Formula &ExprVal,
424 const Formula &HasValueVal)) {
425 auto &
Env = State.Env;
432 if (HasValueVal ==
nullptr)
436 HasValueVal->formula()));
439void transferValueOrStringEmptyCall(
const clang::Expr *ComparisonExpr,
440 const MatchFinder::MatchResult &
Result,
441 LatticeTransferState &State) {
442 return transferValueOrImpl(ComparisonExpr,
Result, State,
443 [](Environment &
Env,
const Formula &ExprVal,
444 const Formula &HasValueVal) ->
const Formula & {
457void transferValueOrNotEqX(
const Expr *ComparisonExpr,
458 const MatchFinder::MatchResult &
Result,
459 LatticeTransferState &State) {
460 transferValueOrImpl(ComparisonExpr,
Result, State,
461 [](Environment &
Env,
const Formula &ExprVal,
462 const Formula &HasValueVal) ->
const Formula & {
471void transferCallReturningOptional(
const CallExpr *
E,
472 const MatchFinder::MatchResult &
Result,
473 LatticeTransferState &State) {
474 RecordStorageLocation *
Loc =
nullptr;
475 if (
E->isPRValue()) {
476 Loc = &State.Env.getResultObjectLocation(*
E);
478 Loc = State.Env.get<RecordStorageLocation>(*E);
479 if (
Loc ==
nullptr) {
480 Loc = &cast<RecordStorageLocation>(State.Env.createStorageLocation(*
E));
481 State.Env.setStorageLocation(*
E, *
Loc);
485 if (State.Env.getValue(locForHasValue(*
Loc)) !=
nullptr)
488 setHasValue(*
Loc, State.Env.makeAtomicBoolValue(), State.Env);
491void constructOptionalValue(
const Expr &
E, Environment &
Env,
492 BoolValue &HasValueVal) {
494 setHasValue(
Loc, HasValueVal,
Env);
500BoolValue &valueOrConversionHasValue(QualType DestType,
const Expr &
E,
501 const MatchFinder::MatchResult &MatchRes,
502 LatticeTransferState &State) {
503 const int DestTypeOptionalWrappersCount =
504 countOptionalWrappers(*MatchRes.Context, DestType);
505 const int ArgTypeOptionalWrappersCount = countOptionalWrappers(
506 *MatchRes.Context,
E.getType().getNonReferenceType());
513 if (DestTypeOptionalWrappersCount != ArgTypeOptionalWrappersCount)
514 return State.Env.getBoolLiteralValue(
true);
520 auto *
Loc = State.Env.get<RecordStorageLocation>(
E);
521 if (
auto *HasValueVal = getHasValue(State.Env,
Loc))
523 return State.Env.makeAtomicBoolValue();
526void transferValueOrConversionConstructor(
527 const CXXConstructExpr *
E,
const MatchFinder::MatchResult &MatchRes,
528 LatticeTransferState &State) {
529 assert(
E->getNumArgs() > 0);
531 constructOptionalValue(
533 valueOrConversionHasValue(
534 E->getConstructor()->getThisType()->getPointeeType(), *
E->getArg(0),
538void transferAssignment(
const CXXOperatorCallExpr *
E, BoolValue &HasValueVal,
539 LatticeTransferState &State) {
540 assert(
E->getNumArgs() > 0);
542 if (
auto *
Loc = State.Env.get<RecordStorageLocation>(*
E->getArg(0))) {
543 setHasValue(*
Loc, HasValueVal, State.Env);
546 State.Env.setStorageLocation(*
E, *
Loc);
550void transferValueOrConversionAssignment(
551 const CXXOperatorCallExpr *
E,
const MatchFinder::MatchResult &MatchRes,
552 LatticeTransferState &State) {
553 assert(
E->getNumArgs() > 1);
556 valueOrConversionHasValue(
E->getArg(0)->getType().getNonReferenceType(),
557 *
E->getArg(1), MatchRes, State),
561void transferNulloptAssignment(
const CXXOperatorCallExpr *
E,
562 const MatchFinder::MatchResult &,
563 LatticeTransferState &State) {
564 transferAssignment(
E, State.Env.getBoolLiteralValue(
false), State);
567void transferSwap(RecordStorageLocation *Loc1, RecordStorageLocation *Loc2,
573 if (Loc1 ==
nullptr) {
578 if (Loc2 ==
nullptr) {
589 BoolValue *BoolVal1 = getHasValue(
Env, Loc1);
590 if (BoolVal1 ==
nullptr)
593 BoolValue *BoolVal2 = getHasValue(
Env, Loc2);
594 if (BoolVal2 ==
nullptr)
597 setHasValue(*Loc1, *BoolVal2,
Env);
598 setHasValue(*Loc2, *BoolVal1,
Env);
601void transferSwapCall(
const CXXMemberCallExpr *
E,
602 const MatchFinder::MatchResult &,
603 LatticeTransferState &State) {
604 assert(
E->getNumArgs() == 1);
605 auto *OtherLoc = State.Env.get<RecordStorageLocation>(*
E->getArg(0));
609void transferStdSwapCall(
const CallExpr *
E,
const MatchFinder::MatchResult &,
610 LatticeTransferState &State) {
611 assert(
E->getNumArgs() == 2);
612 auto *Arg0Loc = State.Env.get<RecordStorageLocation>(*
E->getArg(0));
613 auto *Arg1Loc = State.Env.get<RecordStorageLocation>(*
E->getArg(1));
614 transferSwap(Arg0Loc, Arg1Loc, State.Env);
617void transferStdForwardCall(
const CallExpr *
E,
const MatchFinder::MatchResult &,
618 LatticeTransferState &State) {
619 assert(
E->getNumArgs() == 1);
621 if (
auto *
Loc = State.Env.getStorageLocation(*
E->getArg(0)))
622 State.Env.setStorageLocation(*
E, *
Loc);
625const Formula &evaluateEquality(Arena &A,
const Formula &EqVal,
626 const Formula &LHS,
const Formula &RHS) {
642 A.makeImplies(EqVal, A.makeOr(A.makeAnd(LHS, RHS),
643 A.makeAnd(A.makeNot(LHS), A.makeNot(RHS)))),
644 A.makeImplies(A.makeNot(EqVal), A.makeOr(LHS, RHS)));
648 const MatchFinder::MatchResult &,
649 LatticeTransferState &State) {
650 Environment &
Env = State.Env;
652 auto *CmpValue = &forceBoolValue(
Env, *CmpExpr);
653 auto *Arg0Loc =
Env.
get<RecordStorageLocation>(*CmpExpr->
getArg(0));
654 if (
auto *LHasVal = getHasValue(
Env, Arg0Loc)) {
655 auto *Arg1Loc =
Env.
get<RecordStorageLocation>(*CmpExpr->
getArg(1));
656 if (
auto *RHasVal = getHasValue(
Env, Arg1Loc)) {
657 if (CmpExpr->
getOperator() == clang::OO_ExclaimEqual)
658 CmpValue = &A.makeNot(*CmpValue);
659 Env.
assume(evaluateEquality(A, *CmpValue, LHasVal->formula(),
660 RHasVal->formula()));
668 auto *CmpValue = &forceBoolValue(
Env, *CmpExpr);
669 auto *
Loc =
Env.
get<RecordStorageLocation>(*E);
670 if (
auto *HasVal = getHasValue(
Env,
Loc)) {
671 if (CmpExpr->
getOperator() == clang::OO_ExclaimEqual)
672 CmpValue = &A.makeNot(*CmpValue);
674 evaluateEquality(A, *CmpValue, HasVal->formula(), A.makeLiteral(
true)));
681 auto *CmpValue = &forceBoolValue(
Env, *CmpExpr);
682 auto *
Loc =
Env.
get<RecordStorageLocation>(*E);
683 if (
auto *HasVal = getHasValue(
Env,
Loc)) {
684 if (CmpExpr->
getOperator() == clang::OO_ExclaimEqual)
685 CmpValue = &A.makeNot(*CmpValue);
686 Env.
assume(evaluateEquality(A, *CmpValue, HasVal->formula(),
687 A.makeLiteral(
false)));
691std::optional<StatementMatcher>
692ignorableOptional(
const UncheckedOptionalAccessModelOptions &Options) {
693 if (Options.IgnoreSmartPointerDereference) {
696 unless(hasArgument(0,
expr(hasOptionalType()))))));
704valueCall(
const std::optional<StatementMatcher> &IgnorableOptional) {
705 return isOptionalMemberCallWithNameMatcher(
hasName(
"value"),
710valueOperatorCall(
const std::optional<StatementMatcher> &IgnorableOptional) {
711 return expr(
anyOf(isOptionalOperatorCallWithName(
"*", IgnorableOptional),
712 isOptionalOperatorCallWithName(
"->", IgnorableOptional)));
715auto buildTransferMatchSwitch() {
719 return CFGMatchSwitchBuilder<LatticeTransferState>()
721 .CaseOfCFGStmt<CallExpr>(isMakeOptionalCall(), transferMakeOptionalCall)
724 .CaseOfCFGStmt<CXXConstructExpr>(
725 isOptionalInPlaceConstructor(),
726 [](
const CXXConstructExpr *
E,
const MatchFinder::MatchResult &,
727 LatticeTransferState &State) {
728 constructOptionalValue(*
E, State.Env,
729 State.Env.getBoolLiteralValue(
true));
732 .CaseOfCFGStmt<CXXConstructExpr>(
733 isOptionalNulloptConstructor(),
734 [](
const CXXConstructExpr *
E,
const MatchFinder::MatchResult &,
735 LatticeTransferState &State) {
736 constructOptionalValue(*
E, State.Env,
737 State.Env.getBoolLiteralValue(
false));
740 .CaseOfCFGStmt<CXXConstructExpr>(isOptionalValueOrConversionConstructor(),
741 transferValueOrConversionConstructor)
744 .CaseOfCFGStmt<CXXOperatorCallExpr>(
745 isOptionalValueOrConversionAssignment(),
746 transferValueOrConversionAssignment)
747 .CaseOfCFGStmt<CXXOperatorCallExpr>(isOptionalNulloptAssignment(),
748 transferNulloptAssignment)
751 .CaseOfCFGStmt<CXXMemberCallExpr>(
752 valueCall(std::nullopt),
753 [](
const CXXMemberCallExpr *
E,
const MatchFinder::MatchResult &,
754 LatticeTransferState &State) {
755 transferUnwrapCall(
E,
E->getImplicitObjectArgument(), State);
759 .CaseOfCFGStmt<CallExpr>(isOptionalOperatorCallWithName(
"*"),
760 [](
const CallExpr *
E,
761 const MatchFinder::MatchResult &,
762 LatticeTransferState &State) {
763 transferUnwrapCall(
E,
E->getArg(0), State);
767 .CaseOfCFGStmt<CallExpr>(isOptionalOperatorCallWithName(
"->"),
768 [](
const CallExpr *
E,
769 const MatchFinder::MatchResult &,
770 LatticeTransferState &State) {
771 transferArrowOpCall(
E,
E->getArg(0), State);
777 .CaseOfCFGStmt<CXXMemberCallExpr>(
778 isOptionalMemberCallWithNameMatcher(
780 transferOptionalHasValueCall)
783 .CaseOfCFGStmt<CXXMemberCallExpr>(
784 isOptionalMemberCallWithNameMatcher(
hasName(
"operator bool")),
785 transferOptionalHasValueCall)
788 .CaseOfCFGStmt<CXXMemberCallExpr>(
789 isOptionalMemberCallWithNameMatcher(
hasName(
"emplace")),
790 [](
const CXXMemberCallExpr *
E,
const MatchFinder::MatchResult &,
791 LatticeTransferState &State) {
792 if (RecordStorageLocation *
Loc =
794 setHasValue(*
Loc, State.Env.getBoolLiteralValue(
true), State.Env);
799 .CaseOfCFGStmt<CXXMemberCallExpr>(
800 isOptionalMemberCallWithNameMatcher(
hasName(
"reset")),
801 [](
const CXXMemberCallExpr *
E,
const MatchFinder::MatchResult &,
802 LatticeTransferState &State) {
803 if (RecordStorageLocation *
Loc =
805 setHasValue(*
Loc, State.Env.getBoolLiteralValue(
false),
811 .CaseOfCFGStmt<CXXMemberCallExpr>(
812 isOptionalMemberCallWithNameMatcher(
hasName(
"swap")),
816 .CaseOfCFGStmt<CallExpr>(isStdSwapCall(), transferStdSwapCall)
819 .CaseOfCFGStmt<CallExpr>(isStdForwardCall(), transferStdForwardCall)
822 .CaseOfCFGStmt<Expr>(isValueOrStringEmptyCall(),
823 transferValueOrStringEmptyCall)
826 .CaseOfCFGStmt<Expr>(isValueOrNotEqX(), transferValueOrNotEqX)
829 .CaseOfCFGStmt<CXXOperatorCallExpr>(
830 isComparisonOperatorCall(hasOptionalType(), hasOptionalType()),
831 transferOptionalAndOptionalCmp)
832 .CaseOfCFGStmt<CXXOperatorCallExpr>(
833 isComparisonOperatorCall(hasOptionalType(), hasNulloptType()),
835 const MatchFinder::MatchResult &, LatticeTransferState &State) {
836 transferOptionalAndNulloptCmp(Cmp, Cmp->getArg(0), State.Env);
838 .CaseOfCFGStmt<CXXOperatorCallExpr>(
839 isComparisonOperatorCall(hasNulloptType(), hasOptionalType()),
841 const MatchFinder::MatchResult &, LatticeTransferState &State) {
842 transferOptionalAndNulloptCmp(Cmp, Cmp->getArg(1), State.Env);
844 .CaseOfCFGStmt<CXXOperatorCallExpr>(
845 isComparisonOperatorCall(
847 unless(
anyOf(hasOptionalType(), hasNulloptType()))),
849 const MatchFinder::MatchResult &, LatticeTransferState &State) {
850 transferOptionalAndValueCmp(Cmp, Cmp->getArg(0), State.Env);
852 .CaseOfCFGStmt<CXXOperatorCallExpr>(
853 isComparisonOperatorCall(
854 unless(
anyOf(hasOptionalType(), hasNulloptType())),
857 const MatchFinder::MatchResult &, LatticeTransferState &State) {
858 transferOptionalAndValueCmp(Cmp, Cmp->getArg(1), State.Env);
862 .CaseOfCFGStmt<CallExpr>(isCallReturningOptional(),
863 transferCallReturningOptional)
869 const Environment &
Env) {
870 if (
auto *OptionalLoc = cast_or_null<RecordStorageLocation>(
871 getLocBehindPossiblePointer(*ObjectExpr,
Env))) {
872 auto *Prop =
Env.
getValue(locForHasValue(*OptionalLoc));
873 if (
auto *HasValueVal = cast_or_null<BoolValue>(Prop)) {
882 return {ObjectExpr->getBeginLoc()};
885auto buildDiagnoseMatchSwitch(
886 const UncheckedOptionalAccessModelOptions &Options) {
890 auto IgnorableOptional = ignorableOptional(Options);
891 return CFGMatchSwitchBuilder<
const Environment,
894 .CaseOfCFGStmt<CXXMemberCallExpr>(
895 valueCall(IgnorableOptional),
896 [](
const CXXMemberCallExpr *
E,
const MatchFinder::MatchResult &,
897 const Environment &
Env) {
898 return diagnoseUnwrapCall(
E->getImplicitObjectArgument(),
Env);
902 .CaseOfCFGStmt<CallExpr>(valueOperatorCall(IgnorableOptional),
903 [](
const CallExpr *
E,
904 const MatchFinder::MatchResult &,
905 const Environment &
Env) {
906 return diagnoseUnwrapCall(
E->getArg(0),
Env);
921 TransferMatchSwitch(buildTransferMatchSwitch()) {
922 Env.getDataflowAnalysisContext().setSyntheticFieldCallback(
923 [&Ctx](
QualType Ty) -> llvm::StringMap<QualType> {
928 return {{
"value", valueTypeFromOptionalDecl(*
Optional)},
929 {
"has_value", Ctx.
BoolTy}};
935 LatticeTransferState State(L,
Env);
941 : 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...
#define AST_MATCHER_P(Type, DefineMatcher, ParamType, Param)
AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) { ... } defines a single-parameter function name...
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 base class of a C++ class.
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.
bool hasDefinition() const
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) const
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_v< StorageLocation, T >, T * > get(const ValueDecl &D) const
Returns the result of casting getStorageLocation(...) to a subclass of StorageLocation (using cast_or...
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).
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.
internal::TrueMatcher anything()
Matches any node.
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, FunctionDecl > functionDecl
Matches function declarations.
const AstTypeMatcher< RecordType > recordType
Matches record types (e.g.
const internal::VariadicDynCastAllOfMatcher< Stmt, MemberExpr > memberExpr
Matches member expressions.
const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class declarations.
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)
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...
static const CXXRecordDecl * getOptionalBaseClass(const CXXRecordDecl *RD)
bool Cast(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.