[clang] 65e710c - [clang][dataflow] Model calls returning optionals

Stanislav Gatev via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 3 06:39:11 PDT 2022


Author: Stanislav Gatev
Date: 2022-06-03T13:38:22Z
New Revision: 65e710c3fc036706ec20b357a1bfce9cbadf5705

URL: https://github.com/llvm/llvm-project/commit/65e710c3fc036706ec20b357a1bfce9cbadf5705
DIFF: https://github.com/llvm/llvm-project/commit/65e710c3fc036706ec20b357a1bfce9cbadf5705.diff

LOG: [clang][dataflow] Model calls returning optionals

Model calls returning optionals

Differential Revision: https://reviews.llvm.org/D126759

Reviewed-by: ymandel, xazax.hun

Added: 
    

Modified: 
    clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
    clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
index c797e02cec990..22a33c397a644 100644
--- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp
@@ -45,6 +45,11 @@ DeclarationMatcher optionalClass() {
 
 auto hasOptionalType() { return hasType(optionalClass()); }
 
+auto hasOptionalOrAliasType() {
+  return hasUnqualifiedDesugaredType(
+      recordType(hasDeclaration(optionalClass())));
+}
+
 auto isOptionalMemberCallWithName(
     llvm::StringRef MemberName,
     llvm::Optional<StatementMatcher> Ignorable = llvm::None) {
@@ -158,6 +163,12 @@ auto isValueOrNotEqX() {
                                ComparesToSame(integerLiteral(equals(0)))));
 }
 
+auto isCallReturningOptional() {
+  return callExpr(callee(functionDecl(
+      returns(anyOf(hasOptionalOrAliasType(),
+                    referenceType(pointee(hasOptionalOrAliasType())))))));
+}
+
 /// Creates a symbolic value for an `optional` value using `HasValueVal` as the
 /// symbolic value of its "has_value" property.
 StructValue &createOptionalValue(Environment &Env, BoolValue &HasValueVal) {
@@ -322,6 +333,18 @@ void transferValueOrNotEqX(const Expr *ComparisonExpr,
                       });
 }
 
+void transferCallReturningOptional(const CallExpr *E,
+                                   const MatchFinder::MatchResult &Result,
+                                   LatticeTransferState &State) {
+  if (State.Env.getStorageLocation(*E, SkipPast::None) != nullptr)
+    return;
+
+  auto &Loc = State.Env.createStorageLocation(*E);
+  State.Env.setStorageLocation(*E, Loc);
+  State.Env.setValue(
+      Loc, createOptionalValue(State.Env, State.Env.makeAtomicBoolValue()));
+}
+
 void assignOptionalValue(const Expr &E, LatticeTransferState &State,
                          BoolValue &HasValueVal) {
   if (auto *OptionalLoc =
@@ -547,6 +570,10 @@ auto buildTransferMatchSwitch(
       // opt.value_or(X) != X
       .CaseOf<Expr>(isValueOrNotEqX(), transferValueOrNotEqX)
 
+      // returns optional
+      .CaseOf<CallExpr>(isCallReturningOptional(),
+                        transferCallReturningOptional)
+
       .Build();
 }
 

diff  --git a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
index a501f549851f9..a4ea2bf5e5abc 100644
--- a/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp
@@ -2150,6 +2150,70 @@ TEST_P(UncheckedOptionalAccessTest, UniquePtrToStructWithOptionalField) {
       UnorderedElementsAre(Pair("check-1", "safe"), Pair("check-2", "safe")));
 }
 
+TEST_P(UncheckedOptionalAccessTest, CallReturningOptional) {
+  ExpectLatticeChecksFor(
+      R"(
+    #include "unchecked_optional_access_test.h"
+
+    $ns::$optional<int> MakeOpt();
+
+    void target() {
+      $ns::$optional<int> opt = 0;
+      opt = MakeOpt();
+      opt.value();
+      /*[[check-1]]*/
+    }
+  )",
+      UnorderedElementsAre(Pair("check-1", "unsafe: input.cc:9:7")));
+
+  ExpectLatticeChecksFor(
+      R"(
+    #include "unchecked_optional_access_test.h"
+
+    const $ns::$optional<int>& MakeOpt();
+
+    void target() {
+      $ns::$optional<int> opt = 0;
+      opt = MakeOpt();
+      opt.value();
+      /*[[check-2]]*/
+    }
+  )",
+      UnorderedElementsAre(Pair("check-2", "unsafe: input.cc:9:7")));
+
+  ExpectLatticeChecksFor(
+      R"(
+    #include "unchecked_optional_access_test.h"
+
+    using IntOpt = $ns::$optional<int>;
+    IntOpt MakeOpt();
+
+    void target() {
+      IntOpt opt = 0;
+      opt = MakeOpt();
+      opt.value();
+      /*[[check-3]]*/
+    }
+  )",
+      UnorderedElementsAre(Pair("check-3", "unsafe: input.cc:10:7")));
+
+  ExpectLatticeChecksFor(
+      R"(
+    #include "unchecked_optional_access_test.h"
+
+    using IntOpt = $ns::$optional<int>;
+    const IntOpt& MakeOpt();
+
+    void target() {
+      IntOpt opt = 0;
+      opt = MakeOpt();
+      opt.value();
+      /*[[check-4]]*/
+    }
+  )",
+      UnorderedElementsAre(Pair("check-4", "unsafe: input.cc:10:7")));
+}
+
 // FIXME: Add support for:
 // - constructors (copy, move)
 // - assignment operators (default, copy, move)


        


More information about the cfe-commits mailing list