Skip to content

Commit d7e3105

Browse files
committed
more tests
1 parent 319ad0b commit d7e3105

File tree

2 files changed

+128
-9
lines changed

2 files changed

+128
-9
lines changed

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

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

583-
// if const method returns a reference
584-
if (CE->isGLValue()) {
583+
// Cache if the const method returns a reference
584+
if (RecordLoc != nullptr && CE->isGLValue()) {
585585
const FunctionDecl *DirectCallee = CE->getDirectCallee();
586586
if (DirectCallee == nullptr)
587587
return;
588588

589-
QualType DeclaredReturnType = DirectCallee->getReturnType();
590-
591-
if (DeclaredReturnType.getTypePtr()->isReferenceType()) {
589+
bool isReference = DirectCallee->getReturnType().getTypePtr()->isReferenceType();
590+
if (isReference) {
592591
StorageLocation &Loc =
593592
State.Lattice.getOrCreateConstMethodReturnStorageLocation(
594593
*RecordLoc, DirectCallee, State.Env, [&](StorageLocation &Loc) {
595-
// No-op
594+
// no-op
596595
});
597596

598597
State.Env.setStorageLocation(*CE, Loc);

clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp

Lines changed: 123 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3918,9 +3918,129 @@ TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorToOptionalViaConstRefAccesso
39183918
)cc");
39193919
}
39203920

3921-
// todo: non const accessor
3922-
// todo: different accessor in between
3923-
// todo: const copy
3921+
TEST_P(UncheckedOptionalAccessTest, ConstRefToOptionalSavedAsTemporaryVariable) {
3922+
ExpectDiagnosticsFor(R"cc(
3923+
#include "unchecked_optional_access_test.h"
3924+
3925+
class A {
3926+
public:
3927+
const $ns::$optional<int>& get() const { return x; }
3928+
3929+
private:
3930+
$ns::$optional<int> x;
3931+
};
3932+
3933+
class B {
3934+
public:
3935+
const A& getA() const { return a; }
3936+
3937+
private:
3938+
A a;
3939+
};
3940+
3941+
void target(B& b) {
3942+
const auto& opt = b.getA().get();
3943+
if (opt.has_value()) {
3944+
opt.value();
3945+
}
3946+
}
3947+
)cc");
3948+
}
3949+
3950+
TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorToOptionalViaConstValueAccessorToHoldingObject) {
3951+
ExpectDiagnosticsFor(R"cc(
3952+
#include "unchecked_optional_access_test.h"
3953+
3954+
class A {
3955+
public:
3956+
const $ns::$optional<int>& get() const { return x; }
3957+
3958+
private:
3959+
$ns::$optional<int> x;
3960+
};
3961+
3962+
class B {
3963+
public:
3964+
const A copyA() const { return a; }
3965+
3966+
private:
3967+
A a;
3968+
};
3969+
3970+
void target(B& b) {
3971+
if (b.copyA().get().has_value()) {
3972+
b.copyA().get().value(); // [[unsafe]]
3973+
}
3974+
}
3975+
)cc");
3976+
}
3977+
3978+
TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorToOptionalViaNonConstRefAccessorToHoldingObject) {
3979+
ExpectDiagnosticsFor(R"cc(
3980+
#include "unchecked_optional_access_test.h"
3981+
3982+
class A {
3983+
public:
3984+
const $ns::$optional<int>& get() const { return x; }
3985+
3986+
private:
3987+
$ns::$optional<int> x;
3988+
};
3989+
3990+
class B {
3991+
public:
3992+
A& getA() { return a; }
3993+
3994+
private:
3995+
A a;
3996+
};
3997+
3998+
void target(B& b) {
3999+
if (b.getA().get().has_value()) {
4000+
b.getA().get().value(); // [[unsafe]]
4001+
}
4002+
}
4003+
)cc");
4004+
}
4005+
4006+
TEST_P(UncheckedOptionalAccessTest, ConstRefAccessorToOptionalViaNonConstRefAccessorToHoldingObjectWithModAfterCheck) {
4007+
ExpectDiagnosticsFor(R"cc(
4008+
#include "unchecked_optional_access_test.h"
4009+
4010+
class A {
4011+
public:
4012+
const $ns::$optional<int>& get() const { return x; }
4013+
private:
4014+
$ns::$optional<int> x;
4015+
};
4016+
4017+
class B {
4018+
public:
4019+
const A& getA() const { return a; }
4020+
4021+
A& getA() { return a; }
4022+
4023+
void clear() { a = A{}; };
4024+
4025+
private:
4026+
A a;
4027+
};
4028+
4029+
void target(B& b) {
4030+
// changing field A via non-const getter after const getter check
4031+
if (b.getA().get().has_value()) {
4032+
b.getA() = A{};
4033+
b.getA().get().value(); // [[unsafe]]
4034+
}
4035+
4036+
// calling non-const method which might change field A
4037+
if (b.getA().get().has_value()) {
4038+
b.clear();
4039+
b.getA().get().value(); // [[unsafe]]
4040+
}
4041+
}
4042+
)cc");
4043+
}
39244044

39254045
// FIXME: Add support for:
39264046
// - constructors (copy, move)

0 commit comments

Comments
 (0)