ConstructionContextItem(const ObjCMessageExpr *ME, unsigned Index)
: Data(ME), Kind(ArgumentKind), Index(Index) {}
+ // A polymorphic version of the previous calls with dynamic type check.
+ ConstructionContextItem(const Expr *E, unsigned Index)
+ : Data(E), Kind(ArgumentKind), Index(Index) {
+ assert(isa<CallExpr>(E) || isa<CXXConstructExpr>(E) ||
+ isa<ObjCMessageExpr>(E));
+ }
+
ConstructionContextItem(const CXXCtorInitializer *Init)
: Data(Init), Kind(InitializerKind), Index(0) {}
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
/// \p D must not be null.
static bool isVariadic(const Decl *D);
+ /// Returns AnalysisDeclContext for the callee stack frame.
+ /// Currently may fail; returns null on failure.
+ AnalysisDeclContext *getCalleeAnalysisDeclContext() const;
+
+ /// Returns the callee stack frame. That stack frame will only be entered
+ /// during analysis if the call is inlined, but it may still be useful
+ /// in intermediate calculations even if the call isn't inlined.
+ /// May fail; returns null on failure.
+ const StackFrameContext *getCalleeStackFrame() const;
+
+ /// Returns memory location for a parameter variable within the callee stack
+ /// frame. May fail; returns null on failure.
+ const VarRegion *getParameterLocation(unsigned Index) const;
+
+ /// Returns true if on the current path, the argument was constructed by
+ /// calling a C++ constructor over it. This is an internal detail of the
+ /// analysis which doesn't necessarily represent the program semantics:
+ /// if we are supposed to construct an argument directly, we may still
+ /// not do that because we don't know how (i.e., construction context is
+ /// unavailable in the CFG or not supported by the analyzer).
+ bool isArgumentConstructedDirectly(unsigned Index) const {
+ // This assumes that the object was not yet removed from the state.
+ return ExprEngine::getObjectUnderConstruction(
+ getState(), {getOriginExpr(), Index}, getCalleeStackFrame()).hasValue();
+ }
+
+ /// Some calls have parameter numbering mismatched from argument numbering.
+ /// This function converts an argument index to the corresponding
+ /// parameter index. Returns None is the argument doesn't correspond
+ /// to any parameter variable.
+ Optional<unsigned> getAdjustedParameterIndex(unsigned ArgumentIndex) const {
+ if (dyn_cast_or_null<CXXOperatorCallExpr>(getOriginExpr()) &&
+ dyn_cast_or_null<CXXMethodDecl>(getDecl())) {
+ // For member operator calls argument 0 on the expression corresponds
+ // to implicit this-parameter on the declaration.
+ return (ArgumentIndex > 0) ? Optional<unsigned>(ArgumentIndex - 1) : None;
+ }
+ return ArgumentIndex;
+ }
+
// Iterator access to formal parameters and their types.
private:
struct GetTypeFn {
return svalBuilder.evalBinOp(ST, Op, LHS, RHS, T);
}
+ /// By looking at a certain item that may be potentially part of an object's
+ /// ConstructionContext, retrieve such object's location. A particular
+ /// statement can be transparently passed as \p Item in most cases.
+ static Optional<SVal>
+ getObjectUnderConstruction(ProgramStateRef State,
+ const ConstructionContextItem &Item,
+ const LocationContext *LC);
+
protected:
/// evalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by evalStore, VisitDeclStmt, and others.
const ConstructionContextItem &Item,
const LocationContext *LC);
- /// If the given statement corresponds to an object under construction,
- /// being part of its construciton context, retrieve that object's location.
- static Optional<SVal>
- getObjectUnderConstruction(ProgramStateRef State,
- const ConstructionContextItem &Item,
- const LocationContext *LC);
-
/// If the given expression corresponds to a temporary that was used for
/// passing into an elidable copy/move constructor and that constructor
/// was actually elided, track that we also need to elide the destructor.
#include "clang/AST/Type.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/CrossTU/CrossTranslationUnit.h"
#include "clang/Basic/IdentifierTable.h"
return CheckerContext::isCLibraryFunction(FD, FunctionName);
}
+AnalysisDeclContext *CallEvent::getCalleeAnalysisDeclContext() const {
+ const Decl *D = getDecl();
+
+ // If the callee is completely unknown, we cannot construct the stack frame.
+ if (!D)
+ return nullptr;
+
+ // FIXME: Skip virtual functions for now. There's no easy procedure to foresee
+ // the exact decl that should be used, especially when it's not a definition.
+ if (const Decl *RD = getRuntimeDefinition().getDecl())
+ if (RD != D)
+ return nullptr;
+
+ return LCtx->getAnalysisDeclContext()->getManager()->getContext(D);
+}
+
+const StackFrameContext *CallEvent::getCalleeStackFrame() const {
+ AnalysisDeclContext *ADC = getCalleeAnalysisDeclContext();
+ if (!ADC)
+ return nullptr;
+
+ const Expr *E = getOriginExpr();
+ if (!E)
+ return nullptr;
+
+ // Recover CFG block via reverse lookup.
+ // TODO: If we were to keep CFG element information as part of the CallEvent
+ // instead of doing this reverse lookup, we would be able to build the stack
+ // frame for non-expression-based calls, and also we wouldn't need the reverse
+ // lookup.
+ CFGStmtMap *Map = LCtx->getAnalysisDeclContext()->getCFGStmtMap();
+ const CFGBlock *B = Map->getBlock(E);
+ assert(B);
+
+ // Also recover CFG index by scanning the CFG block.
+ unsigned Idx = 0, Sz = B->size();
+ for (; Idx < Sz; ++Idx)
+ if (auto StmtElem = (*B)[Idx].getAs<CFGStmt>())
+ if (StmtElem->getStmt() == E)
+ break;
+ assert(Idx < Sz);
+
+ return ADC->getManager()->getStackFrame(ADC, LCtx, E, B, Idx);
+}
+
+const VarRegion *CallEvent::getParameterLocation(unsigned Index) const {
+ const StackFrameContext *SFC = getCalleeStackFrame();
+ // We cannot construct a VarRegion without a stack frame.
+ if (!SFC)
+ return nullptr;
+
+ const ParmVarDecl *PVD = parameters()[Index];
+ const VarRegion *VR =
+ State->getStateManager().getRegionManager().getVarRegion(PVD, SFC);
+
+ // This sanity check would fail if our parameter declaration doesn't
+ // correspond to the stack frame's function declaration.
+ assert(VR->getStackFrame() == SFC);
+
+ return VR;
+}
+
/// Returns true if a type is a pointer-to-const or reference-to-const
/// with no further indirection.
static bool isPointerToConst(QualType Ty) {