/*
* Copyright 2011, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "slang_rs_ast_replace.h"
#include "slang_assert.h"
#include "llvm/Support/Casting.h"
namespace slang {
void RSASTReplace::ReplaceStmt(
clang::Stmt *OuterStmt,
clang::Stmt *OldStmt,
clang::Stmt *NewStmt) {
mOldStmt = OldStmt;
mNewStmt = NewStmt;
mOuterStmt = OuterStmt;
// This simplifies use in various Stmt visitor passes where the only
// valid type is an Expr.
mOldExpr = llvm::dyn_cast<clang::Expr>(OldStmt);
if (mOldExpr) {
mNewExpr = llvm::dyn_cast<clang::Expr>(NewStmt);
}
Visit(mOuterStmt);
}
void RSASTReplace::ReplaceInCompoundStmt(clang::CompoundStmt *CS) {
clang::Stmt **UpdatedStmtList = new clang::Stmt*[CS->size()];
unsigned UpdatedStmtCount = 0;
clang::CompoundStmt::body_iterator bI = CS->body_begin();
clang::CompoundStmt::body_iterator bE = CS->body_end();
for ( ; bI != bE; bI++) {
if (matchesStmt(*bI)) {
UpdatedStmtList[UpdatedStmtCount++] = mNewStmt;
} else {
UpdatedStmtList[UpdatedStmtCount++] = *bI;
}
}
CS->setStmts(C, UpdatedStmtList, UpdatedStmtCount);
delete [] UpdatedStmtList;
return;
}
void RSASTReplace::VisitStmt(clang::Stmt *S) {
// This function does the actual iteration through all sub-Stmt's within
// a given Stmt. Note that this function is skipped by all of the other
// Visit* functions if we have already found a higher-level match.
for (clang::Stmt::child_iterator I = S->child_begin(), E = S->child_end();
I != E;
I++) {
if (clang::Stmt *Child = *I) {
if (!matchesStmt(Child)) {
Visit(Child);
}
}
}
return;
}
void RSASTReplace::VisitCompoundStmt(clang::CompoundStmt *CS) {
VisitStmt(CS);
ReplaceInCompoundStmt(CS);
return;
}
void RSASTReplace::VisitCaseStmt(clang::CaseStmt *CS) {
if (matchesStmt(CS->getSubStmt())) {
CS->setSubStmt(mNewStmt);
} else {
VisitStmt(CS);
}
return;
}
void RSASTReplace::VisitDefaultStmt(clang::DefaultStmt *DS) {
if (matchesStmt(DS->getSubStmt())) {
DS->setSubStmt(mNewStmt);
} else {
VisitStmt(DS);
}
return;
}
void RSASTReplace::VisitDoStmt(clang::DoStmt *DS) {
if (matchesExpr(DS->getCond())) {
DS->setCond(mNewExpr);
} else if (matchesStmt(DS->getBody())) {
DS->setBody(mNewStmt);
} else {
VisitStmt(DS);
}
return;
}
void RSASTReplace::VisitForStmt(clang::ForStmt *FS) {
if (matchesStmt(FS->getInit())) {
FS->setInit(mNewStmt);
} else if (matchesExpr(FS->getCond())) {
FS->setCond(mNewExpr);
} else if (matchesExpr(FS->getInc())) {
FS->setInc(mNewExpr);
} else if (matchesStmt(FS->getBody())) {
FS->setBody(mNewStmt);
} else {
VisitStmt(FS);
}
return;
}
void RSASTReplace::VisitIfStmt(clang::IfStmt *IS) {
if (matchesExpr(IS->getCond())) {
IS->setCond(mNewExpr);
} else if (matchesStmt(IS->getThen())) {
IS->setThen(mNewStmt);
} else if (matchesStmt(IS->getElse())) {
IS->setElse(mNewStmt);
} else {
VisitStmt(IS);
}
return;
}
void RSASTReplace::VisitSwitchCase(clang::SwitchCase *SC) {
slangAssert(false && "Both case and default have specialized handlers");
VisitStmt(SC);
return;
}
void RSASTReplace::VisitSwitchStmt(clang::SwitchStmt *SS) {
if (matchesExpr(SS->getCond())) {
SS->setCond(mNewExpr);
} else {
VisitStmt(SS);
}
return;
}
void RSASTReplace::VisitWhileStmt(clang::WhileStmt *WS) {
if (matchesExpr(WS->getCond())) {
WS->setCond(mNewExpr);
} else if (matchesStmt(WS->getBody())) {
WS->setBody(mNewStmt);
} else {
VisitStmt(WS);
}
return;
}
} // namespace slang