@@ -3863,6 +3863,200 @@ TEST_P(UncheckedOptionalAccessTest, ConstBoolAccessorWithModInBetween) {
3863
3863
)cc" );
3864
3864
}
3865
3865
3866
+ TEST_P (UncheckedOptionalAccessTest,
3867
+ ConstRefAccessorToOptionalViaConstRefAccessorToHoldingObject) {
3868
+ ExpectDiagnosticsFor (R"cc(
3869
+ #include "unchecked_optional_access_test.h"
3870
+
3871
+ struct A {
3872
+ const $ns::$optional<int>& get() const { return x; }
3873
+
3874
+ $ns::$optional<int> x;
3875
+ };
3876
+
3877
+ struct B {
3878
+ const A& getA() const { return a; }
3879
+
3880
+ A a;
3881
+ };
3882
+
3883
+ void target(B& b) {
3884
+ if (b.getA().get().has_value()) {
3885
+ b.getA().get().value();
3886
+ }
3887
+ }
3888
+ )cc" );
3889
+ }
3890
+
3891
+ TEST_P (
3892
+ UncheckedOptionalAccessTest,
3893
+ ConstRefAccessorToOptionalViaConstRefAccessorToHoldingObjectWithoutValueCheck) {
3894
+ ExpectDiagnosticsFor (R"cc(
3895
+ #include "unchecked_optional_access_test.h"
3896
+
3897
+ struct A {
3898
+ const $ns::$optional<int>& get() const { return x; }
3899
+
3900
+ $ns::$optional<int> x;
3901
+ };
3902
+
3903
+ struct B {
3904
+ const A& getA() const { return a; }
3905
+
3906
+ A a;
3907
+ };
3908
+
3909
+ void target(B& b) {
3910
+ b.getA().get().value(); // [[unsafe]]
3911
+ }
3912
+ )cc" );
3913
+ }
3914
+
3915
+ TEST_P (UncheckedOptionalAccessTest,
3916
+ ConstRefToOptionalSavedAsTemporaryVariable) {
3917
+ ExpectDiagnosticsFor (R"cc(
3918
+ #include "unchecked_optional_access_test.h"
3919
+
3920
+ struct A {
3921
+ const $ns::$optional<int>& get() const { return x; }
3922
+
3923
+ $ns::$optional<int> x;
3924
+ };
3925
+
3926
+ struct B {
3927
+ const A& getA() const { return a; }
3928
+
3929
+ A a;
3930
+ };
3931
+
3932
+ void target(B& b) {
3933
+ const auto& opt = b.getA().get();
3934
+ if (opt.has_value()) {
3935
+ opt.value();
3936
+ }
3937
+ }
3938
+ )cc" );
3939
+ }
3940
+
3941
+ TEST_P (UncheckedOptionalAccessTest,
3942
+ ConstRefAccessorToOptionalViaAccessorToHoldingObjectByValue) {
3943
+ ExpectDiagnosticsFor (R"cc(
3944
+ #include "unchecked_optional_access_test.h"
3945
+
3946
+ struct A {
3947
+ const $ns::$optional<int>& get() const { return x; }
3948
+
3949
+ $ns::$optional<int> x;
3950
+ };
3951
+
3952
+ struct B {
3953
+ const A copyA() const { return a; }
3954
+
3955
+ A a;
3956
+ };
3957
+
3958
+ void target(B& b) {
3959
+ if (b.copyA().get().has_value()) {
3960
+ b.copyA().get().value(); // [[unsafe]]
3961
+ }
3962
+ }
3963
+ )cc" );
3964
+ }
3965
+
3966
+ TEST_P (UncheckedOptionalAccessTest,
3967
+ ConstRefAccessorToOptionalViaNonConstRefAccessorToHoldingObject) {
3968
+ ExpectDiagnosticsFor (R"cc(
3969
+ #include "unchecked_optional_access_test.h"
3970
+
3971
+ struct A {
3972
+ const $ns::$optional<int>& get() const { return x; }
3973
+
3974
+ $ns::$optional<int> x;
3975
+ };
3976
+
3977
+ struct B {
3978
+ A& getA() { return a; }
3979
+
3980
+ A a;
3981
+ };
3982
+
3983
+ void target(B& b) {
3984
+ if (b.getA().get().has_value()) {
3985
+ b.getA().get().value(); // [[unsafe]]
3986
+ }
3987
+ }
3988
+ )cc" );
3989
+ }
3990
+
3991
+ TEST_P (
3992
+ UncheckedOptionalAccessTest,
3993
+ ConstRefAccessorToOptionalViaConstRefAccessorToHoldingObjectWithModAfterCheck) {
3994
+ ExpectDiagnosticsFor (R"cc(
3995
+ #include "unchecked_optional_access_test.h"
3996
+
3997
+ struct A {
3998
+ const $ns::$optional<int>& get() const { return x; }
3999
+
4000
+ $ns::$optional<int> x;
4001
+ };
4002
+
4003
+ struct B {
4004
+ const A& getA() const { return a; }
4005
+
4006
+ A& getA() { return a; }
4007
+
4008
+ void clear() { a = A{}; }
4009
+
4010
+ A a;
4011
+ };
4012
+
4013
+ void target(B& b) {
4014
+ // changing field A via non-const getter after const getter check
4015
+ if (b.getA().get().has_value()) {
4016
+ b.getA() = A{};
4017
+ b.getA().get().value(); // [[unsafe]]
4018
+ }
4019
+
4020
+ // calling non-const method which might change field A
4021
+ if (b.getA().get().has_value()) {
4022
+ b.clear();
4023
+ b.getA().get().value(); // [[unsafe]]
4024
+ }
4025
+ }
4026
+ )cc" );
4027
+ }
4028
+
4029
+ TEST_P (
4030
+ UncheckedOptionalAccessTest,
4031
+ ConstRefAccessorToOptionalViaConstRefAccessorToHoldingObjectWithAnotherConstCallAfterCheck) {
4032
+ ExpectDiagnosticsFor (R"cc(
4033
+ #include "unchecked_optional_access_test.h"
4034
+
4035
+ struct A {
4036
+ const $ns::$optional<int>& get() const { return x; }
4037
+
4038
+ $ns::$optional<int> x;
4039
+ };
4040
+
4041
+ struct B {
4042
+ const A& getA() const { return a; }
4043
+
4044
+ void callWithoutChanges() const {
4045
+ // no-op
4046
+ }
4047
+
4048
+ A a;
4049
+ };
4050
+
4051
+ void target(B& b) {
4052
+ if (b.getA().get().has_value()) {
4053
+ b.callWithoutChanges(); // calling const method which cannot change A
4054
+ b.getA().get().value();
4055
+ }
4056
+ }
4057
+ )cc" );
4058
+ }
4059
+
3866
4060
// FIXME: Add support for:
3867
4061
// - constructors (copy, move)
3868
4062
// - assignment operators (default, copy, move)
0 commit comments