================ @@ -523,6 +544,99 @@ void transferCallReturningOptional(const CallExpr *E, setHasValue(*Loc, State.Env.makeAtomicBoolValue(), State.Env); } +void handleConstMemberCall(const CallExpr *CE, + dataflow::RecordStorageLocation *RecordLoc, + const MatchFinder::MatchResult &Result, + LatticeTransferState &State) { + // If the const method returns an optional or reference to an optional. + if (RecordLoc != nullptr && isSupportedOptionalType(CE->getType())) { + StorageLocation *Loc = + State.Lattice.getOrCreateConstMethodReturnStorageLocation( + *RecordLoc, CE, State.Env, [&](StorageLocation &Loc) { + setHasValue(cast<RecordStorageLocation>(Loc), + State.Env.makeAtomicBoolValue(), State.Env); + }); + if (Loc == nullptr) + return; + if (CE->isGLValue()) { + // If the call to the const method returns a reference to an optional, + // link the call expression to the cached StorageLocation. + State.Env.setStorageLocation(*CE, *Loc); + } else { + // If the call to the const method returns an optional by value, we + // need to use CopyRecord to link the optional to the result object + // of the call expression. + auto &ResultLoc = State.Env.getResultObjectLocation(*CE); + copyRecord(*cast<RecordStorageLocation>(Loc), ResultLoc, State.Env); + } + return; + } + + // Cache if the const method returns a boolean type. + // We may decide to cache other return types in the future. + if (RecordLoc != nullptr && CE->getType()->isBooleanType()) { + Value *Val = State.Lattice.getOrCreateConstMethodReturnValue(*RecordLoc, CE, + State.Env); + if (Val == nullptr) + return; + State.Env.setValue(*CE, *Val); + return; + } + + // Perform default handling if the call returns an optional + // but wasn't handled above (if RecordLoc is nullptr). + if (isSupportedOptionalType(CE->getType())) { + transferCallReturningOptional(CE, Result, State); + } +} + +void transferValue_ConstMemberCall(const CXXMemberCallExpr *MCE, + const MatchFinder::MatchResult &Result, + LatticeTransferState &State) { + handleConstMemberCall( + MCE, dataflow::getImplicitObjectLocation(*MCE, State.Env), Result, State); +} + +void handleNonConstMemberCall(const CallExpr *CE, + dataflow::RecordStorageLocation *RecordLoc, + const MatchFinder::MatchResult &Result, + LatticeTransferState &State) { + // When a non-const member function is called, reset some state. + if (RecordLoc != nullptr) { + for (const auto [Field, FieldLoc] : RecordLoc->children()) { + if (isSupportedOptionalType(Field->getType())) { + auto *FieldRecordLoc = cast_or_null<RecordStorageLocation>(FieldLoc); + if (FieldRecordLoc) { + setHasValue(*FieldRecordLoc, State.Env.makeAtomicBoolValue(), + State.Env); + } + } + } ---------------- jvoung wrote:
Yes this is new and independent of the accessors feature (overlap is handling non-const method calls now). Sounds good! Added a test. https://github.com/llvm/llvm-project/pull/112605 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits