clang 23.0.0git
UncheckedStatusOrAccessModel.cpp
Go to the documentation of this file.
1//===- UncheckedStatusOrAccessModel.cpp -----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
11#include <cassert>
12#include <utility>
13
14#include "clang/AST/DeclCXX.h"
16#include "clang/AST/Expr.h"
17#include "clang/AST/ExprCXX.h"
18#include "clang/AST/TypeBase.h"
22#include "clang/Analysis/CFG.h"
31#include "clang/Basic/LLVM.h"
33#include "llvm/ADT/StringMap.h"
34
36namespace {
37
38using ::clang::ast_matchers::MatchFinder;
40
41} // namespace
42
43static bool namespaceEquals(const NamespaceDecl *NS,
44 clang::ArrayRef<clang::StringRef> NamespaceNames) {
45 while (!NamespaceNames.empty() && NS) {
46 if (NS->getName() != NamespaceNames.consume_back())
47 return false;
48 NS = dyn_cast_or_null<NamespaceDecl>(NS->getParent());
49 }
50 return NamespaceNames.empty() && !NS;
51}
52
53// TODO: move this to a proper place to share with the rest of clang
55 StringRef Name) {
56 if (Type.isNull())
57 return false;
58 if (auto *RD = Type->getAsRecordDecl())
59 if (RD->getName() == Name)
60 if (const auto *N = dyn_cast_or_null<NamespaceDecl>(RD->getDeclContext()))
61 return namespaceEquals(N, NS);
62 return false;
63}
64
66 return isTypeNamed(Type, {"absl", "internal_statusor"}, "OperatorBase");
67}
68
69static bool isSafeUnwrap(RecordStorageLocation *StatusOrLoc,
70 const Environment &Env) {
71 if (!StatusOrLoc)
72 return false;
73 auto &StatusLoc = locForStatus(*StatusOrLoc);
74 auto *OkVal = Env.get<BoolValue>(locForOk(StatusLoc));
75 return OkVal != nullptr && Env.proves(OkVal->formula());
76}
77
80 auto *RD = Ty->getAsCXXRecordDecl();
81 if (RD == nullptr)
82 return nullptr;
83 if (isStatusOrType(Ty) ||
84 // In case we are analyzing code under OperatorBase itself that uses
85 // operator* (e.g. to implement operator->).
88 if (!RD->hasDefinition())
89 return nullptr;
90 for (const auto &Base : RD->bases())
91 if (auto *QT = getStatusOrBaseClass(Base.getType()))
92 return QT;
93 return nullptr;
94}
95
99
100static auto ofClassStatus() {
101 using namespace ::clang::ast_matchers;
102 return ofClass(hasName("::absl::Status"));
103}
104
105static auto isStatusMemberCallWithName(llvm::StringRef member_name) {
106 using namespace ::clang::ast_matchers;
107 return cxxMemberCallExpr(
108 on(expr(unless(cxxThisExpr()))),
109 callee(cxxMethodDecl(hasName(member_name), ofClassStatus())));
110}
111
112static auto isStatusOrMemberCallWithName(llvm::StringRef member_name) {
113 using namespace ::clang::ast_matchers;
114 return cxxMemberCallExpr(
115 on(expr(unless(cxxThisExpr()))),
116 callee(cxxMethodDecl(
117 hasName(member_name),
119}
120
121static auto isStatusOrOperatorCallWithName(llvm::StringRef operator_name) {
122 using namespace ::clang::ast_matchers;
123 return cxxOperatorCallExpr(
124 hasOverloadedOperatorName(operator_name),
125 callee(cxxMethodDecl(
127}
128
129static auto valueCall() {
130 using namespace ::clang::ast_matchers;
131 return anyOf(isStatusOrMemberCallWithName("value"),
132 isStatusOrMemberCallWithName("ValueOrDie"));
133}
134
135static auto valueOperatorCall() {
136 using namespace ::clang::ast_matchers;
139}
140
141static auto isComparisonOperatorCall(llvm::StringRef operator_name) {
142 using namespace ::clang::ast_matchers;
143 return cxxOperatorCallExpr(
144 hasOverloadedOperatorName(operator_name), argumentCountIs(2),
145 hasArgument(0, anyOf(hasType(statusType()), hasType(statusOrType()))),
146 hasArgument(1, anyOf(hasType(statusType()), hasType(statusOrType()))));
147}
148
149static auto isOkStatusCall() {
150 using namespace ::clang::ast_matchers;
151 return callExpr(callee(functionDecl(hasName("::absl::OkStatus"))));
152}
153
154static auto isNotOkStatusCall() {
155 using namespace ::clang::ast_matchers;
156 return callExpr(callee(functionDecl(hasAnyName(
157 "::absl::AbortedError", "::absl::AlreadyExistsError",
158 "::absl::CancelledError", "::absl::DataLossError",
159 "::absl::DeadlineExceededError", "::absl::FailedPreconditionError",
160 "::absl::InternalError", "::absl::InvalidArgumentError",
161 "::absl::NotFoundError", "::absl::OutOfRangeError",
162 "::absl::PermissionDeniedError", "::absl::ResourceExhaustedError",
163 "::absl::UnauthenticatedError", "::absl::UnavailableError",
164 "::absl::UnimplementedError", "::absl::UnknownError"))));
165}
166
167static auto isPointerComparisonOperatorCall(std::string operator_name) {
168 using namespace ::clang::ast_matchers;
169 return binaryOperator(hasOperatorName(operator_name),
170 hasLHS(hasType(hasCanonicalType(pointerType(
171 pointee(anyOf(statusOrType(), statusType())))))),
172 hasRHS(hasType(hasCanonicalType(pointerType(
173 pointee(anyOf(statusOrType(), statusType())))))));
174}
175
176// The nullPointerConstant in the two matchers below is to support
177// absl::StatusOr<void*> X = nullptr.
178// nullptr does not match the bound type.
179// TODO: be less restrictive around convertible types in general.
181 using namespace ::clang::ast_matchers;
182 return cxxOperatorCallExpr(
184 callee(cxxMethodDecl(ofClass(statusOrClass()))),
185 hasArgument(1, anyOf(hasType(hasUnqualifiedDesugaredType(
186 type(equalsBoundNode("T")))),
187 nullPointerConstant())));
188}
189
191 using namespace ::clang::ast_matchers;
192 return cxxConstructExpr(
193 hasType(statusOrType()),
194 hasArgument(0,
195 anyOf(hasType(hasCanonicalType(type(equalsBoundNode("T")))),
196 nullPointerConstant(),
197 hasType(namedDecl(hasAnyName("absl::in_place_t",
198 "std::in_place_t"))))));
199}
200
202 using namespace ::clang::ast_matchers;
203 return cxxConstructExpr(hasType(statusOrType()));
204}
205
206static auto isStatusConstructor() {
207 using namespace ::clang::ast_matchers;
208 return cxxConstructExpr(hasType(statusType()));
209}
211 using namespace ::clang::ast_matchers;
212 return callExpr(callee(
213 functionDecl(hasName("::absl::log_internal::GetReferenceableValue"))));
214}
215
216static auto isLoggingCheckEqImpl() {
217 using namespace ::clang::ast_matchers;
218 return callExpr(
219 callee(functionDecl(hasName("::absl::log_internal::Check_EQImpl"))));
220}
221
223 using namespace ::clang::ast_matchers;
224 return callExpr(
225 callee(functionDecl(hasName("::absl::log_internal::AsStatus"))),
226 hasArgument(0, hasType(statusClass())));
227}
228
230 using namespace ::clang::ast_matchers;
231 return callExpr(
232 callee(functionDecl(hasName("::absl::log_internal::AsStatus"))),
233 hasArgument(0, hasType(statusOrType())));
234}
235
237 using namespace ::clang::ast_matchers;
238 return anyOf(statusOrType(), referenceType(pointee(statusOrType())));
239}
240
242 using namespace ::clang::ast_matchers;
243 return cxxMemberCallExpr(callee(cxxMethodDecl(
244 parameterCountIs(0), isConst(),
245 returns(hasCanonicalType(anyOf(referenceType(), recordType()))))));
246}
247
249 using namespace ::clang::ast_matchers;
251 parameterCountIs(0), isConst(),
252 returns(hasCanonicalType(anyOf(referenceType(), recordType()))))));
253}
254
256 using namespace ::clang::ast_matchers;
257 return cxxMemberCallExpr(callee(
258 cxxMethodDecl(parameterCountIs(0), isConst(), returns(pointerType()))));
259}
260
262 using namespace ::clang::ast_matchers;
263 return cxxOperatorCallExpr(callee(
264 cxxMethodDecl(parameterCountIs(0), isConst(), returns(pointerType()))));
265}
266
267static auto isNonConstMemberCall() {
268 using namespace ::clang::ast_matchers;
269 return cxxMemberCallExpr(callee(cxxMethodDecl(unless(isConst()))));
270}
271
273 using namespace ::clang::ast_matchers;
274 return cxxOperatorCallExpr(callee(cxxMethodDecl(unless(isConst()))));
275}
276
278 using namespace ::clang::ast_matchers;
279 return callExpr(
280 callee(functionDecl(
281 hasName("::testing::internal::MakePredicateFormatterFromMatcher"))),
282 hasArgument(
283 0, hasType(cxxRecordDecl(hasAnyName(
284 "::testing::status::internal_status::IsOkMatcher",
285 "::absl_testing::status_internal::IsOkMatcher",
286 "::testing::status::internal_status::IsOkAndHoldsMatcher",
287 "::absl_testing::status_internal::IsOkAndHoldsMatcher")))));
288}
289
291 using namespace ::clang::ast_matchers;
292 return callExpr(callee(functionDecl(hasAnyName(
293 "::testing::status::StatusIs", "absl_testing::StatusIs",
294 "::testing::status::CanonicalStatusIs",
295 "::absl_testing::CanonicalStatusIs"))),
296 hasArgument(0, declRefExpr(to(enumConstantDecl(hasAnyName(
297 "::absl::StatusCode::kOk", "OK"))))));
298}
299
301 using namespace ::clang::ast_matchers;
302 return callExpr(
303 callee(functionDecl(
304 hasName("::testing::internal::MakePredicateFormatterFromMatcher"))),
305 hasArgument(0, hasType(cxxRecordDecl(hasAnyName(
306 "::testing::status::internal_status::StatusIsMatcher",
307 "::testing::status::internal_status::"
308 "CanonicalStatusIsMatcher",
309 "::absl_testing::status_internal::StatusIsMatcher",
310 "::absl_testing::status_internal::"
311 "CanonicalStatusIsMatcher")))));
312}
313
315 using namespace ::clang::ast_matchers;
316 return cxxOperatorCallExpr(
318 callee(cxxMethodDecl(ofClass(
319 hasName("testing::internal::PredicateFormatterFromMatcher")))),
320 hasArgument(2, hasType(statusType())));
321}
322
324 using namespace ::clang::ast_matchers;
325 return cxxOperatorCallExpr(
327 callee(cxxMethodDecl(ofClass(
328 hasName("testing::internal::PredicateFormatterFromMatcher")))),
329 hasArgument(2, hasType(statusOrType())));
330}
331
333 using namespace ::clang::ast_matchers;
334 return cxxMemberCallExpr(
335 on(expr(unless(cxxThisExpr()))),
336 callee(cxxMethodDecl(hasName("operator bool"),
337 ofClass(hasName("testing::AssertionResult")))));
338}
339
341 using namespace ::clang::ast_matchers;
342 return cxxConstructExpr(
343 hasType(recordDecl(hasName("testing::AssertionResult"))),
344 hasArgument(0, hasType(booleanType())));
345}
346
348 using namespace ::clang::ast_matchers;
349 return callExpr(
350 callee(functionDecl(returns(possiblyReferencedStatusOrType()))));
351}
352
354 using namespace ::clang::ast_matchers;
355 return callExpr(callee(functionDecl(returns(hasUnqualifiedDesugaredType(
357}
358
360 using namespace ::clang::ast_matchers;
361 return callExpr(callee(functionDecl(returns(hasUnqualifiedDesugaredType(
362 pointerType(pointee(hasUnqualifiedDesugaredType(
364}
365
366static auto
370 // StatusOr::value, StatusOr::ValueOrDie
371 .CaseOfCFGStmt<CXXMemberCallExpr>(
372 valueCall(),
373 [](const CXXMemberCallExpr *E,
375 const Environment &Env) {
376 if (!isSafeUnwrap(getImplicitObjectLocation(*E, Env), Env))
379 })
380
381 // StatusOr::operator*, StatusOr::operator->
382 .CaseOfCFGStmt<CXXOperatorCallExpr>(
384 [](const CXXOperatorCallExpr *E,
386 const Environment &Env) {
387 RecordStorageLocation *StatusOrLoc =
388 Env.get<RecordStorageLocation>(*E->getArg(0));
389 if (!isSafeUnwrap(StatusOrLoc, Env))
390 return llvm::SmallVector<SourceLocation>({E->getOperatorLoc()});
392 })
393 .Build();
394}
395
399
406
408 Environment &Env) {
409 auto &OkVal = Env.makeAtomicBoolValue();
410 Env.setValue(locForOk(StatusLoc), OkVal);
411 return OkVal;
412}
413
415 Environment &Env) {
416 return initializeStatus(locForStatus(StatusOrLoc), Env);
417}
418
420 using namespace ::clang::ast_matchers;
422 hasName("absl::StatusOr"),
423 hasTemplateArgument(0, refersToType(type().bind("T"))));
424}
425
427 using namespace ::clang::ast_matchers;
428 return cxxRecordDecl(hasName("absl::Status"));
429}
430
432 using namespace ::clang::ast_matchers;
434 hasName("absl::internal_statusor::OperatorBase"));
435}
436
438 using namespace ::clang::ast_matchers;
439 return hasCanonicalType(qualType(hasDeclaration(statusOrClass())));
440}
441
443 using namespace ::clang::ast_matchers;
444 return hasCanonicalType(qualType(hasDeclaration(statusClass())));
445}
446
448 return isTypeNamed(Type, {"absl"}, "StatusOr");
449}
450
452 return isTypeNamed(Type, {"absl"}, "Status");
453}
454
456 return isTypeNamed(Type, {"testing", "internal"},
457 "PredicateFormatterFromMatcher");
458}
459
461 return isTypeNamed(Type, {"testing"}, "AssertionResult");
462}
463
465 return isTypeNamed(Type, {"testing", "status", "internal_status"},
466 "StatusIsMatcher") ||
467 isTypeNamed(Type, {"testing", "status", "internal_status"},
468 "CanonicalStatusIsMatcher") ||
469 isTypeNamed(Type, {"absl_testing", "status_internal"},
470 "StatusIsMatcher") ||
471 isTypeNamed(Type, {"absl_testing", "status_internal"},
472 "CanonicalStatusIsMatcher");
473}
474
475llvm::StringMap<QualType> getSyntheticFields(QualType Ty, QualType StatusType,
476 const CXXRecordDecl &RD) {
477 if (auto *TRD = getStatusOrBaseClass(Ty))
478 return {{"status", StatusType}, {"value", getStatusOrValueType(TRD)}};
479 if (isStatusType(Ty) || (RD.hasDefinition() &&
480 RD.isDerivedFrom(StatusType->getAsCXXRecordDecl())))
481 return {{"ok", RD.getASTContext().BoolTy}};
482 if (isAssertionResultType(Ty))
483 return {{"ok", RD.getASTContext().BoolTy}};
485 return {{"ok_predicate", RD.getASTContext().BoolTy}};
486 if (isStatusIsMatcherType(Ty))
487 return {{"ok_matcher", RD.getASTContext().BoolTy}};
488 return {};
489}
490
494
496 return StatusLoc.getSyntheticField("ok");
497}
498
500 if (auto *Val = Env.get<BoolValue>(locForOk(StatusLoc)))
501 return *Val;
502 return initializeStatus(StatusLoc, Env);
503}
505 return StatusLoc.getSyntheticField("ok_predicate");
506}
507
509 return StatusLoc.getSyntheticField("ok_matcher");
510}
511
514 LatticeTransferState &State) {
515 RecordStorageLocation *StatusOrLoc =
516 getImplicitObjectLocation(*Expr, State.Env);
517 if (StatusOrLoc == nullptr)
518 return;
519
520 auto &OkVal = valForOk(locForStatus(*StatusOrLoc), State.Env);
521 State.Env.setValue(*Expr, OkVal);
522}
523
526 LatticeTransferState &State) {
527 RecordStorageLocation *StatusOrLoc =
528 getImplicitObjectLocation(*Expr, State.Env);
529 if (StatusOrLoc == nullptr)
530 return;
531
532 RecordStorageLocation &StatusLoc = locForStatus(*StatusOrLoc);
533
534 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
535 initializeStatusOr(*StatusOrLoc, State.Env);
536
537 if (Expr->isPRValue())
538 copyRecord(StatusLoc, State.Env.getResultObjectLocation(*Expr), State.Env);
539 else
540 State.Env.setStorageLocation(*Expr, StatusLoc);
541}
542
545 LatticeTransferState &State) {
546 RecordStorageLocation *StatusLoc =
547 getImplicitObjectLocation(*Expr, State.Env);
548 if (StatusLoc == nullptr)
549 return;
550
551 if (Value *Val = State.Env.getValue(locForOk(*StatusLoc)))
552 State.Env.setValue(*Expr, *Val);
553}
554
557 LatticeTransferState &State) {
558 // S.Update(OtherS) sets S to the error code of OtherS if it is OK,
559 // otherwise does nothing.
560 assert(Expr->getNumArgs() == 1);
561 auto *Arg = Expr->getArg(0);
562 RecordStorageLocation *ArgRecord =
563 Arg->isPRValue() ? &State.Env.getResultObjectLocation(*Arg)
564 : State.Env.get<RecordStorageLocation>(*Arg);
566 if (ThisLoc == nullptr || ArgRecord == nullptr)
567 return;
568
569 auto &ThisOkVal = valForOk(*ThisLoc, State.Env);
570 auto &ArgOkVal = valForOk(*ArgRecord, State.Env);
571 auto &A = State.Env.arena();
572 auto &NewVal = State.Env.makeAtomicBoolValue();
573 State.Env.assume(A.makeImplies(A.makeNot(ThisOkVal.formula()),
574 A.makeNot(NewVal.formula())));
575 State.Env.assume(A.makeImplies(NewVal.formula(), ArgOkVal.formula()));
576 State.Env.setValue(locForOk(*ThisLoc), NewVal);
577}
578
580 RecordStorageLocation &RhsStatusLoc,
581 Environment &Env) {
582 auto &A = Env.arena();
583 // Logically, a Status object is composed of an error code that could take one
584 // of multiple possible values, including the "ok" value. We track whether a
585 // Status object has an "ok" value and represent this as an `ok` bit. Equality
586 // of Status objects compares their error codes. Therefore, merely comparing
587 // the `ok` bits isn't sufficient: when two Status objects are assigned non-ok
588 // error codes the equality of their respective error codes matters. Since we
589 // only track the `ok` bits, we can't make any conclusions about equality when
590 // we know that two Status objects have non-ok values.
591
592 auto &LhsOkVal = valForOk(LhsStatusLoc, Env);
593 auto &RhsOkVal = valForOk(RhsStatusLoc, Env);
594
595 auto &Res = Env.makeAtomicBoolValue();
596
597 // lhs && rhs => res (a.k.a. !res => !lhs || !rhs)
598 Env.assume(A.makeImplies(A.makeAnd(LhsOkVal.formula(), RhsOkVal.formula()),
599 Res.formula()));
600 // res => (lhs == rhs)
601 Env.assume(A.makeImplies(
602 Res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
603
604 return &Res;
605}
606
607static BoolValue *
609 RecordStorageLocation &RhsStatusOrLoc,
610 Environment &Env) {
611 auto &A = Env.arena();
612 // Logically, a StatusOr<T> object is composed of two values - a Status and a
613 // value of type T. Equality of StatusOr objects compares both values.
614 // Therefore, merely comparing the `ok` bits of the Status values isn't
615 // sufficient. When two StatusOr objects are engaged, the equality of their
616 // respective values of type T matters. Similarly, when two StatusOr objects
617 // have Status values that have non-ok error codes, the equality of the error
618 // codes matters. Since we only track the `ok` bits of the Status values, we
619 // can't make any conclusions about equality when we know that two StatusOr
620 // objects are engaged or when their Status values contain non-ok error codes.
621 auto &LhsOkVal = valForOk(locForStatus(LhsStatusOrLoc), Env);
622 auto &RhsOkVal = valForOk(locForStatus(RhsStatusOrLoc), Env);
623 auto &res = Env.makeAtomicBoolValue();
624
625 // res => (lhs == rhs)
626 Env.assume(A.makeImplies(
627 res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
628 return &res;
629}
630
631static BoolValue *evaluateEquality(const Expr *LhsExpr, const Expr *RhsExpr,
632 Environment &Env) {
633 // Check the type of both sides in case an operator== is added that admits
634 // different types.
635 if (isStatusOrType(LhsExpr->getType()) &&
636 isStatusOrType(RhsExpr->getType())) {
637 auto *LhsStatusOrLoc = Env.get<RecordStorageLocation>(*LhsExpr);
638 if (LhsStatusOrLoc == nullptr)
639 return nullptr;
640 auto *RhsStatusOrLoc = Env.get<RecordStorageLocation>(*RhsExpr);
641 if (RhsStatusOrLoc == nullptr)
642 return nullptr;
643
644 return evaluateStatusOrEquality(*LhsStatusOrLoc, *RhsStatusOrLoc, Env);
645 }
646 if (isStatusType(LhsExpr->getType()) && isStatusType(RhsExpr->getType())) {
647 auto *LhsStatusLoc = Env.get<RecordStorageLocation>(*LhsExpr);
648 if (LhsStatusLoc == nullptr)
649 return nullptr;
650
651 auto *RhsStatusLoc = Env.get<RecordStorageLocation>(*RhsExpr);
652 if (RhsStatusLoc == nullptr)
653 return nullptr;
654
655 return evaluateStatusEquality(*LhsStatusLoc, *RhsStatusLoc, Env);
656 }
657 return nullptr;
658}
659
662 bool IsNegative) {
663 auto *LhsAndRhsVal =
664 evaluateEquality(Expr->getArg(0), Expr->getArg(1), State.Env);
665 if (LhsAndRhsVal == nullptr)
666 return;
667
668 if (IsNegative)
669 State.Env.setValue(*Expr, State.Env.makeNot(*LhsAndRhsVal));
670 else
671 State.Env.setValue(*Expr, *LhsAndRhsVal);
672}
673
675 Environment &Env) {
676 if (auto *PointerVal = Env.get<PointerValue>(Expr))
677 return dyn_cast<RecordStorageLocation>(&PointerVal->getPointeeLoc());
678 return nullptr;
679}
680
682 const Expr *RhsExpr,
683 Environment &Env) {
684 assert(LhsExpr->getType()->isPointerType());
685 assert(RhsExpr->getType()->isPointerType());
686 RecordStorageLocation *LhsStatusLoc = nullptr;
687 RecordStorageLocation *RhsStatusLoc = nullptr;
688 if (isStatusOrType(LhsExpr->getType()->getPointeeType()) &&
689 isStatusOrType(RhsExpr->getType()->getPointeeType())) {
690 auto *LhsStatusOrLoc = getPointeeLocation(*LhsExpr, Env);
691 auto *RhsStatusOrLoc = getPointeeLocation(*RhsExpr, Env);
692 if (LhsStatusOrLoc == nullptr || RhsStatusOrLoc == nullptr)
693 return nullptr;
694 LhsStatusLoc = &locForStatus(*LhsStatusOrLoc);
695 RhsStatusLoc = &locForStatus(*RhsStatusOrLoc);
696 } else if (isStatusType(LhsExpr->getType()->getPointeeType()) &&
697 isStatusType(RhsExpr->getType()->getPointeeType())) {
698 LhsStatusLoc = getPointeeLocation(*LhsExpr, Env);
699 RhsStatusLoc = getPointeeLocation(*RhsExpr, Env);
700 }
701 if (LhsStatusLoc == nullptr || RhsStatusLoc == nullptr)
702 return nullptr;
703 auto &LhsOkVal = valForOk(*LhsStatusLoc, Env);
704 auto &RhsOkVal = valForOk(*RhsStatusLoc, Env);
705 auto &Res = Env.makeAtomicBoolValue();
706 auto &A = Env.arena();
707 Env.assume(A.makeImplies(
708 Res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
709 return &Res;
710}
711
714 bool IsNegative) {
715 auto *LhsAndRhsVal =
716 evaluatePointerEquality(Expr->getLHS(), Expr->getRHS(), State.Env);
717 if (LhsAndRhsVal == nullptr)
718 return;
719
720 if (IsNegative)
721 State.Env.setValue(*Expr, State.Env.makeNot(*LhsAndRhsVal));
722 else
723 State.Env.setValue(*Expr, *LhsAndRhsVal);
724}
725
728 LatticeTransferState &State) {
729 auto &OkVal =
730 initializeStatus(State.Env.getResultObjectLocation(*Expr), State.Env);
731 State.Env.assume(OkVal.formula());
732}
733
736 LatticeTransferState &State) {
737 auto &OkVal =
738 initializeStatus(State.Env.getResultObjectLocation(*Expr), State.Env);
739 auto &A = State.Env.arena();
740 State.Env.assume(A.makeNot(OkVal.formula()));
741}
742
745 LatticeTransferState &State) {
746 RecordStorageLocation *StatusOrLoc =
747 getImplicitObjectLocation(*Expr, State.Env);
748 if (StatusOrLoc == nullptr)
749 return;
750
751 auto &OkVal = valForOk(locForStatus(*StatusOrLoc), State.Env);
752 State.Env.assume(OkVal.formula());
753}
754
757 LatticeTransferState &State) {
758 assert(Expr->getNumArgs() > 1);
759
760 auto *StatusOrLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
761 if (StatusOrLoc == nullptr)
762 return;
763
764 auto &OkVal = initializeStatusOr(*StatusOrLoc, State.Env);
765 State.Env.assume(OkVal.formula());
766}
767
770 LatticeTransferState &State) {
771 auto &OkVal =
772 initializeStatusOr(State.Env.getResultObjectLocation(*Expr), State.Env);
773 State.Env.assume(OkVal.formula());
774}
775
778 LatticeTransferState &State) {
779 RecordStorageLocation &StatusOrLoc = State.Env.getResultObjectLocation(*Expr);
780 RecordStorageLocation &StatusLoc = locForStatus(StatusOrLoc);
781
782 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
783 initializeStatusOr(StatusOrLoc, State.Env);
784}
785
788 LatticeTransferState &State) {
789 RecordStorageLocation &StatusLoc = State.Env.getResultObjectLocation(*Expr);
790
791 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
792 initializeStatus(StatusLoc, State.Env);
793}
794static void
797 LatticeTransferState &State) {
798 assert(Expr->getNumArgs() == 1);
799 if (Expr->getArg(0)->isPRValue())
800 return;
801 auto *ArgLoc = State.Env.getStorageLocation(*Expr->getArg(0));
802 if (ArgLoc == nullptr)
803 return;
804
805 State.Env.setStorageLocation(*Expr, *ArgLoc);
806}
807
810 LatticeTransferState &State) {
811 assert(Expr->getNumArgs() > 2);
812
813 auto *EqVal = evaluateEquality(Expr->getArg(0), Expr->getArg(1), State.Env);
814 if (EqVal == nullptr)
815 return;
816
817 // Consider modelling this more accurately instead of assigning BoolValue
818 // as the value of an expression of pointer type.
819 // For now, this is being handled in transferPointerToBoolean.
820 State.Env.setValue(*Expr, State.Env.makeNot(*EqVal));
821}
822
825 LatticeTransferState &State) {
826 assert(Expr->getNumArgs() == 1);
827
828 auto *ArgLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
829 if (ArgLoc == nullptr)
830 return;
831
832 if (State.Env.getValue(locForOk(*ArgLoc)) == nullptr)
833 initializeStatus(*ArgLoc, State.Env);
834
835 auto &ExprVal = State.Env.create<PointerValue>(*ArgLoc);
836 State.Env.setValue(*Expr, ExprVal);
837}
838
841 LatticeTransferState &State) {
842 assert(Expr->getNumArgs() == 1);
843
844 auto *ArgLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
845 if (ArgLoc == nullptr)
846 return;
847
848 RecordStorageLocation &StatusLoc = locForStatus(*ArgLoc);
849
850 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
851 initializeStatusOr(*ArgLoc, State.Env);
852
853 auto &ExprVal = State.Env.create<PointerValue>(StatusLoc);
854 State.Env.setValue(*Expr, ExprVal);
855}
856
859 LatticeTransferState &State) {
860 if (auto *SubExprVal =
861 dyn_cast_or_null<BoolValue>(State.Env.getValue(*Expr->getSubExpr())))
862 State.Env.setValue(*Expr, *SubExprVal);
863}
864
866 LatticeTransferState &State) {
867 RecordStorageLocation *StatusOrLoc =
868 Expr->isPRValue() ? &State.Env.getResultObjectLocation(*Expr)
869 : State.Env.get<RecordStorageLocation>(*Expr);
870 if (StatusOrLoc != nullptr &&
871 State.Env.getValue(locForOk(locForStatus(*StatusOrLoc))) == nullptr)
872 initializeStatusOr(*StatusOrLoc, State.Env);
873}
874
878 if (RecordLoc == nullptr)
879 return false;
880 const FunctionDecl *DirectCallee = Expr->getDirectCallee();
881 if (DirectCallee == nullptr)
882 return false;
883 StorageLocation &Loc =
884 State.Lattice.getOrCreateConstMethodReturnStorageLocation(
885 *RecordLoc, DirectCallee, State.Env, [&](StorageLocation &Loc) {
886 if (isStatusOrType(Expr->getType()))
887 initializeStatusOr(cast<RecordStorageLocation>(Loc), State.Env);
888 });
889 if (Expr->isPRValue()) {
890 auto &ResultLoc = State.Env.getResultObjectLocation(*Expr);
891 copyRecord(cast<RecordStorageLocation>(Loc), ResultLoc, State.Env);
892 } else {
893 State.Env.setStorageLocation(*Expr, Loc);
894 }
895 return true;
896}
897
908 if (RecordLoc == nullptr)
909 return;
910 auto *Val = State.Lattice.getOrCreateConstMethodReturnValue(*RecordLoc, Expr,
911 State.Env);
912 State.Env.setValue(*Expr, *Val);
913}
914
915static void
925
926static void
929 LatticeTransferState &State) {
930 auto Type = Expr->getArg(0)->getType();
931 if (!Type->isRecordType() && !Type->isReferenceType())
932 return;
933 auto *RecordLoc = cast_or_null<RecordStorageLocation>(
934 State.Env.getStorageLocation(*Expr->getArg(0)));
936}
937
938static void
945
948 LatticeTransferState &State) {
949 auto *RecordLoc = cast_or_null<RecordStorageLocation>(
950 State.Env.getStorageLocation(*Expr->getArg(0)));
952}
953
957 LatticeTransferState &State) {
958 if (RecordLoc) {
959 State.Lattice.clearConstMethodReturnValues(*RecordLoc);
960 State.Lattice.clearConstMethodReturnStorageLocations(*RecordLoc);
961 }
964}
965
972
973static void
976 LatticeTransferState &State) {
977 auto *RecordLoc = cast_or_null<RecordStorageLocation>(
978 State.Env.getStorageLocation(*Expr->getArg(0)));
980}
981
983 const CallExpr *Expr, const MatchFinder::MatchResult &,
984 LatticeTransferState &State) {
985 State.Env.setValue(
986 locForOkPredicate(State.Env.getResultObjectLocation(*Expr)),
987 State.Env.getBoolLiteralValue(true));
988}
989
992 LatticeTransferState &State) {
993 BoolValue &OkMatcherVal = State.Env.getBoolLiteralValue(true);
994 State.Env.setValue(locForOkMatcher(State.Env.getResultObjectLocation(*Expr)),
995 OkMatcherVal);
996}
997
999 const CallExpr *Expr, const MatchFinder::MatchResult &,
1000 LatticeTransferState &State) {
1001 assert(Expr->isPRValue());
1002 auto &Loc = State.Env.getResultObjectLocation(*Expr->getArg(0));
1003 auto &OkMatcherLoc = locForOkMatcher(Loc);
1004 BoolValue *OkMatcherVal = State.Env.get<BoolValue>(OkMatcherLoc);
1005 if (OkMatcherVal == nullptr)
1006 return;
1007 State.Env.setValue(
1008 locForOkPredicate(State.Env.getResultObjectLocation(*Expr)),
1009 *OkMatcherVal);
1010}
1011
1012static void
1014 LatticeTransferState &State,
1015 bool IsStatusOr) {
1016 auto *Loc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
1017 if (Loc == nullptr)
1018 return;
1019
1020 auto *ObjectLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(2));
1021 if (ObjectLoc == nullptr)
1022 return;
1023
1024 auto &OkPredicateLoc = locForOkPredicate(*Loc);
1025 BoolValue *OkPredicateVal = State.Env.get<BoolValue>(OkPredicateLoc);
1026 if (OkPredicateVal == nullptr)
1027 return;
1028
1029 if (IsStatusOr)
1030 ObjectLoc = &locForStatus(*ObjectLoc);
1031 auto &StatusOk = valForOk(*ObjectLoc, State.Env);
1032
1033 auto &A = State.Env.arena();
1034 auto &Res = State.Env.makeAtomicBoolValue();
1035 State.Env.assume(
1036 A.makeImplies(OkPredicateVal->formula(),
1037 A.makeEquals(StatusOk.formula(), Res.formula())));
1038 State.Env.setValue(locForOk(State.Env.getResultObjectLocation(*Expr)), Res);
1039}
1040
1041static void
1044 LatticeTransferState &State) {
1045 assert(Expr->getNumArgs() > 0);
1046
1047 auto *StatusAdaptorLoc = State.Env.get<StorageLocation>(*Expr->getArg(0));
1048 if (StatusAdaptorLoc == nullptr)
1049 return;
1050 BoolValue *OkVal = State.Env.get<BoolValue>(*StatusAdaptorLoc);
1051 if (OkVal == nullptr)
1052 return;
1053 State.Env.setValue(locForOk(State.Env.getResultObjectLocation(*Expr)),
1054 *OkVal);
1055}
1056
1057static void
1060 LatticeTransferState &State) {
1061 auto *RecordLoc = getImplicitObjectLocation(*Expr, State.Env);
1062 if (RecordLoc == nullptr)
1063 return;
1064 BoolValue *OkVal = State.Env.get<BoolValue>(locForOk(*RecordLoc));
1065 if (OkVal == nullptr)
1066 return;
1067 auto &A = State.Env.arena();
1068 auto &Res = State.Env.makeAtomicBoolValue();
1069 State.Env.assume(A.makeEquals(OkVal->formula(), Res.formula()));
1070 State.Env.setValue(*Expr, Res);
1071}
1072
1075 LatticeTransferState &State) {
1076 auto *StatusOrLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
1077
1078 if (StatusOrLoc && State.Env.getStorageLocation(*Expr) == nullptr)
1079 State.Env.setStorageLocation(*Expr,
1080 StatusOrLoc->getSyntheticField("value"));
1081}
1082
1085 LatticeTransferState &State) {
1086 auto *StatusOrLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
1087 if (!StatusOrLoc)
1088 return;
1089 State.Env.setValue(*Expr, State.Env.create<PointerValue>(
1090 StatusOrLoc->getSyntheticField("value")));
1091}
1092
1095 LatticeTransferState &State) {
1096 auto *StatusOrLoc = getImplicitObjectLocation(*Expr, State.Env);
1097
1098 if (StatusOrLoc && State.Env.getStorageLocation(*Expr) == nullptr)
1099 State.Env.setStorageLocation(*Expr,
1100 StatusOrLoc->getSyntheticField("value"));
1101}
1102
1105 LatticeTransferState &State) {
1106 PointerValue *PointerVal =
1107 dyn_cast_or_null<PointerValue>(State.Env.getValue(*Expr));
1108 if (!PointerVal) {
1109 PointerVal = cast<PointerValue>(State.Env.createValue(Expr->getType()));
1110 State.Env.setValue(*Expr, *PointerVal);
1111 }
1112
1113 auto *RecordLoc =
1114 dyn_cast_or_null<RecordStorageLocation>(&PointerVal->getPointeeLoc());
1115 if (RecordLoc != nullptr &&
1116 State.Env.getValue(locForOk(locForStatus(*RecordLoc))) == nullptr)
1117 initializeStatusOr(*RecordLoc, State.Env);
1118}
1119
1122 LatticeTransferState &State) {
1123 PointerValue *PointerVal =
1124 dyn_cast_or_null<PointerValue>(State.Env.getValue(*Expr));
1125 if (!PointerVal) {
1126 PointerVal = cast<PointerValue>(State.Env.createValue(Expr->getType()));
1127 State.Env.setValue(*Expr, *PointerVal);
1128 }
1129
1130 auto *RecordLoc =
1131 dyn_cast_or_null<RecordStorageLocation>(&PointerVal->getPointeeLoc());
1132 if (RecordLoc != nullptr &&
1133 State.Env.getValue(locForOk(*RecordLoc)) == nullptr)
1134 initializeStatus(*RecordLoc, State.Env);
1135}
1136
1137static RecordStorageLocation *
1139 if (!E.isPRValue())
1140 return dyn_cast_or_null<RecordStorageLocation>(Env.getStorageLocation(E));
1141 if (auto *PointerVal = dyn_cast_or_null<PointerValue>(Env.getValue(E)))
1142 return dyn_cast_or_null<RecordStorageLocation>(
1143 &PointerVal->getPointeeLoc());
1144 return nullptr;
1145}
1146
1150 using namespace ::clang::ast_matchers;
1151 return std::move(Builder)
1152 .CaseOfCFGStmt<CallExpr>(
1155 .CaseOfCFGStmt<CallExpr>(isStatusIsOkMatcherCall(),
1157 .CaseOfCFGStmt<CallExpr>(
1160 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1163 LatticeTransferState &State) {
1165 /*IsStatusOr=*/true);
1166 })
1167 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1170 LatticeTransferState &State) {
1172 /*IsStatusOr=*/false);
1173 })
1174 .CaseOfCFGStmt<CXXConstructExpr>(
1179 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("ok"),
1181 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("status"),
1183 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusMemberCallWithName("ok"),
1185 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusMemberCallWithName("Update"),
1187 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1190 LatticeTransferState &State) {
1192 /*IsNegative=*/false);
1193 })
1194 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1197 LatticeTransferState &State) {
1199 /*IsNegative=*/true);
1200 })
1201 .CaseOfCFGStmt<BinaryOperator>(
1203 [](const BinaryOperator *Expr, const MatchFinder::MatchResult &,
1204 LatticeTransferState &State) {
1206 /*IsNegative=*/false);
1207 })
1208 .CaseOfCFGStmt<BinaryOperator>(
1210 [](const BinaryOperator *Expr, const MatchFinder::MatchResult &,
1211 LatticeTransferState &State) {
1213 /*IsNegative=*/true);
1214 })
1215 .CaseOfCFGStmt<CallExpr>(isOkStatusCall(), transferOkStatusCall)
1217 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("emplace"),
1221 .CaseOfCFGStmt<CXXConstructExpr>(isStatusOrValueConstructor(),
1225 .CaseOfCFGStmt<CXXOperatorCallExpr>(isStatusOrOperatorCallWithName("*"),
1227 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("value"),
1229 .CaseOfCFGStmt<CallExpr>(isAsStatusCallWithStatus(),
1231 .CaseOfCFGStmt<CallExpr>(isAsStatusCallWithStatusOr(),
1233 .CaseOfCFGStmt<CallExpr>(isLoggingGetReferenceableValueCall(),
1235 .CaseOfCFGStmt<CallExpr>(isLoggingCheckEqImpl(),
1237 // This needs to go before the const accessor call matcher, because these
1238 // look like them, but we model `operator`* and `get` to return the same
1239 // object. Also, we model them for non-const cases.
1240 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1242 [](const CXXOperatorCallExpr *E,
1244 LatticeTransferState &State) {
1246 E, getSmartPtrLikeStorageLocation(*E->getArg(0), State.Env),
1247 State, [](StorageLocation &Loc) {});
1248 })
1249 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1251 [](const CXXOperatorCallExpr *E,
1253 LatticeTransferState &State) {
1255 E, getSmartPtrLikeStorageLocation(*E->getArg(0), State.Env),
1256 State, [](StorageLocation &Loc) {});
1257 })
1258 .CaseOfCFGStmt<CXXMemberCallExpr>(
1261 LatticeTransferState &State) {
1263 E, getImplicitObjectLocation(*E, State.Env), State,
1264 [](StorageLocation &Loc) {});
1265 })
1266 .CaseOfCFGStmt<CXXMemberCallExpr>(
1269 LatticeTransferState &State) {
1271 E, getImplicitObjectLocation(*E, State.Env), State,
1272 [](StorageLocation &Loc) {});
1273 })
1274 // const accessor calls
1275 .CaseOfCFGStmt<CXXMemberCallExpr>(isConstAccessorMemberCall(),
1277 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1280 .CaseOfCFGStmt<CXXMemberCallExpr>(isConstPointerAccessorMemberCall(),
1282 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1285 // non-const member calls that may modify the state of an object.
1286 .CaseOfCFGStmt<CXXMemberCallExpr>(isNonConstMemberCall(),
1290 // N.B. this has to be after transferConstMemberCall, otherwise we would
1291 // always return a fresh RecordStorageLocation for the StatusOr.
1292 .CaseOfCFGStmt<CallExpr>(isStatusOrReturningCall(),
1293 [](const CallExpr *Expr,
1295 LatticeTransferState &State) {
1297 })
1298 .CaseOfCFGStmt<CallExpr>(isStatusOrPtrReturningCall(),
1300 .CaseOfCFGStmt<CallExpr>(isStatusPtrReturningCall(),
1302 // N.B. These need to come after all other CXXConstructExpr.
1303 // These are there to make sure that every Status and StatusOr object
1304 // have their ok boolean initialized when constructed. If we were to
1305 // lazily initialize them when we first access them, we can produce
1306 // false positives if that first access is in a control flow statement.
1307 // You can comment out these two constructors and see tests fail.
1308 .CaseOfCFGStmt<CXXConstructExpr>(isStatusOrConstructor(),
1310 .CaseOfCFGStmt<CXXConstructExpr>(isStatusConstructor(),
1312 .CaseOfCFGStmt<ImplicitCastExpr>(
1313 implicitCastExpr(hasCastKind(CK_PointerToBoolean)),
1315 .Build();
1316}
1317
1319 for (Type *Ty : Ctx.getTypes())
1320 if (isStatusType(QualType(Ty, 0)))
1321 return QualType(Ty, 0);
1322
1323 return QualType();
1324}
1325
1327 Environment &Env)
1330 TransferMatchSwitch(buildTransferMatchSwitch(Ctx, {})) {
1331 QualType StatusType = findStatusType(Ctx);
1332 Env.getDataflowAnalysisContext().setSyntheticFieldCallback(
1333 [StatusType](QualType Ty) -> llvm::StringMap<QualType> {
1335 if (RD == nullptr)
1336 return {};
1337
1338 if (auto Fields = getSyntheticFields(Ty, StatusType, *RD);
1339 !Fields.empty())
1340 return Fields;
1341 return {};
1342 });
1343}
1344
1346 Environment &Env) {
1347 LatticeTransferState State(L, Env);
1348 TransferMatchSwitch(Elt, getASTContext(), State);
1349}
1350
1351} // namespace clang::dataflow::statusor_model
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Defines the clang::Expr interface and subclasses for C++ expressions.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
llvm::MachO::RecordLoc RecordLoc
Definition MachO.h:41
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 ...
Definition ASTContext.h:226
const SmallVectorImpl< Type * > & getTypes() const
CanQualType BoolTy
A builtin binary operation expression such as "x + y" or "x <= y".
Definition Expr.h:4041
Represents a top-level expression in a basic block.
Definition CFG.h:55
Represents a call to a C++ constructor.
Definition ExprCXX.h:1549
Represents a call to a member function that may be written either with member call syntax (e....
Definition ExprCXX.h:180
SourceLocation getExprLoc() const LLVM_READONLY
Definition ExprCXX.h:221
A call to an overloaded operator written using operator syntax.
Definition ExprCXX.h:85
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
bool hasDefinition() const
Definition DeclCXX.h:561
bool isDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is derived from the class Base.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2946
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3150
Represents a class template specialization, which refers to a class template with a given set of temp...
const TemplateArgumentList & getTemplateArgs() const
Retrieve the template arguments of the class template specialization.
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition DeclBase.h:2109
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:546
This represents one expression.
Definition Expr.h:112
bool isPRValue() const
Definition Expr.h:285
QualType getType() const
Definition Expr.h:144
Represents a function declaration or definition.
Definition Decl.h:2000
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition Expr.h:3856
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:301
Represent a C++ namespace.
Definition Decl.h:592
A (possibly-)qualified type.
Definition TypeBase.h:937
const TemplateArgument & get(unsigned Idx) const
Retrieve the template argument at a given index.
QualType getAsType() const
Retrieve the type for a type template argument.
The base class of the type hierarchy.
Definition TypeBase.h:1839
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isPointerType() const
Definition TypeBase.h:8625
bool isReferenceType() const
Definition TypeBase.h:8649
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:753
bool isRecordType() const
Definition TypeBase.h:8752
Models a boolean.
Definition Value.h:94
const Formula & formula() const
Definition Value.h:107
Collects cases of a "match switch": a collection of matchers paired with callbacks,...
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.
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...
Models a symbolic pointer. Specifically, any value of type T*.
Definition Value.h:170
StorageLocation & getPointeeLoc() const
Definition Value.h:179
A storage location for a record (struct, class, or union).
StorageLocation & getSyntheticField(llvm::StringRef Name) const
Returns the storage location for the synthetic field Name.
Base class for elements of the local variable store and of the heap.
Base class for all values computed by abstract interpretation.
Definition Value.h:33
UncheckedStatusOrAccessDiagnoser(UncheckedStatusOrAccessModelOptions Options={})
llvm::SmallVector< SourceLocation > operator()(const CFGElement &Elt, ASTContext &Ctx, const TransferStateForDiagnostics< UncheckedStatusOrAccessModel::Lattice > &State)
void transfer(const CFGElement &Elt, Lattice &L, Environment &Env)
internal::Matcher< QualType > TypeMatcher
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, ImplicitCastExpr > implicitCastExpr
Matches the implicit cast nodes of Clang's AST.
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.
internal::Matcher< Stmt > StatementMatcher
const internal::VariadicDynCastAllOfMatcher< Decl, EnumConstantDecl > enumConstantDecl
Matches enum constants.
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator
Matches binary operator expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXConstructExpr > cxxConstructExpr
Matches constructor call expressions (including implicit ones).
const internal::VariadicDynCastAllOfMatcher< Decl, ClassTemplateSpecializationDecl > classTemplateSpecializationDecl
Matches C++ class template specializations.
const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl
Matches function declarations.
const AstTypeMatcher< RecordType > recordType
const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class declarations.
const internal::VariadicDynCastAllOfMatcher< Decl, RecordDecl > recordDecl
Matches class, struct, and union declarations.
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::VariadicAllOfMatcher< QualType > qualType
Matches QualTypes in the clang AST.
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXThisExpr > cxxThisExpr
Matches implicit and explicit this expressions.
static void transferLoggingCheckEqImpl(const CallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static void transferStatusOrReturningCall(const CallExpr *Expr, LatticeTransferState &State)
static bool doHandleConstAccessorMemberCall(const CallExpr *Expr, RecordStorageLocation *RecordLoc, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
static void transferValueAssignmentCall(const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
TransferState< UncheckedStatusOrAccessModel::Lattice > LatticeTransferState
static ClassTemplateSpecializationDecl * getStatusOrBaseClass(const QualType &Ty)
static bool isStatusOrOperatorBaseType(QualType Type)
static void transferValueCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static StorageLocation & locForOkMatcher(RecordStorageLocation &StatusLoc)
static void handleConstAccessorMemberCall(const CallExpr *Expr, RecordStorageLocation *RecordLoc, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
static auto isStatusMemberCallWithName(llvm::StringRef member_name)
static auto buildDiagnoseMatchSwitch(const UncheckedStatusOrAccessModelOptions &Options)
static auto isComparisonOperatorCall(llvm::StringRef operator_name)
static void transferAssertionResultConstructFromBoolCall(const CXXConstructExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
RecordStorageLocation & locForStatus(RecordStorageLocation &StatusOrLoc)
static void transferNotOkStatusCall(const CallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static BoolValue * evaluateStatusEquality(RecordStorageLocation &LhsStatusLoc, RecordStorageLocation &RhsStatusLoc, Environment &Env)
static void transferStatusConstructor(const CXXConstructExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static BoolValue * evaluateStatusOrEquality(RecordStorageLocation &LhsStatusOrLoc, RecordStorageLocation &RhsStatusOrLoc, Environment &Env)
static void transferMakePredicateFormatterFromIsOkMatcherCall(const CallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static bool isPredicateFormatterFromMatcherType(QualType Type)
static auto isStatusOrOperatorCallWithName(llvm::StringRef operator_name)
clang::ast_matchers::TypeMatcher statusType()
static void transferNonConstMemberOperatorCall(const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
static void transferValueConstructor(const CXXConstructExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static void transferComparisonOperator(const CXXOperatorCallExpr *Expr, LatticeTransferState &State, bool IsNegative)
clang::ast_matchers::DeclarationMatcher statusOrClass()
static void transferOkStatusCall(const CallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static auto isPointerComparisonOperatorCall(std::string operator_name)
clang::ast_matchers::TypeMatcher statusOrType()
static bool isSafeUnwrap(RecordStorageLocation *StatusOrLoc, const Environment &Env)
static void transferPointerComparisonOperator(const BinaryOperator *Expr, LatticeTransferState &State, bool IsNegative)
static void transferNonConstMemberCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
static void transferStatusOrOkCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static bool namespaceEquals(const NamespaceDecl *NS, clang::ArrayRef< clang::StringRef > NamespaceNames)
static bool isTypeNamed(QualType Type, clang::ArrayRef< clang::StringRef > NS, StringRef Name)
static void transferConstAccessorMemberCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
static void transferStatusOrConstructor(const CXXConstructExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static void transferLoggingGetReferenceableValueCall(const CallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
clang::ast_matchers::DeclarationMatcher statusClass()
static RecordStorageLocation * getSmartPtrLikeStorageLocation(const Expr &E, const Environment &Env)
static void handleNonConstMemberCall(const CallExpr *Expr, RecordStorageLocation *RecordLoc, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
BoolValue & initializeStatusOr(RecordStorageLocation &StatusOrLoc, Environment &Env)
static void transferAsStatusCallWithStatusOr(const CallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
QualType findStatusType(const ASTContext &Ctx)
BoolValue & initializeStatus(RecordStorageLocation &StatusLoc, Environment &Env)
static void transferDerefCall(const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static void transferPointerToBoolean(const ImplicitCastExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
llvm::StringMap< QualType > getSyntheticFields(QualType Ty, QualType StatusType, const CXXRecordDecl &RD)
StorageLocation & locForOk(RecordStorageLocation &StatusLoc)
static void transferStatusIsOkMatcherCall(const CallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static auto isStatusOrMemberCallWithName(llvm::StringRef member_name)
static BoolValue * evaluateEquality(const Expr *LhsExpr, const Expr *RhsExpr, Environment &Env)
static void transferStatusCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static void transferConstPointerAccessorMemberCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
static void transferStatusOkCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static void transferPredicateFormatterMatcherCall(const CXXOperatorCallExpr *Expr, LatticeTransferState &State, bool IsStatusOr)
static void transferAssertionResultOperatorBoolCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static StorageLocation & locForOkPredicate(RecordStorageLocation &StatusLoc)
static void transferMakePredicateFormatterFromStatusIsMatcherCall(const CallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static void transferEmplaceCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static void transferAsStatusCallWithStatus(const CallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static void transferStatusOrPtrReturningCall(const CallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static BoolValue * evaluatePointerEquality(const Expr *LhsExpr, const Expr *RhsExpr, Environment &Env)
static QualType getStatusOrValueType(ClassTemplateSpecializationDecl *TRD)
static RecordStorageLocation * getPointeeLocation(const Expr &Expr, Environment &Env)
static void transferArrowCall(const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static void transferStatusPtrReturningCall(const CallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
BoolValue & valForOk(RecordStorageLocation &StatusLoc, Environment &Env)
static void transferConstPointerAccessorMemberOperatorCall(const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
static void transferStatusUpdateCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static void handleConstPointerAccessorMemberCall(const CallExpr *Expr, RecordStorageLocation *RecordLoc, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
static void transferConstAccessorMemberOperatorCall(const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
CFGMatchSwitch< LatticeTransferState > buildTransferMatchSwitch(ASTContext &Ctx, CFGMatchSwitchBuilder< LatticeTransferState > Builder)
clang::ast_matchers::DeclarationMatcher statusOrOperatorBaseClass()
ast_matchers::StatementMatcher isSmartPointerLikeValueMethodCall(clang::StringRef MethodName="value")
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.
ast_matchers::StatementMatcher isPointerLikeOperatorStar()
Matchers: For now, these match on any class with an operator* or operator-> where the return types ha...
void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst, Environment &Env, QualType TypeToCopy=QualType())
Copies a record (struct, class, or union) from Src to Dst.
Definition RecordOps.cpp:57
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.
internal::Matcher< NamedDecl > hasName(StringRef Name)
Matches NamedDecl nodes that have the specified name.
std::function< Result(const CFGElement &, ASTContext &, State &)> CFGMatchSwitch
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXMemberCallExpr > cxxMemberCallExpr
Matches member call expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, CXXOperatorCallExpr > cxxOperatorCallExpr
Matches overloaded operator calls.
const AstTypeMatcher< PointerType > pointerType
internal::PolymorphicMatcher< internal::HasOverloadedOperatorNameMatcher, AST_POLYMORPHIC_SUPPORTED_TYPES(CXXOperatorCallExpr, FunctionDecl), std::vector< std::string > > hasOverloadedOperatorName(StringRef Name)
Matches overloaded operator names.
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...
const internal::VariadicDynCastAllOfMatcher< Decl, CXXMethodDecl > cxxMethodDecl
Matches method declarations.
ast_matchers::StatementMatcher isSmartPointerLikeGetMethodCall(clang::StringRef MethodName="get")
ast_matchers::StatementMatcher isPointerLikeOperatorArrow()
const AstTypeMatcher< ReferenceType > referenceType
@ Result
The result type of a method or function.
Definition TypeBase.h:905
U cast(CodeGen::Address addr)
Definition Address.h:327
Contains all information for a given match.
A read-only version of TransferState.
Definition MatchSwitch.h:55
Contains all information for a given match.