Unverified Commit 3b9f8f03 authored by tigbr's avatar tigbr Committed by GitHub
Browse files

[analyzer][NFC] Merge `BlockInvocationContext` class into `StackFrameContext` (#194857)

At the moment, the execution stack in the analyzer is represented with
the `LocationContext` base class and its two sub-classes
`StackFrameContext` and `BlockInvocationContext`. This hierarchy,
however, is more complicated than necessary and, in issue #190973, a
roadmap was created to reduce this hierarchy down to just a single
`StackFrame` class.

This patch implements the first five steps of that roadmap.
Specifically, the functionality of `BlockInvocationContext` was merged
into the `StackFrameContext` class and the `BlockInvocationContext`
class was removed together with its usages.
parent 8442c9c4
Loading
Loading
Loading
Loading
+22 −67
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ namespace clang {
class AnalysisDeclContextManager;
class ASTContext;
class BlockDecl;
class BlockInvocationContext;
class CFGReverseBlockReachabilityAnalysis;
class ImplicitParamDecl;
class LocationContext;
@@ -179,14 +178,10 @@ public:

  /// \copydoc LocationContextManager::getStackFrame()
  const StackFrameContext *getStackFrame(LocationContext const *ParentLC,
                                         const Expr *E, const CFGBlock *Blk,
                                         const void *Data, const Expr *E,
                                         const CFGBlock *Blk,
                                         unsigned BlockCount, unsigned Index);

  /// \copydoc LocationContextManager::getBlockInvocationContext()
  const BlockInvocationContext *
  getBlockInvocationContext(const LocationContext *ParentLC,
                            const BlockDecl *BD, const void *Data);

  /// \returns The specified analysis object, lazily running the analysis if
  /// necessary or nullptr if the analysis could not run.
  template <typename T> T *getAnalysis() {
@@ -208,13 +203,9 @@ private:
  LocationContextManager &getLocationContextManager();
};

/// It wraps the AnalysisDeclContext to represent both the call stack with
/// the help of StackFrameContext and inside the function calls the
/// BlockInvocationContext. It is needed for context sensitive analysis to
/// model entering, leaving or inlining function calls.
class LocationContext : public llvm::FoldingSetNode {
public:
  enum ContextKind { StackFrame, Block };
  enum ContextKind { StackFrame };

private:
  ContextKind Kind;
@@ -299,6 +290,9 @@ public:
class StackFrameContext : public LocationContext {
  friend class LocationContextManager;

  // Extra data for BlockInvocations
  const void *Data;

  // The call site where this stack frame is established.
  const Expr *CallSite;

@@ -314,14 +308,16 @@ class StackFrameContext : public LocationContext {
  const unsigned Index;

  StackFrameContext(AnalysisDeclContext *ADC, const LocationContext *ParentLC,
                    const Expr *E, const CFGBlock *Block, unsigned BlockCount,
                    unsigned Index, int64_t ID)
      : LocationContext(StackFrame, ADC, ParentLC, ID), CallSite(E),
                    const void *Data, const Expr *E, const CFGBlock *Block,
                    unsigned BlockCount, unsigned Index, int64_t ID)
      : LocationContext(StackFrame, ADC, ParentLC, ID), Data(Data), CallSite(E),
        Block(Block), BlockCount(BlockCount), Index(Index) {}

public:
  ~StackFrameContext() override = default;

  const void *getData() const { return Data; }

  const Expr *getCallSite() const { return CallSite; }

  const CFGBlock *getCallSiteBlock() const { return Block; }
@@ -335,10 +331,11 @@ public:
  void Profile(llvm::FoldingSetNodeID &ID) override;

  static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ADC,
                      const LocationContext *ParentLC, const Expr *E,
                      const CFGBlock *Block, unsigned BlockCount,
                      const LocationContext *ParentLC, const void *Data,
                      const Expr *E, const CFGBlock *Block, unsigned BlockCount,
                      unsigned Index) {
    ProfileCommon(ID, StackFrame, ADC, ParentLC, E);
    ID.AddPointer(Data);
    ID.AddPointer(Block);
    ID.AddInteger(BlockCount);
    ID.AddInteger(Index);
@@ -349,41 +346,6 @@ public:
  }
};

/// It represents a block invocation (based on BlockCall).
class BlockInvocationContext : public LocationContext {
  friend class LocationContextManager;

  const BlockDecl *BD;

  // FIXME: Come up with a more type-safe way to model context-sensitivity.
  const void *Data;

  BlockInvocationContext(AnalysisDeclContext *ADC,
                         const LocationContext *ParentLC, const BlockDecl *BD,
                         const void *Data, int64_t ID)
      : LocationContext(Block, ADC, ParentLC, ID), BD(BD), Data(Data) {}

public:
  ~BlockInvocationContext() override = default;

  const BlockDecl *getBlockDecl() const { return BD; }

  const void *getData() const { return Data; }

  void Profile(llvm::FoldingSetNodeID &ID) override;

  static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ADC,
                      const LocationContext *ParentLC, const BlockDecl *BD,
                      const void *Data) {
    ProfileCommon(ID, Block, ADC, ParentLC, BD);
    ID.AddPointer(Data);
  }

  static bool classof(const LocationContext *LC) {
    return LC->getKind() == Block;
  }
};

class LocationContextManager {
  llvm::FoldingSet<LocationContext> Contexts;

@@ -396,7 +358,10 @@ public:
  /// Obtain a context of the call stack using its parent context.
  ///
  /// \param ADC        The AnalysisDeclContext.
  /// \param ParentLC   The parent context of this newly created context.
  /// \param ParentLC   The parent context of this newly created
  ///                   context.
  /// \param Data       Extra data in case this StackFrameContext is
  ///                   created for a BlockInvocation.
  /// \param E          The call expression.
  /// \param Block      The basic block.
  /// \param BlockCount The current count of entering into \p Block.
@@ -405,20 +370,10 @@ public:
  /// \returns The stack frame context corresponding to the call.
  const StackFrameContext *getStackFrame(AnalysisDeclContext *ADC,
                                         const LocationContext *ParentLC,
                                         const Expr *E, const CFGBlock *Block,
                                         const void *Data, const Expr *E,
                                         const CFGBlock *Block,
                                         unsigned BlockCount, unsigned StmtIdx);

  /// Obtain a context of the block invocation using its parent context.
  ///
  /// \param ADC      The AnalysisDeclContext.
  /// \param ParentLC The parent context of this newly created context.
  /// \param BD       The BlockDecl.
  /// \param Data     The raw data to store as part of the context.
  const BlockInvocationContext *
  getBlockInvocationContext(AnalysisDeclContext *ADC,
                            const LocationContext *ParentLC,
                            const BlockDecl *BD, const void *Data);

  /// Discard all previously created LocationContext objects.
  void clear();
};
@@ -469,8 +424,8 @@ public:
  ///
  /// \returns The top level stack frame for \p D.
  const StackFrameContext *getStackFrame(const Decl *D) {
    return LocCtxMgr.getStackFrame(getContext(D), nullptr, nullptr, nullptr, 0,
                                   0);
    return LocCtxMgr.getStackFrame(getContext(D), nullptr, nullptr, nullptr,
                                   nullptr, 0, 0);
  }

  BodyFarm &getBodyFarm();
+10 −51
Original line number Diff line number Diff line
@@ -310,20 +310,13 @@ AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) {

BodyFarm &AnalysisDeclContextManager::getBodyFarm() { return FunctionBodyFarm; }

const StackFrameContext *
AnalysisDeclContext::getStackFrame(const LocationContext *ParentLC,
                                   const Expr *E, const CFGBlock *Blk,
                                   unsigned BlockCount, unsigned Index) {
  return getLocationContextManager().getStackFrame(this, ParentLC, E, Blk,
const StackFrameContext *AnalysisDeclContext::getStackFrame(
    const LocationContext *ParentLC, const void *Data, const Expr *E,
    const CFGBlock *Blk, unsigned BlockCount, unsigned Index) {
  return getLocationContextManager().getStackFrame(this, ParentLC, Data, E, Blk,
                                                   BlockCount, Index);
}

const BlockInvocationContext *AnalysisDeclContext::getBlockInvocationContext(
    const LocationContext *ParentLC, const BlockDecl *BD, const void *Data) {
  return getLocationContextManager().getBlockInvocationContext(this, ParentLC,
                                                               BD, Data);
}

bool AnalysisDeclContext::isInStdNamespace(const Decl *D) {
  const DeclContext *DC = D->getDeclContext()->getEnclosingNamespaceContext();
  const auto *ND = dyn_cast<NamespaceDecl>(DC);
@@ -415,50 +408,31 @@ void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID,
}

void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) {
  Profile(ID, getAnalysisDeclContext(), getParent(), CallSite, Block,
  Profile(ID, getAnalysisDeclContext(), getParent(), Data, CallSite, Block,
          BlockCount, Index);
}

void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) {
  Profile(ID, getAnalysisDeclContext(), getParent(), BD, Data);
}

//===----------------------------------------------------------------------===//
// LocationContext creation.
//===----------------------------------------------------------------------===//

const StackFrameContext *LocationContextManager::getStackFrame(
    AnalysisDeclContext *Ctx, const LocationContext *Parent, const Expr *E,
    const CFGBlock *Blk, unsigned BlockCount, unsigned StmtIdx) {
    AnalysisDeclContext *Ctx, const LocationContext *Parent, const void *Data,
    const Expr *E, const CFGBlock *Blk, unsigned BlockCount, unsigned StmtIdx) {
  llvm::FoldingSetNodeID ID;
  StackFrameContext::Profile(ID, Ctx, Parent, E, Blk, BlockCount, StmtIdx);
  StackFrameContext::Profile(ID, Ctx, Parent, Data, E, Blk, BlockCount,
                             StmtIdx);
  void *InsertPos;
  auto *L =
   cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
  if (!L) {
    L = new StackFrameContext(Ctx, Parent, E, Blk, BlockCount, StmtIdx,
    L = new StackFrameContext(Ctx, Parent, Data, E, Blk, BlockCount, StmtIdx,
                              ++NewID);
    Contexts.InsertNode(L, InsertPos);
  }
  return L;
}

const BlockInvocationContext *LocationContextManager::getBlockInvocationContext(
    AnalysisDeclContext *ADC, const LocationContext *ParentLC,
    const BlockDecl *BD, const void *Data) {
  llvm::FoldingSetNodeID ID;
  BlockInvocationContext::Profile(ID, ADC, ParentLC, BD, Data);
  void *InsertPos;
  auto *L =
    cast_or_null<BlockInvocationContext>(Contexts.FindNodeOrInsertPos(ID,
                                                                    InsertPos));
  if (!L) {
    L = new BlockInvocationContext(ADC, ParentLC, BD, Data, ++NewID);
    Contexts.InsertNode(L, InsertPos);
  }
  return L;
}

//===----------------------------------------------------------------------===//
// LocationContext methods.
//===----------------------------------------------------------------------===//
@@ -520,13 +494,6 @@ void LocationContext::dumpStack(raw_ostream &Out) const {
        printLocation(Out, SM, E->getBeginLoc());
      }
      break;
    case Block:
      Out << "Invoking block";
      if (const Decl *D = cast<BlockInvocationContext>(LCtx)->getDecl()) {
        Out << " defined at line ";
        printLocation(Out, SM, D->getBeginLoc());
      }
      break;
    }
    Out << '\n';
  }
@@ -565,14 +532,6 @@ void LocationContext::printJson(raw_ostream &Out, const char *NL,

      Out << ", \"items\": ";
      break;
    case Block:
      Out << "Invoking block\" ";
      if (const Decl *D = cast<BlockInvocationContext>(LCtx)->getDecl()) {
        Out << ", \"location\": ";
        printSourceLocationAsJson(Out, D->getBeginLoc(), SM);
        Out << ' ';
      }
      break;
    }

    printMoreInfoPerContext(LCtx);
+1 −1
Original line number Diff line number Diff line
@@ -186,7 +186,7 @@ CallEvent::getCalleeStackFrame(unsigned BlockCount) const {
        break;
  assert(Idx < Sz);

  return ADC->getStackFrame(LCtx, E, B, BlockCount, Idx);
  return ADC->getStackFrame(LCtx, nullptr, E, B, BlockCount, Idx);
}

const ParamVarRegion
+0 −12
Original line number Diff line number Diff line
@@ -222,12 +222,6 @@ SVal ExprEngine::computeObjectUnderConstruction(
          // able to find construction context at all.
          break;
        }
        if (isa<BlockInvocationContext>(CallerLCtx)) {
          // Unwrap block invocation contexts. They're mostly part of
          // the current stack frame.
          CallerLCtx = CallerLCtx->getParent();
          assert(!isa<BlockInvocationContext>(CallerLCtx));
        }

        unsigned NVCaller = getNumVisited(CallerLCtx, SFC->getCallSiteBlock());
        return computeObjectUnderConstruction(
@@ -447,12 +441,6 @@ ProgramStateRef ExprEngine::updateObjectsUnderConstruction(
      auto RTC = (*SFC->getCallSiteBlock())[SFC->getIndex()]
                     .getAs<CFGCXXRecordTypedCall>();
      assert(RTC && "Could not have had a target region without it");
      if (isa<BlockInvocationContext>(CallerLCtx)) {
        // Unwrap block invocation contexts. They're mostly part of
        // the current stack frame.
        CallerLCtx = CallerLCtx->getParent();
        assert(!isa<BlockInvocationContext>(CallerLCtx));
      }

      return updateObjectsUnderConstruction(
          V, SFC->getCallSite(), State, CallerLCtx,
+7 −10
Original line number Diff line number Diff line
@@ -534,15 +534,12 @@ void ExprEngine::inlineCall(WorkList *WList, const CallEvent &Call,

  const LocationContext *CurLC = Pred->getLocationContext();
  const StackFrameContext *CallerSFC = CurLC->getStackFrame();
  const LocationContext *ParentOfCallee = CallerSFC;
  const BlockDataRegion *BlockInvocationData = nullptr;
  if (Call.getKind() == CE_Block &&
      !cast<BlockCall>(Call).isConversionFromLambda()) {
    const BlockDataRegion *BR = cast<BlockCall>(Call).getBlockRegion();
    assert(BR && "If we have the block definition we should have its region");
    AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(D);
    ParentOfCallee = BlockCtx->getBlockInvocationContext(CallerSFC,
                                                         cast<BlockDecl>(D),
                                                         BR);
    BlockInvocationData = cast<BlockCall>(Call).getBlockRegion();
    assert(BlockInvocationData &&
           "If we have the block definition we should have its region");
  }

  // This may be NULL, but that's fine.
@@ -550,8 +547,8 @@ void ExprEngine::inlineCall(WorkList *WList, const CallEvent &Call,

  // Construct a new stack frame for the callee.
  AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
  const StackFrameContext *CalleeSFC =
      CalleeADC->getStackFrame(ParentOfCallee, CallE, getCurrBlock(),
  const StackFrameContext *CalleeSFC = CalleeADC->getStackFrame(
      CallerSFC, BlockInvocationData, CallE, getCurrBlock(),
      getNumVisitedCurrent(), currStmtIdx);

  CallEnter Loc(CallE, CalleeSFC, CurLC);
Loading