teak-llvm/clang/lib/AST/ParentMap.cpp
Jordan Rose c3f1cb3ba6 [analyzer] "Fix" ParentMap to handle non-syntactic OpaqueValueExprs.
Constructs like PseudoObjectExpr, where an expression can appear more than
once in the AST, use OpaqueValueExprs to guard against inadvertent
re-processing of the shared expression during AST traversal. The most
common form of this is to share expressions between the syntactic
"as-written" form of, say, an Objective-C property access 'obj.prop', and
the underlying "semantic" form '[obj prop]'.

However, some constructs can produce OpaqueValueExprs that don't appear in
the syntactic form at all; in these cases the ParentMap wasn't ever traversing
the children of these expressions. This patch fixes that by checking to see
if an OpaqueValueExpr's child has ever been traversed before. There's also a
bit of reset logic when visiting a PseudoObjectExpr to handle the case of
updating the ParentMap, which some external clients depend on.

This still isn't exactly the right fix because we probably want the parent
of the OpaqueValueExpr itself to be its location in the syntactic form if
it's syntactic and the PseudoObjectExpr or BinaryConditionalOperator itself
if it's semantic. Whe I originally wrote the code to do this, I didn't realize
that OpaqueValueExprs themselves are shared in the AST, not just their source
expressions. This patch doesn't change the existing behavior so as not to
break anything inadvertently relying on it; we'll come back to this later.

llvm-svn: 182187
2013-05-18 02:27:09 +00:00

190 lines
5.2 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===--- ParentMap.cpp - Mappings from Stmts to their Parents ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the ParentMap class.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ParentMap.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.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) {
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::child_range I = S->children(); I; ++I)
M[*I] = 0;
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;
}
default:
for (Stmt::child_range I = S->children(); I; ++I) {
if (*I) {
M[*I] = S;
BuildParentMap(M, *I, OVMode);
}
}
break;
}
}
ParentMap::ParentMap(Stmt* S) : Impl(0) {
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);
}
}
Stmt* ParentMap::getParent(Stmt* S) const {
MapTy* M = (MapTy*) Impl;
MapTy::iterator I = M->find(S);
return I == M->end() ? 0 : 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 = 0;
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 are parentheses or casts.
while (P && (isa<ParenExpr>(P) || isa<CastExpr>(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::ReturnStmtClass:
return true;
}
}