This revision was automatically updated to reflect the committed changes.
Closed by commit rL338474: [analyzer] CallEvent: Add helper methods for 
obtaining the callee stack frame. (authored by dergachev, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D49715?vs=157550&id=158446#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D49715

Files:
  cfe/trunk/include/clang/Analysis/ConstructionContext.h
  cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
  cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
  cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp

Index: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
===================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -581,6 +581,14 @@
     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.
@@ -773,13 +781,6 @@
                            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.
Index: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
===================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -29,6 +29,7 @@
 #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"
@@ -404,6 +405,46 @@
   /// \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 {
Index: cfe/trunk/include/clang/Analysis/ConstructionContext.h
===================================================================
--- cfe/trunk/include/clang/Analysis/ConstructionContext.h
+++ cfe/trunk/include/clang/Analysis/ConstructionContext.h
@@ -112,6 +112,13 @@
   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) {}
 
Index: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
===================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -27,6 +27,7 @@
 #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"
@@ -166,6 +167,68 @@
   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) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to