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) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits