clang 24.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
35#include "GtestModelHelpers.h"
36
38namespace {
39
40using ::clang::ast_matchers::MatchFinder;
42
43} // namespace
44
45static bool namespaceEquals(const NamespaceDecl *NS,
46 clang::ArrayRef<clang::StringRef> NamespaceNames) {
47 while (!NamespaceNames.empty() && NS) {
48 if (NS->getName() != NamespaceNames.consume_back())
49 return false;
50 NS = dyn_cast_or_null<NamespaceDecl>(NS->getParent());
51 }
52 return NamespaceNames.empty() && !NS;
53}
54
55// TODO: move this to a proper place to share with the rest of clang
57 StringRef Name) {
58 if (Type.isNull())
59 return false;
60 if (auto *RD = Type->getAsRecordDecl())
61 if (RD->getName() == Name)
62 if (const auto *N = dyn_cast_or_null<NamespaceDecl>(RD->getDeclContext()))
63 return namespaceEquals(N, NS);
64 return false;
65}
66
68 return isTypeNamed(Type, {"absl", "internal_statusor"}, "OperatorBase");
69}
70
71static bool isSafeUnwrap(RecordStorageLocation *StatusOrLoc,
72 const Environment &Env) {
73 if (!StatusOrLoc)
74 return false;
75 auto &StatusLoc = locForStatus(*StatusOrLoc);
76 auto *OkVal = Env.get<BoolValue>(locForOk(StatusLoc));
77 return OkVal != nullptr && Env.proves(OkVal->formula());
78}
79
82 auto *RD = Ty->getAsCXXRecordDecl();
83 if (RD == nullptr)
84 return nullptr;
85 if (isStatusOrType(Ty) ||
86 // In case we are analyzing code under OperatorBase itself that uses
87 // operator* (e.g. to implement operator->).
90 if (!RD->hasDefinition())
91 return nullptr;
92 for (const auto &Base : RD->bases())
93 if (auto *QT = getStatusOrBaseClass(Base.getType()))
94 return QT;
95 return nullptr;
96}
97
101
102static auto ofClassStatus() {
103 using namespace ::clang::ast_matchers;
104 return ofClass(hasName("::absl::Status"));
105}
106
107static auto isStatusMemberCallWithName(llvm::StringRef member_name) {
108 using namespace ::clang::ast_matchers;
109 return cxxMemberCallExpr(
110 on(expr(unless(cxxThisExpr()))),
111 callee(cxxMethodDecl(hasName(member_name), ofClassStatus())));
112}
113
114static auto isStatusOrMemberCallWithName(llvm::StringRef member_name) {
115 using namespace ::clang::ast_matchers;
116 return cxxMemberCallExpr(
117 on(expr(unless(cxxThisExpr()))),
118 callee(cxxMethodDecl(
119 hasName(member_name),
121}
122
123static auto isStatusOrOperatorCallWithName(llvm::StringRef operator_name) {
124 using namespace ::clang::ast_matchers;
125 return cxxOperatorCallExpr(
126 hasOverloadedOperatorName(operator_name),
127 callee(cxxMethodDecl(
129}
130
131static auto valueCall() {
132 using namespace ::clang::ast_matchers;
133 return anyOf(isStatusOrMemberCallWithName("value"),
134 isStatusOrMemberCallWithName("ValueOrDie"));
135}
136
137static auto valueOperatorCall() {
138 using namespace ::clang::ast_matchers;
141}
142
143static auto isComparisonOperatorCall(llvm::StringRef operator_name) {
144 using namespace ::clang::ast_matchers;
145 return cxxOperatorCallExpr(
146 hasOverloadedOperatorName(operator_name), argumentCountIs(2),
147 hasArgument(0, anyOf(hasType(statusType()), hasType(statusOrType()))),
148 hasArgument(1, anyOf(hasType(statusType()), hasType(statusOrType()))));
149}
150
151static auto isOkStatusCall() {
152 using namespace ::clang::ast_matchers;
153 return callExpr(callee(functionDecl(hasName("::absl::OkStatus"))));
154}
155
156static auto isNotOkStatusCall() {
157 using namespace ::clang::ast_matchers;
158 return callExpr(callee(functionDecl(hasAnyName(
159 "::absl::AbortedError", "::absl::AlreadyExistsError",
160 "::absl::CancelledError", "::absl::DataLossError",
161 "::absl::DeadlineExceededError", "::absl::FailedPreconditionError",
162 "::absl::InternalError", "::absl::InvalidArgumentError",
163 "::absl::NotFoundError", "::absl::OutOfRangeError",
164 "::absl::PermissionDeniedError", "::absl::ResourceExhaustedError",
165 "::absl::UnauthenticatedError", "::absl::UnavailableError",
166 "::absl::UnimplementedError", "::absl::UnknownError"))));
167}
168
169static auto isPointerComparisonOperatorCall(std::string operator_name) {
170 using namespace ::clang::ast_matchers;
171 return binaryOperator(hasOperatorName(operator_name),
172 hasLHS(hasType(hasCanonicalType(pointerType(
173 pointee(anyOf(statusOrType(), statusType())))))),
174 hasRHS(hasType(hasCanonicalType(pointerType(
175 pointee(anyOf(statusOrType(), statusType())))))));
176}
177
178// The nullPointerConstant in the two matchers below is to support
179// absl::StatusOr<void*> X = nullptr.
180// nullptr does not match the bound type.
181// TODO: be less restrictive around convertible types in general.
183 using namespace ::clang::ast_matchers;
184 return cxxOperatorCallExpr(
186 callee(cxxMethodDecl(ofClass(statusOrClass()))),
187 hasArgument(1, anyOf(hasType(hasUnqualifiedDesugaredType(
188 type(equalsBoundNode("T")))),
189 nullPointerConstant())));
190}
191
193 using namespace ::clang::ast_matchers;
194 return cxxConstructExpr(
195 hasType(statusOrType()),
196 hasArgument(0,
197 anyOf(hasType(hasCanonicalType(type(equalsBoundNode("T")))),
198 nullPointerConstant(),
199 hasType(namedDecl(hasAnyName("absl::in_place_t",
200 "std::in_place_t"))))));
201}
202
204 using namespace ::clang::ast_matchers;
205 return cxxConstructExpr(hasType(statusOrType()));
206}
207
208static auto isStatusConstructor() {
209 using namespace ::clang::ast_matchers;
210 return cxxConstructExpr(hasType(statusType()));
211}
213 using namespace ::clang::ast_matchers;
214 return callExpr(callee(
215 functionDecl(hasName("::absl::log_internal::GetReferenceableValue"))));
216}
217
218static auto isLoggingCheckEqImpl() {
219 using namespace ::clang::ast_matchers;
220 return callExpr(
221 callee(functionDecl(hasName("::absl::log_internal::Check_EQImpl"))));
222}
223
225 using namespace ::clang::ast_matchers;
226 return callExpr(
227 callee(functionDecl(hasName("::absl::log_internal::AsStatus"))),
228 hasArgument(0, hasType(statusClass())));
229}
230
232 using namespace ::clang::ast_matchers;
233 return callExpr(
234 callee(functionDecl(hasName("::absl::log_internal::AsStatus"))),
235 hasArgument(0, hasType(statusOrType())));
236}
237
239 using namespace ::clang::ast_matchers;
240 return anyOf(statusOrType(), referenceType(pointee(statusOrType())));
241}
242
244 using namespace ::clang::ast_matchers;
245 return cxxMemberCallExpr(callee(cxxMethodDecl(
246 parameterCountIs(0), isConst(),
247 returns(hasCanonicalType(anyOf(referenceType(), recordType()))))));
248}
249
251 using namespace ::clang::ast_matchers;
253 parameterCountIs(0), isConst(),
254 returns(hasCanonicalType(anyOf(referenceType(), recordType()))))));
255}
256
258 using namespace ::clang::ast_matchers;
259 return cxxMemberCallExpr(callee(
260 cxxMethodDecl(parameterCountIs(0), isConst(), returns(pointerType()))));
261}
262
264 using namespace ::clang::ast_matchers;
265 return cxxOperatorCallExpr(callee(
266 cxxMethodDecl(parameterCountIs(0), isConst(), returns(pointerType()))));
267}
268
269static auto isNonConstMemberCall() {
270 using namespace ::clang::ast_matchers;
271 return cxxMemberCallExpr(callee(cxxMethodDecl(unless(isConst()))));
272}
273
275 using namespace ::clang::ast_matchers;
276 return cxxOperatorCallExpr(callee(cxxMethodDecl(unless(isConst()))));
277}
278
280 using namespace ::clang::ast_matchers;
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;
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;
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;
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;
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;
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;
344 return cxxConstructExpr(
345 hasType(recordDecl(hasName("testing::AssertionResult"))),
346 hasArgument(0, hasType(booleanType())));
347}
348
350 using namespace ::clang::ast_matchers;
351 return callExpr(
352 callee(functionDecl(returns(possiblyReferencedStatusOrType()))));
353}
354
356 using namespace ::clang::ast_matchers;
357 return callExpr(callee(functionDecl(returns(hasUnqualifiedDesugaredType(
359}
360
362 using namespace ::clang::ast_matchers;
363 return callExpr(callee(functionDecl(returns(hasUnqualifiedDesugaredType(
364 pointerType(pointee(hasUnqualifiedDesugaredType(
366}
367
369 using namespace ::clang::ast_matchers;
370 return ofClass(
371 hasName("::absl::status_macro_internal::ReturnIfErrorAdaptor"));
372}
373
375 using namespace ::clang::ast_matchers;
376 return cxxRecordDecl(
377 hasName("::absl::status_macro_internal::ReturnIfErrorAdaptor"));
378}
379
381 using namespace ::clang::ast_matchers;
382 return hasUnqualifiedDesugaredType(
384}
385
387 using namespace ::clang::ast_matchers;
388 return cxxMemberCallExpr(
389 on(expr(unless(cxxThisExpr()))),
390 callee(cxxMethodDecl(hasName("operator bool"),
392}
393
394static auto isMacroAdaptorCall() {
395 using namespace ::clang::ast_matchers;
396 return callExpr(callee(
397 functionDecl(hasName("::absl::status_macro_internal::MacroAdaptor"),
398 returns(returnIfErrorAdaptorType()))));
399}
400
401static auto
405 // StatusOr::value, StatusOr::ValueOrDie
406 .CaseOfCFGStmt<CXXMemberCallExpr>(
407 valueCall(),
408 [](const CXXMemberCallExpr *E,
410 const Environment &Env) {
411 if (!isSafeUnwrap(getImplicitObjectLocation(*E, Env), Env))
414 })
415
416 // StatusOr::operator*, StatusOr::operator->
417 .CaseOfCFGStmt<CXXOperatorCallExpr>(
419 [](const CXXOperatorCallExpr *E,
421 const Environment &Env) {
422 RecordStorageLocation *StatusOrLoc =
423 Env.get<RecordStorageLocation>(*E->getArg(0));
424 if (!isSafeUnwrap(StatusOrLoc, Env))
425 return llvm::SmallVector<SourceLocation>({E->getOperatorLoc()});
427 })
428 .Build();
429}
430
434
441
443 Environment &Env) {
444 auto &OkVal = Env.makeAtomicBoolValue();
445 Env.setValue(locForOk(StatusLoc), OkVal);
446 return OkVal;
447}
448
450 Environment &Env) {
451 return initializeStatus(locForStatus(StatusOrLoc), Env);
452}
453
455 using namespace ::clang::ast_matchers;
457 hasName("absl::StatusOr"),
458 hasTemplateArgument(0, refersToType(type().bind("T"))));
459}
460
462 using namespace ::clang::ast_matchers;
463 return cxxRecordDecl(hasName("absl::Status"));
464}
465
467 using namespace ::clang::ast_matchers;
469 hasName("absl::internal_statusor::OperatorBase"));
470}
471
473 using namespace ::clang::ast_matchers;
474 return hasCanonicalType(qualType(hasDeclaration(statusOrClass())));
475}
476
478 using namespace ::clang::ast_matchers;
479 return hasCanonicalType(qualType(hasDeclaration(statusClass())));
480}
481
483 return isTypeNamed(Type, {"absl"}, "StatusOr");
484}
485
487 return isTypeNamed(Type, {"absl"}, "Status");
488}
489
491 return isTypeNamed(Type, {"testing", "internal"},
492 "PredicateFormatterFromMatcher");
493}
494
496 return isTypeNamed(Type, {"testing"}, "AssertionResult");
497}
498
500 return isTypeNamed(Type, {"testing", "status", "internal_status"},
501 "StatusIsMatcher") ||
502 isTypeNamed(Type, {"testing", "status", "internal_status"},
503 "CanonicalStatusIsMatcher") ||
504 isTypeNamed(Type, {"absl_testing", "status_internal"},
505 "StatusIsMatcher") ||
506 isTypeNamed(Type, {"absl_testing", "status_internal"},
507 "CanonicalStatusIsMatcher");
508}
509
511 return isTypeNamed(type, {"absl", "status_macro_internal"},
512 "ReturnIfErrorAdaptor");
513}
514
515llvm::StringMap<QualType> getSyntheticFields(QualType Ty, QualType StatusType,
516 const CXXRecordDecl &RD) {
517 if (auto *TRD = getStatusOrBaseClass(Ty))
518 return {{"status", StatusType}, {"value", getStatusOrValueType(TRD)}};
519 if (isStatusType(Ty) || (RD.hasDefinition() &&
520 RD.isDerivedFrom(StatusType->getAsCXXRecordDecl())))
521 return {{"ok", RD.getASTContext().BoolTy}};
522 if (isAssertionResultType(Ty))
523 return {{"ok", RD.getASTContext().BoolTy}};
525 return {{"ok_predicate", RD.getASTContext().BoolTy}};
526 if (isStatusIsMatcherType(Ty))
527 return {{"ok_matcher", RD.getASTContext().BoolTy}};
528 if (IsMacroAdaptorType(Ty))
529 return {{"status", StatusType}};
530 return {};
531}
532
536
538 return StatusLoc.getSyntheticField("ok");
539}
540
542 if (auto *Val = Env.get<BoolValue>(locForOk(StatusLoc)))
543 return *Val;
544 return initializeStatus(StatusLoc, Env);
545}
547 return StatusLoc.getSyntheticField("ok_predicate");
548}
549
551 return StatusLoc.getSyntheticField("ok_matcher");
552}
553
556 LatticeTransferState &State) {
557 RecordStorageLocation *StatusOrLoc =
558 getImplicitObjectLocation(*Expr, State.Env);
559 if (StatusOrLoc == nullptr)
560 return;
561
562 auto &OkVal = valForOk(locForStatus(*StatusOrLoc), State.Env);
563 State.Env.setValue(*Expr, OkVal);
564}
565
568 LatticeTransferState &State) {
569 RecordStorageLocation *StatusOrLoc =
570 getImplicitObjectLocation(*Expr, State.Env);
571 if (StatusOrLoc == nullptr)
572 return;
573
574 RecordStorageLocation &StatusLoc = locForStatus(*StatusOrLoc);
575
576 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
577 initializeStatusOr(*StatusOrLoc, State.Env);
578
579 if (Expr->isPRValue())
580 copyRecord(StatusLoc, State.Env.getResultObjectLocation(*Expr), State.Env);
581 else
582 State.Env.setStorageLocation(*Expr, StatusLoc);
583}
584
587 LatticeTransferState &State) {
588 RecordStorageLocation *StatusLoc =
589 getImplicitObjectLocation(*Expr, State.Env);
590 if (StatusLoc == nullptr)
591 return;
592
593 if (Value *Val = State.Env.getValue(locForOk(*StatusLoc)))
594 State.Env.setValue(*Expr, *Val);
595}
596
599 LatticeTransferState &State) {
600 // S.Update(OtherS) sets S to the error code of OtherS if it is OK,
601 // otherwise does nothing.
602 assert(Expr->getNumArgs() == 1);
603 auto *Arg = Expr->getArg(0);
604 RecordStorageLocation *ArgRecord =
605 Arg->isPRValue() ? &State.Env.getResultObjectLocation(*Arg)
606 : State.Env.get<RecordStorageLocation>(*Arg);
608 if (ThisLoc == nullptr || ArgRecord == nullptr)
609 return;
610
611 auto &ThisOkVal = valForOk(*ThisLoc, State.Env);
612 auto &ArgOkVal = valForOk(*ArgRecord, State.Env);
613 auto &A = State.Env.arena();
614 auto &NewVal = State.Env.makeAtomicBoolValue();
615 State.Env.assume(A.makeImplies(A.makeNot(ThisOkVal.formula()),
616 A.makeNot(NewVal.formula())));
617 State.Env.assume(A.makeImplies(NewVal.formula(), ArgOkVal.formula()));
618 State.Env.setValue(locForOk(*ThisLoc), NewVal);
619}
620
622 RecordStorageLocation &RhsStatusLoc,
623 Environment &Env) {
624 auto &A = Env.arena();
625 // Logically, a Status object is composed of an error code that could take one
626 // of multiple possible values, including the "ok" value. We track whether a
627 // Status object has an "ok" value and represent this as an `ok` bit. Equality
628 // of Status objects compares their error codes. Therefore, merely comparing
629 // the `ok` bits isn't sufficient: when two Status objects are assigned non-ok
630 // error codes the equality of their respective error codes matters. Since we
631 // only track the `ok` bits, we can't make any conclusions about equality when
632 // we know that two Status objects have non-ok values.
633
634 auto &LhsOkVal = valForOk(LhsStatusLoc, Env);
635 auto &RhsOkVal = valForOk(RhsStatusLoc, Env);
636
637 auto &Res = Env.makeAtomicBoolValue();
638
639 // lhs && rhs => res (a.k.a. !res => !lhs || !rhs)
640 Env.assume(A.makeImplies(A.makeAnd(LhsOkVal.formula(), RhsOkVal.formula()),
641 Res.formula()));
642 // res => (lhs == rhs)
643 Env.assume(A.makeImplies(
644 Res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
645
646 return &Res;
647}
648
649static BoolValue *
651 RecordStorageLocation &RhsStatusOrLoc,
652 Environment &Env) {
653 auto &A = Env.arena();
654 // Logically, a StatusOr<T> object is composed of two values - a Status and a
655 // value of type T. Equality of StatusOr objects compares both values.
656 // Therefore, merely comparing the `ok` bits of the Status values isn't
657 // sufficient. When two StatusOr objects are engaged, the equality of their
658 // respective values of type T matters. Similarly, when two StatusOr objects
659 // have Status values that have non-ok error codes, the equality of the error
660 // codes matters. Since we only track the `ok` bits of the Status values, we
661 // can't make any conclusions about equality when we know that two StatusOr
662 // objects are engaged or when their Status values contain non-ok error codes.
663 auto &LhsOkVal = valForOk(locForStatus(LhsStatusOrLoc), Env);
664 auto &RhsOkVal = valForOk(locForStatus(RhsStatusOrLoc), Env);
665 auto &res = Env.makeAtomicBoolValue();
666
667 // res => (lhs == rhs)
668 Env.assume(A.makeImplies(
669 res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
670 return &res;
671}
672
673static BoolValue *evaluateEquality(const Expr *LhsExpr, const Expr *RhsExpr,
674 Environment &Env) {
675 // Check the type of both sides in case an operator== is added that admits
676 // different types.
677 if (isStatusOrType(LhsExpr->getType()) &&
678 isStatusOrType(RhsExpr->getType())) {
679 auto *LhsStatusOrLoc = Env.get<RecordStorageLocation>(*LhsExpr);
680 if (LhsStatusOrLoc == nullptr)
681 return nullptr;
682 auto *RhsStatusOrLoc = Env.get<RecordStorageLocation>(*RhsExpr);
683 if (RhsStatusOrLoc == nullptr)
684 return nullptr;
685
686 return evaluateStatusOrEquality(*LhsStatusOrLoc, *RhsStatusOrLoc, Env);
687 }
688 if (isStatusType(LhsExpr->getType()) && isStatusType(RhsExpr->getType())) {
689 auto *LhsStatusLoc = Env.get<RecordStorageLocation>(*LhsExpr);
690 if (LhsStatusLoc == nullptr)
691 return nullptr;
692
693 auto *RhsStatusLoc = Env.get<RecordStorageLocation>(*RhsExpr);
694 if (RhsStatusLoc == nullptr)
695 return nullptr;
696
697 return evaluateStatusEquality(*LhsStatusLoc, *RhsStatusLoc, Env);
698 }
699 return nullptr;
700}
701
704 bool IsNegative) {
705 auto *LhsAndRhsVal =
706 evaluateEquality(Expr->getArg(0), Expr->getArg(1), State.Env);
707 if (LhsAndRhsVal == nullptr)
708 return;
709
710 if (IsNegative)
711 State.Env.setValue(*Expr, State.Env.makeNot(*LhsAndRhsVal));
712 else
713 State.Env.setValue(*Expr, *LhsAndRhsVal);
714}
715
717 Environment &Env) {
718 if (auto *PointerVal = Env.get<PointerValue>(Expr))
719 return dyn_cast<RecordStorageLocation>(&PointerVal->getPointeeLoc());
720 return nullptr;
721}
722
724 const Expr *RhsExpr,
725 Environment &Env) {
726 assert(LhsExpr->getType()->isPointerType());
727 assert(RhsExpr->getType()->isPointerType());
728 RecordStorageLocation *LhsStatusLoc = nullptr;
729 RecordStorageLocation *RhsStatusLoc = nullptr;
730 if (isStatusOrType(LhsExpr->getType()->getPointeeType()) &&
731 isStatusOrType(RhsExpr->getType()->getPointeeType())) {
732 auto *LhsStatusOrLoc = getPointeeLocation(*LhsExpr, Env);
733 auto *RhsStatusOrLoc = getPointeeLocation(*RhsExpr, Env);
734 if (LhsStatusOrLoc == nullptr || RhsStatusOrLoc == nullptr)
735 return nullptr;
736 LhsStatusLoc = &locForStatus(*LhsStatusOrLoc);
737 RhsStatusLoc = &locForStatus(*RhsStatusOrLoc);
738 } else if (isStatusType(LhsExpr->getType()->getPointeeType()) &&
739 isStatusType(RhsExpr->getType()->getPointeeType())) {
740 LhsStatusLoc = getPointeeLocation(*LhsExpr, Env);
741 RhsStatusLoc = getPointeeLocation(*RhsExpr, Env);
742 }
743 if (LhsStatusLoc == nullptr || RhsStatusLoc == nullptr)
744 return nullptr;
745 auto &LhsOkVal = valForOk(*LhsStatusLoc, Env);
746 auto &RhsOkVal = valForOk(*RhsStatusLoc, Env);
747 auto &Res = Env.makeAtomicBoolValue();
748 auto &A = Env.arena();
749 Env.assume(A.makeImplies(
750 Res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
751 return &Res;
752}
753
756 bool IsNegative) {
757 auto *LhsAndRhsVal =
758 evaluatePointerEquality(Expr->getLHS(), Expr->getRHS(), State.Env);
759 if (LhsAndRhsVal == nullptr)
760 return;
761
762 if (IsNegative)
763 State.Env.setValue(*Expr, State.Env.makeNot(*LhsAndRhsVal));
764 else
765 State.Env.setValue(*Expr, *LhsAndRhsVal);
766}
767
770 LatticeTransferState &State) {
771 auto &OkVal =
772 initializeStatus(State.Env.getResultObjectLocation(*Expr), State.Env);
773 State.Env.assume(OkVal.formula());
774}
775
778 LatticeTransferState &State) {
779 auto &OkVal =
780 initializeStatus(State.Env.getResultObjectLocation(*Expr), State.Env);
781 auto &A = State.Env.arena();
782 State.Env.assume(A.makeNot(OkVal.formula()));
783}
784
787 LatticeTransferState &State) {
788 RecordStorageLocation *StatusOrLoc =
789 getImplicitObjectLocation(*Expr, State.Env);
790 if (StatusOrLoc == nullptr)
791 return;
792
793 auto &OkVal = valForOk(locForStatus(*StatusOrLoc), State.Env);
794 State.Env.assume(OkVal.formula());
795}
796
799 LatticeTransferState &State) {
800 assert(Expr->getNumArgs() > 1);
801
802 auto *StatusOrLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
803 if (StatusOrLoc == nullptr)
804 return;
805
806 auto &OkVal = initializeStatusOr(*StatusOrLoc, State.Env);
807 State.Env.assume(OkVal.formula());
808}
809
812 LatticeTransferState &State) {
813 auto &OkVal =
814 initializeStatusOr(State.Env.getResultObjectLocation(*Expr), State.Env);
815 State.Env.assume(OkVal.formula());
816}
817
820 LatticeTransferState &State) {
821 RecordStorageLocation &StatusOrLoc = State.Env.getResultObjectLocation(*Expr);
822 RecordStorageLocation &StatusLoc = locForStatus(StatusOrLoc);
823
824 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
825 initializeStatusOr(StatusOrLoc, State.Env);
826}
827
830 LatticeTransferState &State) {
831 RecordStorageLocation &StatusLoc = State.Env.getResultObjectLocation(*Expr);
832
833 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
834 initializeStatus(StatusLoc, State.Env);
835}
836static void
839 LatticeTransferState &State) {
840 assert(Expr->getNumArgs() == 1);
841 if (Expr->getArg(0)->isPRValue())
842 return;
843 auto *ArgLoc = State.Env.getStorageLocation(*Expr->getArg(0));
844 if (ArgLoc == nullptr)
845 return;
846
847 State.Env.setStorageLocation(*Expr, *ArgLoc);
848}
849
852 LatticeTransferState &State) {
853 assert(Expr->getNumArgs() > 2);
854
855 auto *EqVal = evaluateEquality(Expr->getArg(0), Expr->getArg(1), State.Env);
856 if (EqVal == nullptr)
857 return;
858
859 // Consider modelling this more accurately instead of assigning BoolValue
860 // as the value of an expression of pointer type.
861 // For now, this is being handled in transferPointerToBoolean.
862 State.Env.setValue(*Expr, State.Env.makeNot(*EqVal));
863}
864
867 LatticeTransferState &State) {
868 assert(Expr->getNumArgs() == 1);
869
870 auto *ArgLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
871 if (ArgLoc == nullptr)
872 return;
873
874 if (State.Env.getValue(locForOk(*ArgLoc)) == nullptr)
875 initializeStatus(*ArgLoc, State.Env);
876
877 auto &ExprVal = State.Env.create<PointerValue>(*ArgLoc);
878 State.Env.setValue(*Expr, ExprVal);
879}
880
883 LatticeTransferState &State) {
884 assert(Expr->getNumArgs() == 1);
885
886 auto *ArgLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
887 if (ArgLoc == nullptr)
888 return;
889
890 RecordStorageLocation &StatusLoc = locForStatus(*ArgLoc);
891
892 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
893 initializeStatusOr(*ArgLoc, State.Env);
894
895 auto &ExprVal = State.Env.create<PointerValue>(StatusLoc);
896 State.Env.setValue(*Expr, ExprVal);
897}
898
901 LatticeTransferState &State) {
902 if (auto *SubExprVal =
903 dyn_cast_or_null<BoolValue>(State.Env.getValue(*Expr->getSubExpr())))
904 State.Env.setValue(*Expr, *SubExprVal);
905}
906
908 LatticeTransferState &State) {
909 RecordStorageLocation *StatusOrLoc =
910 Expr->isPRValue() ? &State.Env.getResultObjectLocation(*Expr)
911 : State.Env.get<RecordStorageLocation>(*Expr);
912 if (StatusOrLoc != nullptr &&
913 State.Env.getValue(locForOk(locForStatus(*StatusOrLoc))) == nullptr)
914 initializeStatusOr(*StatusOrLoc, State.Env);
915}
916
920 if (RecordLoc == nullptr)
921 return false;
922 const FunctionDecl *DirectCallee = Expr->getDirectCallee();
923 if (DirectCallee == nullptr)
924 return false;
925 StorageLocation &Loc =
926 State.Lattice.getOrCreateConstMethodReturnStorageLocation(
927 *RecordLoc, DirectCallee, State.Env, [&](StorageLocation &Loc) {
928 if (isStatusOrType(Expr->getType()))
929 initializeStatusOr(cast<RecordStorageLocation>(Loc), State.Env);
930 });
931 if (Expr->isPRValue()) {
932 auto &ResultLoc = State.Env.getResultObjectLocation(*Expr);
933 copyRecord(cast<RecordStorageLocation>(Loc), ResultLoc, State.Env);
934 } else {
935 State.Env.setStorageLocation(*Expr, Loc);
936 }
937 return true;
938}
939
950 if (RecordLoc == nullptr)
951 return;
952 auto *Val = State.Lattice.getOrCreateConstMethodReturnValue(*RecordLoc, Expr,
953 State.Env);
954 State.Env.setValue(*Expr, *Val);
955}
956
957static void
967
968static void
971 LatticeTransferState &State) {
972 auto Type = Expr->getArg(0)->getType();
973 if (!Type->isRecordType() && !Type->isReferenceType())
974 return;
975 auto *RecordLoc = cast_or_null<RecordStorageLocation>(
976 State.Env.getStorageLocation(*Expr->getArg(0)));
978}
979
980static void
987
990 LatticeTransferState &State) {
991 auto *RecordLoc = cast_or_null<RecordStorageLocation>(
992 State.Env.getStorageLocation(*Expr->getArg(0)));
994}
995
999 LatticeTransferState &State) {
1000 if (RecordLoc) {
1001 State.Lattice.clearConstMethodReturnValues(*RecordLoc);
1002 State.Lattice.clearConstMethodReturnStorageLocations(*RecordLoc);
1003 }
1004 if (isStatusOrType(Expr->getType()))
1006}
1007
1014
1015static void
1018 LatticeTransferState &State) {
1019 auto *RecordLoc = cast_or_null<RecordStorageLocation>(
1020 State.Env.getStorageLocation(*Expr->getArg(0)));
1022}
1023
1025 const CallExpr *Expr, const MatchFinder::MatchResult &,
1026 LatticeTransferState &State) {
1027 State.Env.setValue(
1028 locForOkPredicate(State.Env.getResultObjectLocation(*Expr)),
1029 State.Env.getBoolLiteralValue(true));
1030}
1031
1034 LatticeTransferState &State) {
1035 BoolValue &OkMatcherVal = State.Env.getBoolLiteralValue(true);
1036 State.Env.setValue(locForOkMatcher(State.Env.getResultObjectLocation(*Expr)),
1037 OkMatcherVal);
1038}
1039
1041 const CallExpr *Expr, const MatchFinder::MatchResult &,
1042 LatticeTransferState &State) {
1043 assert(Expr->isPRValue());
1044 auto &Loc = State.Env.getResultObjectLocation(*Expr->getArg(0));
1045 auto &OkMatcherLoc = locForOkMatcher(Loc);
1046 BoolValue *OkMatcherVal = State.Env.get<BoolValue>(OkMatcherLoc);
1047 if (OkMatcherVal == nullptr)
1048 return;
1049 State.Env.setValue(
1050 locForOkPredicate(State.Env.getResultObjectLocation(*Expr)),
1051 *OkMatcherVal);
1052}
1053
1054static void
1056 LatticeTransferState &State,
1057 bool IsStatusOr) {
1058 auto *Loc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
1059 if (Loc == nullptr)
1060 return;
1061
1062 auto *ObjectLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(2));
1063 if (ObjectLoc == nullptr)
1064 return;
1065
1066 auto &OkPredicateLoc = locForOkPredicate(*Loc);
1067 BoolValue *OkPredicateVal = State.Env.get<BoolValue>(OkPredicateLoc);
1068 if (OkPredicateVal == nullptr)
1069 return;
1070
1071 if (IsStatusOr)
1072 ObjectLoc = &locForStatus(*ObjectLoc);
1073 auto &StatusOk = valForOk(*ObjectLoc, State.Env);
1074
1075 auto &A = State.Env.arena();
1076 auto &Res = State.Env.makeAtomicBoolValue();
1077 State.Env.assume(
1078 A.makeImplies(OkPredicateVal->formula(),
1079 A.makeEquals(StatusOk.formula(), Res.formula())));
1080 State.Env.setValue(locForOk(State.Env.getResultObjectLocation(*Expr)), Res);
1081}
1082
1083static void
1086 LatticeTransferState &State) {
1087 assert(Expr->getNumArgs() > 0);
1088
1089 auto *StatusAdaptorLoc = State.Env.get<StorageLocation>(*Expr->getArg(0));
1090 if (StatusAdaptorLoc == nullptr)
1091 return;
1092 BoolValue *OkVal = State.Env.get<BoolValue>(*StatusAdaptorLoc);
1093 if (OkVal == nullptr)
1094 return;
1095 State.Env.setValue(locForOk(State.Env.getResultObjectLocation(*Expr)),
1096 *OkVal);
1097}
1098
1099static void
1102 LatticeTransferState &State) {
1103 auto *RecordLoc = getImplicitObjectLocation(*Expr, State.Env);
1104 if (RecordLoc == nullptr)
1105 return;
1106 BoolValue *OkVal = State.Env.get<BoolValue>(locForOk(*RecordLoc));
1107 if (OkVal == nullptr)
1108 return;
1109 auto &A = State.Env.arena();
1110 auto &Res = State.Env.makeAtomicBoolValue();
1111 State.Env.assume(A.makeEquals(OkVal->formula(), Res.formula()));
1112 State.Env.setValue(*Expr, Res);
1113}
1114
1117 LatticeTransferState &State) {
1118 auto *StatusOrLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
1119
1120 if (StatusOrLoc && State.Env.getStorageLocation(*Expr) == nullptr)
1121 State.Env.setStorageLocation(*Expr,
1122 StatusOrLoc->getSyntheticField("value"));
1123}
1124
1127 LatticeTransferState &State) {
1128 auto *StatusOrLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
1129 if (!StatusOrLoc)
1130 return;
1131 State.Env.setValue(*Expr, State.Env.create<PointerValue>(
1132 StatusOrLoc->getSyntheticField("value")));
1133}
1134
1137 LatticeTransferState &State) {
1138 auto *StatusOrLoc = getImplicitObjectLocation(*Expr, State.Env);
1139
1140 if (StatusOrLoc && State.Env.getStorageLocation(*Expr) == nullptr)
1141 State.Env.setStorageLocation(*Expr,
1142 StatusOrLoc->getSyntheticField("value"));
1143}
1144
1147 LatticeTransferState &State) {
1148 PointerValue *PointerVal =
1149 dyn_cast_or_null<PointerValue>(State.Env.getValue(*Expr));
1150 if (!PointerVal) {
1151 PointerVal = cast<PointerValue>(State.Env.createValue(Expr->getType()));
1152 State.Env.setValue(*Expr, *PointerVal);
1153 }
1154
1155 auto *RecordLoc =
1156 dyn_cast_or_null<RecordStorageLocation>(&PointerVal->getPointeeLoc());
1157 if (RecordLoc != nullptr &&
1158 State.Env.getValue(locForOk(locForStatus(*RecordLoc))) == nullptr)
1159 initializeStatusOr(*RecordLoc, State.Env);
1160}
1161
1164 LatticeTransferState &State) {
1165 PointerValue *PointerVal =
1166 dyn_cast_or_null<PointerValue>(State.Env.getValue(*Expr));
1167 if (!PointerVal) {
1168 PointerVal = cast<PointerValue>(State.Env.createValue(Expr->getType()));
1169 State.Env.setValue(*Expr, *PointerVal);
1170 }
1171
1172 auto *RecordLoc =
1173 dyn_cast_or_null<RecordStorageLocation>(&PointerVal->getPointeeLoc());
1174 if (RecordLoc != nullptr &&
1175 State.Env.getValue(locForOk(*RecordLoc)) == nullptr)
1176 initializeStatus(*RecordLoc, State.Env);
1177}
1178
1179static RecordStorageLocation *
1181 if (!E.isPRValue())
1182 return dyn_cast_or_null<RecordStorageLocation>(Env.getStorageLocation(E));
1183 if (auto *PointerVal = dyn_cast_or_null<PointerValue>(Env.getValue(E)))
1184 return dyn_cast_or_null<RecordStorageLocation>(
1185 &PointerVal->getPointeeLoc());
1186 return nullptr;
1187}
1190 LatticeTransferState &State) {
1191 assert(Expr->getNumArgs() > 0);
1192
1193 auto *StatusAdaptorLoc =
1194 State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
1195 if (StatusAdaptorLoc == nullptr)
1196 return;
1197
1198 copyRecord(*StatusAdaptorLoc,
1199 locForStatus(State.Env.getResultObjectLocation(*Expr)), State.Env);
1200}
1201
1204 LatticeTransferState &State) {
1205 RecordStorageLocation *StatusAdaptorLoc =
1206 getImplicitObjectLocation(*Expr, State.Env);
1207 if (StatusAdaptorLoc == nullptr)
1208 return;
1209
1210 auto &OkVal = valForOk(locForStatus(*StatusAdaptorLoc), State.Env);
1211 State.Env.setValue(*Expr, OkVal);
1212}
1213
1217 using namespace ::clang::ast_matchers;
1218 return std::move(Builder)
1219 .CaseOfCFGStmt<CallExpr>(
1222 .CaseOfCFGStmt<CallExpr>(isStatusIsOkMatcherCall(),
1224 .CaseOfCFGStmt<CallExpr>(
1227 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1230 LatticeTransferState &State) {
1232 /*IsStatusOr=*/true);
1233 })
1234 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1237 LatticeTransferState &State) {
1239 /*IsStatusOr=*/false);
1240 })
1241 .CaseOfCFGStmt<CXXConstructExpr>(
1246 .CaseOfCFGStmt<CXXMemberCallExpr>(
1249 LatticeTransferState &State) {
1251 Expr, State.Env, locForOk);
1252 })
1253 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("ok"),
1255 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("status"),
1257 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusMemberCallWithName("ok"),
1259 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusMemberCallWithName("Update"),
1261 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1264 LatticeTransferState &State) {
1266 /*IsNegative=*/false);
1267 })
1268 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1271 LatticeTransferState &State) {
1273 /*IsNegative=*/true);
1274 })
1275 .CaseOfCFGStmt<BinaryOperator>(
1277 [](const BinaryOperator *Expr, const MatchFinder::MatchResult &,
1278 LatticeTransferState &State) {
1280 /*IsNegative=*/false);
1281 })
1282 .CaseOfCFGStmt<BinaryOperator>(
1284 [](const BinaryOperator *Expr, const MatchFinder::MatchResult &,
1285 LatticeTransferState &State) {
1287 /*IsNegative=*/true);
1288 })
1289 .CaseOfCFGStmt<CallExpr>(isOkStatusCall(), transferOkStatusCall)
1291 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("emplace"),
1295 .CaseOfCFGStmt<CXXConstructExpr>(isStatusOrValueConstructor(),
1299 .CaseOfCFGStmt<CXXOperatorCallExpr>(isStatusOrOperatorCallWithName("*"),
1301 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("value"),
1303 .CaseOfCFGStmt<CallExpr>(isAsStatusCallWithStatus(),
1305 .CaseOfCFGStmt<CallExpr>(isAsStatusCallWithStatusOr(),
1307 .CaseOfCFGStmt<CallExpr>(isLoggingGetReferenceableValueCall(),
1309 .CaseOfCFGStmt<CallExpr>(isLoggingCheckEqImpl(),
1311 // This needs to go before the const accessor call matcher, because these
1312 // look like them, but we model `operator`* and `get` to return the same
1313 // object. Also, we model them for non-const cases.
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<CXXOperatorCallExpr>(
1325 [](const CXXOperatorCallExpr *E,
1327 LatticeTransferState &State) {
1329 E, getSmartPtrLikeStorageLocation(*E->getArg(0), State.Env),
1330 State, [](StorageLocation &Loc) {});
1331 })
1332 .CaseOfCFGStmt<CXXMemberCallExpr>(
1335 LatticeTransferState &State) {
1337 E, getImplicitObjectLocation(*E, State.Env), State,
1338 [](StorageLocation &Loc) {});
1339 })
1340 .CaseOfCFGStmt<CXXMemberCallExpr>(
1343 LatticeTransferState &State) {
1345 E, getImplicitObjectLocation(*E, State.Env), State,
1346 [](StorageLocation &Loc) {});
1347 })
1348 // const accessor calls
1349 .CaseOfCFGStmt<CXXMemberCallExpr>(isConstAccessorMemberCall(),
1351 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1354 .CaseOfCFGStmt<CXXMemberCallExpr>(isConstPointerAccessorMemberCall(),
1356 .CaseOfCFGStmt<CXXOperatorCallExpr>(
1359 // non-const member calls that may modify the state of an object.
1360 .CaseOfCFGStmt<CXXMemberCallExpr>(isNonConstMemberCall(),
1364 // N.B. this has to be after transferConstMemberCall, otherwise we would
1365 // always return a fresh RecordStorageLocation for the StatusOr.
1366 .CaseOfCFGStmt<CallExpr>(isStatusOrReturningCall(),
1367 [](const CallExpr *Expr,
1369 LatticeTransferState &State) {
1371 })
1372 .CaseOfCFGStmt<CallExpr>(isStatusOrPtrReturningCall(),
1374 .CaseOfCFGStmt<CallExpr>(isStatusPtrReturningCall(),
1376 // N.B. These need to come after all other CXXConstructExpr.
1377 // These are there to make sure that every Status and StatusOr object
1378 // have their ok boolean initialized when constructed. If we were to
1379 // lazily initialize them when we first access them, we can produce
1380 // false positives if that first access is in a control flow statement.
1381 // You can comment out these two constructors and see tests fail.
1382 .CaseOfCFGStmt<CXXConstructExpr>(isStatusOrConstructor(),
1384 .CaseOfCFGStmt<CXXConstructExpr>(isStatusConstructor(),
1386 .CaseOfCFGStmt<ImplicitCastExpr>(
1387 implicitCastExpr(hasCastKind(CK_PointerToBoolean)),
1389 .CaseOfCFGStmt<clang::CXXMemberCallExpr>(
1392 .CaseOfCFGStmt<clang::CallExpr>(isMacroAdaptorCall(),
1394 .Build();
1395}
1396
1398 for (Type *Ty : Ctx.getTypes())
1399 if (isStatusType(QualType(Ty, 0)))
1400 return QualType(Ty, 0);
1401
1402 return QualType();
1403}
1404
1406 Environment &Env)
1409 TransferMatchSwitch(buildTransferMatchSwitch(Ctx, {})) {
1410 QualType StatusType = findStatusType(Ctx);
1411 Env.getDataflowAnalysisContext().setSyntheticFieldCallback(
1412 [StatusType](QualType Ty) -> llvm::StringMap<QualType> {
1414 if (RD == nullptr)
1415 return {};
1416
1417 if (auto Fields = getSyntheticFields(Ty, StatusType, *RD);
1418 !Fields.empty())
1419 return Fields;
1420 return {};
1421 });
1422}
1423
1425 Environment &Env) {
1426 LatticeTransferState State(L, Env);
1427 TransferMatchSwitch(Elt, getASTContext(), State);
1428}
1429
1430} // 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:245
const SmallVectorImpl< Type * > & getTypes() const
CanQualType BoolTy
A builtin binary operation expression such as "x + y" or "x <= y".
Definition Expr.h:4107
Represents a top-level expression in a basic block.
Definition CFG.h:55
Represents a call to a C++ constructor.
Definition ExprCXX.h:1553
Represents a call to a member function that may be written either with member call syntax (e....
Definition ExprCXX.h:184
SourceLocation getExprLoc() const LLVM_READONLY
Definition ExprCXX.h:225
A call to an overloaded operator written using operator syntax.
Definition ExprCXX.h:86
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
bool hasDefinition() const
Definition DeclCXX.h:562
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:3012
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3216
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:550
This represents one expression.
Definition Expr.h:114
bool isPRValue() const
Definition Expr.h:287
QualType getType() const
Definition Expr.h:146
Represents a function declaration or definition.
Definition Decl.h:2071
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition Expr.h:3922
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:303
Represent a C++ namespace.
Definition Decl.h:594
A (possibly-)qualified type.
Definition TypeBase.h:938
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:1879
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:8683
bool isReferenceType() const
Definition TypeBase.h:8707
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:885
bool isRecordType() const
Definition TypeBase.h:8810
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.
void transferAssertionResultExpectationOperatorBoolCall(const CXXMemberCallExpr *Expr, Environment &Env, llvm::function_ref< StorageLocation &(RecordStorageLocation &)> GetOk)
clang::ast_matchers::StatementMatcher isAssertionResultExpectationOperatorBoolCall()
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:906
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.