1919#include " clang/AST/DeclBase.h"
2020#include " clang/AST/Expr.h"
2121#include " clang/AST/Type.h"
22+ #include " clang/Analysis/FlowSensitive/ASTOps.h"
2223#include " clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
2324#include " clang/Analysis/FlowSensitive/DataflowLattice.h"
2425#include " clang/Analysis/FlowSensitive/Formula.h"
3031#include " llvm/ADT/MapVector.h"
3132#include " llvm/Support/Compiler.h"
3233#include " llvm/Support/ErrorHandling.h"
34+ #include < cassert>
3335#include < memory>
3436#include < type_traits>
3537#include < utility>
38+ #include < vector>
3639
3740namespace clang {
3841namespace dataflow {
@@ -155,32 +158,40 @@ class Environment {
155158
156159 // / Creates an environment that uses `DACtx` to store objects that encompass
157160 // / the state of a program.
158- explicit Environment (DataflowAnalysisContext &DACtx);
161+ explicit Environment (DataflowAnalysisContext &DACtx)
162+ : DACtx(&DACtx),
163+ FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {}
164+
165+ // / Creates an environment that uses `DACtx` to store objects that encompass
166+ // / the state of a program, with `S` as the statement to analyze.
167+ Environment (DataflowAnalysisContext &DACtx, Stmt &S) : Environment(DACtx) {
168+ InitialTargetStmt = &S;
169+ }
170+
171+ // / Creates an environment that uses `DACtx` to store objects that encompass
172+ // / the state of a program, with `FD` as the function to analyze.
173+ // /
174+ // / Requirements:
175+ // /
176+ // / The function must have a body, i.e.
177+ // / `FunctionDecl::doesThisDecalarationHaveABody()` must be true.
178+ Environment (DataflowAnalysisContext &DACtx, const FunctionDecl &FD)
179+ : Environment(DACtx, *FD.getBody()) {
180+ assert (FD.doesThisDeclarationHaveABody ());
181+ InitialTargetFunc = &FD;
182+ }
159183
160184 // Copy-constructor is private, Environments should not be copied. See fork().
161185 Environment &operator =(const Environment &Other) = delete ;
162186
163187 Environment (Environment &&Other) = default ;
164188 Environment &operator =(Environment &&Other) = default ;
165189
166- // / Creates an environment that uses `DACtx` to store objects that encompass
167- // / the state of a program.
168- // /
169- // / If `DeclCtx` is a function, initializes the environment with symbolic
170- // / representations of the function parameters.
171- // /
172- // / If `DeclCtx` is a non-static member function, initializes the environment
173- // / with a symbolic representation of the `this` pointee.
174- Environment (DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx);
175-
176190 // / Assigns storage locations and values to all parameters, captures, global
177- // / variables, fields and functions referenced in the function currently being
178- // / analyzed.
179- // /
180- // / Requirements:
191+ // / variables, fields and functions referenced in the `Stmt` or `FunctionDecl`
192+ // / passed to the constructor.
181193 // /
182- // / The function must have a body, i.e.
183- // / `FunctionDecl::doesThisDecalarationHaveABody()` must be true.
194+ // / If no `Stmt` or `FunctionDecl` was supplied, this function does nothing.
184195 void initialize ();
185196
186197 // / Returns a new environment that is a copy of this one.
@@ -193,7 +204,7 @@ class Environment {
193204 // / forked flow condition references the original).
194205 Environment fork () const ;
195206
196- // / Creates and returns an environment to use for an inline analysis of the
207+ // / Creates and returns an environment to use for an inline analysis of the
197208 // / callee. Uses the storage location from each argument in the `Call` as the
198209 // / storage location for the corresponding parameter in the callee.
199210 // /
@@ -365,46 +376,51 @@ class Environment {
365376 RecordStorageLocation &
366377 getResultObjectLocation (const Expr &RecordPRValue) const ;
367378
368- // / Returns the return value of the current function. This can be null if:
379+ // / Returns the return value of the function currently being analyzed.
380+ // / This can be null if:
369381 // / - The function has a void return type
370382 // / - No return value could be determined for the function, for example
371383 // / because it calls a function without a body.
372384 // /
373385 // / Requirements:
374- // / The current function must have a non-reference return type.
386+ // / The current analysis target must be a function and must have a
387+ // / non-reference return type.
375388 Value *getReturnValue () const {
376389 assert (getCurrentFunc () != nullptr &&
377390 !getCurrentFunc ()->getReturnType ()->isReferenceType ());
378391 return ReturnVal;
379392 }
380393
381- // / Returns the storage location for the reference returned by the current
382- // / function . This can be null if function doesn't return a single consistent
383- // / reference.
394+ // / Returns the storage location for the reference returned by the function
395+ // / currently being analyzed . This can be null if the function doesn't return
396+ // / a single consistent reference.
384397 // /
385398 // / Requirements:
386- // / The current function must have a reference return type.
399+ // / The current analysis target must be a function and must have a reference
400+ // / return type.
387401 StorageLocation *getReturnStorageLocation () const {
388402 assert (getCurrentFunc () != nullptr &&
389403 getCurrentFunc ()->getReturnType ()->isReferenceType ());
390404 return ReturnLoc;
391405 }
392406
393- // / Sets the return value of the current function.
407+ // / Sets the return value of the function currently being analyzed .
394408 // /
395409 // / Requirements:
396- // / The current function must have a non-reference return type.
410+ // / The current analysis target must be a function and must have a
411+ // / non-reference return type.
397412 void setReturnValue (Value *Val) {
398413 assert (getCurrentFunc () != nullptr &&
399414 !getCurrentFunc ()->getReturnType ()->isReferenceType ());
400415 ReturnVal = Val;
401416 }
402417
403- // / Sets the storage location for the reference returned by the current
404- // / function .
418+ // / Sets the storage location for the reference returned by the function
419+ // / currently being analyzed .
405420 // /
406421 // / Requirements:
407- // / The current function must have a reference return type.
422+ // / The current analysis target must be a function and must have a reference
423+ // / return type.
408424 void setReturnStorageLocation (StorageLocation *Loc) {
409425 assert (getCurrentFunc () != nullptr &&
410426 getCurrentFunc ()->getReturnType ()->isReferenceType ());
@@ -641,23 +657,21 @@ class Environment {
641657 // / (or the flow condition is overly constraining) or if the solver times out.
642658 bool allows (const Formula &) const ;
643659
644- // / Returns the `DeclContext` of the block being analysed, if any. Otherwise,
645- // / returns null.
646- const DeclContext *getDeclCtx () const { return CallStack.back (); }
647-
648660 // / Returns the function currently being analyzed, or null if the code being
649661 // / analyzed isn't part of a function.
650662 const FunctionDecl *getCurrentFunc () const {
651- return dyn_cast<FunctionDecl>( getDeclCtx () );
663+ return CallStack. empty () ? InitialTargetFunc : CallStack. back ( );
652664 }
653665
654- // / Returns the size of the call stack.
666+ // / Returns the size of the call stack, not counting the initial analysis
667+ // / target.
655668 size_t callStackSize () const { return CallStack.size (); }
656669
657670 // / Returns whether this `Environment` can be extended to analyze the given
658- // / `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a
659- // / given `MaxDepth`.
660- bool canDescend (unsigned MaxDepth, const DeclContext *Callee) const ;
671+ // / `Callee` (i.e. if `pushCall` can be used).
672+ // / Recursion is not allowed. `MaxDepth` is the maximum size of the call stack
673+ // / (i.e. the maximum value that `callStackSize()` may assume after the call).
674+ bool canDescend (unsigned MaxDepth, const FunctionDecl *Callee) const ;
661675
662676 // / Returns the `DataflowAnalysisContext` used by the environment.
663677 DataflowAnalysisContext &getDataflowAnalysisContext () const { return *DACtx; }
@@ -719,15 +733,20 @@ class Environment {
719733 ArrayRef<const Expr *> Args);
720734
721735 // / Assigns storage locations and values to all global variables, fields
722- // / and functions referenced in `FuncDecl`. `FuncDecl` must have a body .
723- void initFieldsGlobalsAndFuncs (const FunctionDecl *FuncDecl );
736+ // / and functions in `Referenced` .
737+ void initFieldsGlobalsAndFuncs (const ReferencedDecls &Referenced );
724738
725739 static PrValueToResultObject
726740 buildResultObjectMap (DataflowAnalysisContext *DACtx,
727741 const FunctionDecl *FuncDecl,
728742 RecordStorageLocation *ThisPointeeLoc,
729743 RecordStorageLocation *LocForRecordReturnVal);
730744
745+ static PrValueToResultObject
746+ buildResultObjectMap (DataflowAnalysisContext *DACtx, Stmt *S,
747+ RecordStorageLocation *ThisPointeeLoc,
748+ RecordStorageLocation *LocForRecordReturnVal);
749+
731750 // `DACtx` is not null and not owned by this object.
732751 DataflowAnalysisContext *DACtx;
733752
@@ -736,11 +755,20 @@ class Environment {
736755 // shared between environments in the same call.
737756 // https://github.com/llvm/llvm-project/issues/59005
738757
739- // `DeclContext` of the block being analysed if provided.
740- std::vector<const DeclContext *> CallStack;
758+ // The stack of functions called from the initial analysis target.
759+ std::vector<const FunctionDecl *> CallStack;
760+
761+ // Initial function to analyze, if a function was passed to the constructor.
762+ // Null otherwise.
763+ const FunctionDecl *InitialTargetFunc = nullptr ;
764+ // Top-level statement of the initial analysis target.
765+ // If a function was passed to the constructor, this is its body.
766+ // If a statement was passed to the constructor, this is that statement.
767+ // Null if no analysis target was passed to the constructor.
768+ Stmt *InitialTargetStmt = nullptr ;
741769
742770 // Maps from prvalues of record type to their result objects. Shared between
743- // all environments for the same function .
771+ // all environments for the same analysis target .
744772 // FIXME: It's somewhat unsatisfactory that we have to use a `shared_ptr`
745773 // here, though the cost is acceptable: The overhead of a `shared_ptr` is
746774 // incurred when it is copied, and this happens only relatively rarely (when
@@ -749,7 +777,7 @@ class Environment {
749777 std::shared_ptr<PrValueToResultObject> ResultObjectMap;
750778
751779 // The following three member variables handle various different types of
752- // return values.
780+ // return values when the current analysis target is a function .
753781 // - If the return type is not a reference and not a record: Value returned
754782 // by the function.
755783 Value *ReturnVal = nullptr ;
@@ -762,7 +790,7 @@ class Environment {
762790 RecordStorageLocation *LocForRecordReturnVal = nullptr ;
763791
764792 // The storage location of the `this` pointee. Should only be null if the
765- // function being analyzed is only a function and not a method.
793+ // analysis target is not a method.
766794 RecordStorageLocation *ThisPointeeLoc = nullptr ;
767795
768796 // Maps from declarations and glvalue expression to storage locations that are
0 commit comments