Skip to content

Commit f8006a5

Browse files
SzelethushaoNoQNagyDonatsteakhal
authored
[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 <[email protected]> Co-authored-by: Donát Nagy <[email protected]> Co-authored-by: Balazs Benics <[email protected]>
1 parent 72532c9 commit f8006a5

File tree

1 file changed

+46
-0
lines changed
  • clang/include/clang/StaticAnalyzer/Core/PathSensitive

1 file changed

+46
-0
lines changed

clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,10 @@ class LocAsInteger : public NonLoc {
326326
static bool classof(SVal V) { return V.getKind() == LocAsIntegerKind; }
327327
};
328328

329+
/// The simplest example of a concrete compound value is nonloc::CompoundVal,
330+
/// which represents a concrete r-value of an initializer-list or a string.
331+
/// Internally, it contains an llvm::ImmutableList of SVal's stored inside the
332+
/// literal.
329333
class CompoundVal : public NonLoc {
330334
friend class ento::SValBuilder;
331335

@@ -346,6 +350,36 @@ class CompoundVal : public NonLoc {
346350
static bool classof(SVal V) { return V.getKind() == CompoundValKind; }
347351
};
348352

353+
/// While nonloc::CompoundVal covers a few simple use cases,
354+
/// nonloc::LazyCompoundVal is a more performant and flexible way to represent
355+
/// an rvalue of record type, so it shows up much more frequently during
356+
/// analysis. This value is an r-value that represents a snapshot of any
357+
/// structure "as a whole" at a given moment during the analysis. Such value is
358+
/// already quite far from being referred to as "concrete", as many fields
359+
/// inside it would be unknown or symbolic. nonloc::LazyCompoundVal operates by
360+
/// storing two things:
361+
/// * a reference to the TypedValueRegion being snapshotted (yes, it is always
362+
/// typed), and also
363+
/// * a reference to the whole Store object, obtained from the ProgramState in
364+
/// which the nonloc::LazyCompoundVal was created.
365+
///
366+
/// Note that the old ProgramState and its Store is kept alive during the
367+
/// analysis because these are immutable functional data structures and each new
368+
/// Store value is represented as "earlier Store" + "additional binding".
369+
///
370+
/// Essentially, nonloc::LazyCompoundVal is a performance optimization for the
371+
/// analyzer. Because Store is immutable, creating a nonloc::LazyCompoundVal is
372+
/// a very cheap operation. Note that the Store contains all region bindings in
373+
/// the program state, not only related to the region. Later, if necessary, such
374+
/// value can be unpacked -- eg. when it is assigned to another variable.
375+
///
376+
/// If you ever need to inspect the contents of the LazyCompoundVal, you can use
377+
/// StoreManager::iterBindings(). It'll iterate through all values in the Store,
378+
/// but you're only interested in the ones that belong to
379+
/// LazyCompoundVal::getRegion(); other bindings are immaterial.
380+
///
381+
/// NOTE: LazyCompoundVal::getRegion() itself is also immaterial (see the actual
382+
/// method docs for details).
349383
class LazyCompoundVal : public NonLoc {
350384
friend class ento::SValBuilder;
351385

@@ -363,6 +397,18 @@ class LazyCompoundVal : public NonLoc {
363397
/// It might return null.
364398
const void *getStore() const;
365399

400+
/// This function itself is immaterial. It is only an implementation detail.
401+
/// LazyCompoundVal represents only the rvalue, the data (known or unknown)
402+
/// that *was* stored in that region *at some point in the past*. The region
403+
/// should not be used for any purpose other than figuring out what part of
404+
/// the frozen Store you're interested in. The value does not represent the
405+
/// *current* value of that region. Sometimes it may, but this should not be
406+
/// relied upon. Instead, if you want to figure out what region it represents,
407+
/// you typically need to see where you got it from in the first place. The
408+
/// region is absolutely not analogous to the C++ "this" pointer. It is also
409+
/// not a valid way to "materialize" the prvalue into a glvalue in C++,
410+
/// because the region represents the *old* storage (sometimes very old), not
411+
/// the *future* storage.
366412
LLVM_ATTRIBUTE_RETURNS_NONNULL
367413
const TypedValueRegion *getRegion() const;
368414

0 commit comments

Comments
 (0)