Skip to content

Commit 319ad0b

Browse files
committed
first implementation and basic tests
1 parent 0cdb467 commit 319ad0b

File tree

2 files changed

+79
-0
lines changed

2 files changed

+79
-0
lines changed

clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,26 @@ void handleConstMemberCall(const CallExpr *CE,
580580
return;
581581
}
582582

583+
// if const method returns a reference
584+
if (CE->isGLValue()) {
585+
const FunctionDecl *DirectCallee = CE->getDirectCallee();
586+
if (DirectCallee == nullptr)
587+
return;
588+
589+
QualType DeclaredReturnType = DirectCallee->getReturnType();
590+
591+
if (DeclaredReturnType.getTypePtr()->isReferenceType()) {
592+
StorageLocation &Loc =
593+
State.Lattice.getOrCreateConstMethodReturnStorageLocation(
594+
*RecordLoc, DirectCallee, State.Env, [&](StorageLocation &Loc) {
595+
// No-op
596+
});
597+
598+
State.Env.setStorageLocation(*CE, Loc);
599+
return;
600+
}
601+
}
602+
583603
// Cache if the const method returns a boolean or pointer type.
584604
// We may decide to cache other return types in the future.
585605
if (RecordLoc != nullptr &&

clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3863,6 +3863,65 @@ TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessorWithModInBetween) {
38633863
)cc");
38643864
}
38653865

3866+
3867+
TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorToOptionalViaConstRefAccessorToHoldingObject) {
3868+
ExpectDiagnosticsFor(R"cc(
3869+
#include "unchecked_optional_access_test.h"
3870+
3871+
class A {
3872+
public:
3873+
const $ns::$optional<int>& get() const { return x; }
3874+
3875+
private:
3876+
$ns::$optional<int> x;
3877+
};
3878+
3879+
class B {
3880+
public:
3881+
const A& getA() const { return a; }
3882+
3883+
private:
3884+
A a;
3885+
};
3886+
3887+
void target(B& b) {
3888+
if (b.getA().get().has_value()) {
3889+
b.getA().get().value();
3890+
}
3891+
}
3892+
)cc");
3893+
}
3894+
3895+
TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorToOptionalViaConstRefAccessorToHoldingObjectWithoutValueCheck) {
3896+
ExpectDiagnosticsFor(R"cc(
3897+
#include "unchecked_optional_access_test.h"
3898+
3899+
class A {
3900+
public:
3901+
const $ns::$optional<int>& get() const { return x; }
3902+
3903+
private:
3904+
$ns::$optional<int> x;
3905+
};
3906+
3907+
class B {
3908+
public:
3909+
const A& getA() const { return a; }
3910+
3911+
private:
3912+
A a;
3913+
};
3914+
3915+
void target(B& b) {
3916+
b.getA().get().value(); // [[unsafe]]
3917+
}
3918+
)cc");
3919+
}
3920+
3921+
// todo: non const accessor
3922+
// todo: different accessor in between
3923+
// todo: const copy
3924+
38663925
// FIXME: Add support for:
38673926
// - constructors (copy, move)
38683927
// - assignment operators (default, copy, move)

0 commit comments

Comments
 (0)