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
367 using namespace ::clang::ast_matchers;
368 return ofClass(
369 hasName("::absl::status_macro_internal::ReturnIfErrorAdaptor"));
370}
371
373 using namespace ::clang::ast_matchers;
374 return cxxRecordDecl(
375 hasName("::absl::status_macro_internal::ReturnIfErrorAdaptor"));
376}
377
379 using namespace ::clang::ast_matchers;
380 return hasUnqualifiedDesugaredType(
382}
383
385 using namespace ::clang::ast_matchers;
386 return cxxMemberCallExpr(
387 on(expr(unless(cxxThisExpr()))),
388 callee(cxxMethodDecl(hasName("operator bool"),
390}
391
392static auto isMacroAdaptorCall() {
393 using namespace ::clang::ast_matchers;
394 return callExpr(callee(
395 functionDecl(hasName("::absl::status_macro_internal::MacroAdaptor"),
396 returns(returnIfErrorAdaptorType()))));
397}
398
399static auto
403 // StatusOr::value, StatusOr::ValueOrDie
404 .CaseOfCFGStmt<CXXMemberCallExpr>(
405 valueCall(),
406 [](const CXXMemberCallExpr *E,
408 const Environment &Env) {
409 if (!isSafeUnwrap(getImplicitObjectLocation(*E, Env), Env))
412 })
413
414 // StatusOr::operator*, StatusOr::operator->
415 .CaseOfCFGStmt<CXXOperatorCallExpr>(
417 [](const CXXOperatorCallExpr *E,
419 const Environment &Env) {
420 RecordStorageLocation *StatusOrLoc =
421 Env.get<RecordStorageLocation>(*E->getArg(0));
422 if (!isSafeUnwrap(StatusOrLoc, Env))
423 return llvm::SmallVector<SourceLocation>({E->getOperatorLoc()});
425 })
426 .Build();
427}
428
432
439
441 Environment &Env) {
442 auto &OkVal = Env.makeAtomicBoolValue();
443 Env.setValue(locForOk(StatusLoc), OkVal);
444 return OkVal;
445}
446
448 Environment &Env) {
449 return initializeStatus(locForStatus(StatusOrLoc), Env);
450}
451
453 using namespace ::clang::ast_matchers;
455 hasName("absl::StatusOr"),
456 hasTemplateArgument(0, refersToType(type().bind("T"))));
457}
458
460 using namespace ::clang::ast_matchers;
461 return cxxRecordDecl(hasName("absl::Status"));
462}
463
465 using namespace ::clang::ast_matchers;
467 hasName("absl::internal_statusor::OperatorBase"));
468}
469
471 using namespace ::clang::ast_matchers;
472 return hasCanonicalType(qualType(hasDeclaration(statusOrClass())));
473}
474
476 using namespace ::clang::ast_matchers;
477 return hasCanonicalType(qualType(hasDeclaration(statusClass())));
478}
479
481 return isTypeNamed(Type, {"absl"}, "StatusOr");
482}
483
485 return isTypeNamed(Type, {"absl"}, "Status");
486}
487
489 return isTypeNamed(Type, {"testing", "internal"},
490 "PredicateFormatterFromMatcher");
491}
492
494 return isTypeNamed(Type, {"testing"}, "AssertionResult");
495}
496
498 return isTypeNamed(Type, {"testing", "status", "internal_status"},
499 "StatusIsMatcher") ||
500 isTypeNamed(Type, {"testing", "status", "internal_status"},
501 "CanonicalStatusIsMatcher") ||
502 isTypeNamed(Type, {"absl_testing", "status_internal"},
503 "StatusIsMatcher") ||
504 isTypeNamed(Type, {"absl_testing", "status_internal"},
505 "CanonicalStatusIsMatcher");
506}
507
509 return isTypeNamed(type, {"absl", "status_macro_internal"},
510 "ReturnIfErrorAdaptor");
511}
512
513llvm::StringMap<QualType> getSyntheticFields(QualType Ty, QualType StatusType,
514 const CXXRecordDecl &RD) {
515 if (auto *TRD = getStatusOrBaseClass(Ty))
516 return {{"status", StatusType}, {"value", getStatusOrValueType(TRD)}};
517 if (isStatusType(Ty) || (RD.hasDefinition() &&
518 RD.isDerivedFrom(StatusType->getAsCXXRecordDecl())))
519 return {{"ok", RD.getASTContext().BoolTy}};
520 if (isAssertionResultType(Ty))
521 return {{"ok", RD.getASTContext().BoolTy}};
523 return {{"ok_predicate", RD.getASTContext().BoolTy}};
524 if (isStatusIsMatcherType(Ty))
525 return {{"ok_matcher", RD.getASTContext().BoolTy}};
526 if (IsMacroAdaptorType(Ty))
527 return {{"status", StatusType}};
528 return {};
529}
530
534
536 return StatusLoc.getSyntheticField("ok");
537}
538
540 if (auto *Val = Env.get<BoolValue>(locForOk(StatusLoc)))
541 return *Val;
542 return initializeStatus(StatusLoc, Env);
543}
545 return StatusLoc.getSyntheticField("ok_predicate");
546}
547
549 return StatusLoc.getSyntheticField("ok_matcher");
550}
551
554 LatticeTransferState &State) {
555 RecordStorageLocation *StatusOrLoc =
556 getImplicitObjectLocation(*Expr, State.Env);
557 if (StatusOrLoc == nullptr)
558 return;
559
560 auto &OkVal = valForOk(locForStatus(*StatusOrLoc), State.Env);
561 State.Env.setValue(*Expr, OkVal);
562}
563
566 LatticeTransferState &State) {
567 RecordStorageLocation *StatusOrLoc =
568 getImplicitObjectLocation(*Expr, State.Env);
569 if (StatusOrLoc == nullptr)
570 return;
571
572 RecordStorageLocation &StatusLoc = locForStatus(*StatusOrLoc);
573
574 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
575 initializeStatusOr(*StatusOrLoc, State.Env);
576
577 if (Expr->isPRValue())
578 copyRecord(StatusLoc, State.Env.getResultObjectLocation(*Expr), State.Env);
579 else
580 State.Env.setStorageLocation(*Expr, StatusLoc);
581}
582
585 LatticeTransferState &State) {
586 RecordStorageLocation *StatusLoc =
587 getImplicitObjectLocation(*Expr, State.Env);
588 if (StatusLoc == nullptr)
589 return;
590
591 if (Value *Val = State.Env.getValue(locForOk(*StatusLoc)))
592 State.Env.setValue(*Expr, *Val);
593}
594
597 LatticeTransferState &State) {
598 // S.Update(OtherS) sets S to the error code of OtherS if it is OK,
599 // otherwise does nothing.
600 assert(Expr->getNumArgs() == 1);
601 auto *Arg = Expr->getArg(0);
602 RecordStorageLocation *ArgRecord =
603 Arg->isPRValue() ? &State.Env.getResultObjectLocation(*Arg)
604 : State.Env.get<RecordStorageLocation>(*Arg);
606 if (ThisLoc == nullptr || ArgRecord == nullptr)
607 return;
608
609 auto &ThisOkVal = valForOk(*ThisLoc, State.Env);
610 auto &ArgOkVal = valForOk(*ArgRecord, State.Env);
611 auto &A = State.Env.arena();
612 auto &NewVal = State.Env.makeAtomicBoolValue();
613 State.Env.assume(A.makeImplies(A.makeNot(ThisOkVal.formula()),
614 A.makeNot(NewVal.formula())));
615 State.Env.assume(A.makeImplies(NewVal.formula(), ArgOkVal.formula()));
616 State.Env.setValue(locForOk(*ThisLoc), NewVal);
617}
618
620 RecordStorageLocation &RhsStatusLoc,
621 Environment &Env) {
622 auto &A = Env.arena();
623 // Logically, a Status object is composed of an error code that could take one
624 // of multiple possible values, including the "ok" value. We track whether a
625 // Status object has an "ok" value and represent this as an `ok` bit. Equality
626 // of Status objects compares their error codes. Therefore, merely comparing
627 // the `ok` bits isn't sufficient: when two Status objects are assigned non-ok
628 // error codes the equality of their respective error codes matters. Since we
629 // only track the `ok` bits, we can't make any conclusions about equality when
630 // we know that two Status objects have non-ok values.
631
632 auto &LhsOkVal = valForOk(LhsStatusLoc, Env);
633 auto &RhsOkVal = valForOk(RhsStatusLoc, Env);
634
635 auto &Res = Env.makeAtomicBoolValue();
636
637 // lhs && rhs => res (a.k.a. !res => !lhs || !rhs)
638 Env.assume(A.makeImplies(A.makeAnd(LhsOkVal.formula(), RhsOkVal.formula()),
639 Res.formula()));
640 // res => (lhs == rhs)
641 Env.assume(A.makeImplies(
642 Res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
643
644 return &Res;
645}
646
647static BoolValue *
649 RecordStorageLocation &RhsStatusOrLoc,
650 Environment &Env) {
651 auto &A = Env.arena();
652 // Logically, a StatusOr<T> object is composed of two values - a Status and a
653 // value of type T. Equality of StatusOr objects compares both values.
654 // Therefore, merely comparing the `ok` bits of the Status values isn't
655 // sufficient. When two StatusOr objects are engaged, the equality of their
656 // respective values of type T matters. Similarly, when two StatusOr objects
657 // have Status values that have non-ok error codes, the equality of the error
658 // codes matters. Since we only track the `ok` bits of the Status values, we
659 // can't make any conclusions about equality when we know that two StatusOr
660 // objects are engaged or when their Status values contain non-ok error codes.
661 auto &LhsOkVal = valForOk(locForStatus(LhsStatusOrLoc), Env);
662 auto &RhsOkVal = valForOk(locForStatus(RhsStatusOrLoc), Env);
663 auto &res = Env.makeAtomicBoolValue();
664
665 // res => (lhs == rhs)
666 Env.assume(A.makeImplies(
667 res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
668 return &res;
669}
670
671static BoolValue *evaluateEquality(const Expr *LhsExpr, const Expr *RhsExpr,
672 Environment &Env) {
673 // Check the type of both sides in case an operator== is added that admits
674 // different types.
675 if (isStatusOrType(LhsExpr->getType()) &&
676 isStatusOrType(RhsExpr->getType())) {
677 auto *LhsStatusOrLoc = Env.get<RecordStorageLocation>(*LhsExpr);
678 if (LhsStatusOrLoc == nullptr)
679 return nullptr;
680 auto *RhsStatusOrLoc = Env.get<RecordStorageLocation>(*RhsExpr);
681 if (RhsStatusOrLoc == nullptr)
682 return nullptr;
683
684 return evaluateStatusOrEquality(*LhsStatusOrLoc, *RhsStatusOrLoc, Env);
685 }
686 if (isStatusType(LhsExpr->getType()) && isStatusType(RhsExpr->getType())) {
687 auto *LhsStatusLoc = Env.get<RecordStorageLocation>(*LhsExpr);
688 if (LhsStatusLoc == nullptr)
689 return nullptr;
690
691 auto *RhsStatusLoc = Env.get<RecordStorageLocation>(*RhsExpr);
692 if (RhsStatusLoc == nullptr)
693 return nullptr;
694
695 return evaluateStatusEquality(*LhsStatusLoc, *RhsStatusLoc, Env);
696 }
697 return nullptr;
698}
699
702 bool IsNegative) {
703 auto *LhsAndRhsVal =
704 evaluateEquality(Expr->getArg(0), Expr->getArg(1), State.Env);
705 if (LhsAndRhsVal == nullptr)
706 return;
707
708 if (IsNegative)
709 State.Env.setValue(*Expr, State.Env.makeNot(*LhsAndRhsVal));
710 else
711 State.Env.setValue(*Expr, *LhsAndRhsVal);
712}
713
715 Environment &Env) {
716 if (auto *PointerVal = Env.get<PointerValue>(Expr))
717 return dyn_cast<RecordStorageLocation>(&PointerVal->getPointeeLoc());
718 return nullptr;
719}
720
722 const Expr *RhsExpr,
723 Environment &Env) {
724 assert(LhsExpr->getType()->isPointerType());
725 assert(RhsExpr->getType()->isPointerType());
726 RecordStorageLocation *LhsStatusLoc = nullptr;
727 RecordStorageLocation *RhsStatusLoc = nullptr;
728 if (isStatusOrType(LhsExpr->getType()->getPointeeType()) &&
729 isStatusOrType(RhsExpr->getType()->getPointeeType())) {
730 auto *LhsStatusOrLoc = getPointeeLocation(*LhsExpr, Env);
731 auto *RhsStatusOrLoc = getPointeeLocation(*RhsExpr, Env);
732 if (LhsStatusOrLoc == nullptr || RhsStatusOrLoc == nullptr)
733 return nullptr;
734 LhsStatusLoc = &locForStatus(*LhsStatusOrLoc);
735 RhsStatusLoc = &locForStatus(*RhsStatusOrLoc);
736 } else if (isStatusType(LhsExpr->getType()->getPointeeType()) &&
737 isStatusType(RhsExpr->getType()->getPointeeType())) {
738 LhsStatusLoc = getPointeeLocation(*LhsExpr, Env);
739 RhsStatusLoc = getPointeeLocation(*RhsExpr, Env);
740 }
741 if (LhsStatusLoc == nullptr || RhsStatusLoc == nullptr)
742 return nullptr;
743 auto &LhsOkVal = valForOk(*LhsStatusLoc, Env);
744 auto &RhsOkVal = valForOk(*RhsStatusLoc, Env);
745 auto &Res = Env.makeAtomicBoolValue();
746 auto &A = Env.arena();
747 Env.assume(A.makeImplies(
748 Res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
749 return &Res;
750}
751
754 bool IsNegative) {
755 auto *LhsAndRhsVal =
756 evaluatePointerEquality(Expr->getLHS(), Expr->getRHS(), State.Env);
757 if (LhsAndRhsVal == nullptr)
758 return;
759
760 if (IsNegative)
761 State.Env.setValue(*Expr, State.Env.makeNot(*LhsAndRhsVal));
762 else
763 State.Env.setValue(*Expr, *LhsAndRhsVal);
764}
765
768 LatticeTransferState &State) {
769 auto &OkVal =
770 initializeStatus(State.Env.getResultObjectLocation(*Expr), State.Env);
771 State.Env.assume(OkVal.formula());
772}
773
776 LatticeTransferState &State) {
777 auto &OkVal =
778 initializeStatus(State.Env.getResultObjectLocation(*Expr), State.Env);
779 auto &A = State.Env.arena();
780 State.Env.assume(A.makeNot(OkVal.formula()));
781}
782
785 LatticeTransferState &State) {
786 RecordStorageLocation *StatusOrLoc =
787 getImplicitObjectLocation(*Expr, State.Env);
788 if (StatusOrLoc == nullptr)
789 return;
790
791 auto &OkVal = valForOk(locForStatus(*StatusOrLoc), State.Env);
792 State.Env.assume(OkVal.formula());
793}
794
797 LatticeTransferState &State) {
798 assert(Expr->getNumArgs() > 1);
799
800 auto *StatusOrLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
801 if (StatusOrLoc == nullptr)
802 return;
803
804 auto &OkVal = initializeStatusOr(*StatusOrLoc, State.Env);
805 State.Env.assume(OkVal.formula());
806}
807
810 LatticeTransferState &State) {
811 auto &OkVal =
812 initializeStatusOr(State.Env.getResultObjectLocation(*Expr), State.Env);
813 State.Env.assume(OkVal.formula());
814}
815
818 LatticeTransferState &State) {
819 RecordStorageLocation &StatusOrLoc = State.Env.getResultObjectLocation(*Expr);
820 RecordStorageLocation &StatusLoc = locForStatus(StatusOrLoc);
821
822 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
823 initializeStatusOr(StatusOrLoc, State.Env);
824}
825
828 LatticeTransferState &State) {
829 RecordStorageLocation &StatusLoc = State.Env.getResultObjectLocation(*Expr);
830
831 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
832 initializeStatus(StatusLoc, State.Env);
833}
834static void
837 LatticeTransferState &State) {
838 assert(Expr->getNumArgs() == 1);
839 if (Expr->getArg(0)->isPRValue())
840 return;
841 auto *ArgLoc = State.Env.getStorageLocation(*Expr->getArg(0));
842 if (ArgLoc == nullptr)
843 return;
844
845 State.Env.setStorageLocation(*Expr, *ArgLoc);
846}
847
850 LatticeTransferState &State) {
851 assert(Expr->getNumArgs() > 2);
852
853 auto *EqVal = evaluateEquality(Expr->getArg(0), Expr->getArg(1), State.Env);
854 if (EqVal == nullptr)
855 return;
856
857 // Consider modelling this more accurately instead of assigning BoolValue
858 // as the value of an expression of pointer type.
859 // For now, this is being handled in transferPointerToBoolean.
860 State.Env.setValue(*Expr, State.Env.makeNot(*EqVal));
861}
862
865 LatticeTransferState &State) {
866 assert(Expr->getNumArgs() == 1);
867
868 auto *ArgLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
869 if (ArgLoc == nullptr)
870 return;
871
872 if (State.Env.getValue(locForOk(*ArgLoc)) == nullptr)
873 initializeStatus(*ArgLoc, State.Env);
874
875 auto &ExprVal = State.Env.create<PointerValue>(*ArgLoc);
876 State.Env.setValue(*Expr, ExprVal);
877}
878
881 LatticeTransferState &State) {
882 assert(Expr->getNumArgs() == 1);
883
884 auto *ArgLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
885 if (ArgLoc == nullptr)
886 return;
887
888 RecordStorageLocation &StatusLoc = locForStatus(*ArgLoc);
889
890 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
891 initializeStatusOr(*ArgLoc, State.Env);
892
893 auto &ExprVal = State.Env.create<PointerValue>(StatusLoc);
894 State.Env.setValue(*Expr, ExprVal);
895}
896
899 LatticeTransferState &State) {
900 if (auto *SubExprVal =
901 dyn_cast_or_null<BoolValue>(State.Env.getValue(*Expr->getSubExpr())))
902 State.Env.setValue(*Expr, *SubExprVal);
903}
904
906 LatticeTransferState &State) {
907 RecordStorageLocation *StatusOrLoc =
908 Expr->isPRValue() ? &State.Env.getResultObjectLocation(*Expr)
909 : State.Env.get<RecordStorageLocation>(*Expr);
910 if (StatusOrLoc != nullptr &&
911 State.Env.getValue(locForOk(locForStatus(*StatusOrLoc))) == nullptr)
912 initializeStatusOr(*StatusOrLoc, State.Env);
913}
914
918 if (RecordLoc == nullptr)
919 return false;
920 const FunctionDecl *DirectCallee = Expr->getDirectCallee();
921 if (DirectCallee == nullptr)
922 return false;
923 StorageLocation &Loc =
924 State.Lattice.getOrCreateConstMethodReturnStorageLocation(
925 *RecordLoc, DirectCallee, State.Env, [&](StorageLocation &Loc) {
926 if (isStatusOrType(Expr->getType()))
927 initializeStatusOr(cast<RecordStorageLocation>(Loc), State.Env);
928 });
929 if (Expr->isPRValue()) {
930 auto &ResultLoc = State.Env.getResultObjectLocation(*Expr);
931 copyRecord(cast<RecordStorageLocation>(Loc), ResultLoc, State.Env);
932 } else {
933 State.Env.setStorageLocation(*Expr, Loc);
934 }
935 return true;
936}
937
948 if (RecordLoc == nullptr)
949 return;
950 auto *Val = State.Lattice.getOrCreateConstMethodReturnValue(*RecordLoc, Expr,
951 State.Env);
952 State.Env.setValue(*Expr, *Val);
953}
954
955static void
965
966static void
969 LatticeTransferState &State) {
970 auto Type = Expr->getArg(0)->getType();
971 if (!Type->isRecordType() && !Type->isReferenceType())
972 return;
973 auto *RecordLoc = cast_or_null<RecordStorageLocation>(
974 State.Env.getStorageLocation(*Expr->getArg(0)));
976}
977
978static void
985
988 LatticeTransferState &State) {
989 auto *RecordLoc = cast_or_null<RecordStorageLocation>(
990 State.Env.getStorageLocation(*Expr->getArg(0)));
992}
993
997 LatticeTransferState &State) {
998 if (RecordLoc) {
999 State.Lattice.clearConstMethodReturnValues(*RecordLoc);
1000 State.Lattice.clearConstMethodReturnStorageLocations(*RecordLoc);
1001 }
1002 if (isStatusOrType(Expr->getType()))
1004}
1005
1012
1013static void
1016 LatticeTransferState &State) {
1017 auto *RecordLoc = cast_or_null<RecordStorageLocation>(
1018 State.Env.getStorageLocation(*Expr->getArg(0)));
1020}
1021
1023 const CallExpr *Expr, const MatchFinder::MatchResult &,
1024 LatticeTransferState &State) {
1025 State.Env.setValue(
1026 locForOkPredicate(State.Env.getResultObjectLocation(*Expr)),
1027 State.Env.getBoolLiteralValue(true));
1028}
1029
1032 LatticeTransferState &State) {
1033 BoolValue &OkMatcherVal = State.Env.getBoolLiteralValue(true);
1034 State.Env.setValue(locForOkMatcher(State.Env.getResultObjectLocation(*Expr)),
1035 OkMatcherVal);
1036}
1037
1039 const CallExpr *Expr, const MatchFinder::MatchResult &,
1040 LatticeTransferState &State) {
1041 assert(Expr->isPRValue());
1042 auto &Loc = State.Env.getResultObjectLocation(*Expr->getArg(0));
1043 auto &OkMatcherLoc = locForOkMatcher(Loc);
1044 BoolValue *OkMatcherVal = State.Env.get<BoolValue>(OkMatcherLoc);
1045 if (OkMatcherVal == nullptr)
1046 return;
1047 State.Env.setValue(
1048 locForOkPredicate(State.Env.getResultObjectLocation(*Expr)),
1049 *OkMatcherVal);
1050}
1051
1052static void
1054 LatticeTransferState &State,
1055 bool IsStatusOr) {
1056 auto *Loc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
1057 if (Loc == nullptr)
1058 return;
1059
1060 auto *ObjectLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(2));
1061 if (ObjectLoc == nullptr)
1062 return;
1063
1064 auto &OkPredicateLoc = locForOkPredicate(*Loc);
1065 BoolValue *OkPredicateVal = State.Env.get<BoolValue>(OkPredicateLoc);
1066 if (OkPredicateVal == nullptr)
1067 return;
1068
1069 if (IsStatusOr)
1070 ObjectLoc = &locForStatus(*ObjectLoc);
1071 auto &StatusOk = valForOk(*ObjectLoc, State.Env);
1072
1073 auto &A = State.Env.arena();
1074 auto &Res = State.Env.makeAtomicBoolValue();
1075 State.Env.assume(
1076 A.makeImplies(OkPredicateVal->formula(),
1077 A.makeEquals(StatusOk.formula(), Res.formula())));
1078 State.Env.setValue(locForOk(State.Env.getResultObjectLocation(*Expr)), Res);
1079}
1080
1081static void
1084 LatticeTransferState &State) {
1085 assert(Expr->getNumArgs() > 0);
1086
1087 auto *StatusAdaptorLoc = State.Env.get<StorageLocation>(*Expr->getArg(0));
1088 if (StatusAdaptorLoc == nullptr)
1089 return;
1090 BoolValue *OkVal = State.Env.get<BoolValue>(*StatusAdaptorLoc);
1091 if (OkVal == nullptr)
1092 return;
1093 State.Env.setValue(locForOk(State.Env.getResultObjectLocation(*Expr)),
1094 *OkVal);
1095}
1096
1097static void
1100 LatticeTransferState &State) {
1101 auto *RecordLoc = getImplicitObjectLocation(*Expr, State.Env);
1102 if (RecordLoc == nullptr)
1103 return;
1104 BoolValue *OkVal = State.Env.get<BoolValue>(locForOk(*RecordLoc));
1105 if (OkVal == nullptr)
1106 return;
1107 auto &A = State.Env.arena();
1108 auto &Res = State.Env.makeAtomicBoolValue();
1109 State.Env.assume(A.makeEquals(OkVal->formula(), Res.formula()));
1110 State.Env.setValue(*Expr, Res);
1111}
1112
1115 LatticeTransferState &State) {
1116 auto *StatusOrLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
1117
1118 if (StatusOrLoc && State.Env.getStorageLocation(*Expr) == nullptr)
1119 State.Env.setStorageLocation(*Expr,
1120 StatusOrLoc->getSyntheticField("value"));
1121}
1122
1125 LatticeTransferState &State) {
1126 auto *StatusOrLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
1127 if (!StatusOrLoc)
1128 return;
1129 State.Env.setValue(*Expr, State.Env.create<PointerValue>(
1130 StatusOrLoc->getSyntheticField("value")));
1131}
1132
1135 LatticeTransferState &State) {
1136 auto *StatusOrLoc = getImplicitObjectLocation(*Expr, State.Env);
1137
1138 if (StatusOrLoc && State.Env.getStorageLocation(*Expr) == nullptr)
1139 State.Env.setStorageLocation(*Expr,
1140 StatusOrLoc->getSyntheticField("value"));
1141}
1142
1145 LatticeTransferState &State) {
1146 PointerValue *PointerVal =
1147 dyn_cast_or_null<PointerValue>(State.Env.getValue(*Expr));
1148 if (!PointerVal) {
1149 PointerVal = cast<PointerValue>(State.Env.createValue(Expr->getType()));
1150 State.Env.setValue(*Expr, *PointerVal);
1151 }
1152
1153 auto *RecordLoc =
1154 dyn_cast_or_null<RecordStorageLocation>(&PointerVal->getPointeeLoc());
1155 if (RecordLoc != nullptr &&
1156 State.Env.getValue(locForOk(locForStatus(*RecordLoc))) == nullptr)
1157 initializeStatusOr(*RecordLoc, State.Env);
1158}
1159
1162 LatticeTransferState &State) {
1163 PointerValue *PointerVal =
1164 dyn_cast_or_null<PointerValue>(State.Env.getValue(*Expr));
1165 if (!PointerVal) {
1166 PointerVal = cast<PointerValue>(State.Env.createValue(Expr->getType()));
1167 State.Env.setValue(*Expr, *PointerVal);
1168 }
1169
1170 auto *RecordLoc =
1171 dyn_cast_or_null<RecordStorageLocation>(&PointerVal->getPointeeLoc());
1172 if (RecordLoc != nullptr &&
1173 State.Env.getValue(locForOk(*RecordLoc)) == nullptr)
1174 initializeStatus(*RecordLoc, State.Env);
1175}
1176
1177static RecordStorageLocation *
1179 if (!E.isPRValue())
1180 return dyn_cast_or_null<RecordStorageLocation>(Env.getStorageLocation(E));
1181 if (auto *PointerVal = dyn_cast_or_null<PointerValue>(Env.getValue(E)))
1182 return dyn_cast_or_null<RecordStorageLocation>(
1183 &PointerVal->getPointeeLoc());
1184 return nullptr;
1185}
1188 LatticeTransferState &State) {
1189 assert(Expr->getNumArgs() > 0);
1190
1191 auto *StatusAdaptorLoc =
1192 State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
1193 if (StatusAdaptorLoc == nullptr)
1194 return;
1195
1196 copyRecord(*StatusAdaptorLoc,
1197 locForStatus(State.Env.getResultObjectLocation(*Expr)), State.Env);
1198}
1199
1202 LatticeTransferState &State) {
1203 RecordStorageLocation *StatusAdaptorLoc =
1204 getImplicitObjectLocation(*Expr, State.Env);
1205 if (StatusAdaptorLoc == nullptr)
1206 return;
1207
1208 auto &OkVal = valForOk(locForStatus(*StatusAdaptorLoc), State.Env);
1209 State.Env.setValue(*Expr, OkVal);
1210}
1211
1215 using namespace ::clang::ast_matchers;
1216 return std::move(Builder)
1217 .CaseOfCFGStmt<CallExpr>(
1220 .CaseOfCFGStmt<CallExpr>(isStatusIsOkMatcherCall(),
1222 .CaseOfCFGStmt<CallExpr>(
1225 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1228 LatticeTransferState &State) {
1230 /*IsStatusOr=*/true);
1231 })
1232 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1235 LatticeTransferState &State) {
1237 /*IsStatusOr=*/false);
1238 })
1239 .CaseOfCFGStmt<CXXConstructExpr>(
1244 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("ok"),
1246 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("status"),
1248 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusMemberCallWithName("ok"),
1250 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusMemberCallWithName("Update"),
1252 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1255 LatticeTransferState &State) {
1257 /*IsNegative=*/false);
1258 })
1259 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1262 LatticeTransferState &State) {
1264 /*IsNegative=*/true);
1265 })
1266 .CaseOfCFGStmt<BinaryOperator>(
1268 [](const BinaryOperator *Expr, const MatchFinder::MatchResult &,
1269 LatticeTransferState &State) {
1271 /*IsNegative=*/false);
1272 })
1273 .CaseOfCFGStmt<BinaryOperator>(
1275 [](const BinaryOperator *Expr, const MatchFinder::MatchResult &,
1276 LatticeTransferState &State) {
1278 /*IsNegative=*/true);
1279 })
1280 .CaseOfCFGStmt<CallExpr>(isOkStatusCall(), transferOkStatusCall)
1282 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("emplace"),
1286 .CaseOfCFGStmt<CXXConstructExpr>(isStatusOrValueConstructor(),
1290 .CaseOfCFGStmt<CXXOperatorCallExpr>(isStatusOrOperatorCallWithName("*"),
1292 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("value"),
1294 .CaseOfCFGStmt<CallExpr>(isAsStatusCallWithStatus(),
1296 .CaseOfCFGStmt<CallExpr>(isAsStatusCallWithStatusOr(),
1298 .CaseOfCFGStmt<CallExpr>(isLoggingGetReferenceableValueCall(),
1300 .CaseOfCFGStmt<CallExpr>(isLoggingCheckEqImpl(),
1302 // This needs to go before the const accessor call matcher, because these
1303 // look like them, but we model `operator`* and `get` to return the same
1304 // object. Also, we model them for non-const cases.
1305 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1307 [](const CXXOperatorCallExpr *E,
1309 LatticeTransferState &State) {
1311 E, getSmartPtrLikeStorageLocation(*E->getArg(0), State.Env),
1312 State, [](StorageLocation &Loc) {});
1313 })
1314 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1316 [](const CXXOperatorCallExpr *E,
1318 LatticeTransferState &State) {
1320 E, getSmartPtrLikeStorageLocation(*E->getArg(0), State.Env),
1321 State, [](StorageLocation &Loc) {});
1322 })
1323 .CaseOfCFGStmt<CXXMemberCallExpr>(
1326 LatticeTransferState &State) {
1328 E, getImplicitObjectLocation(*E, State.Env), State,
1329 [](StorageLocation &Loc) {});
1330 })
1331 .CaseOfCFGStmt<CXXMemberCallExpr>(
1334 LatticeTransferState &State) {
1336 E, getImplicitObjectLocation(*E, State.Env), State,
1337 [](StorageLocation &Loc) {});
1338 })
1339 // const accessor calls
1340 .CaseOfCFGStmt<CXXMemberCallExpr>(isConstAccessorMemberCall(),
1342 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1345 .CaseOfCFGStmt<CXXMemberCallExpr>(isConstPointerAccessorMemberCall(),
1347 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1350 // non-const member calls that may modify the state of an object.
1351 .CaseOfCFGStmt<CXXMemberCallExpr>(isNonConstMemberCall(),
1355 // N.B. this has to be after transferConstMemberCall, otherwise we would
1356 // always return a fresh RecordStorageLocation for the StatusOr.
1357 .CaseOfCFGStmt<CallExpr>(isStatusOrReturningCall(),
1358 [](const CallExpr *Expr,
1360 LatticeTransferState &State) {
1362 })
1363 .CaseOfCFGStmt<CallExpr>(isStatusOrPtrReturningCall(),
1365 .CaseOfCFGStmt<CallExpr>(isStatusPtrReturningCall(),
1367 // N.B. These need to come after all other CXXConstructExpr.
1368 // These are there to make sure that every Status and StatusOr object
1369 // have their ok boolean initialized when constructed. If we were to
1370 // lazily initialize them when we first access them, we can produce
1371 // false positives if that first access is in a control flow statement.
1372 // You can comment out these two constructors and see tests fail.
1373 .CaseOfCFGStmt<CXXConstructExpr>(isStatusOrConstructor(),
1375 .CaseOfCFGStmt<CXXConstructExpr>(isStatusConstructor(),
1377 .CaseOfCFGStmt<ImplicitCastExpr>(
1378 implicitCastExpr(hasCastKind(CK_PointerToBoolean)),
1380 .CaseOfCFGStmt<clang::CXXMemberCallExpr>(
1383 .CaseOfCFGStmt<clang::CallExpr>(isMacroAdaptorCall(),
1385 .Build();
1386}
1387
1389 for (Type *Ty : Ctx.getTypes())
1390 if (isStatusType(QualType(Ty, 0)))
1391 return QualType(Ty, 0);
1392
1393 return QualType();
1394}
1395
1397 Environment &Env)
1400 TransferMatchSwitch(buildTransferMatchSwitch(Ctx, {})) {
1401 QualType StatusType = findStatusType(Ctx);
1402 Env.getDataflowAnalysisContext().setSyntheticFieldCallback(
1403 [StatusType](QualType Ty) -> llvm::StringMap<QualType> {
1405 if (RD == nullptr)
1406 return {};
1407
1408 if (auto Fields = getSyntheticFields(Ty, StatusType, *RD);
1409 !Fields.empty())
1410 return Fields;
1411 return {};
1412 });
1413}
1414
1416 Environment &Env) {
1417 LatticeTransferState State(L, Env);
1418 TransferMatchSwitch(Elt, getASTContext(), State);
1419}
1420
1421} // 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:1552
Represents a call to a member function that may be written either with member call syntax (e....
Definition ExprCXX.h:183
SourceLocation getExprLoc() const LLVM_READONLY
Definition ExprCXX.h:224
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:2122
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:547
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:2018
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:1875
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:8677
bool isReferenceType() const
Definition TypeBase.h:8701
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:790
bool isRecordType() const
Definition TypeBase.h:8804
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)
static void transferMacroAdaptorCall(const clang::CallExpr *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 bool IsMacroAdaptorType(clang::QualType type)
static void transferConstAccessorMemberOperatorCall(const CXXOperatorCallExpr *Expr, const MatchFinder::MatchResult &Result, LatticeTransferState &State)
CFGMatchSwitch< LatticeTransferState > buildTransferMatchSwitch(ASTContext &Ctx, CFGMatchSwitchBuilder< LatticeTransferState > Builder)
static void transferReturnIfErrorAdaptorOperatorBoolCall(const clang::CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &, 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.