clang 22.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; // NOLINT: Too many names
102 return ofClass(hasName("::absl::Status"));
103}
104
105static auto isStatusMemberCallWithName(llvm::StringRef member_name) {
106 using namespace ::clang::ast_matchers; // NOLINT: Too many names
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; // NOLINT: Too many names
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; // NOLINT: Too many names
123 return cxxOperatorCallExpr(
124 hasOverloadedOperatorName(operator_name),
125 callee(cxxMethodDecl(
127}
128
129static auto valueCall() {
130 using namespace ::clang::ast_matchers; // NOLINT: Too many names
131 return anyOf(isStatusOrMemberCallWithName("value"),
132 isStatusOrMemberCallWithName("ValueOrDie"));
133}
134
135static auto valueOperatorCall() {
136 using namespace ::clang::ast_matchers; // NOLINT: Too many names
139}
140
141static auto isComparisonOperatorCall(llvm::StringRef operator_name) {
142 using namespace ::clang::ast_matchers; // NOLINT: Too many names
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; // NOLINT: Too many names
151 return callExpr(callee(functionDecl(hasName("::absl::OkStatus"))));
152}
153
154static auto isNotOkStatusCall() {
155 using namespace ::clang::ast_matchers; // NOLINT: Too many names
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; // NOLINT: Too many names
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; // NOLINT: Too many names
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; // NOLINT: Too many names
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; // NOLINT: Too many names
203 return cxxConstructExpr(hasType(statusOrType()));
204}
205
206static auto isStatusConstructor() {
207 using namespace ::clang::ast_matchers; // NOLINT: Too many names
208 return cxxConstructExpr(hasType(statusType()));
209}
211 using namespace ::clang::ast_matchers; // NOLINT: Too many names
212 return callExpr(callee(
213 functionDecl(hasName("::absl::log_internal::GetReferenceableValue"))));
214}
215
216static auto isLoggingCheckEqImpl() {
217 using namespace ::clang::ast_matchers; // NOLINT: Too many names
218 return callExpr(
219 callee(functionDecl(hasName("::absl::log_internal::Check_EQImpl"))));
220}
221
223 using namespace ::clang::ast_matchers; // NOLINT: Too many names
224 return callExpr(
225 callee(functionDecl(hasName("::absl::log_internal::AsStatus"))),
226 hasArgument(0, hasType(statusClass())));
227}
228
230 using namespace ::clang::ast_matchers; // NOLINT: Too many names
231 return callExpr(
232 callee(functionDecl(hasName("::absl::log_internal::AsStatus"))),
233 hasArgument(0, hasType(statusOrType())));
234}
235
237 using namespace ::clang::ast_matchers; // NOLINT: Too many names
238 return anyOf(statusOrType(), referenceType(pointee(statusOrType())));
239}
240
242 using namespace ::clang::ast_matchers; // NOLINT: Too many names
243 return cxxMemberCallExpr(callee(
244 cxxMethodDecl(parameterCountIs(0), isConst(),
246}
247
249 using namespace ::clang::ast_matchers; // NOLINT: Too many names
250 return cxxOperatorCallExpr(
251 callee(cxxMethodDecl(parameterCountIs(0), isConst(),
252 returns(possiblyReferencedStatusOrType()))));
253}
254
256 using namespace ::clang::ast_matchers; // NOLINT: Too many names
257 return cxxMemberCallExpr(callee(cxxMethodDecl(
258 parameterCountIs(0), isConst(),
259 returns(pointerType(pointee(possiblyReferencedStatusOrType()))))));
260}
261
263 using namespace ::clang::ast_matchers; // NOLINT: Too many names
265 parameterCountIs(0), isConst(),
266 returns(pointerType(pointee(possiblyReferencedStatusOrType()))))));
267}
268
269static auto isNonConstMemberCall() {
270 using namespace ::clang::ast_matchers; // NOLINT: Too many names
271 return cxxMemberCallExpr(callee(cxxMethodDecl(unless(isConst()))));
272}
273
275 using namespace ::clang::ast_matchers; // NOLINT: Too many names
276 return cxxOperatorCallExpr(callee(cxxMethodDecl(unless(isConst()))));
277}
278
280 using namespace ::clang::ast_matchers; // NOLINT: Too many names
281 return callExpr(
282 callee(functionDecl(
283 hasName("::testing::internal::MakePredicateFormatterFromMatcher"))),
284 hasArgument(
285 0, hasType(cxxRecordDecl(hasAnyName(
286 "::testing::status::internal_status::IsOkMatcher",
287 "::absl_testing::status_internal::IsOkMatcher",
288 "::testing::status::internal_status::IsOkAndHoldsMatcher",
289 "::absl_testing::status_internal::IsOkAndHoldsMatcher")))));
290}
291
293 using namespace ::clang::ast_matchers; // NOLINT: Too many names
294 return callExpr(callee(functionDecl(hasAnyName(
295 "::testing::status::StatusIs", "absl_testing::StatusIs",
296 "::testing::status::CanonicalStatusIs",
297 "::absl_testing::CanonicalStatusIs"))),
298 hasArgument(0, declRefExpr(to(enumConstantDecl(hasAnyName(
299 "::absl::StatusCode::kOk", "OK"))))));
300}
301
303 using namespace ::clang::ast_matchers; // NOLINT: Too many names
304 return callExpr(
305 callee(functionDecl(
306 hasName("::testing::internal::MakePredicateFormatterFromMatcher"))),
307 hasArgument(0, hasType(cxxRecordDecl(hasAnyName(
308 "::testing::status::internal_status::StatusIsMatcher",
309 "::testing::status::internal_status::"
310 "CanonicalStatusIsMatcher",
311 "::absl_testing::status_internal::StatusIsMatcher",
312 "::absl_testing::status_internal::"
313 "CanonicalStatusIsMatcher")))));
314}
315
317 using namespace ::clang::ast_matchers; // NOLINT: Too many names
318 return cxxOperatorCallExpr(
320 callee(cxxMethodDecl(ofClass(
321 hasName("testing::internal::PredicateFormatterFromMatcher")))),
322 hasArgument(2, hasType(statusType())));
323}
324
326 using namespace ::clang::ast_matchers; // NOLINT: Too many names
327 return cxxOperatorCallExpr(
329 callee(cxxMethodDecl(ofClass(
330 hasName("testing::internal::PredicateFormatterFromMatcher")))),
331 hasArgument(2, hasType(statusOrType())));
332}
333
335 using namespace ::clang::ast_matchers; // NOLINT: Too many names
336 return cxxMemberCallExpr(
337 on(expr(unless(cxxThisExpr()))),
338 callee(cxxMethodDecl(hasName("operator bool"),
339 ofClass(hasName("testing::AssertionResult")))));
340}
341
343 using namespace ::clang::ast_matchers; // NOLINT: Too many names
344 return cxxConstructExpr(
345 hasType(recordDecl(hasName("testing::AssertionResult"))),
346 hasArgument(0, hasType(booleanType())));
347}
348
350 using namespace ::clang::ast_matchers; // NOLINT: Too many names
351 return callExpr(
352 callee(functionDecl(returns(possiblyReferencedStatusOrType()))));
353}
354
356 using namespace ::clang::ast_matchers; // NOLINT: Too many names
357 return callExpr(callee(functionDecl(returns(hasUnqualifiedDesugaredType(
359}
360
362 using namespace ::clang::ast_matchers; // NOLINT: Too many names
363 return callExpr(callee(functionDecl(returns(hasUnqualifiedDesugaredType(
364 pointerType(pointee(hasUnqualifiedDesugaredType(
366}
367
368static auto
372 // StatusOr::value, StatusOr::ValueOrDie
373 .CaseOfCFGStmt<CXXMemberCallExpr>(
374 valueCall(),
375 [](const CXXMemberCallExpr *E,
377 const Environment &Env) {
378 if (!isSafeUnwrap(getImplicitObjectLocation(*E, Env), Env))
381 })
382
383 // StatusOr::operator*, StatusOr::operator->
384 .CaseOfCFGStmt<CXXOperatorCallExpr>(
386 [](const CXXOperatorCallExpr *E,
388 const Environment &Env) {
389 RecordStorageLocation *StatusOrLoc =
390 Env.get<RecordStorageLocation>(*E->getArg(0));
391 if (!isSafeUnwrap(StatusOrLoc, Env))
392 return llvm::SmallVector<SourceLocation>({E->getOperatorLoc()});
394 })
395 .Build();
396}
397
401
408
410 Environment &Env) {
411 auto &OkVal = Env.makeAtomicBoolValue();
412 Env.setValue(locForOk(StatusLoc), OkVal);
413 return OkVal;
414}
415
417 Environment &Env) {
418 return initializeStatus(locForStatus(StatusOrLoc), Env);
419}
420
422 using namespace ::clang::ast_matchers; // NOLINT: Too many names
424 hasName("absl::StatusOr"),
425 hasTemplateArgument(0, refersToType(type().bind("T"))));
426}
427
429 using namespace ::clang::ast_matchers; // NOLINT: Too many names
430 return cxxRecordDecl(hasName("absl::Status"));
431}
432
434 using namespace ::clang::ast_matchers; // NOLINT: Too many names
436 hasName("absl::internal_statusor::OperatorBase"));
437}
438
440 using namespace ::clang::ast_matchers; // NOLINT: Too many names
441 return hasCanonicalType(qualType(hasDeclaration(statusOrClass())));
442}
443
445 using namespace ::clang::ast_matchers; // NOLINT: Too many names
446 return hasCanonicalType(qualType(hasDeclaration(statusClass())));
447}
448
450 return isTypeNamed(Type, {"absl"}, "StatusOr");
451}
452
454 return isTypeNamed(Type, {"absl"}, "Status");
455}
456
458 return isTypeNamed(Type, {"testing", "internal"},
459 "PredicateFormatterFromMatcher");
460}
461
463 return isTypeNamed(Type, {"testing"}, "AssertionResult");
464}
465
467 return isTypeNamed(Type, {"testing", "status", "internal_status"},
468 "StatusIsMatcher") ||
469 isTypeNamed(Type, {"testing", "status", "internal_status"},
470 "CanonicalStatusIsMatcher") ||
471 isTypeNamed(Type, {"absl_testing", "status_internal"},
472 "StatusIsMatcher") ||
473 isTypeNamed(Type, {"absl_testing", "status_internal"},
474 "CanonicalStatusIsMatcher");
475}
476
477llvm::StringMap<QualType> getSyntheticFields(QualType Ty, QualType StatusType,
478 const CXXRecordDecl &RD) {
479 if (auto *TRD = getStatusOrBaseClass(Ty))
480 return {{"status", StatusType}, {"value", getStatusOrValueType(TRD)}};
481 if (isStatusType(Ty) || (RD.hasDefinition() &&
482 RD.isDerivedFrom(StatusType->getAsCXXRecordDecl())))
483 return {{"ok", RD.getASTContext().BoolTy}};
484 if (isAssertionResultType(Ty))
485 return {{"ok", RD.getASTContext().BoolTy}};
487 return {{"ok_predicate", RD.getASTContext().BoolTy}};
488 if (isStatusIsMatcherType(Ty))
489 return {{"ok_matcher", RD.getASTContext().BoolTy}};
490 return {};
491}
492
496
498 return StatusLoc.getSyntheticField("ok");
499}
500
502 if (auto *Val = Env.get<BoolValue>(locForOk(StatusLoc)))
503 return *Val;
504 return initializeStatus(StatusLoc, Env);
505}
507 return StatusLoc.getSyntheticField("ok_predicate");
508}
509
511 return StatusLoc.getSyntheticField("ok_matcher");
512}
513
516 LatticeTransferState &State) {
517 RecordStorageLocation *StatusOrLoc =
518 getImplicitObjectLocation(*Expr, State.Env);
519 if (StatusOrLoc == nullptr)
520 return;
521
522 auto &OkVal = valForOk(locForStatus(*StatusOrLoc), State.Env);
523 State.Env.setValue(*Expr, OkVal);
524}
525
528 LatticeTransferState &State) {
529 RecordStorageLocation *StatusOrLoc =
530 getImplicitObjectLocation(*Expr, State.Env);
531 if (StatusOrLoc == nullptr)
532 return;
533
534 RecordStorageLocation &StatusLoc = locForStatus(*StatusOrLoc);
535
536 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
537 initializeStatusOr(*StatusOrLoc, State.Env);
538
539 if (Expr->isPRValue())
540 copyRecord(StatusLoc, State.Env.getResultObjectLocation(*Expr), State.Env);
541 else
542 State.Env.setStorageLocation(*Expr, StatusLoc);
543}
544
547 LatticeTransferState &State) {
548 RecordStorageLocation *StatusLoc =
549 getImplicitObjectLocation(*Expr, State.Env);
550 if (StatusLoc == nullptr)
551 return;
552
553 if (Value *Val = State.Env.getValue(locForOk(*StatusLoc)))
554 State.Env.setValue(*Expr, *Val);
555}
556
559 LatticeTransferState &State) {
560 // S.Update(OtherS) sets S to the error code of OtherS if it is OK,
561 // otherwise does nothing.
562 assert(Expr->getNumArgs() == 1);
563 auto *Arg = Expr->getArg(0);
564 RecordStorageLocation *ArgRecord =
565 Arg->isPRValue() ? &State.Env.getResultObjectLocation(*Arg)
566 : State.Env.get<RecordStorageLocation>(*Arg);
568 if (ThisLoc == nullptr || ArgRecord == nullptr)
569 return;
570
571 auto &ThisOkVal = valForOk(*ThisLoc, State.Env);
572 auto &ArgOkVal = valForOk(*ArgRecord, State.Env);
573 auto &A = State.Env.arena();
574 auto &NewVal = State.Env.makeAtomicBoolValue();
575 State.Env.assume(A.makeImplies(A.makeNot(ThisOkVal.formula()),
576 A.makeNot(NewVal.formula())));
577 State.Env.assume(A.makeImplies(NewVal.formula(), ArgOkVal.formula()));
578 State.Env.setValue(locForOk(*ThisLoc), NewVal);
579}
580
582 RecordStorageLocation &RhsStatusLoc,
583 Environment &Env) {
584 auto &A = Env.arena();
585 // Logically, a Status object is composed of an error code that could take one
586 // of multiple possible values, including the "ok" value. We track whether a
587 // Status object has an "ok" value and represent this as an `ok` bit. Equality
588 // of Status objects compares their error codes. Therefore, merely comparing
589 // the `ok` bits isn't sufficient: when two Status objects are assigned non-ok
590 // error codes the equality of their respective error codes matters. Since we
591 // only track the `ok` bits, we can't make any conclusions about equality when
592 // we know that two Status objects have non-ok values.
593
594 auto &LhsOkVal = valForOk(LhsStatusLoc, Env);
595 auto &RhsOkVal = valForOk(RhsStatusLoc, Env);
596
597 auto &Res = Env.makeAtomicBoolValue();
598
599 // lhs && rhs => res (a.k.a. !res => !lhs || !rhs)
600 Env.assume(A.makeImplies(A.makeAnd(LhsOkVal.formula(), RhsOkVal.formula()),
601 Res.formula()));
602 // res => (lhs == rhs)
603 Env.assume(A.makeImplies(
604 Res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
605
606 return &Res;
607}
608
609static BoolValue *
611 RecordStorageLocation &RhsStatusOrLoc,
612 Environment &Env) {
613 auto &A = Env.arena();
614 // Logically, a StatusOr<T> object is composed of two values - a Status and a
615 // value of type T. Equality of StatusOr objects compares both values.
616 // Therefore, merely comparing the `ok` bits of the Status values isn't
617 // sufficient. When two StatusOr objects are engaged, the equality of their
618 // respective values of type T matters. Similarly, when two StatusOr objects
619 // have Status values that have non-ok error codes, the equality of the error
620 // codes matters. Since we only track the `ok` bits of the Status values, we
621 // can't make any conclusions about equality when we know that two StatusOr
622 // objects are engaged or when their Status values contain non-ok error codes.
623 auto &LhsOkVal = valForOk(locForStatus(LhsStatusOrLoc), Env);
624 auto &RhsOkVal = valForOk(locForStatus(RhsStatusOrLoc), Env);
625 auto &res = Env.makeAtomicBoolValue();
626
627 // res => (lhs == rhs)
628 Env.assume(A.makeImplies(
629 res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
630 return &res;
631}
632
633static BoolValue *evaluateEquality(const Expr *LhsExpr, const Expr *RhsExpr,
634 Environment &Env) {
635 // Check the type of both sides in case an operator== is added that admits
636 // different types.
637 if (isStatusOrType(LhsExpr->getType()) &&
638 isStatusOrType(RhsExpr->getType())) {
639 auto *LhsStatusOrLoc = Env.get<RecordStorageLocation>(*LhsExpr);
640 if (LhsStatusOrLoc == nullptr)
641 return nullptr;
642 auto *RhsStatusOrLoc = Env.get<RecordStorageLocation>(*RhsExpr);
643 if (RhsStatusOrLoc == nullptr)
644 return nullptr;
645
646 return evaluateStatusOrEquality(*LhsStatusOrLoc, *RhsStatusOrLoc, Env);
647 }
648 if (isStatusType(LhsExpr->getType()) && isStatusType(RhsExpr->getType())) {
649 auto *LhsStatusLoc = Env.get<RecordStorageLocation>(*LhsExpr);
650 if (LhsStatusLoc == nullptr)
651 return nullptr;
652
653 auto *RhsStatusLoc = Env.get<RecordStorageLocation>(*RhsExpr);
654 if (RhsStatusLoc == nullptr)
655 return nullptr;
656
657 return evaluateStatusEquality(*LhsStatusLoc, *RhsStatusLoc, Env);
658 }
659 return nullptr;
660}
661
664 bool IsNegative) {
665 auto *LhsAndRhsVal =
666 evaluateEquality(Expr->getArg(0), Expr->getArg(1), State.Env);
667 if (LhsAndRhsVal == nullptr)
668 return;
669
670 if (IsNegative)
671 State.Env.setValue(*Expr, State.Env.makeNot(*LhsAndRhsVal));
672 else
673 State.Env.setValue(*Expr, *LhsAndRhsVal);
674}
675
677 Environment &Env) {
678 if (auto *PointerVal = Env.get<PointerValue>(Expr))
679 return dyn_cast<RecordStorageLocation>(&PointerVal->getPointeeLoc());
680 return nullptr;
681}
682
684 const Expr *RhsExpr,
685 Environment &Env) {
686 assert(LhsExpr->getType()->isPointerType());
687 assert(RhsExpr->getType()->isPointerType());
688 RecordStorageLocation *LhsStatusLoc = nullptr;
689 RecordStorageLocation *RhsStatusLoc = nullptr;
690 if (isStatusOrType(LhsExpr->getType()->getPointeeType()) &&
691 isStatusOrType(RhsExpr->getType()->getPointeeType())) {
692 auto *LhsStatusOrLoc = getPointeeLocation(*LhsExpr, Env);
693 auto *RhsStatusOrLoc = getPointeeLocation(*RhsExpr, Env);
694 if (LhsStatusOrLoc == nullptr || RhsStatusOrLoc == nullptr)
695 return nullptr;
696 LhsStatusLoc = &locForStatus(*LhsStatusOrLoc);
697 RhsStatusLoc = &locForStatus(*RhsStatusOrLoc);
698 } else if (isStatusType(LhsExpr->getType()->getPointeeType()) &&
699 isStatusType(RhsExpr->getType()->getPointeeType())) {
700 LhsStatusLoc = getPointeeLocation(*LhsExpr, Env);
701 RhsStatusLoc = getPointeeLocation(*RhsExpr, Env);
702 }
703 if (LhsStatusLoc == nullptr || RhsStatusLoc == nullptr)
704 return nullptr;
705 auto &LhsOkVal = valForOk(*LhsStatusLoc, Env);
706 auto &RhsOkVal = valForOk(*RhsStatusLoc, Env);
707 auto &Res = Env.makeAtomicBoolValue();
708 auto &A = Env.arena();
709 Env.assume(A.makeImplies(
710 Res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
711 return &Res;
712}
713
716 bool IsNegative) {
717 auto *LhsAndRhsVal =
718 evaluatePointerEquality(Expr->getLHS(), Expr->getRHS(), State.Env);
719 if (LhsAndRhsVal == nullptr)
720 return;
721
722 if (IsNegative)
723 State.Env.setValue(*Expr, State.Env.makeNot(*LhsAndRhsVal));
724 else
725 State.Env.setValue(*Expr, *LhsAndRhsVal);
726}
727
730 LatticeTransferState &State) {
731 auto &OkVal =
732 initializeStatus(State.Env.getResultObjectLocation(*Expr), State.Env);
733 State.Env.assume(OkVal.formula());
734}
735
738 LatticeTransferState &State) {
739 auto &OkVal =
740 initializeStatus(State.Env.getResultObjectLocation(*Expr), State.Env);
741 auto &A = State.Env.arena();
742 State.Env.assume(A.makeNot(OkVal.formula()));
743}
744
747 LatticeTransferState &State) {
748 RecordStorageLocation *StatusOrLoc =
749 getImplicitObjectLocation(*Expr, State.Env);
750 if (StatusOrLoc == nullptr)
751 return;
752
753 auto &OkVal = valForOk(locForStatus(*StatusOrLoc), State.Env);
754 State.Env.assume(OkVal.formula());
755}
756
759 LatticeTransferState &State) {
760 assert(Expr->getNumArgs() > 1);
761
762 auto *StatusOrLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
763 if (StatusOrLoc == nullptr)
764 return;
765
766 auto &OkVal = initializeStatusOr(*StatusOrLoc, State.Env);
767 State.Env.assume(OkVal.formula());
768}
769
772 LatticeTransferState &State) {
773 auto &OkVal =
774 initializeStatusOr(State.Env.getResultObjectLocation(*Expr), State.Env);
775 State.Env.assume(OkVal.formula());
776}
777
780 LatticeTransferState &State) {
781 RecordStorageLocation &StatusOrLoc = State.Env.getResultObjectLocation(*Expr);
782 RecordStorageLocation &StatusLoc = locForStatus(StatusOrLoc);
783
784 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
785 initializeStatusOr(StatusOrLoc, State.Env);
786}
787
790 LatticeTransferState &State) {
791 RecordStorageLocation &StatusLoc = State.Env.getResultObjectLocation(*Expr);
792
793 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
794 initializeStatus(StatusLoc, State.Env);
795}
796static void
799 LatticeTransferState &State) {
800 assert(Expr->getNumArgs() == 1);
801 if (Expr->getArg(0)->isPRValue())
802 return;
803 auto *ArgLoc = State.Env.getStorageLocation(*Expr->getArg(0));
804 if (ArgLoc == nullptr)
805 return;
806
807 State.Env.setStorageLocation(*Expr, *ArgLoc);
808}
809
812 LatticeTransferState &State) {
813 assert(Expr->getNumArgs() > 2);
814
815 auto *EqVal = evaluateEquality(Expr->getArg(0), Expr->getArg(1), State.Env);
816 if (EqVal == nullptr)
817 return;
818
819 // Consider modelling this more accurately instead of assigning BoolValue
820 // as the value of an expression of pointer type.
821 // For now, this is being handled in transferPointerToBoolean.
822 State.Env.setValue(*Expr, State.Env.makeNot(*EqVal));
823}
824
827 LatticeTransferState &State) {
828 assert(Expr->getNumArgs() == 1);
829
830 auto *ArgLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
831 if (ArgLoc == nullptr)
832 return;
833
834 if (State.Env.getValue(locForOk(*ArgLoc)) == nullptr)
835 initializeStatus(*ArgLoc, State.Env);
836
837 auto &ExprVal = State.Env.create<PointerValue>(*ArgLoc);
838 State.Env.setValue(*Expr, ExprVal);
839}
840
843 LatticeTransferState &State) {
844 assert(Expr->getNumArgs() == 1);
845
846 auto *ArgLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
847 if (ArgLoc == nullptr)
848 return;
849
850 RecordStorageLocation &StatusLoc = locForStatus(*ArgLoc);
851
852 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
853 initializeStatusOr(*ArgLoc, State.Env);
854
855 auto &ExprVal = State.Env.create<PointerValue>(StatusLoc);
856 State.Env.setValue(*Expr, ExprVal);
857}
858
861 LatticeTransferState &State) {
862 if (auto *SubExprVal =
863 dyn_cast_or_null<BoolValue>(State.Env.getValue(*Expr->getSubExpr())))
864 State.Env.setValue(*Expr, *SubExprVal);
865}
866
868 LatticeTransferState &State) {
869 RecordStorageLocation *StatusOrLoc =
870 Expr->isPRValue() ? &State.Env.getResultObjectLocation(*Expr)
871 : State.Env.get<RecordStorageLocation>(*Expr);
872 if (StatusOrLoc != nullptr &&
873 State.Env.getValue(locForOk(locForStatus(*StatusOrLoc))) == nullptr)
874 initializeStatusOr(*StatusOrLoc, State.Env);
875}
876
880 assert(isStatusOrType(Expr->getType()));
881 if (RecordLoc == nullptr)
882 return false;
883 const FunctionDecl *DirectCallee = Expr->getDirectCallee();
884 if (DirectCallee == nullptr)
885 return false;
886 StorageLocation &Loc =
887 State.Lattice.getOrCreateConstMethodReturnStorageLocation(
888 *RecordLoc, DirectCallee, State.Env, [&](StorageLocation &Loc) {
889 initializeStatusOr(cast<RecordStorageLocation>(Loc), State.Env);
890 });
891 if (Expr->isPRValue()) {
892 auto &ResultLoc = State.Env.getResultObjectLocation(*Expr);
893 copyRecord(cast<RecordStorageLocation>(Loc), ResultLoc, State.Env);
894 } else {
895 State.Env.setStorageLocation(*Expr, Loc);
896 }
897 return true;
898}
899
909 if (RecordLoc == nullptr)
910 return;
911 auto *Val = State.Lattice.getOrCreateConstMethodReturnValue(*RecordLoc, Expr,
912 State.Env);
913 State.Env.setValue(*Expr, *Val);
914}
915
916static void
923
926 LatticeTransferState &State) {
927 auto *RecordLoc = cast_or_null<RecordStorageLocation>(
928 State.Env.getStorageLocation(*Expr->getArg(0)));
930}
931
938
941 LatticeTransferState &State) {
942 auto *RecordLoc = cast_or_null<RecordStorageLocation>(
943 State.Env.getStorageLocation(*Expr->getArg(0)));
945}
946
950 LatticeTransferState &State) {
951 if (RecordLoc) {
952 State.Lattice.clearConstMethodReturnValues(*RecordLoc);
953 State.Lattice.clearConstMethodReturnStorageLocations(*RecordLoc);
954 }
957}
958
965
966static void
969 LatticeTransferState &State) {
970 auto *RecordLoc = cast_or_null<RecordStorageLocation>(
971 State.Env.getStorageLocation(*Expr->getArg(0)));
973}
974
976 const CallExpr *Expr, const MatchFinder::MatchResult &,
977 LatticeTransferState &State) {
978 State.Env.setValue(
979 locForOkPredicate(State.Env.getResultObjectLocation(*Expr)),
980 State.Env.getBoolLiteralValue(true));
981}
982
985 LatticeTransferState &State) {
986 BoolValue &OkMatcherVal = State.Env.getBoolLiteralValue(true);
987 State.Env.setValue(locForOkMatcher(State.Env.getResultObjectLocation(*Expr)),
988 OkMatcherVal);
989}
990
992 const CallExpr *Expr, const MatchFinder::MatchResult &,
993 LatticeTransferState &State) {
994 assert(Expr->isPRValue());
995 auto &Loc = State.Env.getResultObjectLocation(*Expr->getArg(0));
996 auto &OkMatcherLoc = locForOkMatcher(Loc);
997 BoolValue *OkMatcherVal = State.Env.get<BoolValue>(OkMatcherLoc);
998 if (OkMatcherVal == nullptr)
999 return;
1000 State.Env.setValue(
1001 locForOkPredicate(State.Env.getResultObjectLocation(*Expr)),
1002 *OkMatcherVal);
1003}
1004
1005static void
1007 LatticeTransferState &State,
1008 bool IsStatusOr) {
1009 auto *Loc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
1010 if (Loc == nullptr)
1011 return;
1012
1013 auto *ObjectLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(2));
1014 if (ObjectLoc == nullptr)
1015 return;
1016
1017 auto &OkPredicateLoc = locForOkPredicate(*Loc);
1018 BoolValue *OkPredicateVal = State.Env.get<BoolValue>(OkPredicateLoc);
1019 if (OkPredicateVal == nullptr)
1020 return;
1021
1022 if (IsStatusOr)
1023 ObjectLoc = &locForStatus(*ObjectLoc);
1024 auto &StatusOk = valForOk(*ObjectLoc, State.Env);
1025
1026 auto &A = State.Env.arena();
1027 auto &Res = State.Env.makeAtomicBoolValue();
1028 State.Env.assume(
1029 A.makeImplies(OkPredicateVal->formula(),
1030 A.makeEquals(StatusOk.formula(), Res.formula())));
1031 State.Env.setValue(locForOk(State.Env.getResultObjectLocation(*Expr)), Res);
1032}
1033
1034static void
1037 LatticeTransferState &State) {
1038 assert(Expr->getNumArgs() > 0);
1039
1040 auto *StatusAdaptorLoc = State.Env.get<StorageLocation>(*Expr->getArg(0));
1041 if (StatusAdaptorLoc == nullptr)
1042 return;
1043 BoolValue *OkVal = State.Env.get<BoolValue>(*StatusAdaptorLoc);
1044 if (OkVal == nullptr)
1045 return;
1046 State.Env.setValue(locForOk(State.Env.getResultObjectLocation(*Expr)),
1047 *OkVal);
1048}
1049
1050static void
1053 LatticeTransferState &State) {
1054 auto *RecordLoc = getImplicitObjectLocation(*Expr, State.Env);
1055 if (RecordLoc == nullptr)
1056 return;
1057 BoolValue *OkVal = State.Env.get<BoolValue>(locForOk(*RecordLoc));
1058 if (OkVal == nullptr)
1059 return;
1060 auto &A = State.Env.arena();
1061 auto &Res = State.Env.makeAtomicBoolValue();
1062 State.Env.assume(A.makeEquals(OkVal->formula(), Res.formula()));
1063 State.Env.setValue(*Expr, Res);
1064}
1065
1068 LatticeTransferState &State) {
1069 auto *StatusOrLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
1070
1071 if (StatusOrLoc && State.Env.getStorageLocation(*Expr) == nullptr)
1072 State.Env.setStorageLocation(*Expr,
1073 StatusOrLoc->getSyntheticField("value"));
1074}
1075
1078 LatticeTransferState &State) {
1079 auto *StatusOrLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
1080 if (!StatusOrLoc)
1081 return;
1082 State.Env.setValue(*Expr, State.Env.create<PointerValue>(
1083 StatusOrLoc->getSyntheticField("value")));
1084}
1085
1088 LatticeTransferState &State) {
1089 auto *StatusOrLoc = getImplicitObjectLocation(*Expr, State.Env);
1090
1091 if (StatusOrLoc && State.Env.getStorageLocation(*Expr) == nullptr)
1092 State.Env.setStorageLocation(*Expr,
1093 StatusOrLoc->getSyntheticField("value"));
1094}
1095
1098 LatticeTransferState &State) {
1099 PointerValue *PointerVal =
1100 dyn_cast_or_null<PointerValue>(State.Env.getValue(*Expr));
1101 if (!PointerVal) {
1102 PointerVal = cast<PointerValue>(State.Env.createValue(Expr->getType()));
1103 State.Env.setValue(*Expr, *PointerVal);
1104 }
1105
1106 auto *RecordLoc =
1107 dyn_cast_or_null<RecordStorageLocation>(&PointerVal->getPointeeLoc());
1108 if (RecordLoc != nullptr &&
1109 State.Env.getValue(locForOk(locForStatus(*RecordLoc))) == nullptr)
1110 initializeStatusOr(*RecordLoc, State.Env);
1111}
1112
1115 LatticeTransferState &State) {
1116 PointerValue *PointerVal =
1117 dyn_cast_or_null<PointerValue>(State.Env.getValue(*Expr));
1118 if (!PointerVal) {
1119 PointerVal = cast<PointerValue>(State.Env.createValue(Expr->getType()));
1120 State.Env.setValue(*Expr, *PointerVal);
1121 }
1122
1123 auto *RecordLoc =
1124 dyn_cast_or_null<RecordStorageLocation>(&PointerVal->getPointeeLoc());
1125 if (RecordLoc != nullptr &&
1126 State.Env.getValue(locForOk(*RecordLoc)) == nullptr)
1127 initializeStatus(*RecordLoc, State.Env);
1128}
1129
1130static RecordStorageLocation *
1132 if (!E.isPRValue())
1133 return dyn_cast_or_null<RecordStorageLocation>(Env.getStorageLocation(E));
1134 if (auto *PointerVal = dyn_cast_or_null<PointerValue>(Env.getValue(E)))
1135 return dyn_cast_or_null<RecordStorageLocation>(
1136 &PointerVal->getPointeeLoc());
1137 return nullptr;
1138}
1139
1143 using namespace ::clang::ast_matchers; // NOLINT: Too many names
1144 return std::move(Builder)
1145 .CaseOfCFGStmt<CallExpr>(
1148 .CaseOfCFGStmt<CallExpr>(isStatusIsOkMatcherCall(),
1150 .CaseOfCFGStmt<CallExpr>(
1153 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1156 LatticeTransferState &State) {
1158 /*IsStatusOr=*/true);
1159 })
1160 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1163 LatticeTransferState &State) {
1165 /*IsStatusOr=*/false);
1166 })
1167 .CaseOfCFGStmt<CXXConstructExpr>(
1172 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("ok"),
1174 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("status"),
1176 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusMemberCallWithName("ok"),
1178 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusMemberCallWithName("Update"),
1180 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1183 LatticeTransferState &State) {
1185 /*IsNegative=*/false);
1186 })
1187 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1190 LatticeTransferState &State) {
1192 /*IsNegative=*/true);
1193 })
1194 .CaseOfCFGStmt<BinaryOperator>(
1196 [](const BinaryOperator *Expr, const MatchFinder::MatchResult &,
1197 LatticeTransferState &State) {
1199 /*IsNegative=*/false);
1200 })
1201 .CaseOfCFGStmt<BinaryOperator>(
1203 [](const BinaryOperator *Expr, const MatchFinder::MatchResult &,
1204 LatticeTransferState &State) {
1206 /*IsNegative=*/true);
1207 })
1208 .CaseOfCFGStmt<CallExpr>(isOkStatusCall(), transferOkStatusCall)
1210 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("emplace"),
1214 .CaseOfCFGStmt<CXXConstructExpr>(isStatusOrValueConstructor(),
1218 .CaseOfCFGStmt<CXXOperatorCallExpr>(isStatusOrOperatorCallWithName("*"),
1220 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("value"),
1222 .CaseOfCFGStmt<CallExpr>(isAsStatusCallWithStatus(),
1224 .CaseOfCFGStmt<CallExpr>(isAsStatusCallWithStatusOr(),
1226 .CaseOfCFGStmt<CallExpr>(isLoggingGetReferenceableValueCall(),
1228 .CaseOfCFGStmt<CallExpr>(isLoggingCheckEqImpl(),
1230 // This needs to go before the const accessor call matcher, because these
1231 // look like them, but we model `operator`* and `get` to return the same
1232 // object. Also, we model them for non-const cases.
1233 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1235 [](const CXXOperatorCallExpr *E,
1237 LatticeTransferState &State) {
1239 E, getSmartPtrLikeStorageLocation(*E->getArg(0), State.Env),
1240 State, [](StorageLocation &Loc) {});
1241 })
1242 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1244 [](const CXXOperatorCallExpr *E,
1246 LatticeTransferState &State) {
1248 E, getSmartPtrLikeStorageLocation(*E->getArg(0), State.Env),
1249 State, [](StorageLocation &Loc) {});
1250 })
1251 .CaseOfCFGStmt<CXXMemberCallExpr>(
1254 LatticeTransferState &State) {
1256 E, getImplicitObjectLocation(*E, State.Env), State,
1257 [](StorageLocation &Loc) {});
1258 })
1259 .CaseOfCFGStmt<CXXMemberCallExpr>(
1262 LatticeTransferState &State) {
1264 E, getImplicitObjectLocation(*E, State.Env), State,
1265 [](StorageLocation &Loc) {});
1266 })
1267 // const accessor calls
1268 .CaseOfCFGStmt<CXXMemberCallExpr>(isConstStatusOrAccessorMemberCall(),
1270 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1273 .CaseOfCFGStmt<CXXMemberCallExpr>(
1276 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1279 // non-const member calls that may modify the state of an object.
1280 .CaseOfCFGStmt<CXXMemberCallExpr>(isNonConstMemberCall(),
1284 // N.B. this has to be after transferConstMemberCall, otherwise we would
1285 // always return a fresh RecordStorageLocation for the StatusOr.
1286 .CaseOfCFGStmt<CallExpr>(isStatusOrReturningCall(),
1287 [](const CallExpr *Expr,
1289 LatticeTransferState &State) {
1291 })
1292 .CaseOfCFGStmt<CallExpr>(isStatusOrPtrReturningCall(),
1294 .CaseOfCFGStmt<CallExpr>(isStatusPtrReturningCall(),
1296 // N.B. These need to come after all other CXXConstructExpr.
1297 // These are there to make sure that every Status and StatusOr object
1298 // have their ok boolean initialized when constructed. If we were to
1299 // lazily initialize them when we first access them, we can produce
1300 // false positives if that first access is in a control flow statement.
1301 // You can comment out these two constructors and see tests fail.
1302 .CaseOfCFGStmt<CXXConstructExpr>(isStatusOrConstructor(),
1304 .CaseOfCFGStmt<CXXConstructExpr>(isStatusConstructor(),
1306 .CaseOfCFGStmt<ImplicitCastExpr>(
1307 implicitCastExpr(hasCastKind(CK_PointerToBoolean)),
1309 .Build();
1310}
1311
1313 for (Type *Ty : Ctx.getTypes())
1314 if (isStatusType(QualType(Ty, 0)))
1315 return QualType(Ty, 0);
1316
1317 return QualType();
1318}
1319
1321 Environment &Env)
1324 TransferMatchSwitch(buildTransferMatchSwitch(Ctx, {})) {
1325 QualType StatusType = findStatusType(Ctx);
1326 Env.getDataflowAnalysisContext().setSyntheticFieldCallback(
1327 [StatusType](QualType Ty) -> llvm::StringMap<QualType> {
1329 if (RD == nullptr)
1330 return {};
1331
1332 if (auto Fields = getSyntheticFields(Ty, StatusType, *RD);
1333 !Fields.empty())
1334 return Fields;
1335 return {};
1336 });
1337}
1338
1340 Environment &Env) {
1341 LatticeTransferState State(L, Env);
1342 TransferMatchSwitch(Elt, getASTContext(), State);
1343}
1344
1345} // 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:220
const SmallVectorImpl< Type * > & getTypes() const
CanQualType BoolTy
A builtin binary operation expression such as "x + y" or "x <= y".
Definition Expr.h:3972
Represents a top-level expression in a basic block.
Definition CFG.h:55
Represents a call to a C++ constructor.
Definition ExprCXX.h:1548
Represents a call to a member function that may be written either with member call syntax (e....
Definition ExprCXX.h:179
SourceLocation getExprLoc() const LLVM_READONLY
Definition ExprCXX.h:220
A call to an overloaded operator written using operator syntax.
Definition ExprCXX.h:84
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:2877
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3081
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:3787
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:1833
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:8515
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:752
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 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 transferConstStatusOrAccessorMemberCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
static void transferValueCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static StorageLocation & locForOkMatcher(RecordStorageLocation &StatusLoc)
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)
static void transferConstStatusOrPointerAccessorMemberCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
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 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 void transferConstStatusOrPointerAccessorMemberOperatorCall(const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
static void handleConstStatusOrPointerAccessorMemberCall(const CallExpr *Expr, RecordStorageLocation *RecordLoc, const MatchFinder::MatchResult &Result, 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 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 transferConstStatusOrAccessorMemberOperatorCall(const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
static void transferStatusUpdateCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static bool doHandleConstStatusOrAccessorMemberCall(const CallExpr *Expr, RecordStorageLocation *RecordLoc, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
CFGMatchSwitch< LatticeTransferState > buildTransferMatchSwitch(ASTContext &Ctx, CFGMatchSwitchBuilder< LatticeTransferState > Builder)
static void handleConstStatusOrAccessorMemberCall(const CallExpr *Expr, RecordStorageLocation *RecordLoc, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
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.