28#include "llvm/ADT/StringRef.h"
29#include "llvm/Support/Casting.h"
30#include "llvm/Support/ErrorHandling.h"
42using LatticeTransferState = TransferState<NoopLattice>;
49 hasTemplateArgument(0, refersToType(
type().bind(
"T"))));
52auto optionalOrAliasType() {
53 return hasUnqualifiedDesugaredType(
58auto hasOptionalType() {
return hasType(optionalOrAliasType()); }
60auto isOptionalMemberCallWithName(
61 llvm::StringRef MemberName,
62 const std::optional<StatementMatcher> &Ignorable = std::nullopt) {
70auto isOptionalOperatorCallWithName(
71 llvm::StringRef operator_name,
72 const std::optional<StatementMatcher> &Ignorable = std::nullopt) {
79auto isMakeOptionalCall() {
82 "std::make_optional",
"base::make_optional",
"absl::make_optional"))),
86auto nulloptTypeDecl() {
88 hasAnyName(
"std::nullopt_t",
"absl::nullopt_t",
"base::nullopt_t"));
91auto hasNulloptType() {
return hasType(nulloptTypeDecl()); }
94auto hasAnyOptionalType() {
95 return hasType(hasUnqualifiedDesugaredType(
102 hasAnyName(
"std::in_place_t",
"absl::in_place_t",
"base::in_place_t"));
105auto isOptionalNulloptConstructor() {
109 hasParameter(0, hasNulloptType()))));
112auto isOptionalInPlaceConstructor() {
114 hasArgument(0, hasType(inPlaceClass())));
117auto isOptionalValueOrConversionConstructor() {
122 argumentCountIs(1), hasArgument(0,
unless(hasNulloptType())));
125auto isOptionalValueOrConversionAssignment() {
130 anyOf(isCopyAssignmentOperator(), isMoveAssignmentOperator())))),
131 argumentCountIs(2), hasArgument(1,
unless(hasNulloptType())));
134auto isNulloptConstructor() {
136 hasArgument(0, hasNulloptType()));
139auto isOptionalNulloptAssignment() {
143 hasArgument(1, hasNulloptType()));
146auto isStdSwapCall() {
148 argumentCountIs(2), hasArgument(0, hasOptionalType()),
149 hasArgument(1, hasOptionalType()));
152constexpr llvm::StringLiteral ValueOrCallID =
"ValueOrCall";
154auto isValueOrStringEmptyCall() {
158 onImplicitObjectArgument(ignoringImplicit(
161 ofClass(optionalClass()))),
163 .bind(ValueOrCallID))));
166auto isValueOrNotEqX() {
167 auto ComparesToSame = [](ast_matchers::internal::Matcher<Stmt> Arg) {
172 ofClass(optionalClass()))),
174 .bind(ValueOrCallID)),
175 ignoringImplicit(Arg));
189auto isCallReturningOptional() {
191 optionalOrAliasType(),
referenceType(pointee(optionalOrAliasType()))))));
194template <
typename L,
typename R>
195auto isComparisonOperatorCall(L lhs_arg_matcher, R rhs_arg_matcher) {
198 argumentCountIs(2), hasArgument(0, lhs_arg_matcher),
199 hasArgument(1, rhs_arg_matcher));
203BoolValue &forceBoolValue(Environment &Env,
const Expr &Expr) {
205 if (
Value !=
nullptr)
208 auto &Loc = Env.createStorageLocation(Expr);
209 Value = &Env.makeAtomicBoolValue();
210 Env.setValue(Loc, *
Value);
211 Env.setStorageLocation(Expr, Loc);
217void setHasValue(
Value &OptionalVal, BoolValue &HasValueVal) {
218 OptionalVal.setProperty(
"has_value", HasValueVal);
223StructValue &createOptionalValue(Environment &Env, BoolValue &HasValueVal) {
224 auto OptionalVal = std::make_unique<StructValue>();
225 setHasValue(*OptionalVal, HasValueVal);
226 return Env.takeOwnership(std::move(OptionalVal));
231BoolValue *getHasValue(Environment &Env,
Value *OptionalVal) {
232 if (OptionalVal !=
nullptr) {
234 cast_or_null<BoolValue>(OptionalVal->getProperty(
"has_value"));
235 if (HasValueVal ==
nullptr) {
236 HasValueVal = &Env.makeAtomicBoolValue();
237 OptionalVal->setProperty(
"has_value", *HasValueVal);
246QualType stripReference(QualType Type) {
247 return Type->isReferenceType() ?
Type->getPointeeType() :
Type;
251bool isOptionalType(QualType Type) {
252 if (!
Type->isRecordType())
255 auto TypeName =
Type->getAsCXXRecordDecl()->getQualifiedNameAsString();
264int countOptionalWrappers(
const ASTContext &ASTCtx, QualType Type) {
265 if (!isOptionalType(Type))
267 return 1 + countOptionalWrappers(
269 cast<ClassTemplateSpecializationDecl>(
Type->getAsRecordDecl())
273 .getDesugaredType(ASTCtx));
278StorageLocation *maybeInitializeOptionalValueMember(QualType Q,
286 if (
auto *ValueProp = OptionalVal.getProperty(
"value")) {
287 auto *ValueRef = clang::cast<ReferenceValue>(ValueProp);
288 auto &ValueLoc = ValueRef->getReferentLoc();
289 if (Env.getValue(ValueLoc) ==
nullptr) {
301 auto *ValueVal = Env.createValue(ValueLoc.getType());
302 if (ValueVal ==
nullptr)
304 Env.setValue(ValueLoc, *ValueVal);
309 auto Ty = stripReference(Q);
310 auto *ValueVal = Env.createValue(Ty);
311 if (ValueVal ==
nullptr)
313 auto &ValueLoc = Env.createStorageLocation(Ty);
314 Env.setValue(ValueLoc, *ValueVal);
315 auto ValueRef = std::make_unique<ReferenceValue>(ValueLoc);
316 OptionalVal.setProperty(
"value", Env.takeOwnership(std::move(ValueRef)));
320void initializeOptionalReference(
const Expr *OptionalExpr,
321 const MatchFinder::MatchResult &,
322 LatticeTransferState &State) {
323 if (
auto *OptionalVal =
325 if (OptionalVal->getProperty(
"has_value") ==
nullptr) {
326 setHasValue(*OptionalVal, State.Env.makeAtomicBoolValue());
333bool isEmptyOptional(
const Value &OptionalVal,
const Environment &Env) {
335 cast_or_null<BoolValue>(OptionalVal.getProperty(
"has_value"));
336 return HasValueVal !=
nullptr &&
337 Env.flowConditionImplies(Env.makeNot(*HasValueVal));
342bool isNonEmptyOptional(
const Value &OptionalVal,
const Environment &Env) {
344 cast_or_null<BoolValue>(OptionalVal.getProperty(
"has_value"));
345 return HasValueVal !=
nullptr && Env.flowConditionImplies(*HasValueVal);
348void transferUnwrapCall(
const Expr *UnwrapExpr,
const Expr *ObjectExpr,
349 LatticeTransferState &State) {
350 if (
auto *OptionalVal =
352 if (State.Env.getStorageLocation(*UnwrapExpr,
SkipPast::None) ==
nullptr)
353 if (
auto *Loc = maybeInitializeOptionalValueMember(
354 UnwrapExpr->getType(), *OptionalVal, State.Env))
355 State.Env.setStorageLocation(*UnwrapExpr, *Loc);
359void transferMakeOptionalCall(
const CallExpr *E,
360 const MatchFinder::MatchResult &,
361 LatticeTransferState &State) {
362 auto &Loc = State.Env.createStorageLocation(*E);
363 State.Env.setStorageLocation(*E, Loc);
365 Loc, createOptionalValue(State.Env, State.Env.getBoolLiteralValue(
true)));
368void transferOptionalHasValueCall(
const CXXMemberCallExpr *CallExpr,
369 const MatchFinder::MatchResult &,
370 LatticeTransferState &State) {
371 if (
auto *HasValueVal = getHasValue(
372 State.Env, State.Env.getValue(*CallExpr->getImplicitObjectArgument(),
374 auto &CallExprLoc = State.Env.createStorageLocation(*CallExpr);
375 State.Env.setValue(CallExprLoc, *HasValueVal);
376 State.Env.setStorageLocation(*CallExpr, CallExprLoc);
382void transferValueOrImpl(
const clang::Expr *ValueOrPredExpr,
383 const MatchFinder::MatchResult &
Result,
384 LatticeTransferState &State,
385 BoolValue &(*ModelPred)(Environment &Env,
387 BoolValue &HasValueVal)) {
388 auto &Env = State.Env;
390 const auto *ObjectArgumentExpr =
392 ->getImplicitObjectArgument();
394 auto *HasValueVal = getHasValue(
397 if (HasValueVal ==
nullptr)
400 Env.addToFlowCondition(
401 ModelPred(Env, forceBoolValue(Env, *ValueOrPredExpr), *HasValueVal));
404void transferValueOrStringEmptyCall(
const clang::Expr *ComparisonExpr,
405 const MatchFinder::MatchResult &
Result,
406 LatticeTransferState &State) {
407 return transferValueOrImpl(ComparisonExpr,
Result, State,
408 [](Environment &Env, BoolValue &ExprVal,
409 BoolValue &HasValueVal) -> BoolValue & {
416 return Env.makeImplication(Env.makeNot(ExprVal),
421void transferValueOrNotEqX(
const Expr *ComparisonExpr,
422 const MatchFinder::MatchResult &
Result,
423 LatticeTransferState &State) {
424 transferValueOrImpl(ComparisonExpr,
Result, State,
425 [](Environment &Env, BoolValue &ExprVal,
426 BoolValue &HasValueVal) -> BoolValue & {
430 return Env.makeImplication(ExprVal, HasValueVal);
434void transferCallReturningOptional(
const CallExpr *E,
435 const MatchFinder::MatchResult &
Result,
436 LatticeTransferState &State) {
440 auto &Loc = State.Env.createStorageLocation(*E);
441 State.Env.setStorageLocation(*E, Loc);
443 Loc, createOptionalValue(State.Env, State.Env.makeAtomicBoolValue()));
446void assignOptionalValue(
const Expr &E, Environment &Env,
447 BoolValue &HasValueVal) {
448 if (
auto *OptionalLoc =
450 Env.setValue(*OptionalLoc, createOptionalValue(Env, HasValueVal));
457BoolValue &valueOrConversionHasValue(
const FunctionDecl &F,
const Expr &E,
458 const MatchFinder::MatchResult &MatchRes,
459 LatticeTransferState &State) {
460 assert(F.getTemplateSpecializationArgs() !=
nullptr);
461 assert(F.getTemplateSpecializationArgs()->size() > 0);
463 const int TemplateParamOptionalWrappersCount = countOptionalWrappers(
465 stripReference(F.getTemplateSpecializationArgs()->get(0).getAsType()));
466 const int ArgTypeOptionalWrappersCount =
467 countOptionalWrappers(*MatchRes.Context, stripReference(E.getType()));
471 if (TemplateParamOptionalWrappersCount == ArgTypeOptionalWrappersCount)
472 return State.Env.getBoolLiteralValue(
true);
476 if (
auto *HasValueVal =
479 return State.Env.makeAtomicBoolValue();
482void transferValueOrConversionConstructor(
483 const CXXConstructExpr *E,
const MatchFinder::MatchResult &MatchRes,
484 LatticeTransferState &State) {
485 assert(E->getNumArgs() > 0);
487 assignOptionalValue(*E, State.Env,
488 valueOrConversionHasValue(*E->getConstructor(),
489 *E->getArg(0), MatchRes,
493void transferAssignment(
const CXXOperatorCallExpr *E, BoolValue &HasValueVal,
494 LatticeTransferState &State) {
495 assert(E->getNumArgs() > 0);
499 if (OptionalLoc ==
nullptr)
502 State.Env.setValue(*OptionalLoc, createOptionalValue(State.Env, HasValueVal));
505 State.Env.setStorageLocation(*E, *OptionalLoc);
508void transferValueOrConversionAssignment(
509 const CXXOperatorCallExpr *E,
const MatchFinder::MatchResult &MatchRes,
510 LatticeTransferState &State) {
511 assert(E->getNumArgs() > 1);
512 transferAssignment(E,
513 valueOrConversionHasValue(*E->getDirectCallee(),
514 *E->getArg(1), MatchRes, State),
518void transferNulloptAssignment(
const CXXOperatorCallExpr *E,
519 const MatchFinder::MatchResult &,
520 LatticeTransferState &State) {
521 transferAssignment(E, State.Env.getBoolLiteralValue(
false), State);
524void transferSwap(
const Expr &E1,
SkipPast E1Skip,
const Expr &E2,
529 auto *Loc1 = Env.getStorageLocation(E1, E1Skip);
532 if (Loc1 ==
nullptr) {
534 Env.setValue(*Loc2, createOptionalValue(Env, Env.makeAtomicBoolValue()));
537 if (Loc2 ==
nullptr) {
538 Env.setValue(*Loc1, createOptionalValue(Env, Env.makeAtomicBoolValue()));
548 auto *Val1 = Env.getValue(*Loc1);
550 Val1 = &createOptionalValue(Env, Env.makeAtomicBoolValue());
552 auto *Val2 = Env.getValue(*Loc2);
554 Val2 = &createOptionalValue(Env, Env.makeAtomicBoolValue());
556 Env.setValue(*Loc1, *Val2);
557 Env.setValue(*Loc2, *Val1);
560void transferSwapCall(
const CXXMemberCallExpr *E,
561 const MatchFinder::MatchResult &,
562 LatticeTransferState &State) {
563 assert(E->getNumArgs() == 1);
565 *E->getArg(0), State.Env);
568void transferStdSwapCall(
const CallExpr *E,
const MatchFinder::MatchResult &,
569 LatticeTransferState &State) {
570 assert(E->getNumArgs() == 2);
574BoolValue &evaluateEquality(Environment &Env, BoolValue &EqVal, BoolValue &LHS,
592 EqVal, Env.makeOr(Env.makeAnd(LHS, RHS),
593 Env.makeAnd(Env.makeNot(LHS), Env.makeNot(RHS)))),
594 Env.makeImplication(Env.makeNot(EqVal), Env.makeOr(LHS, RHS)));
598 const MatchFinder::MatchResult &,
599 LatticeTransferState &State) {
600 Environment &Env = State.Env;
601 auto *CmpValue = &forceBoolValue(Env, *CmpExpr);
602 if (
auto *LHasVal = getHasValue(
604 if (
auto *RHasVal = getHasValue(
606 if (CmpExpr->
getOperator() == clang::OO_ExclaimEqual)
607 CmpValue = &State.Env.makeNot(*CmpValue);
608 Env.addToFlowCondition(
609 evaluateEquality(Env, *CmpValue, *LHasVal, *RHasVal));
615 auto *CmpValue = &forceBoolValue(Env, *CmpExpr);
617 if (CmpExpr->
getOperator() == clang::OO_ExclaimEqual)
618 CmpValue = &Env.makeNot(*CmpValue);
619 Env.addToFlowCondition(evaluateEquality(Env, *CmpValue, *HasVal,
620 Env.getBoolLiteralValue(
true)));
624std::optional<StatementMatcher>
625ignorableOptional(
const UncheckedOptionalAccessModelOptions &Options) {
626 if (Options.IgnoreSmartPointerDereference) {
629 unless(hasArgument(0,
expr(hasOptionalType()))))));
637valueCall(
const std::optional<StatementMatcher> &IgnorableOptional) {
638 return isOptionalMemberCallWithName(
"value", IgnorableOptional);
642valueOperatorCall(
const std::optional<StatementMatcher> &IgnorableOptional) {
643 return expr(
anyOf(isOptionalOperatorCallWithName(
"*", IgnorableOptional),
644 isOptionalOperatorCallWithName(
"->", IgnorableOptional)));
647auto buildTransferMatchSwitch() {
651 return CFGMatchSwitchBuilder<LatticeTransferState>()
654 .CaseOfCFGStmt<Expr>(
656 initializeOptionalReference)
659 .CaseOfCFGStmt<CallExpr>(isMakeOptionalCall(), transferMakeOptionalCall)
662 .CaseOfCFGStmt<CXXConstructExpr>(
663 isOptionalInPlaceConstructor(),
664 [](
const CXXConstructExpr *E,
const MatchFinder::MatchResult &,
665 LatticeTransferState &State) {
666 assignOptionalValue(*E, State.Env,
667 State.Env.getBoolLiteralValue(
true));
670 .CaseOfCFGStmt<CXXConstructExpr>(
671 isNulloptConstructor(),
672 [](
const CXXConstructExpr *E,
const MatchFinder::MatchResult &,
673 LatticeTransferState &State) {
674 assignOptionalValue(*E, State.Env,
675 State.Env.getBoolLiteralValue(
false));
678 .CaseOfCFGStmt<CXXConstructExpr>(
679 isOptionalNulloptConstructor(),
680 [](
const CXXConstructExpr *E,
const MatchFinder::MatchResult &,
681 LatticeTransferState &State) {
682 assignOptionalValue(*E, State.Env,
683 State.Env.getBoolLiteralValue(
false));
686 .CaseOfCFGStmt<CXXConstructExpr>(isOptionalValueOrConversionConstructor(),
687 transferValueOrConversionConstructor)
691 .CaseOfCFGStmt<CXXOperatorCallExpr>(
692 isOptionalValueOrConversionAssignment(),
693 transferValueOrConversionAssignment)
694 .CaseOfCFGStmt<CXXOperatorCallExpr>(isOptionalNulloptAssignment(),
695 transferNulloptAssignment)
698 .CaseOfCFGStmt<CXXMemberCallExpr>(
699 valueCall(std::nullopt),
700 [](
const CXXMemberCallExpr *E,
const MatchFinder::MatchResult &,
701 LatticeTransferState &State) {
702 transferUnwrapCall(E, E->getImplicitObjectArgument(), State);
706 .CaseOfCFGStmt<CallExpr>(valueOperatorCall(std::nullopt),
707 [](
const CallExpr *E,
708 const MatchFinder::MatchResult &,
709 LatticeTransferState &State) {
710 transferUnwrapCall(E, E->getArg(0), State);
714 .CaseOfCFGStmt<CXXMemberCallExpr>(
715 isOptionalMemberCallWithName(
"has_value"),
716 transferOptionalHasValueCall)
719 .CaseOfCFGStmt<CXXMemberCallExpr>(
720 isOptionalMemberCallWithName(
"operator bool"),
721 transferOptionalHasValueCall)
724 .CaseOfCFGStmt<CXXMemberCallExpr>(
725 isOptionalMemberCallWithName(
"emplace"),
726 [](
const CXXMemberCallExpr *E,
const MatchFinder::MatchResult &,
727 LatticeTransferState &State) {
728 assignOptionalValue(*E->getImplicitObjectArgument(), State.Env,
729 State.Env.getBoolLiteralValue(
true));
733 .CaseOfCFGStmt<CXXMemberCallExpr>(
734 isOptionalMemberCallWithName(
"reset"),
735 [](
const CXXMemberCallExpr *E,
const MatchFinder::MatchResult &,
736 LatticeTransferState &State) {
737 assignOptionalValue(*E->getImplicitObjectArgument(), State.Env,
738 State.Env.getBoolLiteralValue(
false));
742 .CaseOfCFGStmt<CXXMemberCallExpr>(isOptionalMemberCallWithName(
"swap"),
746 .CaseOfCFGStmt<CallExpr>(isStdSwapCall(), transferStdSwapCall)
749 .CaseOfCFGStmt<Expr>(isValueOrStringEmptyCall(),
750 transferValueOrStringEmptyCall)
753 .CaseOfCFGStmt<Expr>(isValueOrNotEqX(), transferValueOrNotEqX)
756 .CaseOfCFGStmt<CXXOperatorCallExpr>(
757 isComparisonOperatorCall(hasAnyOptionalType(), hasAnyOptionalType()),
758 transferOptionalAndOptionalCmp)
759 .CaseOfCFGStmt<CXXOperatorCallExpr>(
760 isComparisonOperatorCall(hasOptionalType(),
761 unless(hasAnyOptionalType())),
763 const MatchFinder::MatchResult &, LatticeTransferState &State) {
764 transferOptionalAndValueCmp(Cmp, Cmp->getArg(0), State.Env);
766 .CaseOfCFGStmt<CXXOperatorCallExpr>(
767 isComparisonOperatorCall(
unless(hasAnyOptionalType()),
770 const MatchFinder::MatchResult &, LatticeTransferState &State) {
771 transferOptionalAndValueCmp(Cmp, Cmp->getArg(1), State.Env);
775 .CaseOfCFGStmt<CallExpr>(isCallReturningOptional(),
776 transferCallReturningOptional)
781std::vector<SourceLocation> diagnoseUnwrapCall(
const Expr *UnwrapExpr,
782 const Expr *ObjectExpr,
783 const Environment &Env) {
784 if (
auto *OptionalVal =
786 auto *Prop = OptionalVal->getProperty(
"has_value");
787 if (
auto *HasValueVal = cast_or_null<BoolValue>(Prop)) {
788 if (Env.flowConditionImplies(*HasValueVal))
796 return {ObjectExpr->getBeginLoc()};
799auto buildDiagnoseMatchSwitch(
800 const UncheckedOptionalAccessModelOptions &Options) {
804 auto IgnorableOptional = ignorableOptional(Options);
805 return CFGMatchSwitchBuilder<const Environment, std::vector<SourceLocation>>()
807 .CaseOfCFGStmt<CXXMemberCallExpr>(
808 valueCall(IgnorableOptional),
809 [](
const CXXMemberCallExpr *E,
const MatchFinder::MatchResult &,
810 const Environment &Env) {
811 return diagnoseUnwrapCall(E, E->getImplicitObjectArgument(), Env);
815 .CaseOfCFGStmt<CallExpr>(
816 valueOperatorCall(IgnorableOptional),
817 [](
const CallExpr *E,
const MatchFinder::MatchResult &,
818 const Environment &Env) {
819 return diagnoseUnwrapCall(E, E->getArg(0), Env);
828 return optionalClass();
833 TransferMatchSwitch(buildTransferMatchSwitch()) {}
837 LatticeTransferState State(L, Env);
844 if (!isOptionalType(
Type))
846 bool MustNonEmpty1 = isNonEmptyOptional(Val1, Env1);
847 bool MustNonEmpty2 = isNonEmptyOptional(Val2, Env2);
853 return (isEmptyOptional(Val1, Env1) && isEmptyOptional(Val2, Env2))
864 if (!isOptionalType(
Type))
869 bool MustNonEmpty1 = isNonEmptyOptional(Val1, Env1);
870 bool MustNonEmpty2 = isNonEmptyOptional(Val2, Env2);
871 if (MustNonEmpty1 && MustNonEmpty2)
876 !MustNonEmpty1 && !MustNonEmpty2 && isEmptyOptional(Val1, Env1) &&
877 isEmptyOptional(Val2, Env2))
879 setHasValue(MergedVal, HasValueVal);
887 switch (
compare(
Type, Prev, PrevEnv, Current, CurrentEnv)) {
891 if (
auto *PrevHasVal =
892 cast_or_null<BoolValue>(Prev.
getProperty(
"has_value"))) {
893 if (isa<TopBoolValue>(PrevHasVal))
896 if (
auto *CurrentHasVal =
897 cast_or_null<BoolValue>(Current.getProperty(
"has_value"))) {
898 if (isa<TopBoolValue>(CurrentHasVal))
905 llvm_unreachable(
"all cases covered in switch");
910 : DiagnoseMatchSwitch(buildDiagnoseMatchSwitch(Options)) {}
914 return DiagnoseMatchSwitch(*Elt, Ctx, Env);
Defines the clang::ASTContext interface.
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.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
This represents one expression.
A (possibly-)qualified type.
The base class of the type hierarchy.
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.
void addToFlowCondition(BoolValue &Val)
Adds Val to the set of clauses that constitute the flow condition.
BoolValue & makeTopBoolValue() const
Returns a unique instance of boolean Top.
BoolValue & makeAtomicBoolValue() const
Returns an atomic boolean value.
BoolValue & makeNot(BoolValue &Val) const
Returns a boolean value that represents the negation of Val.
Trivial lattice for dataflow analysis with exactly one element.
UncheckedOptionalAccessDiagnoser(UncheckedOptionalAccessModelOptions Options={})
std::vector< SourceLocation > diagnose(ASTContext &Ctx, const CFGElement *Elt, const Environment &Env)
Dataflow analysis that models whether optionals hold values or not.
ComparisonResult compare(QualType Type, const Value &Val1, const Environment &Env1, const Value &Val2, const Environment &Env2) override
Returns: Same: Val1 is equivalent to Val2, according to the model.
UncheckedOptionalAccessModel(ASTContext &Ctx)
bool merge(QualType Type, const Value &Val1, const Environment &Env1, const Value &Val2, const Environment &Env2, Value &MergedVal, Environment &MergedEnv) override
Modifies MergedVal to approximate both Val1 and Val2.
void transfer(const CFGElement &Elt, NoopLattice &L, Environment &Env)
Value * widen(QualType Type, Value &Prev, const Environment &PrevEnv, Value &Current, Environment &CurrentEnv) override
This function may widen the current value – replace it with an approximation that can reach a fixed p...
static ast_matchers::DeclarationMatcher optionalClassDecl()
Returns a matcher for the optional classes covered by this model.
Base class for all values computed by abstract interpretation.
Value * getProperty(llvm::StringRef Name) const
Returns the value of the synthetic property with the given Name or null if the property isn't assigne...
const internal::VariadicDynCastAllOfMatcher< Stmt, DeclRefExpr > declRefExpr
Matches expressions that refer to declarations.
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.
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.
ComparisonResult
Indicates the result of a tentative comparison.
SkipPast
Indicates what kind of indirections should be skipped past when retrieving storage locations or value...
@ ReferenceThenPointer
An optional reference should be skipped past, then an optional pointer should be skipped past.
@ Reference
An optional reference should be skipped past.
@ None
No indirections should be skipped past.
@ Result
The result type of a method or function.