@@ -1282,28 +1282,35 @@ static raw_ostream &operator<<(raw_ostream &OS,
12821282class UncheckedOptionalAccessTest
12831283 : public ::testing::TestWithParam<OptionalTypeIdentifier> {
12841284protected:
1285- void ExpectDiagnosticsFor (std::string SourceCode) {
1286- ExpectDiagnosticsFor (SourceCode, ast_matchers::hasName (" target" ));
1285+ void ExpectDiagnosticsFor (std::string SourceCode,
1286+ bool IgnoreSmartPointerDereference = true ) {
1287+ ExpectDiagnosticsFor (SourceCode, ast_matchers::hasName (" target" ),
1288+ IgnoreSmartPointerDereference);
12871289 }
12881290
1289- void ExpectDiagnosticsForLambda (std::string SourceCode) {
1291+ void ExpectDiagnosticsForLambda (std::string SourceCode,
1292+ bool IgnoreSmartPointerDereference = true ) {
12901293 ExpectDiagnosticsFor (
1291- SourceCode, ast_matchers::hasDeclContext (
1292- ast_matchers::cxxRecordDecl (ast_matchers::isLambda ())));
1294+ SourceCode,
1295+ ast_matchers::hasDeclContext (
1296+ ast_matchers::cxxRecordDecl (ast_matchers::isLambda ())),
1297+ IgnoreSmartPointerDereference);
12931298 }
12941299
12951300 template <typename FuncDeclMatcher>
1296- void ExpectDiagnosticsFor (std::string SourceCode,
1297- FuncDeclMatcher FuncMatcher ) {
1301+ void ExpectDiagnosticsFor (std::string SourceCode, FuncDeclMatcher FuncMatcher,
1302+ bool IgnoreSmartPointerDereference = true ) {
12981303 // Run in C++17 and C++20 mode to cover differences in the AST between modes
12991304 // (e.g. C++20 can contain `CXXRewrittenBinaryOperator`).
13001305 for (const char *CxxMode : {" -std=c++17" , " -std=c++20" })
1301- ExpectDiagnosticsFor (SourceCode, FuncMatcher, CxxMode);
1306+ ExpectDiagnosticsFor (SourceCode, FuncMatcher, CxxMode,
1307+ IgnoreSmartPointerDereference);
13021308 }
13031309
13041310 template <typename FuncDeclMatcher>
13051311 void ExpectDiagnosticsFor (std::string SourceCode, FuncDeclMatcher FuncMatcher,
1306- const char *CxxMode) {
1312+ const char *CxxMode,
1313+ bool IgnoreSmartPointerDereference) {
13071314 ReplaceAllOccurrences (SourceCode, " $ns" , GetParam ().NamespaceName );
13081315 ReplaceAllOccurrences (SourceCode, " $optional" , GetParam ().TypeName );
13091316
@@ -1328,8 +1335,7 @@ class UncheckedOptionalAccessTest
13281335 template <typename T>
13291336 T Make();
13301337 )" );
1331- UncheckedOptionalAccessModelOptions Options{
1332- /* IgnoreSmartPointerDereference=*/ true };
1338+ UncheckedOptionalAccessModelOptions Options{IgnoreSmartPointerDereference};
13331339 std::vector<SourceLocation> Diagnostics;
13341340 llvm::Error Error = checkDataflow<UncheckedOptionalAccessModel>(
13351341 AnalysisInputs<UncheckedOptionalAccessModel>(
@@ -3721,6 +3727,50 @@ TEST_P(UncheckedOptionalAccessTest, ConstByValueAccessorWithModInBetween) {
37213727 )cc" );
37223728}
37233729
3730+ TEST_P (UncheckedOptionalAccessTest, ConstPointerAccessor) {
3731+ ExpectDiagnosticsFor (R"cc(
3732+ #include "unchecked_optional_access_test.h"
3733+
3734+ struct A {
3735+ $ns::$optional<int> x;
3736+ };
3737+
3738+ struct MyUniquePtr {
3739+ A* operator->() const;
3740+ };
3741+
3742+ void target(MyUniquePtr p) {
3743+ if (p->x) {
3744+ *p->x;
3745+ }
3746+ }
3747+ )cc" ,
3748+ /* IgnoreSmartPointerDereference=*/ false );
3749+ }
3750+
3751+ TEST_P (UncheckedOptionalAccessTest, ConstPointerAccessorWithModInBetween) {
3752+ ExpectDiagnosticsFor (R"cc(
3753+ #include "unchecked_optional_access_test.h"
3754+
3755+ struct A {
3756+ $ns::$optional<int> x;
3757+ };
3758+
3759+ struct MyUniquePtr {
3760+ A* operator->() const;
3761+ void reset(A*);
3762+ };
3763+
3764+ void target(MyUniquePtr p) {
3765+ if (p->x) {
3766+ p.reset(nullptr);
3767+ *p->x; // [[unsafe]]
3768+ }
3769+ }
3770+ )cc" ,
3771+ /* IgnoreSmartPointerDereference=*/ false );
3772+ }
3773+
37243774TEST_P (UncheckedOptionalAccessTest, ConstBoolAccessor) {
37253775 ExpectDiagnosticsFor (R"cc(
37263776 #include "unchecked_optional_access_test.h"
0 commit comments