PseudoConstantAnalysis.cpp [plain text]
#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Stmt.h"
#include "llvm/ADT/SmallPtrSet.h"
#include <deque>
using namespace clang;
typedef llvm::SmallPtrSet<const VarDecl*, 32> VarDeclSet;
PseudoConstantAnalysis::PseudoConstantAnalysis(const Stmt *DeclBody) :
DeclBody(DeclBody), Analyzed(false) {
NonConstantsImpl = new VarDeclSet;
UsedVarsImpl = new VarDeclSet;
}
PseudoConstantAnalysis::~PseudoConstantAnalysis() {
delete (VarDeclSet*)NonConstantsImpl;
delete (VarDeclSet*)UsedVarsImpl;
}
bool PseudoConstantAnalysis::isPseudoConstant(const VarDecl *VD) {
if (!VD->hasLocalStorage() && !VD->isStaticLocal())
return false;
if (!Analyzed) {
RunAnalysis();
Analyzed = true;
}
VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl;
return !NonConstants->count(VD);
}
bool PseudoConstantAnalysis::wasReferenced(const VarDecl *VD) {
if (!Analyzed) {
RunAnalysis();
Analyzed = true;
}
VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl;
return UsedVars->count(VD);
}
const Decl *PseudoConstantAnalysis::getDecl(const Expr *E) {
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
return DR->getDecl();
else
return nullptr;
}
void PseudoConstantAnalysis::RunAnalysis() {
std::deque<const Stmt *> WorkList;
VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl;
VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl;
WorkList.push_back(DeclBody);
while (!WorkList.empty()) {
const Stmt *Head = WorkList.front();
WorkList.pop_front();
if (const Expr *Ex = dyn_cast<Expr>(Head))
Head = Ex->IgnoreParenCasts();
switch (Head->getStmtClass()) {
case Stmt::BinaryOperatorClass: {
const BinaryOperator *BO = cast<BinaryOperator>(Head);
const Decl *LHSDecl = getDecl(BO->getLHS()->IgnoreParenCasts());
if (!LHSDecl)
break;
switch (BO->getOpcode()) {
case BO_Assign: {
const Decl *RHSDecl = getDecl(BO->getRHS()->IgnoreParenCasts());
if (LHSDecl == RHSDecl)
continue;
}
case BO_AddAssign:
case BO_SubAssign:
case BO_MulAssign:
case BO_DivAssign:
case BO_AndAssign:
case BO_OrAssign:
case BO_XorAssign:
case BO_ShlAssign:
case BO_ShrAssign: {
const VarDecl *VD = dyn_cast<VarDecl>(LHSDecl);
if (VD)
NonConstants->insert(VD);
break;
}
default:
break;
}
break;
}
case Stmt::UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(Head);
const Decl *D = getDecl(UO->getSubExpr()->IgnoreParenCasts());
if (!D)
break;
switch (UO->getOpcode()) {
case UO_PostDec:
case UO_PostInc:
case UO_PreDec:
case UO_PreInc:
case UO_AddrOf: {
const VarDecl *VD = dyn_cast<VarDecl>(D);
if (VD)
NonConstants->insert(VD);
break;
}
default:
break;
}
break;
}
case Stmt::DeclStmtClass: {
const DeclStmt *DS = cast<DeclStmt>(Head);
for (const auto *I : DS->decls()) {
const VarDecl *VD = dyn_cast<VarDecl>(I);
if (!VD)
continue;
if (!VD->getType().getTypePtr()->isReferenceType())
continue;
const Decl *D = getDecl(VD->getInit()->IgnoreParenCasts());
if (!D)
break;
if (const VarDecl *RefVD = dyn_cast<VarDecl>(D)) {
NonConstants->insert(RefVD);
continue;
}
}
break;
}
case Stmt::DeclRefExprClass: {
const DeclRefExpr *DR = cast<DeclRefExpr>(Head);
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
UsedVars->insert(VD);
continue;
}
break;
}
case Stmt::BlockExprClass: {
const BlockExpr *B = cast<BlockExpr>(Head);
WorkList.push_back(B->getBody());
continue;
}
default:
break;
}
for (const Stmt *SubStmt : Head->children())
if (SubStmt)
WorkList.push_back(SubStmt);
} }