clang 22.0.0git
UncheckedStatusOrAccessModel.cpp
Go to the documentation of this file.
1//===- UncheckedStatusOrAccessModel.cpp -----------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
11#include <cassert>
12#include <utility>
13
14#include "clang/AST/DeclCXX.h"
16#include "clang/AST/Expr.h"
17#include "clang/AST/ExprCXX.h"
18#include "clang/AST/TypeBase.h"
22#include "clang/Analysis/CFG.h"
30#include "clang/Basic/LLVM.h"
32#include "llvm/ADT/StringMap.h"
33
35namespace {
36
37using ::clang::ast_matchers::MatchFinder;
39
40} // namespace
41
42static bool namespaceEquals(const NamespaceDecl *NS,
43 clang::ArrayRef<clang::StringRef> NamespaceNames) {
44 while (!NamespaceNames.empty() && NS) {
45 if (NS->getName() != NamespaceNames.consume_back())
46 return false;
47 NS = dyn_cast_or_null<NamespaceDecl>(NS->getParent());
48 }
49 return NamespaceNames.empty() && !NS;
50}
51
52// TODO: move this to a proper place to share with the rest of clang
54 StringRef Name) {
55 if (Type.isNull())
56 return false;
57 if (auto *RD = Type->getAsRecordDecl())
58 if (RD->getName() == Name)
59 if (const auto *N = dyn_cast_or_null<NamespaceDecl>(RD->getDeclContext()))
60 return namespaceEquals(N, NS);
61 return false;
62}
63
65 return isTypeNamed(Type, {"absl", "internal_statusor"}, "OperatorBase");
66}
67
68static bool isSafeUnwrap(RecordStorageLocation *StatusOrLoc,
69 const Environment &Env) {
70 if (!StatusOrLoc)
71 return false;
72 auto &StatusLoc = locForStatus(*StatusOrLoc);
73 auto *OkVal = Env.get<BoolValue>(locForOk(StatusLoc));
74 return OkVal != nullptr && Env.proves(OkVal->formula());
75}
76
79 auto *RD = Ty->getAsCXXRecordDecl();
80 if (RD == nullptr)
81 return nullptr;
82 if (isStatusOrType(Ty) ||
83 // In case we are analyzing code under OperatorBase itself that uses
84 // operator* (e.g. to implement operator->).
87 if (!RD->hasDefinition())
88 return nullptr;
89 for (const auto &Base : RD->bases())
90 if (auto *QT = getStatusOrBaseClass(Base.getType()))
91 return QT;
92 return nullptr;
93}
94
98
99static auto ofClassStatus() {
100 using namespace ::clang::ast_matchers; // NOLINT: Too many names
101 return ofClass(hasName("::absl::Status"));
102}
103
104static auto isStatusMemberCallWithName(llvm::StringRef member_name) {
105 using namespace ::clang::ast_matchers; // NOLINT: Too many names
106 return cxxMemberCallExpr(
107 on(expr(unless(cxxThisExpr()))),
108 callee(cxxMethodDecl(hasName(member_name), ofClassStatus())));
109}
110
111static auto isStatusOrMemberCallWithName(llvm::StringRef member_name) {
112 using namespace ::clang::ast_matchers; // NOLINT: Too many names
113 return cxxMemberCallExpr(
114 on(expr(unless(cxxThisExpr()))),
115 callee(cxxMethodDecl(
116 hasName(member_name),
118}
119
120static auto isStatusOrOperatorCallWithName(llvm::StringRef operator_name) {
121 using namespace ::clang::ast_matchers; // NOLINT: Too many names
122 return cxxOperatorCallExpr(
123 hasOverloadedOperatorName(operator_name),
124 callee(cxxMethodDecl(
126}
127
128static auto valueCall() {
129 using namespace ::clang::ast_matchers; // NOLINT: Too many names
130 return anyOf(isStatusOrMemberCallWithName("value"),
131 isStatusOrMemberCallWithName("ValueOrDie"));
132}
133
134static auto valueOperatorCall() {
135 using namespace ::clang::ast_matchers; // NOLINT: Too many names
138}
139
141 using namespace ::clang::ast_matchers; // NOLINT: Too many names
142 return hasCanonicalType(qualType(hasDeclaration(statusClass())));
143}
144
145static auto isComparisonOperatorCall(llvm::StringRef operator_name) {
146 using namespace ::clang::ast_matchers; // NOLINT: Too many names
147 return cxxOperatorCallExpr(
148 hasOverloadedOperatorName(operator_name), argumentCountIs(2),
149 hasArgument(0, anyOf(hasType(statusType()), hasType(statusOrType()))),
150 hasArgument(1, anyOf(hasType(statusType()), hasType(statusOrType()))));
151}
152
153static auto isOkStatusCall() {
154 using namespace ::clang::ast_matchers; // NOLINT: Too many names
155 return callExpr(callee(functionDecl(hasName("::absl::OkStatus"))));
156}
157
158static auto isNotOkStatusCall() {
159 using namespace ::clang::ast_matchers; // NOLINT: Too many names
160 return callExpr(callee(functionDecl(hasAnyName(
161 "::absl::AbortedError", "::absl::AlreadyExistsError",
162 "::absl::CancelledError", "::absl::DataLossError",
163 "::absl::DeadlineExceededError", "::absl::FailedPreconditionError",
164 "::absl::InternalError", "::absl::InvalidArgumentError",
165 "::absl::NotFoundError", "::absl::OutOfRangeError",
166 "::absl::PermissionDeniedError", "::absl::ResourceExhaustedError",
167 "::absl::UnauthenticatedError", "::absl::UnavailableError",
168 "::absl::UnimplementedError", "::absl::UnknownError"))));
169}
170
171static auto isPointerComparisonOperatorCall(std::string operator_name) {
172 using namespace ::clang::ast_matchers; // NOLINT: Too many names
173 return binaryOperator(hasOperatorName(operator_name),
174 hasLHS(hasType(hasCanonicalType(pointerType(
175 pointee(anyOf(statusOrType(), statusType())))))),
176 hasRHS(hasType(hasCanonicalType(pointerType(
177 pointee(anyOf(statusOrType(), statusType())))))));
178}
179
180// The nullPointerConstant in the two matchers below is to support
181// absl::StatusOr<void*> X = nullptr.
182// nullptr does not match the bound type.
183// TODO: be less restrictive around convertible types in general.
185 using namespace ::clang::ast_matchers; // NOLINT: Too many names
186 return cxxOperatorCallExpr(
188 callee(cxxMethodDecl(ofClass(statusOrClass()))),
189 hasArgument(1, anyOf(hasType(hasUnqualifiedDesugaredType(
190 type(equalsBoundNode("T")))),
191 nullPointerConstant())));
192}
193
195 using namespace ::clang::ast_matchers; // NOLINT: Too many names
196 return cxxConstructExpr(
197 hasType(statusOrType()),
198 hasArgument(0,
199 anyOf(hasType(hasCanonicalType(type(equalsBoundNode("T")))),
200 nullPointerConstant(),
201 hasType(namedDecl(hasAnyName("absl::in_place_t",
202 "std::in_place_t"))))));
203}
204
206 using namespace ::clang::ast_matchers; // NOLINT: Too many names
207 return cxxConstructExpr(hasType(statusOrType()));
208}
209
210static auto isStatusConstructor() {
211 using namespace ::clang::ast_matchers; // NOLINT: Too many names
212 return cxxConstructExpr(hasType(statusType()));
213}
214
215static auto
219 // StatusOr::value, StatusOr::ValueOrDie
220 .CaseOfCFGStmt<CXXMemberCallExpr>(
221 valueCall(),
222 [](const CXXMemberCallExpr *E,
224 const Environment &Env) {
225 if (!isSafeUnwrap(getImplicitObjectLocation(*E, Env), Env))
228 })
229
230 // StatusOr::operator*, StatusOr::operator->
231 .CaseOfCFGStmt<CXXOperatorCallExpr>(
233 [](const CXXOperatorCallExpr *E,
235 const Environment &Env) {
236 RecordStorageLocation *StatusOrLoc =
237 Env.get<RecordStorageLocation>(*E->getArg(0));
238 if (!isSafeUnwrap(StatusOrLoc, Env))
239 return llvm::SmallVector<SourceLocation>({E->getOperatorLoc()});
241 })
242 .Build();
243}
244
248
255
257 Environment &Env) {
258 auto &OkVal = Env.makeAtomicBoolValue();
259 Env.setValue(locForOk(StatusLoc), OkVal);
260 return OkVal;
261}
262
264 Environment &Env) {
265 return initializeStatus(locForStatus(StatusOrLoc), Env);
266}
267
269 using namespace ::clang::ast_matchers; // NOLINT: Too many names
271 hasName("absl::StatusOr"),
272 hasTemplateArgument(0, refersToType(type().bind("T"))));
273}
274
276 using namespace ::clang::ast_matchers; // NOLINT: Too many names
277 return cxxRecordDecl(hasName("absl::Status"));
278}
279
281 using namespace ::clang::ast_matchers; // NOLINT: Too many names
283 hasName("absl::internal_statusor::OperatorBase"));
284}
285
287 using namespace ::clang::ast_matchers; // NOLINT: Too many names
288 return hasCanonicalType(qualType(hasDeclaration(statusOrClass())));
289}
290
292 return isTypeNamed(Type, {"absl"}, "StatusOr");
293}
294
296 return isTypeNamed(Type, {"absl"}, "Status");
297}
298
299llvm::StringMap<QualType> getSyntheticFields(QualType Ty, QualType StatusType,
300 const CXXRecordDecl &RD) {
301 if (auto *TRD = getStatusOrBaseClass(Ty))
302 return {{"status", StatusType}, {"value", getStatusOrValueType(TRD)}};
303 if (isStatusType(Ty) || (RD.hasDefinition() &&
304 RD.isDerivedFrom(StatusType->getAsCXXRecordDecl())))
305 return {{"ok", RD.getASTContext().BoolTy}};
306 return {};
307}
308
312
314 return StatusLoc.getSyntheticField("ok");
315}
316
318 if (auto *Val = Env.get<BoolValue>(locForOk(StatusLoc)))
319 return *Val;
320 return initializeStatus(StatusLoc, Env);
321}
322
325 LatticeTransferState &State) {
326 RecordStorageLocation *StatusOrLoc =
327 getImplicitObjectLocation(*Expr, State.Env);
328 if (StatusOrLoc == nullptr)
329 return;
330
331 auto &OkVal = valForOk(locForStatus(*StatusOrLoc), State.Env);
332 State.Env.setValue(*Expr, OkVal);
333}
334
337 LatticeTransferState &State) {
338 RecordStorageLocation *StatusOrLoc =
339 getImplicitObjectLocation(*Expr, State.Env);
340 if (StatusOrLoc == nullptr)
341 return;
342
343 RecordStorageLocation &StatusLoc = locForStatus(*StatusOrLoc);
344
345 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
346 initializeStatusOr(*StatusOrLoc, State.Env);
347
348 if (Expr->isPRValue())
349 copyRecord(StatusLoc, State.Env.getResultObjectLocation(*Expr), State.Env);
350 else
351 State.Env.setStorageLocation(*Expr, StatusLoc);
352}
353
356 LatticeTransferState &State) {
357 RecordStorageLocation *StatusLoc =
358 getImplicitObjectLocation(*Expr, State.Env);
359 if (StatusLoc == nullptr)
360 return;
361
362 if (Value *Val = State.Env.getValue(locForOk(*StatusLoc)))
363 State.Env.setValue(*Expr, *Val);
364}
365
368 LatticeTransferState &State) {
369 // S.Update(OtherS) sets S to the error code of OtherS if it is OK,
370 // otherwise does nothing.
371 assert(Expr->getNumArgs() == 1);
372 auto *Arg = Expr->getArg(0);
373 RecordStorageLocation *ArgRecord =
374 Arg->isPRValue() ? &State.Env.getResultObjectLocation(*Arg)
375 : State.Env.get<RecordStorageLocation>(*Arg);
377 if (ThisLoc == nullptr || ArgRecord == nullptr)
378 return;
379
380 auto &ThisOkVal = valForOk(*ThisLoc, State.Env);
381 auto &ArgOkVal = valForOk(*ArgRecord, State.Env);
382 auto &A = State.Env.arena();
383 auto &NewVal = State.Env.makeAtomicBoolValue();
384 State.Env.assume(A.makeImplies(A.makeNot(ThisOkVal.formula()),
385 A.makeNot(NewVal.formula())));
386 State.Env.assume(A.makeImplies(NewVal.formula(), ArgOkVal.formula()));
387 State.Env.setValue(locForOk(*ThisLoc), NewVal);
388}
389
391 RecordStorageLocation &RhsStatusLoc,
392 Environment &Env) {
393 auto &A = Env.arena();
394 // Logically, a Status object is composed of an error code that could take one
395 // of multiple possible values, including the "ok" value. We track whether a
396 // Status object has an "ok" value and represent this as an `ok` bit. Equality
397 // of Status objects compares their error codes. Therefore, merely comparing
398 // the `ok` bits isn't sufficient: when two Status objects are assigned non-ok
399 // error codes the equality of their respective error codes matters. Since we
400 // only track the `ok` bits, we can't make any conclusions about equality when
401 // we know that two Status objects have non-ok values.
402
403 auto &LhsOkVal = valForOk(LhsStatusLoc, Env);
404 auto &RhsOkVal = valForOk(RhsStatusLoc, Env);
405
406 auto &Res = Env.makeAtomicBoolValue();
407
408 // lhs && rhs => res (a.k.a. !res => !lhs || !rhs)
409 Env.assume(A.makeImplies(A.makeAnd(LhsOkVal.formula(), RhsOkVal.formula()),
410 Res.formula()));
411 // res => (lhs == rhs)
412 Env.assume(A.makeImplies(
413 Res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
414
415 return &Res;
416}
417
418static BoolValue *
420 RecordStorageLocation &RhsStatusOrLoc,
421 Environment &Env) {
422 auto &A = Env.arena();
423 // Logically, a StatusOr<T> object is composed of two values - a Status and a
424 // value of type T. Equality of StatusOr objects compares both values.
425 // Therefore, merely comparing the `ok` bits of the Status values isn't
426 // sufficient. When two StatusOr objects are engaged, the equality of their
427 // respective values of type T matters. Similarly, when two StatusOr objects
428 // have Status values that have non-ok error codes, the equality of the error
429 // codes matters. Since we only track the `ok` bits of the Status values, we
430 // can't make any conclusions about equality when we know that two StatusOr
431 // objects are engaged or when their Status values contain non-ok error codes.
432 auto &LhsOkVal = valForOk(locForStatus(LhsStatusOrLoc), Env);
433 auto &RhsOkVal = valForOk(locForStatus(RhsStatusOrLoc), Env);
434 auto &res = Env.makeAtomicBoolValue();
435
436 // res => (lhs == rhs)
437 Env.assume(A.makeImplies(
438 res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
439 return &res;
440}
441
442static BoolValue *evaluateEquality(const Expr *LhsExpr, const Expr *RhsExpr,
443 Environment &Env) {
444 // Check the type of both sides in case an operator== is added that admits
445 // different types.
446 if (isStatusOrType(LhsExpr->getType()) &&
447 isStatusOrType(RhsExpr->getType())) {
448 auto *LhsStatusOrLoc = Env.get<RecordStorageLocation>(*LhsExpr);
449 if (LhsStatusOrLoc == nullptr)
450 return nullptr;
451 auto *RhsStatusOrLoc = Env.get<RecordStorageLocation>(*RhsExpr);
452 if (RhsStatusOrLoc == nullptr)
453 return nullptr;
454
455 return evaluateStatusOrEquality(*LhsStatusOrLoc, *RhsStatusOrLoc, Env);
456 }
457 if (isStatusType(LhsExpr->getType()) && isStatusType(RhsExpr->getType())) {
458 auto *LhsStatusLoc = Env.get<RecordStorageLocation>(*LhsExpr);
459 if (LhsStatusLoc == nullptr)
460 return nullptr;
461
462 auto *RhsStatusLoc = Env.get<RecordStorageLocation>(*RhsExpr);
463 if (RhsStatusLoc == nullptr)
464 return nullptr;
465
466 return evaluateStatusEquality(*LhsStatusLoc, *RhsStatusLoc, Env);
467 }
468 return nullptr;
469}
470
473 bool IsNegative) {
474 auto *LhsAndRhsVal =
475 evaluateEquality(Expr->getArg(0), Expr->getArg(1), State.Env);
476 if (LhsAndRhsVal == nullptr)
477 return;
478
479 if (IsNegative)
480 State.Env.setValue(*Expr, State.Env.makeNot(*LhsAndRhsVal));
481 else
482 State.Env.setValue(*Expr, *LhsAndRhsVal);
483}
484
486 Environment &Env) {
487 if (auto *PointerVal = Env.get<PointerValue>(Expr))
488 return dyn_cast<RecordStorageLocation>(&PointerVal->getPointeeLoc());
489 return nullptr;
490}
491
493 const Expr *RhsExpr,
494 Environment &Env) {
495 assert(LhsExpr->getType()->isPointerType());
496 assert(RhsExpr->getType()->isPointerType());
497 RecordStorageLocation *LhsStatusLoc = nullptr;
498 RecordStorageLocation *RhsStatusLoc = nullptr;
499 if (isStatusOrType(LhsExpr->getType()->getPointeeType()) &&
500 isStatusOrType(RhsExpr->getType()->getPointeeType())) {
501 auto *LhsStatusOrLoc = getPointeeLocation(*LhsExpr, Env);
502 auto *RhsStatusOrLoc = getPointeeLocation(*RhsExpr, Env);
503 if (LhsStatusOrLoc == nullptr || RhsStatusOrLoc == nullptr)
504 return nullptr;
505 LhsStatusLoc = &locForStatus(*LhsStatusOrLoc);
506 RhsStatusLoc = &locForStatus(*RhsStatusOrLoc);
507 } else if (isStatusType(LhsExpr->getType()->getPointeeType()) &&
508 isStatusType(RhsExpr->getType()->getPointeeType())) {
509 LhsStatusLoc = getPointeeLocation(*LhsExpr, Env);
510 RhsStatusLoc = getPointeeLocation(*RhsExpr, Env);
511 }
512 if (LhsStatusLoc == nullptr || RhsStatusLoc == nullptr)
513 return nullptr;
514 auto &LhsOkVal = valForOk(*LhsStatusLoc, Env);
515 auto &RhsOkVal = valForOk(*RhsStatusLoc, Env);
516 auto &Res = Env.makeAtomicBoolValue();
517 auto &A = Env.arena();
518 Env.assume(A.makeImplies(
519 Res.formula(), A.makeEquals(LhsOkVal.formula(), RhsOkVal.formula())));
520 return &Res;
521}
522
525 bool IsNegative) {
526 auto *LhsAndRhsVal =
527 evaluatePointerEquality(Expr->getLHS(), Expr->getRHS(), State.Env);
528 if (LhsAndRhsVal == nullptr)
529 return;
530
531 if (IsNegative)
532 State.Env.setValue(*Expr, State.Env.makeNot(*LhsAndRhsVal));
533 else
534 State.Env.setValue(*Expr, *LhsAndRhsVal);
535}
536
539 LatticeTransferState &State) {
540 auto &OkVal =
541 initializeStatus(State.Env.getResultObjectLocation(*Expr), State.Env);
542 State.Env.assume(OkVal.formula());
543}
544
547 LatticeTransferState &State) {
548 auto &OkVal =
549 initializeStatus(State.Env.getResultObjectLocation(*Expr), State.Env);
550 auto &A = State.Env.arena();
551 State.Env.assume(A.makeNot(OkVal.formula()));
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.assume(OkVal.formula());
564}
565
568 LatticeTransferState &State) {
569 assert(Expr->getNumArgs() > 1);
570
571 auto *StatusOrLoc = State.Env.get<RecordStorageLocation>(*Expr->getArg(0));
572 if (StatusOrLoc == nullptr)
573 return;
574
575 auto &OkVal = initializeStatusOr(*StatusOrLoc, State.Env);
576 State.Env.assume(OkVal.formula());
577}
578
581 LatticeTransferState &State) {
582 auto &OkVal =
583 initializeStatusOr(State.Env.getResultObjectLocation(*Expr), State.Env);
584 State.Env.assume(OkVal.formula());
585}
586
589 LatticeTransferState &State) {
590 RecordStorageLocation &StatusOrLoc = State.Env.getResultObjectLocation(*Expr);
591 RecordStorageLocation &StatusLoc = locForStatus(StatusOrLoc);
592
593 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
594 initializeStatusOr(StatusOrLoc, State.Env);
595}
596
599 LatticeTransferState &State) {
600 RecordStorageLocation &StatusLoc = State.Env.getResultObjectLocation(*Expr);
601
602 if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
603 initializeStatus(StatusLoc, State.Env);
604}
605
609 using namespace ::clang::ast_matchers; // NOLINT: Too many names
610 return std::move(Builder)
613 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("status"),
615 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusMemberCallWithName("ok"),
617 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusMemberCallWithName("Update"),
619 .CaseOfCFGStmt<CXXOperatorCallExpr>(
622 LatticeTransferState &State) {
624 /*IsNegative=*/false);
625 })
626 .CaseOfCFGStmt<CXXOperatorCallExpr>(
629 LatticeTransferState &State) {
631 /*IsNegative=*/true);
632 })
633 .CaseOfCFGStmt<BinaryOperator>(
636 LatticeTransferState &State) {
638 /*IsNegative=*/false);
639 })
640 .CaseOfCFGStmt<BinaryOperator>(
643 LatticeTransferState &State) {
645 /*IsNegative=*/true);
646 })
647 .CaseOfCFGStmt<CallExpr>(isOkStatusCall(), transferOkStatusCall)
649 .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("emplace"),
653 .CaseOfCFGStmt<CXXConstructExpr>(isStatusOrValueConstructor(),
655 // N.B. These need to come after all other CXXConstructExpr.
656 // These are there to make sure that every Status and StatusOr object
657 // have their ok boolean initialized when constructed. If we were to
658 // lazily initialize them when we first access them, we can produce
659 // false positives if that first access is in a control flow statement.
660 // You can comment out these two constructors and see tests fail.
661 .CaseOfCFGStmt<CXXConstructExpr>(isStatusOrConstructor(),
663 .CaseOfCFGStmt<CXXConstructExpr>(isStatusConstructor(),
665 .Build();
666}
667
669 for (Type *Ty : Ctx.getTypes())
670 if (isStatusType(QualType(Ty, 0)))
671 return QualType(Ty, 0);
672
673 return QualType();
674}
675
677 Environment &Env)
680 TransferMatchSwitch(buildTransferMatchSwitch(Ctx, {})) {
681 QualType StatusType = findStatusType(Ctx);
682 Env.getDataflowAnalysisContext().setSyntheticFieldCallback(
683 [StatusType](QualType Ty) -> llvm::StringMap<QualType> {
685 if (RD == nullptr)
686 return {};
687
688 if (auto Fields = getSyntheticFields(Ty, StatusType, *RD);
689 !Fields.empty())
690 return Fields;
691 return {};
692 });
693}
694
696 Environment &Env) {
697 LatticeTransferState State(L, Env);
698 TransferMatchSwitch(Elt, getASTContext(), State);
699}
700
701} // 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.
Defines the clang::SourceLocation class and associated facilities.
C Language Family Type Representation.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:220
const SmallVectorImpl< Type * > & getTypes() const
CanQualType BoolTy
A builtin binary operation expression such as "x + y" or "x <= y".
Definition Expr.h:3972
Represents a top-level expression in a basic block.
Definition CFG.h:55
Represents a call to a C++ constructor.
Definition ExprCXX.h:1549
Represents a call to a member function that may be written either with member call syntax (e....
Definition ExprCXX.h:179
SourceLocation getExprLoc() const LLVM_READONLY
Definition ExprCXX.h:220
A call to an overloaded operator written using operator syntax.
Definition ExprCXX.h:84
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
bool hasDefinition() const
Definition DeclCXX.h:561
bool isDerivedFrom(const CXXRecordDecl *Base) const
Determine whether this class is derived from the class Base.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2877
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3081
Represents a class template specialization, which refers to a class template with a given set of temp...
const TemplateArgumentList & getTemplateArgs() const
Retrieve the template arguments of the class template specialization.
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition DeclBase.h:2109
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:546
This represents one expression.
Definition Expr.h:112
bool isPRValue() const
Definition Expr.h:285
QualType getType() const
Definition Expr.h:144
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition Decl.h:301
Represent a C++ namespace.
Definition Decl.h:592
A (possibly-)qualified type.
Definition TypeBase.h:937
const TemplateArgument & get(unsigned Idx) const
Retrieve the template argument at a given index.
QualType getAsType() const
Retrieve the type for a type template argument.
The base class of the type hierarchy.
Definition TypeBase.h:1833
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition Type.h:26
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isPointerType() const
Definition TypeBase.h:8515
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:752
Models a boolean.
Definition Value.h:94
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.
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.
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
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::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, 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< 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 internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class 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 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 auto isStatusMemberCallWithName(llvm::StringRef member_name)
static auto buildDiagnoseMatchSwitch(const UncheckedStatusOrAccessModelOptions &Options)
static auto isComparisonOperatorCall(llvm::StringRef operator_name)
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 auto isStatusOrOperatorCallWithName(llvm::StringRef operator_name)
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 transferStatusOrOkCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static bool namespaceEquals(const NamespaceDecl *NS, clang::ArrayRef< clang::StringRef > NamespaceNames)
static bool isTypeNamed(QualType Type, clang::ArrayRef< clang::StringRef > NS, StringRef Name)
static void transferStatusOrConstructor(const CXXConstructExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
clang::ast_matchers::DeclarationMatcher statusClass()
BoolValue & initializeStatusOr(RecordStorageLocation &StatusOrLoc, Environment &Env)
QualType findStatusType(const ASTContext &Ctx)
BoolValue & initializeStatus(RecordStorageLocation &StatusLoc, Environment &Env)
llvm::StringMap< QualType > getSyntheticFields(QualType Ty, QualType StatusType, const CXXRecordDecl &RD)
StorageLocation & locForOk(RecordStorageLocation &StatusLoc)
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 clang::ast_matchers::TypeMatcher statusType()
static void transferStatusOkCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
static void transferEmplaceCall(const CXXMemberCallExpr *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)
BoolValue & valForOk(RecordStorageLocation &StatusLoc, Environment &Env)
static void transferStatusUpdateCall(const CXXMemberCallExpr *Expr, const MatchFinder::MatchResult &, LatticeTransferState &State)
CFGMatchSwitch< LatticeTransferState > buildTransferMatchSwitch(ASTContext &Ctx, CFGMatchSwitchBuilder< LatticeTransferState > Builder)
clang::ast_matchers::DeclarationMatcher statusOrOperatorBaseClass()
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
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.
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.