diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -389,6 +389,12 @@ /// necessary storage locations and values for indirections until it finds a /// non-pointer/non-reference type. /// + /// If `Type` is one of the following types, this function will always return + /// a non-null pointer: + /// - `bool` + /// - Any integer type + /// - Any class, struct, or union type + /// /// Requirements: /// /// `Type` must not be null. @@ -692,6 +698,24 @@ /// order in which they appear in `InitListExpr::inits()`. std::vector getFieldsForInitListExpr(const RecordDecl *RD); +/// Associates a new `StructValue` with `Loc` and returns the new value. +/// It is not defined whether the field values remain the same or not. +/// +/// This function is primarily intended for use by checks that set custom +/// properties on `StructValue`s to model the state of these values. Such checks +/// should avoid modifying the properties of an existing `StructValue` because +/// these changes would be visible to other `Environment`s that share the same +/// `StructValue`. Instead, call `refreshStructValue()`, then set the properties +/// on the new `StructValue` that it returns. Typical usage: +/// +/// refreshStructValue(Loc, Env).setProperty("my_prop", MyPropValue); +StructValue &refreshStructValue(AggregateStorageLocation &Loc, + Environment &Env); + +/// Associates a new `StructValue` with `Expr` and returns the new value. +/// See also documentation for the overload above. +StructValue &refreshStructValue(const Expr &Expr, Environment &Env); + } // namespace dataflow } // namespace clang diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -987,5 +987,30 @@ return Fields; } +StructValue &refreshStructValue(AggregateStorageLocation &Loc, + Environment &Env) { + auto &NewVal = *cast(Env.createValue(Loc.getType())); + Env.setValue(Loc, NewVal); + return NewVal; +} + +StructValue &refreshStructValue(const Expr &Expr, Environment &Env) { + assert(Expr.getType()->isRecordType()); + + auto &NewVal = *cast(Env.createValue(Expr.getType())); + + if (Expr.isPRValue()) { + Env.setValueStrict(Expr, NewVal); + } else { + StorageLocation *Loc = Env.getStorageLocationStrict(Expr); + if (Loc == nullptr) { + Loc = &Env.createStorageLocation(Expr); + } + Env.setValue(*Loc, NewVal); + } + + return NewVal; +} + } // namespace dataflow } // namespace clang diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -370,13 +370,6 @@ // FIXME: Called functions at point `p` should contain only "foo". } -StructValue &createNewStructValue(AggregateStorageLocation &Loc, - Environment &Env) { - auto &Val = *cast(Env.createValue(Loc.getType())); - Env.setValue(Loc, Val); - return Val; -} - // Models an analysis that uses flow conditions. class SpecialBoolAnalysis final : public DataflowAnalysis { @@ -407,7 +400,7 @@ auto &ObjectLoc = *cast(getImplicitObjectLocation(*E, Env)); - createNewStructValue(ObjectLoc, Env) + refreshStructValue(ObjectLoc, Env) .setProperty("is_set", Env.getBoolLiteralValue(true)); } } @@ -562,10 +555,7 @@ auto *Object = E->getArg(0); assert(Object != nullptr); - auto &ObjectLoc = *cast( - Env.getStorageLocation(*Object, SkipPast::Reference)); - - createNewStructValue(ObjectLoc, Env) + refreshStructValue(*Object, Env) .setProperty("has_value", Env.getBoolLiteralValue(true)); } }