aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp')
-rw-r--r--clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp74
1 files changed, 74 insertions, 0 deletions
diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp
index c88a470..f068be5 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedStatusOrAccessModel.cpp
@@ -24,6 +24,7 @@
#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
#include "clang/Analysis/FlowSensitive/MatchSwitch.h"
+#include "clang/Analysis/FlowSensitive/RecordOps.h"
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
#include "clang/Analysis/FlowSensitive/Value.h"
#include "clang/Basic/LLVM.h"
@@ -95,6 +96,18 @@ static QualType getStatusOrValueType(ClassTemplateSpecializationDecl *TRD) {
return TRD->getTemplateArgs().get(0).getAsType();
}
+static auto ofClassStatus() {
+ using namespace ::clang::ast_matchers; // NOLINT: Too many names
+ return ofClass(hasName("::absl::Status"));
+}
+
+static auto isStatusMemberCallWithName(llvm::StringRef member_name) {
+ using namespace ::clang::ast_matchers; // NOLINT: Too many names
+ return cxxMemberCallExpr(
+ on(expr(unless(cxxThisExpr()))),
+ callee(cxxMethodDecl(hasName(member_name), ofClassStatus())));
+}
+
static auto isStatusOrMemberCallWithName(llvm::StringRef member_name) {
using namespace ::clang::ast_matchers; // NOLINT: Too many names
return cxxMemberCallExpr(
@@ -244,6 +257,61 @@ static void transferStatusOrOkCall(const CXXMemberCallExpr *Expr,
State.Env.setValue(*Expr, OkVal);
}
+static void transferStatusCall(const CXXMemberCallExpr *Expr,
+ const MatchFinder::MatchResult &,
+ LatticeTransferState &State) {
+ RecordStorageLocation *StatusOrLoc =
+ getImplicitObjectLocation(*Expr, State.Env);
+ if (StatusOrLoc == nullptr)
+ return;
+
+ RecordStorageLocation &StatusLoc = locForStatus(*StatusOrLoc);
+
+ if (State.Env.getValue(locForOk(StatusLoc)) == nullptr)
+ initializeStatusOr(*StatusOrLoc, State.Env);
+
+ if (Expr->isPRValue())
+ copyRecord(StatusLoc, State.Env.getResultObjectLocation(*Expr), State.Env);
+ else
+ State.Env.setStorageLocation(*Expr, StatusLoc);
+}
+
+static void transferStatusOkCall(const CXXMemberCallExpr *Expr,
+ const MatchFinder::MatchResult &,
+ LatticeTransferState &State) {
+ RecordStorageLocation *StatusLoc =
+ getImplicitObjectLocation(*Expr, State.Env);
+ if (StatusLoc == nullptr)
+ return;
+
+ if (Value *Val = State.Env.getValue(locForOk(*StatusLoc)))
+ State.Env.setValue(*Expr, *Val);
+}
+
+static void transferStatusUpdateCall(const CXXMemberCallExpr *Expr,
+ const MatchFinder::MatchResult &,
+ LatticeTransferState &State) {
+ // S.Update(OtherS) sets S to the error code of OtherS if it is OK,
+ // otherwise does nothing.
+ assert(Expr->getNumArgs() == 1);
+ auto *Arg = Expr->getArg(0);
+ RecordStorageLocation *ArgRecord =
+ Arg->isPRValue() ? &State.Env.getResultObjectLocation(*Arg)
+ : State.Env.get<RecordStorageLocation>(*Arg);
+ RecordStorageLocation *ThisLoc = getImplicitObjectLocation(*Expr, State.Env);
+ if (ThisLoc == nullptr || ArgRecord == nullptr)
+ return;
+
+ auto &ThisOkVal = valForOk(*ThisLoc, State.Env);
+ auto &ArgOkVal = valForOk(*ArgRecord, State.Env);
+ auto &A = State.Env.arena();
+ auto &NewVal = State.Env.makeAtomicBoolValue();
+ State.Env.assume(A.makeImplies(A.makeNot(ThisOkVal.formula()),
+ A.makeNot(NewVal.formula())));
+ State.Env.assume(A.makeImplies(NewVal.formula(), ArgOkVal.formula()));
+ State.Env.setValue(locForOk(*ThisLoc), NewVal);
+}
+
CFGMatchSwitch<LatticeTransferState>
buildTransferMatchSwitch(ASTContext &Ctx,
CFGMatchSwitchBuilder<LatticeTransferState> Builder) {
@@ -251,6 +319,12 @@ buildTransferMatchSwitch(ASTContext &Ctx,
return std::move(Builder)
.CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("ok"),
transferStatusOrOkCall)
+ .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrMemberCallWithName("status"),
+ transferStatusCall)
+ .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusMemberCallWithName("ok"),
+ transferStatusOkCall)
+ .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusMemberCallWithName("Update"),
+ transferStatusUpdateCall)
.Build();
}