//===--- ParentMap.cpp - Mappings from Stmts to their Parents ---*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//  This file defines the ParentMap class.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/ParentMap.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/StmtObjC.h"
#include "llvm/ADT/DenseMap.h"

using namespace clang;

typedef llvm::DenseMap<Stmt*, Stmt*> MapTy;

enum OpaqueValueMode {
  OV_Transparent,
  OV_Opaque
};

static void BuildParentMap(MapTy& M, Stmt* S,
                           OpaqueValueMode OVMode = OV_Transparent) {
  if (!S)
    return;

  switch (S->getStmtClass()) {
  case Stmt::PseudoObjectExprClass: {
    PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S);
    Expr *SF = POE->getSyntacticForm();

    auto [Iter, Inserted] = M.try_emplace(SF, S);
    if (!Inserted) {
      // Nothing more to do in opaque mode if we are updating an existing map.
      if (OVMode == OV_Opaque)
        break;
      // Update the entry in transparent mode, and clear existing state.
      Iter->second = S;
      for (Stmt *SubStmt : S->children())
        M.erase(SubStmt);
    }
    BuildParentMap(M, SF, OV_Transparent);

    for (PseudoObjectExpr::semantics_iterator I = POE->semantics_begin(),
                                              E = POE->semantics_end();
         I != E; ++I) {
      M[*I] = S;
      BuildParentMap(M, *I, OV_Opaque);
    }
    break;
  }
  case Stmt::BinaryConditionalOperatorClass: {
    assert(OVMode == OV_Transparent && "Should not appear alongside OVEs");
    BinaryConditionalOperator *BCO = cast<BinaryConditionalOperator>(S);

    M[BCO->getCommon()] = S;
    BuildParentMap(M, BCO->getCommon(), OV_Transparent);

    M[BCO->getCond()] = S;
    BuildParentMap(M, BCO->getCond(), OV_Opaque);

    M[BCO->getTrueExpr()] = S;
    BuildParentMap(M, BCO->getTrueExpr(), OV_Opaque);

    M[BCO->getFalseExpr()] = S;
    BuildParentMap(M, BCO->getFalseExpr(), OV_Transparent);

    break;
  }
  case Stmt::OpaqueValueExprClass: {
    // FIXME: This isn't correct; it assumes that multiple OpaqueValueExprs
    // share a single source expression, but in the AST a single
    // OpaqueValueExpr is shared among multiple parent expressions.
    // The right thing to do is to give the OpaqueValueExpr its syntactic
    // parent, then not reassign that when traversing the semantic expressions.
    OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S);
    Expr *SrcExpr = OVE->getSourceExpr();
    auto [Iter, Inserted] = M.try_emplace(SrcExpr, S);
    // Force update in transparent mode.
    if (!Inserted && OVMode == OV_Transparent) {
      Iter->second = S;
      Inserted = true;
    }
    if (Inserted)
      BuildParentMap(M, SrcExpr, OV_Transparent);
    break;
  }
  case Stmt::CapturedStmtClass:
    for (Stmt *SubStmt : S->children()) {
      if (SubStmt) {
        M[SubStmt] = S;
        BuildParentMap(M, SubStmt, OVMode);
      }
    }
    if (Stmt *SubStmt = cast<CapturedStmt>(S)->getCapturedStmt()) {
      M[SubStmt] = S;
      BuildParentMap(M, SubStmt, OVMode);
    }
    break;
  default:
    for (Stmt *SubStmt : S->children()) {
      if (SubStmt) {
        M[SubStmt] = S;
        BuildParentMap(M, SubStmt, OVMode);
      }
    }
    break;
  }
}

ParentMap::ParentMap(Stmt *S) : Impl(nullptr) {
  if (S) {
    MapTy *M = new MapTy();
    BuildParentMap(*M, S);
    Impl = M;
  }
}

ParentMap::~ParentMap() {
  delete (MapTy*) Impl;
}

void ParentMap::addStmt(Stmt* S) {
  if (S) {
    BuildParentMap(*(MapTy*) Impl, S);
  }
}

void ParentMap::setParent(const Stmt *S, const Stmt *Parent) {
  assert(S);
  assert(Parent);
  MapTy *M = reinterpret_cast<MapTy *>(Impl);
  M->insert(std::make_pair(const_cast<Stmt *>(S), const_cast<Stmt *>(Parent)));
}

Stmt* ParentMap::getParent(Stmt* S) const {
  MapTy* M = (MapTy*) Impl;
  return M->lookup(S);
}

Stmt *ParentMap::getParentIgnoreParens(Stmt *S) const {
  do {
    S = getParent(S);
  } while (isa_and_nonnull<ParenExpr>(S));
  return S;
}

Stmt *ParentMap::getParentIgnoreParenCasts(Stmt *S) const {
  do {
    S = getParent(S);
  }
  while (S && (isa<ParenExpr>(S) || isa<CastExpr>(S)));

  return S;
}

Stmt *ParentMap::getParentIgnoreParenImpCasts(Stmt *S) const {
  do {
    S = getParent(S);
  } while (isa_and_nonnull<Expr>(S) &&
           cast<Expr>(S)->IgnoreParenImpCasts() != S);

  return S;
}

Stmt *ParentMap::getOuterParenParent(Stmt *S) const {
  Stmt *Paren = nullptr;
  while (isa<ParenExpr>(S)) {
    Paren = S;
    S = getParent(S);
  };
  return Paren;
}

bool ParentMap::isConsumedExpr(Expr* E) const {
  Stmt *P = getParent(E);
  Stmt *DirectChild = E;

  // Ignore parents that don't guarantee consumption.
  while (P && (isa<ParenExpr>(P) || isa<CastExpr>(P) ||
               isa<FullExpr>(P))) {
    DirectChild = P;
    P = getParent(P);
  }

  if (!P)
    return false;

  switch (P->getStmtClass()) {
    default:
      return isa<Expr>(P);
    case Stmt::DeclStmtClass:
      return true;
    case Stmt::BinaryOperatorClass: {
      BinaryOperator *BE = cast<BinaryOperator>(P);
      // If it is a comma, only the right side is consumed.
      // If it isn't a comma, both sides are consumed.
      return BE->getOpcode()!=BO_Comma ||DirectChild==BE->getRHS();
    }
    case Stmt::ForStmtClass:
      return DirectChild == cast<ForStmt>(P)->getCond();
    case Stmt::WhileStmtClass:
      return DirectChild == cast<WhileStmt>(P)->getCond();
    case Stmt::DoStmtClass:
      return DirectChild == cast<DoStmt>(P)->getCond();
    case Stmt::IfStmtClass:
      return DirectChild == cast<IfStmt>(P)->getCond();
    case Stmt::IndirectGotoStmtClass:
      return DirectChild == cast<IndirectGotoStmt>(P)->getTarget();
    case Stmt::SwitchStmtClass:
      return DirectChild == cast<SwitchStmt>(P)->getCond();
    case Stmt::ObjCForCollectionStmtClass:
      return DirectChild == cast<ObjCForCollectionStmt>(P)->getCollection();
    case Stmt::ReturnStmtClass:
      return true;
  }
}

