<
class... NameTypes>
54 if constexpr(
sizeof...(NameTypes) > 0) {
57 if(
const auto*NextNS = dyn_cast_or_null<NamespaceDecl>(NS.
getParent()))
69 if(RD.
getName() ==
"optional") {
70 if(
const auto*N = dyn_cast_or_null<NamespaceDecl>(RD.
getDeclContext()))
71 returnN->isStdNamespace() ||
77 if(RD.
getName() ==
"Optional") {
79 const auto*N = dyn_cast_or_null<NamespaceDecl>(RD.
getDeclContext());
84 if(RD.
getName() ==
"NullableValue") {
85 const auto*N = dyn_cast_or_null<NamespaceDecl>(RD.
getDeclContext());
86 returnN !=
nullptr&&
120usingLatticeTransferState = TransferState<UncheckedOptionalAccessLattice>;
124AST_MATCHER(CXXRecordDecl, optionalOrDerivedClass) {
128autodesugarsToOptionalType() {
129 returnhasUnqualifiedDesugaredType(
133autodesugarsToOptionalOrDerivedType() {
134 returnhasUnqualifiedDesugaredType(
138autohasOptionalType() {
returnhasType(desugarsToOptionalType()); }
142autohasOptionalOrDerivedType() {
143 returnhasType(desugarsToOptionalOrDerivedType());
146QualType getPublicType(
constExpr *
E) {
147 auto*
Cast= dyn_cast<ImplicitCastExpr>(
E->IgnoreParens());
148 if(Cast ==
nullptr||
Cast->getCastKind() != CK_UncheckedDerivedToBase) {
149QualType Ty =
E->getType();
150 if(Ty->isPointerType())
151 returnTy->getPointeeType();
158 boolCastingFromThis = isa<CXXThisExpr>(
Cast->getSubExpr());
162 constCXXBaseSpecifier *PublicBase =
nullptr;
163 for(
constCXXBaseSpecifier *
Base:
Cast->path()) {
164 if(
Base->getAccessSpecifier() !=
AS_public&& !CastingFromThis)
167CastingFromThis =
false;
170 if(PublicBase !=
nullptr)
171 returnPublicBase->getType();
176 returngetPublicType(
Cast->getSubExpr());
203QualType getPublicReceiverType(
constCXXMemberCallExpr &MCE) {
204 returngetPublicType(MCE.getImplicitObjectArgument());
208ast_matchers::internal::Matcher<QualType>, InnerMatcher) {
209 returnInnerMatcher.matches(getPublicReceiverType(
Node), Finder, Builder);
212autoisOptionalMemberCallWithNameMatcher(
213ast_matchers::internal::Matcher<NamedDecl> matcher,
214 conststd::optional<StatementMatcher> &Ignorable = std::nullopt) {
217publicReceiverType(desugarsToOptionalType()),
221autoisOptionalOperatorCallWithName(
222llvm::StringRef operator_name,
223 conststd::optional<StatementMatcher> &Ignorable = std::nullopt) {
230autoisMakeOptionalCall() {
233 "std::make_optional",
"base::make_optional",
"absl::make_optional",
234 "folly::make_optional",
"bsl::make_optional"))),
238autonulloptTypeDecl() {
240 "base::nullopt_t",
"folly::None",
244autohasNulloptType() {
returnhasType(nulloptTypeDecl()); }
248 "base::in_place_t",
"folly::in_place_t",
249 "bsl::in_place_t"));
252autoisOptionalNulloptConstructor() {
255hasParameter(0, hasNulloptType()))),
256hasOptionalOrDerivedType());
259autoisOptionalInPlaceConstructor() {
261hasOptionalOrDerivedType());
264autoisOptionalValueOrConversionConstructor() {
268argumentCountIs(1), hasArgument(0,
unless(hasNulloptType())),
269hasOptionalOrDerivedType());
272autoisOptionalValueOrConversionAssignment() {
277 anyOf(isCopyAssignmentOperator(), isMoveAssignmentOperator())))),
278argumentCountIs(2), hasArgument(1,
unless(hasNulloptType())));
281autoisOptionalNulloptAssignment() {
285argumentCountIs(2), hasArgument(1, hasNulloptType()));
288autoisStdSwapCall() {
291hasArgument(0, hasOptionalOrDerivedType()),
292hasArgument(1, hasOptionalOrDerivedType()));
295autoisStdForwardCall() {
298hasArgument(0, hasOptionalOrDerivedType()));
301constexprllvm::StringLiteral ValueOrCallID =
"ValueOrCall";
303autoisValueOrStringEmptyCall() {
307onImplicitObjectArgument(ignoringImplicit(
310ofClass(optionalClass()))),
312.bind(ValueOrCallID))));
315autoisValueOrNotEqX() {
316 autoComparesToSame = [](ast_matchers::internal::Matcher<Stmt> Arg) {
321ofClass(optionalClass()))),
323.bind(ValueOrCallID)),
324ignoringImplicit(Arg));
338autoisZeroParamConstMemberCall() {
343autoisZeroParamConstMemberOperatorCall() {
348autoisNonConstMemberCall() {
352autoisNonConstMemberOperatorCall() {
356autoisCallReturningOptional() {
358 anyOf(desugarsToOptionalOrDerivedType(),
359 referenceType(pointee(desugarsToOptionalOrDerivedType()))))));
362template<
typenameL,
typenameR>
363autoisComparisonOperatorCall(L lhs_arg_matcher, R rhs_arg_matcher) {
366argumentCountIs(2), hasArgument(0, lhs_arg_matcher),
367hasArgument(1, rhs_arg_matcher));
371constFormula &forceBoolValue(Environment &
Env,
constExpr &Expr) {
373 if(
Value!=
nullptr)
374 return Value->formula();
378 return Value->formula();
381StorageLocation &locForHasValue(
constRecordStorageLocation &OptionalLoc) {
382 returnOptionalLoc.getSyntheticField(
"has_value");
385StorageLocation &locForValue(
constRecordStorageLocation &OptionalLoc) {
386 returnOptionalLoc.getSyntheticField(
"value");
391voidsetHasValue(RecordStorageLocation &OptionalLoc, BoolValue &HasValueVal,
392Environment &
Env) {
393 Env.
setValue(locForHasValue(OptionalLoc), HasValueVal);
398BoolValue *getHasValue(Environment &
Env, RecordStorageLocation *OptionalLoc) {
399 if(OptionalLoc ==
nullptr)
401StorageLocation &HasValueLoc = locForHasValue(*OptionalLoc);
402 auto*HasValueVal =
Env.
get<BoolValue>(HasValueLoc);
403 if(HasValueVal ==
nullptr) {
410QualType valueTypeFromOptionalDecl(
constCXXRecordDecl &RD) {
411 auto&CTSD = cast<ClassTemplateSpecializationDecl>(RD);
412 returnCTSD.getTemplateArgs()[0].getAsType();
419intcountOptionalWrappers(
constASTContext &ASTCtx, QualType Type) {
424 return1 + countOptionalWrappers(
426valueTypeFromOptionalDecl(*Optional).getDesugaredType(ASTCtx));
429StorageLocation *getLocBehindPossiblePointer(
constExpr &
E,
430 constEnvironment &
Env) {
431 if(
E.isPRValue()) {
432 if(
auto*PointerVal = dyn_cast_or_null<PointerValue>(
Env.
getValue(
E)))
433 return&PointerVal->getPointeeLoc();
439voidtransferUnwrapCall(
constExpr *UnwrapExpr,
constExpr *ObjectExpr,
440LatticeTransferState &State) {
441 if(
auto*OptionalLoc = cast_or_null<RecordStorageLocation>(
442getLocBehindPossiblePointer(*ObjectExpr, State.Env))) {
443 if(State.Env.getStorageLocation(*UnwrapExpr) ==
nullptr)
444State.Env.setStorageLocation(*UnwrapExpr, locForValue(*OptionalLoc));
448voidtransferArrowOpCall(
constExpr *UnwrapExpr,
constExpr *ObjectExpr,
449LatticeTransferState &State) {
450 if(
auto*OptionalLoc = cast_or_null<RecordStorageLocation>(
451getLocBehindPossiblePointer(*ObjectExpr, State.Env)))
453*UnwrapExpr, State.Env.create<PointerValue>(locForValue(*OptionalLoc)));
456voidtransferMakeOptionalCall(
constCallExpr *
E,
457 constMatchFinder::MatchResult &,
458LatticeTransferState &State) {
459setHasValue(State.Env.getResultObjectLocation(*
E),
460State.Env.getBoolLiteralValue(
true), State.Env);
463voidtransferOptionalHasValueCall(
constCXXMemberCallExpr *CallExpr,
464 constMatchFinder::MatchResult &,
465LatticeTransferState &State) {
466 if(
auto*HasValueVal = getHasValue(
468State.Env.setValue(*CallExpr, *HasValueVal);
472voidtransferOptionalIsNullCall(
constCXXMemberCallExpr *CallExpr,
473 constMatchFinder::MatchResult &,
474LatticeTransferState &State) {
475 if(
auto*HasValueVal = getHasValue(
477State.Env.setValue(*CallExpr, State.Env.makeNot(*HasValueVal));
483voidtransferValueOrImpl(
485LatticeTransferState &State,
486 constFormula &(*ModelPred)(Environment &
Env,
constFormula &ExprVal,
487 constFormula &HasValueVal)) {
488 auto&
Env= State.Env;
495 if(HasValueVal ==
nullptr)
498 Env.
assume(ModelPred(
Env, forceBoolValue(
Env, *ValueOrPredExpr),
499HasValueVal->formula()));
502voidtransferValueOrStringEmptyCall(
const clang::Expr*ComparisonExpr,
503 constMatchFinder::MatchResult &
Result,
504LatticeTransferState &State) {
505 returntransferValueOrImpl(ComparisonExpr,
Result, State,
506[](Environment &
Env,
constFormula &ExprVal,
507 constFormula &HasValueVal) ->
constFormula & {
520voidtransferValueOrNotEqX(
constExpr *ComparisonExpr,
521 constMatchFinder::MatchResult &
Result,
522LatticeTransferState &State) {
523transferValueOrImpl(ComparisonExpr,
Result, State,
524[](Environment &
Env,
constFormula &ExprVal,
525 constFormula &HasValueVal) ->
constFormula & {
534voidtransferCallReturningOptional(
constCallExpr *
E,
535 constMatchFinder::MatchResult &
Result,
536LatticeTransferState &State) {
537RecordStorageLocation *
Loc=
nullptr;
538 if(
E->isPRValue()) {
539 Loc= &State.Env.getResultObjectLocation(*
E);
541 Loc= State.Env.get<RecordStorageLocation>(*E);
542 if(
Loc==
nullptr) {
543 Loc= &cast<RecordStorageLocation>(State.Env.createStorageLocation(*
E));
544State.Env.setStorageLocation(*
E, *
Loc);
548 if(State.Env.getValue(locForHasValue(*
Loc)) !=
nullptr)
551setHasValue(*
Loc, State.Env.makeAtomicBoolValue(), State.Env);
554voidhandleConstMemberCall(
constCallExpr *CE,
555dataflow::RecordStorageLocation *
RecordLoc,
556 constMatchFinder::MatchResult &
Result,
557LatticeTransferState &State) {
560 constFunctionDecl *DirectCallee = CE->getDirectCallee();
561 if(DirectCallee ==
nullptr)
563StorageLocation &
Loc=
564State.Lattice.getOrCreateConstMethodReturnStorageLocation(
565*
RecordLoc, DirectCallee, State.Env, [&](StorageLocation &
Loc) {
566setHasValue(cast<RecordStorageLocation>(Loc),
567State.Env.makeAtomicBoolValue(), State.Env);
569 if(CE->isGLValue()) {
572State.Env.setStorageLocation(*CE,
Loc);
577 auto&ResultLoc = State.Env.getResultObjectLocation(*CE);
578 copyRecord(cast<RecordStorageLocation>(
Loc), ResultLoc, State.Env);
586(CE->getType()->isBooleanType() || CE->getType()->isPointerType())) {
587 Value*Val = State.Lattice.getOrCreateConstMethodReturnValue(*
RecordLoc, CE,
591State.Env.setValue(*CE, *Val);
598transferCallReturningOptional(CE,
Result, State);
602voidtransferValue_ConstMemberCall(
constCXXMemberCallExpr *MCE,
603 constMatchFinder::MatchResult &
Result,
604LatticeTransferState &State) {
605handleConstMemberCall(
609voidtransferValue_ConstMemberOperatorCall(
610 constCXXOperatorCallExpr *OCE,
constMatchFinder::MatchResult &
Result,
611LatticeTransferState &State) {
612 auto*
RecordLoc= cast_or_null<dataflow::RecordStorageLocation>(
613State.Env.getStorageLocation(*OCE->getArg(0)));
617voidhandleNonConstMemberCall(
constCallExpr *CE,
618dataflow::RecordStorageLocation *
RecordLoc,
619 constMatchFinder::MatchResult &
Result,
620LatticeTransferState &State) {
625 for(
const auto&[Field, FieldLoc] :
RecordLoc->children()) {
626QualType FieldType =
Field->getType();
627 if(!FieldType.isConstQualified() &&
629 auto*FieldRecordLoc = cast_or_null<RecordStorageLocation>(FieldLoc);
630 if(FieldRecordLoc) {
631setHasValue(*FieldRecordLoc, State.Env.makeAtomicBoolValue(),
636State.Lattice.clearConstMethodReturnValues(*
RecordLoc);
637State.Lattice.clearConstMethodReturnStorageLocations(*
RecordLoc);
642transferCallReturningOptional(CE,
Result, State);
646voidtransferValue_NonConstMemberCall(
constCXXMemberCallExpr *MCE,
647 constMatchFinder::MatchResult &
Result,
648LatticeTransferState &State) {
649handleNonConstMemberCall(
653voidtransferValue_NonConstMemberOperatorCall(
654 constCXXOperatorCallExpr *OCE,
constMatchFinder::MatchResult &
Result,
655LatticeTransferState &State) {
656 auto*
RecordLoc= cast_or_null<dataflow::RecordStorageLocation>(
657State.Env.getStorageLocation(*OCE->getArg(0)));
661voidconstructOptionalValue(
constExpr &
E, Environment &
Env,
662BoolValue &HasValueVal) {
664setHasValue(
Loc, HasValueVal,
Env);
670BoolValue &valueOrConversionHasValue(QualType DestType,
constExpr &
E,
671 constMatchFinder::MatchResult &MatchRes,
672LatticeTransferState &State) {
673 const intDestTypeOptionalWrappersCount =
674countOptionalWrappers(*MatchRes.Context, DestType);
675 const intArgTypeOptionalWrappersCount = countOptionalWrappers(
676*MatchRes.Context,
E.getType().getNonReferenceType());
683 if(DestTypeOptionalWrappersCount != ArgTypeOptionalWrappersCount)
684 returnState.Env.getBoolLiteralValue(
true);
690 auto*
Loc= State.Env.get<RecordStorageLocation>(
E);
691 if(
auto*HasValueVal = getHasValue(State.Env,
Loc))
693 returnState.Env.makeAtomicBoolValue();
696voidtransferValueOrConversionConstructor(
697 constCXXConstructExpr *
E,
constMatchFinder::MatchResult &MatchRes,
698LatticeTransferState &State) {
699assert(
E->getNumArgs() > 0);
701constructOptionalValue(
703valueOrConversionHasValue(
704 E->getConstructor()->getThisType()->getPointeeType(), *
E->getArg(0),
708voidtransferAssignment(
constCXXOperatorCallExpr *
E, BoolValue &HasValueVal,
709LatticeTransferState &State) {
710assert(
E->getNumArgs() > 0);
712 if(
auto*
Loc= State.Env.get<RecordStorageLocation>(*
E->getArg(0))) {
713setHasValue(*
Loc, HasValueVal, State.Env);
716State.Env.setStorageLocation(*
E, *
Loc);
720voidtransferValueOrConversionAssignment(
721 constCXXOperatorCallExpr *
E,
constMatchFinder::MatchResult &MatchRes,
722LatticeTransferState &State) {
723assert(
E->getNumArgs() > 1);
726valueOrConversionHasValue(
E->getArg(0)->getType().getNonReferenceType(),
727*
E->getArg(1), MatchRes, State),
731voidtransferNulloptAssignment(
constCXXOperatorCallExpr *
E,
732 constMatchFinder::MatchResult &,
733LatticeTransferState &State) {
734transferAssignment(
E, State.Env.getBoolLiteralValue(
false), State);
737voidtransferSwap(RecordStorageLocation *Loc1, RecordStorageLocation *Loc2,
738Environment &
Env) {
743 if(Loc1 ==
nullptr) {
744 if(Loc2 !=
nullptr)
748 if(Loc2 ==
nullptr) {
759BoolValue *BoolVal1 = getHasValue(
Env, Loc1);
760 if(BoolVal1 ==
nullptr)
763BoolValue *BoolVal2 = getHasValue(
Env, Loc2);
764 if(BoolVal2 ==
nullptr)
767setHasValue(*Loc1, *BoolVal2,
Env);
768setHasValue(*Loc2, *BoolVal1,
Env);
771voidtransferSwapCall(
constCXXMemberCallExpr *
E,
772 constMatchFinder::MatchResult &,
773LatticeTransferState &State) {
774assert(
E->getNumArgs() == 1);
775 auto*OtherLoc = State.Env.get<RecordStorageLocation>(*
E->getArg(0));
779voidtransferStdSwapCall(
constCallExpr *
E,
constMatchFinder::MatchResult &,
780LatticeTransferState &State) {
781assert(
E->getNumArgs() == 2);
782 auto*Arg0Loc = State.Env.get<RecordStorageLocation>(*
E->getArg(0));
783 auto*Arg1Loc = State.Env.get<RecordStorageLocation>(*
E->getArg(1));
784transferSwap(Arg0Loc, Arg1Loc, State.Env);
787voidtransferStdForwardCall(
constCallExpr *
E,
constMatchFinder::MatchResult &,
788LatticeTransferState &State) {
789assert(
E->getNumArgs() == 1);
791 if(
auto*
Loc= State.Env.getStorageLocation(*
E->getArg(0)))
792State.Env.setStorageLocation(*
E, *
Loc);
795constFormula &evaluateEquality(Arena &A,
constFormula &EqVal,
796 constFormula &LHS,
constFormula &RHS) {
812A.makeImplies(EqVal, A.makeOr(A.makeAnd(LHS, RHS),
813A.makeAnd(A.makeNot(LHS), A.makeNot(RHS)))),
814A.makeImplies(A.makeNot(EqVal), A.makeOr(LHS, RHS)));
818 constMatchFinder::MatchResult &,
819LatticeTransferState &State) {
820Environment &
Env= State.Env;
822 auto*CmpValue = &forceBoolValue(
Env, *CmpExpr);
823 auto*Arg0Loc =
Env.
get<RecordStorageLocation>(*CmpExpr->
getArg(0));
824 if(
auto*LHasVal = getHasValue(
Env, Arg0Loc)) {
825 auto*Arg1Loc =
Env.
get<RecordStorageLocation>(*CmpExpr->
getArg(1));
826 if(
auto*RHasVal = getHasValue(
Env, Arg1Loc)) {
827 if(CmpExpr->
getOperator() == clang::OO_ExclaimEqual)
828CmpValue = &A.makeNot(*CmpValue);
829 Env.
assume(evaluateEquality(A, *CmpValue, LHasVal->formula(),
830RHasVal->formula()));
838 auto*CmpValue = &forceBoolValue(
Env, *CmpExpr);
839 auto*
Loc=
Env.
get<RecordStorageLocation>(*E);
840 if(
auto*HasVal = getHasValue(
Env,
Loc)) {
841 if(CmpExpr->
getOperator() == clang::OO_ExclaimEqual)
842CmpValue = &A.makeNot(*CmpValue);
844evaluateEquality(A, *CmpValue, HasVal->formula(), A.makeLiteral(
true)));
851 auto*CmpValue = &forceBoolValue(
Env, *CmpExpr);
852 auto*
Loc=
Env.
get<RecordStorageLocation>(*E);
853 if(
auto*HasVal = getHasValue(
Env,
Loc)) {
854 if(CmpExpr->
getOperator() == clang::OO_ExclaimEqual)
855CmpValue = &A.makeNot(*CmpValue);
856 Env.
assume(evaluateEquality(A, *CmpValue, HasVal->formula(),
857A.makeLiteral(
false)));
861std::optional<StatementMatcher>
862ignorableOptional(
constUncheckedOptionalAccessModelOptions &Options) {
863 if(Options.IgnoreSmartPointerDereference) {
866 unless(hasArgument(0,
expr(hasOptionalType()))))));
874valueCall(
conststd::optional<StatementMatcher> &IgnorableOptional) {
875 returnisOptionalMemberCallWithNameMatcher(
hasName(
"value"),
880valueOperatorCall(
conststd::optional<StatementMatcher> &IgnorableOptional) {
881 return expr(
anyOf(isOptionalOperatorCallWithName(
"*", IgnorableOptional),
882isOptionalOperatorCallWithName(
"->", IgnorableOptional)));
885autobuildTransferMatchSwitch() {
889 returnCFGMatchSwitchBuilder<LatticeTransferState>()
891.CaseOfCFGStmt<CallExpr>(isMakeOptionalCall(), transferMakeOptionalCall)
894.CaseOfCFGStmt<CXXConstructExpr>(
895isOptionalInPlaceConstructor(),
896[](
constCXXConstructExpr *
E,
constMatchFinder::MatchResult &,
897LatticeTransferState &State) {
898constructOptionalValue(*
E, State.Env,
899State.Env.getBoolLiteralValue(
true));
902.CaseOfCFGStmt<CXXConstructExpr>(
903isOptionalNulloptConstructor(),
904[](
constCXXConstructExpr *
E,
constMatchFinder::MatchResult &,
905LatticeTransferState &State) {
906constructOptionalValue(*
E, State.Env,
907State.Env.getBoolLiteralValue(
false));
910.CaseOfCFGStmt<CXXConstructExpr>(isOptionalValueOrConversionConstructor(),
911transferValueOrConversionConstructor)
914.CaseOfCFGStmt<CXXOperatorCallExpr>(
915isOptionalValueOrConversionAssignment(),
916transferValueOrConversionAssignment)
917.CaseOfCFGStmt<CXXOperatorCallExpr>(isOptionalNulloptAssignment(),
918transferNulloptAssignment)
921.CaseOfCFGStmt<CXXMemberCallExpr>(
922valueCall(std::nullopt),
923[](
constCXXMemberCallExpr *
E,
constMatchFinder::MatchResult &,
924LatticeTransferState &State) {
925transferUnwrapCall(
E,
E->getImplicitObjectArgument(), State);
929.CaseOfCFGStmt<CallExpr>(isOptionalOperatorCallWithName(
"*"),
930[](
constCallExpr *
E,
931 constMatchFinder::MatchResult &,
932LatticeTransferState &State) {
933transferUnwrapCall(
E,
E->getArg(0), State);
937.CaseOfCFGStmt<CallExpr>(isOptionalOperatorCallWithName(
"->"),
938[](
constCallExpr *
E,
939 constMatchFinder::MatchResult &,
940LatticeTransferState &State) {
941transferArrowOpCall(
E,
E->getArg(0), State);
947.CaseOfCFGStmt<CXXMemberCallExpr>(
948isOptionalMemberCallWithNameMatcher(
950transferOptionalHasValueCall)
953.CaseOfCFGStmt<CXXMemberCallExpr>(
954isOptionalMemberCallWithNameMatcher(
hasName(
"operator bool")),
955transferOptionalHasValueCall)
959.CaseOfCFGStmt<CXXMemberCallExpr>(
960isOptionalMemberCallWithNameMatcher(
hasName(
"isNull")),
961transferOptionalIsNullCall)
964.CaseOfCFGStmt<CXXMemberCallExpr>(
965isOptionalMemberCallWithNameMatcher(
hasName(
"emplace")),
966[](
constCXXMemberCallExpr *
E,
constMatchFinder::MatchResult &,
967LatticeTransferState &State) {
968 if(RecordStorageLocation *
Loc=
970setHasValue(*
Loc, State.Env.getBoolLiteralValue(
true), State.Env);
975.CaseOfCFGStmt<CXXMemberCallExpr>(
976isOptionalMemberCallWithNameMatcher(
hasName(
"reset")),
977[](
constCXXMemberCallExpr *
E,
constMatchFinder::MatchResult &,
978LatticeTransferState &State) {
979 if(RecordStorageLocation *
Loc=
981setHasValue(*
Loc, State.Env.getBoolLiteralValue(
false),
987.CaseOfCFGStmt<CXXMemberCallExpr>(
988isOptionalMemberCallWithNameMatcher(
hasName(
"swap")),
992.CaseOfCFGStmt<CallExpr>(isStdSwapCall(), transferStdSwapCall)
995.CaseOfCFGStmt<CallExpr>(isStdForwardCall(), transferStdForwardCall)
998.CaseOfCFGStmt<Expr>(isValueOrStringEmptyCall(),
999transferValueOrStringEmptyCall)
1002.CaseOfCFGStmt<Expr>(isValueOrNotEqX(), transferValueOrNotEqX)
1005.CaseOfCFGStmt<CXXOperatorCallExpr>(
1006isComparisonOperatorCall(hasOptionalType(), hasOptionalType()),
1007transferOptionalAndOptionalCmp)
1008.CaseOfCFGStmt<CXXOperatorCallExpr>(
1009isComparisonOperatorCall(hasOptionalType(), hasNulloptType()),
1011 constMatchFinder::MatchResult &, LatticeTransferState &State) {
1012transferOptionalAndNulloptCmp(Cmp, Cmp->getArg(0), State.Env);
1014.CaseOfCFGStmt<CXXOperatorCallExpr>(
1015isComparisonOperatorCall(hasNulloptType(), hasOptionalType()),
1017 constMatchFinder::MatchResult &, LatticeTransferState &State) {
1018transferOptionalAndNulloptCmp(Cmp, Cmp->getArg(1), State.Env);
1020.CaseOfCFGStmt<CXXOperatorCallExpr>(
1021isComparisonOperatorCall(
1023 unless(
anyOf(hasOptionalType(), hasNulloptType()))),
1025 constMatchFinder::MatchResult &, LatticeTransferState &State) {
1026transferOptionalAndValueCmp(Cmp, Cmp->getArg(0), State.Env);
1028.CaseOfCFGStmt<CXXOperatorCallExpr>(
1029isComparisonOperatorCall(
1030 unless(
anyOf(hasOptionalType(), hasNulloptType())),
1033 constMatchFinder::MatchResult &, LatticeTransferState &State) {
1034transferOptionalAndValueCmp(Cmp, Cmp->getArg(1), State.Env);
1040.CaseOfCFGStmt<CXXOperatorCallExpr>(
1042[](
constCXXOperatorCallExpr *
E,
1043 constMatchFinder::MatchResult &
Result,
1044LatticeTransferState &State) {
1047dyn_cast_or_null<RecordStorageLocation>(
1048getLocBehindPossiblePointer(*
E->getArg(0), State.Env)),
1049State, [](StorageLocation &
Loc) {});
1051.CaseOfCFGStmt<CXXOperatorCallExpr>(
1053[](
constCXXOperatorCallExpr *
E,
1054 constMatchFinder::MatchResult &
Result,
1055LatticeTransferState &State) {
1058dyn_cast_or_null<RecordStorageLocation>(
1059getLocBehindPossiblePointer(*
E->getArg(0), State.Env)),
1060State, [](StorageLocation &
Loc) {});
1062.CaseOfCFGStmt<CXXMemberCallExpr>(
1064[](
constCXXMemberCallExpr *
E,
constMatchFinder::MatchResult &
Result,
1065LatticeTransferState &State) {
1068[](StorageLocation &
Loc) {});
1070.CaseOfCFGStmt<CXXMemberCallExpr>(
1072[](
constCXXMemberCallExpr *
E,
constMatchFinder::MatchResult &
Result,
1073LatticeTransferState &State) {
1076[](StorageLocation &
Loc) {});
1080.CaseOfCFGStmt<CXXMemberCallExpr>(isZeroParamConstMemberCall(),
1081transferValue_ConstMemberCall)
1082.CaseOfCFGStmt<CXXOperatorCallExpr>(isZeroParamConstMemberOperatorCall(),
1083transferValue_ConstMemberOperatorCall)
1085.CaseOfCFGStmt<CXXMemberCallExpr>(isNonConstMemberCall(),
1086transferValue_NonConstMemberCall)
1087.CaseOfCFGStmt<CXXOperatorCallExpr>(
1088isNonConstMemberOperatorCall(),
1089transferValue_NonConstMemberOperatorCall)
1092.CaseOfCFGStmt<CallExpr>(isCallReturningOptional(),
1093transferCallReturningOptional)
1099 constEnvironment &
Env) {
1100 if(
auto*OptionalLoc = cast_or_null<RecordStorageLocation>(
1101getLocBehindPossiblePointer(*ObjectExpr,
Env))) {
1102 auto*Prop =
Env.
getValue(locForHasValue(*OptionalLoc));
1103 if(
auto*HasValueVal = cast_or_null<BoolValue>(Prop)) {
1104 if(
Env.
proves(HasValueVal->formula()))
1112 return{ObjectExpr->getBeginLoc()};
1115autobuildDiagnoseMatchSwitch(
1116 constUncheckedOptionalAccessModelOptions &Options) {
1120 autoIgnorableOptional = ignorableOptional(Options);
1121 returnCFGMatchSwitchBuilder<
constEnvironment,
1124.CaseOfCFGStmt<CXXMemberCallExpr>(
1125valueCall(IgnorableOptional),
1126[](
constCXXMemberCallExpr *
E,
constMatchFinder::MatchResult &,
1127 constEnvironment &
Env) {
1128 returndiagnoseUnwrapCall(
E->getImplicitObjectArgument(),
Env);
1132.CaseOfCFGStmt<CallExpr>(valueOperatorCall(IgnorableOptional),
1133[](
constCallExpr *
E,
1134 constMatchFinder::MatchResult &,
1135 constEnvironment &
Env) {
1136 returndiagnoseUnwrapCall(
E->getArg(0),
Env);
1152TransferMatchSwitch(buildTransferMatchSwitch()) {
1153 Env.getDataflowAnalysisContext().setSyntheticFieldCallback(
1154[&Ctx](
QualTypeTy) -> llvm::StringMap<QualType> {
1159 return{{
"value", valueTypeFromOptionalDecl(*
Optional)},
1160{
"has_value", Ctx.BoolTy}};
1167LatticeTransferState State(L,
Env);
1173: 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.
llvm::MachO::RecordLoc RecordLoc
Defines an enumeration for C++ overloaded operators.
Defines the clang::SourceLocation class and associated facilities.
C Language Family Type Representation.
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.
A mixin for a lattice that additionally maintains a cache of stable method call return values to mode...
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...
UncheckedOptionalAccessDiagnoser(UncheckedOptionalAccessModelOptions Options={})
Dataflow analysis that models whether optionals hold values or not.
UncheckedOptionalAccessModel(ASTContext &Ctx, dataflow::Environment &Env)
void transfer(const CFGElement &Elt, UncheckedOptionalAccessLattice &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 isFullyQualifiedNamespaceEqualTo(const NamespaceDecl &NS, llvm::StringRef Name, NameTypes... Names)
void transferSmartPointerLikeCachedDeref(const CallExpr *DerefExpr, RecordStorageLocation *SmartPointerLoc, TransferState< LatticeT > &State, llvm::function_ref< void(StorageLocation &)> InitializeLoc)
A transfer function for operator* (and value) calls that can be cached.
static bool hasOptionalClassName(const CXXRecordDecl &RD)
void transferSmartPointerLikeCachedGet(const CallExpr *GetExpr, RecordStorageLocation *SmartPointerLoc, TransferState< LatticeT > &State, llvm::function_ref< void(StorageLocation &)> InitializeLoc)
A transfer function for operator-> (and get) calls that can be cached.
ast_matchers::StatementMatcher isSmartPointerLikeGetMethodCall()
ast_matchers::StatementMatcher isSmartPointerLikeValueMethodCall()
void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst, Environment &Env)
Copies a record (struct, class, or union) from Src to Dst.
static bool isSupportedOptionalType(QualType Ty)
ast_matchers::StatementMatcher isSmartPointerLikeOperatorArrow()
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)
ast_matchers::StatementMatcher isSmartPointerLikeOperatorStar()
Matchers: For now, these match on any class with an operator* or operator-> where the return types ha...
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.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4