Author: Kristóf Umann Date: 2024-07-25T13:26:59+02:00 New Revision: f8006a5932b1ccdf3a1eed7b20b5cb608c0a020c
URL: https://github.com/llvm/llvm-project/commit/f8006a5932b1ccdf3a1eed7b20b5cb608c0a020c DIFF: https://github.com/llvm/llvm-project/commit/f8006a5932b1ccdf3a1eed7b20b5cb608c0a020c.diff LOG: [analyzer][NFC] Add some docs for LazyCompoundValue (#97407) Yes, I basically copy-pasted some posts from discord and Artem's book, but these make for a rather decent docs. --------- Co-authored-by: Artem Dergachev <noqnoq...@gmail.com> Co-authored-by: Donát Nagy <donat.n...@ericsson.com> Co-authored-by: Balazs Benics <benicsbal...@gmail.com> Added: Modified: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h Removed: ################################################################################ diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index 3a4b087257149..def2970d448d4 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -326,6 +326,10 @@ class LocAsInteger : public NonLoc { static bool classof(SVal V) { return V.getKind() == LocAsIntegerKind; } }; +/// The simplest example of a concrete compound value is nonloc::CompoundVal, +/// which represents a concrete r-value of an initializer-list or a string. +/// Internally, it contains an llvm::ImmutableList of SVal's stored inside the +/// literal. class CompoundVal : public NonLoc { friend class ento::SValBuilder; @@ -346,6 +350,36 @@ class CompoundVal : public NonLoc { static bool classof(SVal V) { return V.getKind() == CompoundValKind; } }; +/// While nonloc::CompoundVal covers a few simple use cases, +/// nonloc::LazyCompoundVal is a more performant and flexible way to represent +/// an rvalue of record type, so it shows up much more frequently during +/// analysis. This value is an r-value that represents a snapshot of any +/// structure "as a whole" at a given moment during the analysis. Such value is +/// already quite far from being referred to as "concrete", as many fields +/// inside it would be unknown or symbolic. nonloc::LazyCompoundVal operates by +/// storing two things: +/// * a reference to the TypedValueRegion being snapshotted (yes, it is always +/// typed), and also +/// * a reference to the whole Store object, obtained from the ProgramState in +/// which the nonloc::LazyCompoundVal was created. +/// +/// Note that the old ProgramState and its Store is kept alive during the +/// analysis because these are immutable functional data structures and each new +/// Store value is represented as "earlier Store" + "additional binding". +/// +/// Essentially, nonloc::LazyCompoundVal is a performance optimization for the +/// analyzer. Because Store is immutable, creating a nonloc::LazyCompoundVal is +/// a very cheap operation. Note that the Store contains all region bindings in +/// the program state, not only related to the region. Later, if necessary, such +/// value can be unpacked -- eg. when it is assigned to another variable. +/// +/// If you ever need to inspect the contents of the LazyCompoundVal, you can use +/// StoreManager::iterBindings(). It'll iterate through all values in the Store, +/// but you're only interested in the ones that belong to +/// LazyCompoundVal::getRegion(); other bindings are immaterial. +/// +/// NOTE: LazyCompoundVal::getRegion() itself is also immaterial (see the actual +/// method docs for details). class LazyCompoundVal : public NonLoc { friend class ento::SValBuilder; @@ -363,6 +397,18 @@ class LazyCompoundVal : public NonLoc { /// It might return null. const void *getStore() const; + /// This function itself is immaterial. It is only an implementation detail. + /// LazyCompoundVal represents only the rvalue, the data (known or unknown) + /// that *was* stored in that region *at some point in the past*. The region + /// should not be used for any purpose other than figuring out what part of + /// the frozen Store you're interested in. The value does not represent the + /// *current* value of that region. Sometimes it may, but this should not be + /// relied upon. Instead, if you want to figure out what region it represents, + /// you typically need to see where you got it from in the first place. The + /// region is absolutely not analogous to the C++ "this" pointer. It is also + /// not a valid way to "materialize" the prvalue into a glvalue in C++, + /// because the region represents the *old* storage (sometimes very old), not + /// the *future* storage. LLVM_ATTRIBUTE_RETURNS_NONNULL const TypedValueRegion *getRegion() const; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits