19
19
#include " clang/AST/DeclBase.h"
20
20
#include " clang/AST/Expr.h"
21
21
#include " clang/AST/Type.h"
22
+ #include " clang/Analysis/FlowSensitive/ASTOps.h"
22
23
#include " clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
23
24
#include " clang/Analysis/FlowSensitive/DataflowLattice.h"
24
25
#include " clang/Analysis/FlowSensitive/Formula.h"
30
31
#include " llvm/ADT/MapVector.h"
31
32
#include " llvm/Support/Compiler.h"
32
33
#include " llvm/Support/ErrorHandling.h"
34
+ #include < cassert>
33
35
#include < memory>
34
36
#include < type_traits>
35
37
#include < utility>
38
+ #include < vector>
36
39
37
40
namespace clang {
38
41
namespace dataflow {
@@ -155,32 +158,40 @@ class Environment {
155
158
156
159
// / Creates an environment that uses `DACtx` to store objects that encompass
157
160
// / 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
+ }
159
183
160
184
// Copy-constructor is private, Environments should not be copied. See fork().
161
185
Environment &operator =(const Environment &Other) = delete ;
162
186
163
187
Environment (Environment &&Other) = default ;
164
188
Environment &operator =(Environment &&Other) = default ;
165
189
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
-
176
190
// / 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.
181
193
// /
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.
184
195
void initialize ();
185
196
186
197
// / Returns a new environment that is a copy of this one.
@@ -193,7 +204,7 @@ class Environment {
193
204
// / forked flow condition references the original).
194
205
Environment fork () const ;
195
206
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
197
208
// / callee. Uses the storage location from each argument in the `Call` as the
198
209
// / storage location for the corresponding parameter in the callee.
199
210
// /
@@ -365,46 +376,51 @@ class Environment {
365
376
RecordStorageLocation &
366
377
getResultObjectLocation (const Expr &RecordPRValue) const ;
367
378
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:
369
381
// / - The function has a void return type
370
382
// / - No return value could be determined for the function, for example
371
383
// / because it calls a function without a body.
372
384
// /
373
385
// / 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.
375
388
Value *getReturnValue () const {
376
389
assert (getCurrentFunc () != nullptr &&
377
390
!getCurrentFunc ()->getReturnType ()->isReferenceType ());
378
391
return ReturnVal;
379
392
}
380
393
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.
384
397
// /
385
398
// / 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.
387
401
StorageLocation *getReturnStorageLocation () const {
388
402
assert (getCurrentFunc () != nullptr &&
389
403
getCurrentFunc ()->getReturnType ()->isReferenceType ());
390
404
return ReturnLoc;
391
405
}
392
406
393
- // / Sets the return value of the current function.
407
+ // / Sets the return value of the function currently being analyzed .
394
408
// /
395
409
// / 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.
397
412
void setReturnValue (Value *Val) {
398
413
assert (getCurrentFunc () != nullptr &&
399
414
!getCurrentFunc ()->getReturnType ()->isReferenceType ());
400
415
ReturnVal = Val;
401
416
}
402
417
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 .
405
420
// /
406
421
// / 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.
408
424
void setReturnStorageLocation (StorageLocation *Loc) {
409
425
assert (getCurrentFunc () != nullptr &&
410
426
getCurrentFunc ()->getReturnType ()->isReferenceType ());
@@ -641,23 +657,21 @@ class Environment {
641
657
// / (or the flow condition is overly constraining) or if the solver times out.
642
658
bool allows (const Formula &) const ;
643
659
644
- // / Returns the `DeclContext` of the block being analysed, if any. Otherwise,
645
- // / returns null.
646
- const DeclContext *getDeclCtx () const { return CallStack.back (); }
647
-
648
660
// / Returns the function currently being analyzed, or null if the code being
649
661
// / analyzed isn't part of a function.
650
662
const FunctionDecl *getCurrentFunc () const {
651
- return dyn_cast<FunctionDecl>( getDeclCtx () );
663
+ return CallStack. empty () ? InitialTargetFunc : CallStack. back ( );
652
664
}
653
665
654
- // / Returns the size of the call stack.
666
+ // / Returns the size of the call stack, not counting the initial analysis
667
+ // / target.
655
668
size_t callStackSize () const { return CallStack.size (); }
656
669
657
670
// / 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 ;
661
675
662
676
// / Returns the `DataflowAnalysisContext` used by the environment.
663
677
DataflowAnalysisContext &getDataflowAnalysisContext () const { return *DACtx; }
@@ -719,15 +733,20 @@ class Environment {
719
733
ArrayRef<const Expr *> Args);
720
734
721
735
// / 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 );
724
738
725
739
static PrValueToResultObject
726
740
buildResultObjectMap (DataflowAnalysisContext *DACtx,
727
741
const FunctionDecl *FuncDecl,
728
742
RecordStorageLocation *ThisPointeeLoc,
729
743
RecordStorageLocation *LocForRecordReturnVal);
730
744
745
+ static PrValueToResultObject
746
+ buildResultObjectMap (DataflowAnalysisContext *DACtx, Stmt *S,
747
+ RecordStorageLocation *ThisPointeeLoc,
748
+ RecordStorageLocation *LocForRecordReturnVal);
749
+
731
750
// `DACtx` is not null and not owned by this object.
732
751
DataflowAnalysisContext *DACtx;
733
752
@@ -736,11 +755,20 @@ class Environment {
736
755
// shared between environments in the same call.
737
756
// https://github.com/llvm/llvm-project/issues/59005
738
757
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 ;
741
769
742
770
// 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 .
744
772
// FIXME: It's somewhat unsatisfactory that we have to use a `shared_ptr`
745
773
// here, though the cost is acceptable: The overhead of a `shared_ptr` is
746
774
// incurred when it is copied, and this happens only relatively rarely (when
@@ -749,7 +777,7 @@ class Environment {
749
777
std::shared_ptr<PrValueToResultObject> ResultObjectMap;
750
778
751
779
// The following three member variables handle various different types of
752
- // return values.
780
+ // return values when the current analysis target is a function .
753
781
// - If the return type is not a reference and not a record: Value returned
754
782
// by the function.
755
783
Value *ReturnVal = nullptr ;
@@ -762,7 +790,7 @@ class Environment {
762
790
RecordStorageLocation *LocForRecordReturnVal = nullptr ;
763
791
764
792
// 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.
766
794
RecordStorageLocation *ThisPointeeLoc = nullptr ;
767
795
768
796
// Maps from declarations and glvalue expression to storage locations that are
0 commit comments