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);
345RecordValue &createOptionalValue(RecordStorageLocation &Loc,
346 BoolValue &HasValueVal, Environment &
Env) {
347 auto &OptionalVal =
Env.
create<RecordValue>(Loc);
349 setHasValue(Loc, HasValueVal,
Env);
355BoolValue *getHasValue(Environment &
Env, RecordStorageLocation *OptionalLoc) {
356 if (OptionalLoc ==
nullptr)
358 StorageLocation &HasValueLoc = locForHasValue(*OptionalLoc);
359 auto *HasValueVal =
Env.
get<BoolValue>(HasValueLoc);
360 if (HasValueVal ==
nullptr) {
367QualType valueTypeFromOptionalDecl(
const CXXRecordDecl &RD) {
368 auto &CTSD = cast<ClassTemplateSpecializationDecl>(RD);
369 return CTSD.getTemplateArgs()[0].getAsType();
376int countOptionalWrappers(
const ASTContext &ASTCtx, QualType Type) {
381 return 1 + countOptionalWrappers(
383 valueTypeFromOptionalDecl(*Optional).getDesugaredType(ASTCtx));
386StorageLocation *getLocBehindPossiblePointer(
const Expr &E,
387 const Environment &
Env) {
389 if (
auto *PointerVal = dyn_cast_or_null<PointerValue>(
Env.
getValue(E)))
390 return &PointerVal->getPointeeLoc();
396void transferUnwrapCall(
const Expr *UnwrapExpr,
const Expr *ObjectExpr,
397 LatticeTransferState &State) {
398 if (
auto *OptionalLoc = cast_or_null<RecordStorageLocation>(
399 getLocBehindPossiblePointer(*ObjectExpr, State.Env))) {
400 if (State.Env.getStorageLocation(*UnwrapExpr) ==
nullptr)
401 State.Env.setStorageLocation(*UnwrapExpr, locForValue(*OptionalLoc));
405void transferArrowOpCall(
const Expr *UnwrapExpr,
const Expr *ObjectExpr,
406 LatticeTransferState &State) {
407 if (
auto *OptionalLoc = cast_or_null<RecordStorageLocation>(
408 getLocBehindPossiblePointer(*ObjectExpr, State.Env)))
410 *UnwrapExpr, State.Env.create<PointerValue>(locForValue(*OptionalLoc)));
413void transferMakeOptionalCall(
const CallExpr *E,
414 const MatchFinder::MatchResult &,
415 LatticeTransferState &State) {
417 *E, createOptionalValue(State.Env.getResultObjectLocation(*E),
418 State.Env.getBoolLiteralValue(
true), State.Env));
421void transferOptionalHasValueCall(
const CXXMemberCallExpr *CallExpr,
422 const MatchFinder::MatchResult &,
423 LatticeTransferState &State) {
424 if (
auto *HasValueVal = getHasValue(
426 State.Env.setValue(*CallExpr, *HasValueVal);
432void transferValueOrImpl(
434 LatticeTransferState &State,
435 const Formula &(*ModelPred)(Environment &
Env,
const Formula &ExprVal,
436 const Formula &HasValueVal)) {
437 auto &
Env = State.Env;
444 if (HasValueVal ==
nullptr)
448 HasValueVal->formula()));
451void transferValueOrStringEmptyCall(
const clang::Expr *ComparisonExpr,
452 const MatchFinder::MatchResult &
Result,
453 LatticeTransferState &State) {
454 return transferValueOrImpl(ComparisonExpr,
Result, State,
455 [](Environment &
Env,
const Formula &ExprVal,
456 const Formula &HasValueVal) ->
const Formula & {
469void transferValueOrNotEqX(
const Expr *ComparisonExpr,
470 const MatchFinder::MatchResult &
Result,
471 LatticeTransferState &State) {
472 transferValueOrImpl(ComparisonExpr,
Result, State,
473 [](Environment &
Env,
const Formula &ExprVal,
474 const Formula &HasValueVal) ->
const Formula & {
483void transferCallReturningOptional(
const CallExpr *E,
484 const MatchFinder::MatchResult &
Result,
485 LatticeTransferState &State) {
486 if (State.Env.getValue(*E) !=
nullptr)
489 RecordStorageLocation *Loc =
nullptr;
490 if (E->isPRValue()) {
491 Loc = &State.Env.getResultObjectLocation(*E);
493 Loc = State.Env.get<RecordStorageLocation>(*E);
494 if (Loc ==
nullptr) {
495 Loc = &cast<RecordStorageLocation>(State.Env.createStorageLocation(*E));
496 State.Env.setStorageLocation(*E, *Loc);
501 createOptionalValue(*Loc, State.Env.makeAtomicBoolValue(), State.Env);
503 State.Env.setValue(*E, Val);
506void constructOptionalValue(
const Expr &E, Environment &
Env,
507 BoolValue &HasValueVal) {
515BoolValue &valueOrConversionHasValue(
const FunctionDecl &F,
const Expr &E,
516 const MatchFinder::MatchResult &MatchRes,
517 LatticeTransferState &State) {
518 assert(F.getTemplateSpecializationArgs() !=
nullptr);
519 assert(F.getTemplateSpecializationArgs()->size() > 0);
521 const int TemplateParamOptionalWrappersCount =
522 countOptionalWrappers(*MatchRes.Context, F.getTemplateSpecializationArgs()
525 .getNonReferenceType());
526 const int ArgTypeOptionalWrappersCount = countOptionalWrappers(
527 *MatchRes.Context, E.getType().getNonReferenceType());
531 if (TemplateParamOptionalWrappersCount == ArgTypeOptionalWrappersCount)
532 return State.Env.getBoolLiteralValue(
true);
536 auto *Loc = State.Env.get<RecordStorageLocation>(E);
537 if (
auto *HasValueVal = getHasValue(State.Env, Loc))
539 return State.Env.makeAtomicBoolValue();
542void transferValueOrConversionConstructor(
543 const CXXConstructExpr *E,
const MatchFinder::MatchResult &MatchRes,
544 LatticeTransferState &State) {
545 assert(E->getNumArgs() > 0);
547 constructOptionalValue(*E, State.Env,
548 valueOrConversionHasValue(*E->getConstructor(),
549 *E->getArg(0), MatchRes,
553void transferAssignment(
const CXXOperatorCallExpr *E, BoolValue &HasValueVal,
554 LatticeTransferState &State) {
555 assert(E->getNumArgs() > 0);
557 if (
auto *Loc = State.Env.get<RecordStorageLocation>(*E->getArg(0))) {
558 createOptionalValue(*Loc, HasValueVal, State.Env);
561 State.Env.setStorageLocation(*E, *Loc);
565void transferValueOrConversionAssignment(
566 const CXXOperatorCallExpr *E,
const MatchFinder::MatchResult &MatchRes,
567 LatticeTransferState &State) {
568 assert(E->getNumArgs() > 1);
569 transferAssignment(E,
570 valueOrConversionHasValue(*E->getDirectCallee(),
571 *E->getArg(1), MatchRes, State),
575void transferNulloptAssignment(
const CXXOperatorCallExpr *E,
576 const MatchFinder::MatchResult &,
577 LatticeTransferState &State) {
578 transferAssignment(E, State.Env.getBoolLiteralValue(
false), State);
581void transferSwap(RecordStorageLocation *Loc1, RecordStorageLocation *Loc2,
587 if (Loc1 ==
nullptr) {
592 if (Loc2 ==
nullptr) {
603 BoolValue *BoolVal1 = getHasValue(
Env, Loc1);
604 if (BoolVal1 ==
nullptr)
607 BoolValue *BoolVal2 = getHasValue(
Env, Loc2);
608 if (BoolVal2 ==
nullptr)
611 createOptionalValue(*Loc1, *BoolVal2,
Env);
612 createOptionalValue(*Loc2, *BoolVal1,
Env);
615void transferSwapCall(
const CXXMemberCallExpr *E,
616 const MatchFinder::MatchResult &,
617 LatticeTransferState &State) {
618 assert(E->getNumArgs() == 1);
619 auto *OtherLoc = State.Env.get<RecordStorageLocation>(*E->getArg(0));
623void transferStdSwapCall(
const CallExpr *E,
const MatchFinder::MatchResult &,
624 LatticeTransferState &State) {
625 assert(E->getNumArgs() == 2);
626 auto *Arg0Loc = State.Env.get<RecordStorageLocation>(*E->getArg(0));
627 auto *Arg1Loc = State.Env.get<RecordStorageLocation>(*E->getArg(1));
628 transferSwap(Arg0Loc, Arg1Loc, State.Env);
631void transferStdForwardCall(
const CallExpr *E,
const MatchFinder::MatchResult &,
632 LatticeTransferState &State) {
633 assert(E->getNumArgs() == 1);
635 if (
auto *Loc = State.Env.getStorageLocation(*E->getArg(0)))
636 State.Env.setStorageLocation(*E, *Loc);
639const Formula &evaluateEquality(Arena &A,
const Formula &EqVal,
640 const Formula &LHS,
const Formula &RHS) {
656 A.makeImplies(EqVal, A.makeOr(A.makeAnd(LHS, RHS),
657 A.makeAnd(A.makeNot(LHS), A.makeNot(RHS)))),
658 A.makeImplies(A.makeNot(EqVal), A.makeOr(LHS, RHS)));
662 const MatchFinder::MatchResult &,
663 LatticeTransferState &State) {
664 Environment &
Env = State.Env;
666 auto *CmpValue = &forceBoolValue(
Env, *CmpExpr);
667 auto *Arg0Loc =
Env.
get<RecordStorageLocation>(*CmpExpr->
getArg(0));
668 if (
auto *LHasVal = getHasValue(
Env, Arg0Loc)) {
669 auto *Arg1Loc =
Env.
get<RecordStorageLocation>(*CmpExpr->
getArg(1));
670 if (
auto *RHasVal = getHasValue(
Env, Arg1Loc)) {
671 if (CmpExpr->
getOperator() == clang::OO_ExclaimEqual)
672 CmpValue = &A.makeNot(*CmpValue);
673 Env.
assume(evaluateEquality(A, *CmpValue, LHasVal->formula(),
674 RHasVal->formula()));
682 auto *CmpValue = &forceBoolValue(
Env, *CmpExpr);
683 auto *Loc =
Env.
get<RecordStorageLocation>(*E);
684 if (
auto *HasVal = getHasValue(
Env, Loc)) {
685 if (CmpExpr->
getOperator() == clang::OO_ExclaimEqual)
686 CmpValue = &A.makeNot(*CmpValue);
688 evaluateEquality(A, *CmpValue, HasVal->formula(), A.makeLiteral(
true)));
695 auto *CmpValue = &forceBoolValue(
Env, *CmpExpr);
696 auto *Loc =
Env.
get<RecordStorageLocation>(*E);
697 if (
auto *HasVal = getHasValue(
Env, Loc)) {
698 if (CmpExpr->
getOperator() == clang::OO_ExclaimEqual)
699 CmpValue = &A.makeNot(*CmpValue);
700 Env.
assume(evaluateEquality(A, *CmpValue, HasVal->formula(),
701 A.makeLiteral(
false)));
705std::optional<StatementMatcher>
706ignorableOptional(
const UncheckedOptionalAccessModelOptions &Options) {
707 if (Options.IgnoreSmartPointerDereference) {
710 unless(hasArgument(0,
expr(hasOptionalType()))))));
718valueCall(
const std::optional<StatementMatcher> &IgnorableOptional) {
719 return isOptionalMemberCallWithNameMatcher(
hasName(
"value"),
724valueOperatorCall(
const std::optional<StatementMatcher> &IgnorableOptional) {
725 return expr(
anyOf(isOptionalOperatorCallWithName(
"*", IgnorableOptional),
726 isOptionalOperatorCallWithName(
"->", IgnorableOptional)));
729auto buildTransferMatchSwitch() {
733 return CFGMatchSwitchBuilder<LatticeTransferState>()
735 .CaseOfCFGStmt<CallExpr>(isMakeOptionalCall(), transferMakeOptionalCall)
738 .CaseOfCFGStmt<CXXConstructExpr>(
739 isOptionalInPlaceConstructor(),
740 [](
const CXXConstructExpr *E,
const MatchFinder::MatchResult &,
741 LatticeTransferState &State) {
742 constructOptionalValue(*E, State.Env,
743 State.Env.getBoolLiteralValue(
true));
746 .CaseOfCFGStmt<CXXConstructExpr>(
747 isOptionalNulloptConstructor(),
748 [](
const CXXConstructExpr *E,
const MatchFinder::MatchResult &,
749 LatticeTransferState &State) {
750 constructOptionalValue(*E, State.Env,
751 State.Env.getBoolLiteralValue(
false));
754 .CaseOfCFGStmt<CXXConstructExpr>(isOptionalValueOrConversionConstructor(),
755 transferValueOrConversionConstructor)
758 .CaseOfCFGStmt<CXXOperatorCallExpr>(
759 isOptionalValueOrConversionAssignment(),
760 transferValueOrConversionAssignment)
761 .CaseOfCFGStmt<CXXOperatorCallExpr>(isOptionalNulloptAssignment(),
762 transferNulloptAssignment)
765 .CaseOfCFGStmt<CXXMemberCallExpr>(
766 valueCall(std::nullopt),
767 [](
const CXXMemberCallExpr *E,
const MatchFinder::MatchResult &,
768 LatticeTransferState &State) {
769 transferUnwrapCall(E, E->getImplicitObjectArgument(), State);
773 .CaseOfCFGStmt<CallExpr>(isOptionalOperatorCallWithName(
"*"),
774 [](
const CallExpr *E,
775 const MatchFinder::MatchResult &,
776 LatticeTransferState &State) {
777 transferUnwrapCall(E, E->getArg(0), State);
781 .CaseOfCFGStmt<CallExpr>(isOptionalOperatorCallWithName(
"->"),
782 [](
const CallExpr *E,
783 const MatchFinder::MatchResult &,
784 LatticeTransferState &State) {
785 transferArrowOpCall(E, E->getArg(0), State);
791 .CaseOfCFGStmt<CXXMemberCallExpr>(
792 isOptionalMemberCallWithNameMatcher(
794 transferOptionalHasValueCall)
797 .CaseOfCFGStmt<CXXMemberCallExpr>(
798 isOptionalMemberCallWithNameMatcher(
hasName(
"operator bool")),
799 transferOptionalHasValueCall)
802 .CaseOfCFGStmt<CXXMemberCallExpr>(
803 isOptionalMemberCallWithNameMatcher(
hasName(
"emplace")),
804 [](
const CXXMemberCallExpr *E,
const MatchFinder::MatchResult &,
805 LatticeTransferState &State) {
806 if (RecordStorageLocation *Loc =
808 createOptionalValue(*Loc, State.Env.getBoolLiteralValue(
true),
814 .CaseOfCFGStmt<CXXMemberCallExpr>(
815 isOptionalMemberCallWithNameMatcher(
hasName(
"reset")),
816 [](
const CXXMemberCallExpr *E,
const MatchFinder::MatchResult &,
817 LatticeTransferState &State) {
818 if (RecordStorageLocation *Loc =
820 createOptionalValue(*Loc, State.Env.getBoolLiteralValue(
false),
826 .CaseOfCFGStmt<CXXMemberCallExpr>(
827 isOptionalMemberCallWithNameMatcher(
hasName(
"swap")),
831 .CaseOfCFGStmt<CallExpr>(isStdSwapCall(), transferStdSwapCall)
834 .CaseOfCFGStmt<CallExpr>(isStdForwardCall(), transferStdForwardCall)
837 .CaseOfCFGStmt<Expr>(isValueOrStringEmptyCall(),
838 transferValueOrStringEmptyCall)
841 .CaseOfCFGStmt<Expr>(isValueOrNotEqX(), transferValueOrNotEqX)
844 .CaseOfCFGStmt<CXXOperatorCallExpr>(
845 isComparisonOperatorCall(hasOptionalType(), hasOptionalType()),
846 transferOptionalAndOptionalCmp)
847 .CaseOfCFGStmt<CXXOperatorCallExpr>(
848 isComparisonOperatorCall(hasOptionalType(), hasNulloptType()),
850 const MatchFinder::MatchResult &, LatticeTransferState &State) {
851 transferOptionalAndNulloptCmp(Cmp, Cmp->getArg(0), State.Env);
853 .CaseOfCFGStmt<CXXOperatorCallExpr>(
854 isComparisonOperatorCall(hasNulloptType(), hasOptionalType()),
856 const MatchFinder::MatchResult &, LatticeTransferState &State) {
857 transferOptionalAndNulloptCmp(Cmp, Cmp->getArg(1), State.Env);
859 .CaseOfCFGStmt<CXXOperatorCallExpr>(
860 isComparisonOperatorCall(
862 unless(
anyOf(hasOptionalType(), hasNulloptType()))),
864 const MatchFinder::MatchResult &, LatticeTransferState &State) {
865 transferOptionalAndValueCmp(Cmp, Cmp->getArg(0), State.Env);
867 .CaseOfCFGStmt<CXXOperatorCallExpr>(
868 isComparisonOperatorCall(
869 unless(
anyOf(hasOptionalType(), hasNulloptType())),
872 const MatchFinder::MatchResult &, LatticeTransferState &State) {
873 transferOptionalAndValueCmp(Cmp, Cmp->getArg(1), State.Env);
877 .CaseOfCFGStmt<CallExpr>(isCallReturningOptional(),
878 transferCallReturningOptional)
884 const Environment &
Env) {
885 if (
auto *OptionalLoc = cast_or_null<RecordStorageLocation>(
886 getLocBehindPossiblePointer(*ObjectExpr,
Env))) {
887 auto *Prop =
Env.
getValue(locForHasValue(*OptionalLoc));
888 if (
auto *HasValueVal = cast_or_null<BoolValue>(Prop)) {
897 return {ObjectExpr->getBeginLoc()};
900auto buildDiagnoseMatchSwitch(
901 const UncheckedOptionalAccessModelOptions &Options) {
905 auto IgnorableOptional = ignorableOptional(Options);
906 return CFGMatchSwitchBuilder<
const Environment,
909 .CaseOfCFGStmt<CXXMemberCallExpr>(
910 valueCall(IgnorableOptional),
911 [](
const CXXMemberCallExpr *E,
const MatchFinder::MatchResult &,
912 const Environment &
Env) {
913 return diagnoseUnwrapCall(E->getImplicitObjectArgument(),
Env);
917 .CaseOfCFGStmt<CallExpr>(valueOperatorCall(IgnorableOptional),
918 [](
const CallExpr *E,
919 const MatchFinder::MatchResult &,
920 const Environment &
Env) {
921 return diagnoseUnwrapCall(E->getArg(0),
Env);
936 TransferMatchSwitch(buildTransferMatchSwitch()) {
937 Env.getDataflowAnalysisContext().setSyntheticFieldCallback(
938 [&Ctx](
QualType Ty) -> llvm::StringMap<QualType> {
943 return {{
"value", valueTypeFromOptionalDecl(*
Optional)},
944 {
"has_value", Ctx.
BoolTy}};
950 LatticeTransferState State(L,
Env);
956 : 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...
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).
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.