diff options
Diffstat (limited to 'clang/lib/AST/ParentMap.cpp')
| -rw-r--r-- | clang/lib/AST/ParentMap.cpp | 214 | 
1 files changed, 214 insertions, 0 deletions
diff --git a/clang/lib/AST/ParentMap.cpp b/clang/lib/AST/ParentMap.cpp new file mode 100644 index 0000000000000..2ff5c9d8aeb57 --- /dev/null +++ b/clang/lib/AST/ParentMap.cpp @@ -0,0 +1,214 @@ +//===--- 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/ExprCXX.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: { +    assert(OVMode == OV_Transparent && "Should not appear alongside OVEs"); +    PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S); + +    // If we are rebuilding the map, clear out any existing state. +    if (M[POE->getSyntacticForm()]) +      for (Stmt *SubStmt : S->children()) +        M[SubStmt] = nullptr; + +    M[POE->getSyntacticForm()] = S; +    BuildParentMap(M, POE->getSyntacticForm(), 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); +    if (OVMode == OV_Transparent || !M[OVE->getSourceExpr()]) { +      M[OVE->getSourceExpr()] = S; +      BuildParentMap(M, OVE->getSourceExpr(), 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; +  MapTy::iterator I = M->find(S); +  return I == M->end() ? nullptr : I->second; +} + +Stmt *ParentMap::getParentIgnoreParens(Stmt *S) const { +  do { S = getParent(S); } while (S && isa<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 (S && isa<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; +  } +} +  | 
