llvm-project
217 строк · 5.9 Кб
1//===--- ParentMap.cpp - Mappings from Stmts to their Parents ---*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the ParentMap class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/AST/ParentMap.h"14#include "clang/AST/Decl.h"15#include "clang/AST/Expr.h"16#include "clang/AST/ExprCXX.h"17#include "clang/AST/StmtObjC.h"18#include "llvm/ADT/DenseMap.h"19
20using namespace clang;21
22typedef llvm::DenseMap<Stmt*, Stmt*> MapTy;23
24enum OpaqueValueMode {25OV_Transparent,26OV_Opaque
27};28
29static void BuildParentMap(MapTy& M, Stmt* S,30OpaqueValueMode OVMode = OV_Transparent) {31if (!S)32return;33
34switch (S->getStmtClass()) {35case Stmt::PseudoObjectExprClass: {36PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S);37
38if (OVMode == OV_Opaque && M[POE->getSyntacticForm()])39break;40
41// If we are rebuilding the map, clear out any existing state.42if (M[POE->getSyntacticForm()])43for (Stmt *SubStmt : S->children())44M[SubStmt] = nullptr;45
46M[POE->getSyntacticForm()] = S;47BuildParentMap(M, POE->getSyntacticForm(), OV_Transparent);48
49for (PseudoObjectExpr::semantics_iterator I = POE->semantics_begin(),50E = POE->semantics_end();51I != E; ++I) {52M[*I] = S;53BuildParentMap(M, *I, OV_Opaque);54}55break;56}57case Stmt::BinaryConditionalOperatorClass: {58assert(OVMode == OV_Transparent && "Should not appear alongside OVEs");59BinaryConditionalOperator *BCO = cast<BinaryConditionalOperator>(S);60
61M[BCO->getCommon()] = S;62BuildParentMap(M, BCO->getCommon(), OV_Transparent);63
64M[BCO->getCond()] = S;65BuildParentMap(M, BCO->getCond(), OV_Opaque);66
67M[BCO->getTrueExpr()] = S;68BuildParentMap(M, BCO->getTrueExpr(), OV_Opaque);69
70M[BCO->getFalseExpr()] = S;71BuildParentMap(M, BCO->getFalseExpr(), OV_Transparent);72
73break;74}75case Stmt::OpaqueValueExprClass: {76// FIXME: This isn't correct; it assumes that multiple OpaqueValueExprs77// share a single source expression, but in the AST a single78// OpaqueValueExpr is shared among multiple parent expressions.79// The right thing to do is to give the OpaqueValueExpr its syntactic80// parent, then not reassign that when traversing the semantic expressions.81OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S);82if (OVMode == OV_Transparent || !M[OVE->getSourceExpr()]) {83M[OVE->getSourceExpr()] = S;84BuildParentMap(M, OVE->getSourceExpr(), OV_Transparent);85}86break;87}88case Stmt::CapturedStmtClass:89for (Stmt *SubStmt : S->children()) {90if (SubStmt) {91M[SubStmt] = S;92BuildParentMap(M, SubStmt, OVMode);93}94}95if (Stmt *SubStmt = cast<CapturedStmt>(S)->getCapturedStmt()) {96M[SubStmt] = S;97BuildParentMap(M, SubStmt, OVMode);98}99break;100default:101for (Stmt *SubStmt : S->children()) {102if (SubStmt) {103M[SubStmt] = S;104BuildParentMap(M, SubStmt, OVMode);105}106}107break;108}109}
110
111ParentMap::ParentMap(Stmt *S) : Impl(nullptr) {112if (S) {113MapTy *M = new MapTy();114BuildParentMap(*M, S);115Impl = M;116}117}
118
119ParentMap::~ParentMap() {120delete (MapTy*) Impl;121}
122
123void ParentMap::addStmt(Stmt* S) {124if (S) {125BuildParentMap(*(MapTy*) Impl, S);126}127}
128
129void ParentMap::setParent(const Stmt *S, const Stmt *Parent) {130assert(S);131assert(Parent);132MapTy *M = reinterpret_cast<MapTy *>(Impl);133M->insert(std::make_pair(const_cast<Stmt *>(S), const_cast<Stmt *>(Parent)));134}
135
136Stmt* ParentMap::getParent(Stmt* S) const {137MapTy* M = (MapTy*) Impl;138return M->lookup(S);139}
140
141Stmt *ParentMap::getParentIgnoreParens(Stmt *S) const {142do {143S = getParent(S);144} while (isa_and_nonnull<ParenExpr>(S));145return S;146}
147
148Stmt *ParentMap::getParentIgnoreParenCasts(Stmt *S) const {149do {150S = getParent(S);151}152while (S && (isa<ParenExpr>(S) || isa<CastExpr>(S)));153
154return S;155}
156
157Stmt *ParentMap::getParentIgnoreParenImpCasts(Stmt *S) const {158do {159S = getParent(S);160} while (isa_and_nonnull<Expr>(S) &&161cast<Expr>(S)->IgnoreParenImpCasts() != S);162
163return S;164}
165
166Stmt *ParentMap::getOuterParenParent(Stmt *S) const {167Stmt *Paren = nullptr;168while (isa<ParenExpr>(S)) {169Paren = S;170S = getParent(S);171};172return Paren;173}
174
175bool ParentMap::isConsumedExpr(Expr* E) const {176Stmt *P = getParent(E);177Stmt *DirectChild = E;178
179// Ignore parents that don't guarantee consumption.180while (P && (isa<ParenExpr>(P) || isa<CastExpr>(P) ||181isa<FullExpr>(P))) {182DirectChild = P;183P = getParent(P);184}185
186if (!P)187return false;188
189switch (P->getStmtClass()) {190default:191return isa<Expr>(P);192case Stmt::DeclStmtClass:193return true;194case Stmt::BinaryOperatorClass: {195BinaryOperator *BE = cast<BinaryOperator>(P);196// If it is a comma, only the right side is consumed.197// If it isn't a comma, both sides are consumed.198return BE->getOpcode()!=BO_Comma ||DirectChild==BE->getRHS();199}200case Stmt::ForStmtClass:201return DirectChild == cast<ForStmt>(P)->getCond();202case Stmt::WhileStmtClass:203return DirectChild == cast<WhileStmt>(P)->getCond();204case Stmt::DoStmtClass:205return DirectChild == cast<DoStmt>(P)->getCond();206case Stmt::IfStmtClass:207return DirectChild == cast<IfStmt>(P)->getCond();208case Stmt::IndirectGotoStmtClass:209return DirectChild == cast<IndirectGotoStmt>(P)->getTarget();210case Stmt::SwitchStmtClass:211return DirectChild == cast<SwitchStmt>(P)->getCond();212case Stmt::ObjCForCollectionStmtClass:213return DirectChild == cast<ObjCForCollectionStmt>(P)->getCollection();214case Stmt::ReturnStmtClass:215return true;216}217}
218
219