More changes necessary to integrate the objc and blocks rewriters.

With this commit, stuff like this is very close to working...

    [foo barf:^(int){ printf("whatever\n"); }];

Here is what is currently translates to...

    ((id (*)(id, SEL, void (^)(int)))(void *)objc_msgSend)((id)foo, sel_registerName("barf:"), (void (*)(int))__main_block_func_0);

I just need make sure the funky cast on objc_msgSend() is converted from "void (^)(int)" to "void (*)(int)". Since the cast doesn't appear in the source code, it needs to be converted in RewriteObjC::SynthMessageExpr().

llvm-svn: 58348
This commit is contained in:
Steve Naroff 2008-10-28 20:29:00 +00:00
parent 2800afa640
commit f4b992a8ec
1 changed files with 409 additions and 310 deletions

View File

@ -300,6 +300,9 @@ namespace {
bool PointerTypeTakesAnyBlockArguments(QualType QT);
void GetExtentOfArgList(const char *Name, const char *&LParen, const char *&RParen);
void RewriteCastExpr(CastExpr *CE);
FunctionDecl *SynthBlockInitFunctionDecl(const char *name);
Stmt *SynthBlockInitExpr(BlockExpr *Exp, VarDecl *VD=0);
};
}
@ -522,149 +525,6 @@ void RewriteObjC::HandleTopLevelDecl(Decl *D) {
return HandleDeclInMainFile(D);
}
/// HandleDeclInMainFile - This is called for each top-level decl defined in the
/// main file of the input.
void RewriteObjC::HandleDeclInMainFile(Decl *D) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// Since function prototypes don't have ParmDecl's, we check the function
// prototype. This enables us to rewrite function declarations and
// definitions using the same code.
RewriteBlocksInFunctionTypeProto(FD->getType(), FD);
if (Stmt *Body = FD->getBody()) {
CurFunctionDef = FD;
FD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
// This synthesizes and inserts the block "impl" struct, invoke function,
// and any copy/dispose helper functions.
InsertBlockLiteralsWithinFunction(FD);
CurFunctionDef = 0;
}
return;
}
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (Stmt *Body = MD->getBody()) {
//Body->dump();
CurMethodDef = MD;
MD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
InsertBlockLiteralsWithinMethod(MD);
CurMethodDef = 0;
}
}
if (ObjCImplementationDecl *CI = dyn_cast<ObjCImplementationDecl>(D))
ClassImplementation.push_back(CI);
else if (ObjCCategoryImplDecl *CI = dyn_cast<ObjCCategoryImplDecl>(D))
CategoryImplementation.push_back(CI);
else if (ObjCClassDecl *CD = dyn_cast<ObjCClassDecl>(D))
RewriteForwardClassDecl(CD);
else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
RewriteObjCQualifiedInterfaceTypes(VD);
if (VD->getInit())
RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
}
// Rewrite rules for blocks.
if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (isBlockPointerType(VD->getType())) {
RewriteBlockPointerDecl(VD);
if (VD->getInit()) {
if (BlockExpr *CBE = dyn_cast<BlockExpr>(VD->getInit())) {
RewriteFunctionBodyOrGlobalInitializer(CBE->getBody());
// We've just rewritten the block body in place.
// Now we snarf the rewritten text and stash it away for later use.
std::string S = Rewrite.getRewritenText(CBE->getSourceRange());
RewrittenBlockExprs[CBE] = S;
std::string Init = SynthesizeBlockInitExpr(CBE, VD);
// Do the rewrite, using S.size() which contains the rewritten size.
ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size());
SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName());
} else if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
RewriteCastExpr(CE);
}
}
} else if (VD->getType()->isFunctionPointerType()) {
CheckFunctionPointerDecl(VD->getType(), VD);
if (VD->getInit()) {
if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
RewriteCastExpr(CE);
}
}
}
return;
}
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
if (isBlockPointerType(TD->getUnderlyingType()))
RewriteBlockPointerDecl(TD);
else if (TD->getUnderlyingType()->isFunctionPointerType())
CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
return;
}
if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
if (RD->isDefinition()) {
for (RecordDecl::field_const_iterator i = RD->field_begin(),
e = RD->field_end(); i != e; ++i) {
FieldDecl *FD = *i;
if (isBlockPointerType(FD->getType()))
RewriteBlockPointerDecl(FD);
}
}
return;
}
// Nothing yet.
}
void RewriteObjC::HandleTranslationUnit(TranslationUnit& TU) {
// Get the top-level buffer that this corresponds to.
// Rewrite tabs if we care.
//RewriteTabs();
if (Diags.hasErrorOccurred())
return;
// Create the output file.
llvm::OwningPtr<llvm::raw_ostream> OwnedStream;
llvm::raw_ostream *OutFile;
if (OutFileName == "-") {
OutFile = &llvm::outs();
} else if (!OutFileName.empty()) {
std::string Err;
OutFile = new llvm::raw_fd_ostream(OutFileName.c_str(), Err);
OwnedStream.reset(OutFile);
} else if (InFileName == "-") {
OutFile = &llvm::outs();
} else {
llvm::sys::Path Path(InFileName);
Path.eraseSuffix();
Path.appendSuffix("cpp");
std::string Err;
OutFile = new llvm::raw_fd_ostream(Path.toString().c_str(), Err);
OwnedStream.reset(OutFile);
}
RewriteInclude();
InsertText(SourceLocation::getFileLoc(MainFileID, 0),
Preamble.c_str(), Preamble.size(), false);
// Rewrite Objective-c meta data*
std::string ResultStr;
RewriteImplementations(ResultStr);
// Get the buffer corresponding to MainFileID. If we haven't changed it, then
// we are done.
if (const RewriteBuffer *RewriteBuf =
Rewrite.getRewriteBufferFor(MainFileID)) {
//printf("Changed:\n");
*OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
} else {
fprintf(stderr, "No changes\n");
}
// Emit metadata.
*OutFile << ResultStr;
OutFile->flush();
}
//===----------------------------------------------------------------------===//
// Syntactic (non-AST) Rewriting Code
//===----------------------------------------------------------------------===//
@ -1115,172 +975,6 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
return IV;
}
//===----------------------------------------------------------------------===//
// Function Body / Expression rewriting
//===----------------------------------------------------------------------===//
Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
isa<DoStmt>(S) || isa<ForStmt>(S))
Stmts.push_back(S);
else if (isa<ObjCForCollectionStmt>(S)) {
Stmts.push_back(S);
ObjCBcLabelNo.push_back(++BcLabelCount);
}
SourceRange OrigStmtRange = S->getSourceRange();
// Start by rewriting all children.
for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
CI != E; ++CI)
if (*CI) {
if (BlockExpr *CBE = dyn_cast<BlockExpr>(*CI)) {
Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(CBE->getBody());
if (newStmt)
*CI = newStmt;
// We've just rewritten the block body in place.
// Now we snarf the rewritten text and stash it away for later use.
std::string S = Rewrite.getRewritenText(CBE->getSourceRange());
RewrittenBlockExprs[CBE] = S;
std::string Init = SynthesizeBlockInitExpr(CBE);
// Do the rewrite, using S.size() which contains the rewritten size.
ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size());
} else {
Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(*CI);
if (newStmt)
*CI = newStmt;
}
}
// Handle specific things.
if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
return RewriteAtEncode(AtEncode);
if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S))
return RewriteObjCIvarRefExpr(IvarRefExpr, OrigStmtRange.getBegin());
if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
return RewriteAtSelector(AtSelector);
if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
return RewriteObjCStringLiteral(AtString);
if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
// Before we rewrite it, put the original message expression in a comment.
SourceLocation startLoc = MessExpr->getLocStart();
SourceLocation endLoc = MessExpr->getLocEnd();
const char *startBuf = SM->getCharacterData(startLoc);
const char *endBuf = SM->getCharacterData(endLoc);
std::string messString;
messString += "// ";
messString.append(startBuf, endBuf-startBuf+1);
messString += "\n";
// FIXME: Missing definition of
// InsertText(clang::SourceLocation, char const*, unsigned int).
// InsertText(startLoc, messString.c_str(), messString.size());
// Tried this, but it didn't work either...
// ReplaceText(startLoc, 0, messString.c_str(), messString.size());
return RewriteMessageExpr(MessExpr);
}
if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S))
return RewriteObjCTryStmt(StmtTry);
if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S))
return RewriteObjCSynchronizedStmt(StmtTry);
if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S))
return RewriteObjCThrowStmt(StmtThrow);
if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S))
return RewriteObjCProtocolExpr(ProtocolExp);
if (ObjCForCollectionStmt *StmtForCollection =
dyn_cast<ObjCForCollectionStmt>(S))
return RewriteObjCForCollectionStmt(StmtForCollection,
OrigStmtRange.getEnd());
if (BreakStmt *StmtBreakStmt =
dyn_cast<BreakStmt>(S))
return RewriteBreakStmt(StmtBreakStmt);
if (ContinueStmt *StmtContinueStmt =
dyn_cast<ContinueStmt>(S))
return RewriteContinueStmt(StmtContinueStmt);
// Need to check for protocol refs (id <P>, Foo <P> *) in variable decls
// and cast exprs.
if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
// FIXME: What we're doing here is modifying the type-specifier that
// precedes the first Decl. In the future the DeclGroup should have
// a separate type-specifier that we can rewrite.
RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin());
// Blocks rewrite rules.
for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
DI != DE; ++DI) {
ScopedDecl *SD = *DI;
if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
if (isBlockPointerType(ND->getType()))
RewriteBlockPointerDecl(ND);
else if (ND->getType()->isFunctionPointerType())
CheckFunctionPointerDecl(ND->getType(), ND);
}
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
if (isBlockPointerType(TD->getUnderlyingType()))
RewriteBlockPointerDecl(TD);
else if (TD->getUnderlyingType()->isFunctionPointerType())
CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
}
}
}
if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S))
RewriteObjCQualifiedInterfaceTypes(CE);
if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
isa<DoStmt>(S) || isa<ForStmt>(S)) {
assert(!Stmts.empty() && "Statement stack is empty");
assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) ||
isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back()))
&& "Statement stack mismatch");
Stmts.pop_back();
}
// Handle blocks rewriting.
if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
if (BDRE->isByRef())
RewriteBlockDeclRefExpr(BDRE);
}
if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
if (CE->getCallee()->getType()->isBlockPointerType())
RewriteBlockCall(CE);
}
if (CastExpr *CE = dyn_cast<CastExpr>(S)) {
if (CE->getLocStart().isValid())
RewriteCastExpr(CE);
}
#if 0
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) {
CastExpr *Replacement = new CastExpr(ICE->getType(), ICE->getSubExpr(), SourceLocation());
// Get the new text.
std::string SStr;
llvm::raw_string_ostream Buf(SStr);
Replacement->printPretty(Buf);
const std::string &Str = Buf.str();
printf("CAST = %s\n", &Str[0]);
InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size());
delete S;
return Replacement;
}
#endif
// Return this stmt unmodified.
return S;
}
/// SynthCountByEnumWithState - To print:
/// ((unsigned int (*)
/// (id, SEL, struct __objcFastEnumerationState *, id *, unsigned int))
@ -3844,7 +3538,11 @@ void RewriteObjC::RewriteBlockDeclRefExpr(BlockDeclRefExpr *BDRE) {
void RewriteObjC::RewriteCastExpr(CastExpr *CE) {
SourceLocation LocStart = CE->getLocStart();
SourceLocation LocEnd = CE->getLocEnd();
// Need to avoid trying to rewrite synthesized casts.
if (LocStart.isInvalid())
return;
const char *startBuf = SM->getCharacterData(LocStart);
const char *endBuf = SM->getCharacterData(LocEnd);
@ -4082,3 +3780,404 @@ std::string RewriteObjC::SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD) {
return Init;
}
FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(const char *name) {
IdentifierInfo *ID = &Context->Idents.get(name);
QualType FType = Context->getFunctionTypeNoProto(Context->VoidPtrTy);
return FunctionDecl::Create(*Context, TUDecl,SourceLocation(),
ID, FType, FunctionDecl::Extern, false, 0);
}
Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, VarDecl *VD) {
Blocks.push_back(Exp);
CollectBlockDeclRefInfo(Exp);
std::string FuncName;
if (CurFunctionDef)
FuncName = std::string(CurFunctionDef->getName());
else if (CurMethodDef) {
FuncName = std::string(CurMethodDef->getSelector().getName());
// Convert colons to underscores.
std::string::size_type loc = 0;
while ((loc = FuncName.find(":", loc)) != std::string::npos)
FuncName.replace(loc, 1, "_");
} else if (VD)
FuncName = std::string(VD->getName());
std::string BlockNumber = utostr(Blocks.size()-1);
std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber;
std::string Func = "__" + FuncName + "_block_func_" + BlockNumber;
// Get a pointer to the function type so we can cast appropriately.
QualType FType = Context->getPointerType(QualType(Exp->getFunctionType(),0));
FunctionDecl *FD;
Expr *NewRep;
// Simulate a contructor call...
FD = SynthBlockInitFunctionDecl(Tag.c_str());
DeclRefExpr *DRE = new DeclRefExpr(FD, FType, SourceLocation());
llvm::SmallVector<Expr*, 4> InitExprs;
FD = SynthBlockInitFunctionDecl(Func.c_str());
DeclRefExpr *Arg = new DeclRefExpr(FD, FD->getType(), SourceLocation());
CastExpr *castExpr = new CStyleCastExpr(Context->VoidPtrTy, Arg,
Context->VoidPtrTy, SourceLocation());
InitExprs.push_back(castExpr);
#if 0
// Initialize the block function.
Init += "((void*)" + Func;
if (ImportedBlockDecls.size()) {
std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber;
Init += ",(void*)" + Buf;
Buf = "__" + FuncName + "_block_dispose_" + BlockNumber;
Init += ",(void*)" + Buf;
}
// Add initializers for any closure decl refs.
if (BlockDeclRefs.size()) {
// Output all "by copy" declarations.
for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(),
E = BlockByCopyDecls.end(); I != E; ++I) {
Init += ",";
if (isObjCType((*I)->getType())) {
Init += "[[";
Init += (*I)->getName();
Init += " retain] autorelease]";
} else if (isBlockPointerType((*I)->getType())) {
Init += "(void *)";
Init += (*I)->getName();
} else {
Init += (*I)->getName();
}
}
// Output all "by ref" declarations.
for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(),
E = BlockByRefDecls.end(); I != E; ++I) {
Init += ",&";
Init += (*I)->getName();
}
}
Init += ")";
#endif
NewRep = new CallExpr(DRE, &InitExprs[0], InitExprs.size(),
FType, SourceLocation());
NewRep = new UnaryOperator(NewRep, UnaryOperator::AddrOf,
Context->getPointerType(NewRep->getType()),
SourceLocation());
NewRep = new CStyleCastExpr(FType, NewRep, FType, SourceLocation());
BlockDeclRefs.clear();
BlockByRefDecls.clear();
BlockByCopyDecls.clear();
ImportedBlockDecls.clear();
return NewRep;
}
//===----------------------------------------------------------------------===//
// Function Body / Expression rewriting
//===----------------------------------------------------------------------===//
Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
isa<DoStmt>(S) || isa<ForStmt>(S))
Stmts.push_back(S);
else if (isa<ObjCForCollectionStmt>(S)) {
Stmts.push_back(S);
ObjCBcLabelNo.push_back(++BcLabelCount);
}
SourceRange OrigStmtRange = S->getSourceRange();
// Perform a bottom up rewrite of all children.
for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end();
CI != E; ++CI)
if (*CI) {
Stmt *newStmt = RewriteFunctionBodyOrGlobalInitializer(*CI);
if (newStmt)
*CI = newStmt;
}
if (BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
// Rewrite the block body in place.
RewriteFunctionBodyOrGlobalInitializer(BE->getBody());
// Now we snarf the rewritten text and stash it away for later use.
std::string S = Rewrite.getRewritenText(BE->getSourceRange());
RewrittenBlockExprs[BE] = S;
Stmt *blockTranscribed = SynthBlockInitExpr(BE);
//blockTranscribed->dump();
return blockTranscribed;
}
// Handle specific things.
if (ObjCEncodeExpr *AtEncode = dyn_cast<ObjCEncodeExpr>(S))
return RewriteAtEncode(AtEncode);
if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S))
return RewriteObjCIvarRefExpr(IvarRefExpr, OrigStmtRange.getBegin());
if (ObjCSelectorExpr *AtSelector = dyn_cast<ObjCSelectorExpr>(S))
return RewriteAtSelector(AtSelector);
if (ObjCStringLiteral *AtString = dyn_cast<ObjCStringLiteral>(S))
return RewriteObjCStringLiteral(AtString);
if (ObjCMessageExpr *MessExpr = dyn_cast<ObjCMessageExpr>(S)) {
// Before we rewrite it, put the original message expression in a comment.
SourceLocation startLoc = MessExpr->getLocStart();
SourceLocation endLoc = MessExpr->getLocEnd();
const char *startBuf = SM->getCharacterData(startLoc);
const char *endBuf = SM->getCharacterData(endLoc);
std::string messString;
messString += "// ";
messString.append(startBuf, endBuf-startBuf+1);
messString += "\n";
// FIXME: Missing definition of
// InsertText(clang::SourceLocation, char const*, unsigned int).
// InsertText(startLoc, messString.c_str(), messString.size());
// Tried this, but it didn't work either...
// ReplaceText(startLoc, 0, messString.c_str(), messString.size());
return RewriteMessageExpr(MessExpr);
}
if (ObjCAtTryStmt *StmtTry = dyn_cast<ObjCAtTryStmt>(S))
return RewriteObjCTryStmt(StmtTry);
if (ObjCAtSynchronizedStmt *StmtTry = dyn_cast<ObjCAtSynchronizedStmt>(S))
return RewriteObjCSynchronizedStmt(StmtTry);
if (ObjCAtThrowStmt *StmtThrow = dyn_cast<ObjCAtThrowStmt>(S))
return RewriteObjCThrowStmt(StmtThrow);
if (ObjCProtocolExpr *ProtocolExp = dyn_cast<ObjCProtocolExpr>(S))
return RewriteObjCProtocolExpr(ProtocolExp);
if (ObjCForCollectionStmt *StmtForCollection =
dyn_cast<ObjCForCollectionStmt>(S))
return RewriteObjCForCollectionStmt(StmtForCollection,
OrigStmtRange.getEnd());
if (BreakStmt *StmtBreakStmt =
dyn_cast<BreakStmt>(S))
return RewriteBreakStmt(StmtBreakStmt);
if (ContinueStmt *StmtContinueStmt =
dyn_cast<ContinueStmt>(S))
return RewriteContinueStmt(StmtContinueStmt);
// Need to check for protocol refs (id <P>, Foo <P> *) in variable decls
// and cast exprs.
if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
// FIXME: What we're doing here is modifying the type-specifier that
// precedes the first Decl. In the future the DeclGroup should have
// a separate type-specifier that we can rewrite.
RewriteObjCQualifiedInterfaceTypes(*DS->decl_begin());
// Blocks rewrite rules.
for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end();
DI != DE; ++DI) {
ScopedDecl *SD = *DI;
if (ValueDecl *ND = dyn_cast<ValueDecl>(SD)) {
if (isBlockPointerType(ND->getType()))
RewriteBlockPointerDecl(ND);
else if (ND->getType()->isFunctionPointerType())
CheckFunctionPointerDecl(ND->getType(), ND);
}
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
if (isBlockPointerType(TD->getUnderlyingType()))
RewriteBlockPointerDecl(TD);
else if (TD->getUnderlyingType()->isFunctionPointerType())
CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
}
}
}
if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(S))
RewriteObjCQualifiedInterfaceTypes(CE);
if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) ||
isa<DoStmt>(S) || isa<ForStmt>(S)) {
assert(!Stmts.empty() && "Statement stack is empty");
assert ((isa<SwitchStmt>(Stmts.back()) || isa<WhileStmt>(Stmts.back()) ||
isa<DoStmt>(Stmts.back()) || isa<ForStmt>(Stmts.back()))
&& "Statement stack mismatch");
Stmts.pop_back();
}
// Handle blocks rewriting.
if (BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) {
if (BDRE->isByRef())
RewriteBlockDeclRefExpr(BDRE);
}
if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
if (CE->getCallee()->getType()->isBlockPointerType())
RewriteBlockCall(CE);
}
if (CastExpr *CE = dyn_cast<CastExpr>(S)) {
RewriteCastExpr(CE);
}
#if 0
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(S)) {
CastExpr *Replacement = new CastExpr(ICE->getType(), ICE->getSubExpr(), SourceLocation());
// Get the new text.
std::string SStr;
llvm::raw_string_ostream Buf(SStr);
Replacement->printPretty(Buf);
const std::string &Str = Buf.str();
printf("CAST = %s\n", &Str[0]);
InsertText(ICE->getSubExpr()->getLocStart(), &Str[0], Str.size());
delete S;
return Replacement;
}
#endif
// Return this stmt unmodified.
return S;
}
/// HandleDeclInMainFile - This is called for each top-level decl defined in the
/// main file of the input.
void RewriteObjC::HandleDeclInMainFile(Decl *D) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// Since function prototypes don't have ParmDecl's, we check the function
// prototype. This enables us to rewrite function declarations and
// definitions using the same code.
RewriteBlocksInFunctionTypeProto(FD->getType(), FD);
if (Stmt *Body = FD->getBody()) {
CurFunctionDef = FD;
FD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
// This synthesizes and inserts the block "impl" struct, invoke function,
// and any copy/dispose helper functions.
InsertBlockLiteralsWithinFunction(FD);
CurFunctionDef = 0;
}
return;
}
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (Stmt *Body = MD->getBody()) {
//Body->dump();
CurMethodDef = MD;
MD->setBody(RewriteFunctionBodyOrGlobalInitializer(Body));
InsertBlockLiteralsWithinMethod(MD);
CurMethodDef = 0;
}
}
if (ObjCImplementationDecl *CI = dyn_cast<ObjCImplementationDecl>(D))
ClassImplementation.push_back(CI);
else if (ObjCCategoryImplDecl *CI = dyn_cast<ObjCCategoryImplDecl>(D))
CategoryImplementation.push_back(CI);
else if (ObjCClassDecl *CD = dyn_cast<ObjCClassDecl>(D))
RewriteForwardClassDecl(CD);
else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
RewriteObjCQualifiedInterfaceTypes(VD);
if (VD->getInit())
RewriteFunctionBodyOrGlobalInitializer(VD->getInit());
}
// Rewrite rules for blocks.
if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (isBlockPointerType(VD->getType())) {
RewriteBlockPointerDecl(VD);
if (VD->getInit()) {
if (BlockExpr *CBE = dyn_cast<BlockExpr>(VD->getInit())) {
RewriteFunctionBodyOrGlobalInitializer(CBE->getBody());
// We've just rewritten the block body in place.
// Now we snarf the rewritten text and stash it away for later use.
std::string S = Rewrite.getRewritenText(CBE->getSourceRange());
RewrittenBlockExprs[CBE] = S;
std::string Init = SynthesizeBlockInitExpr(CBE, VD);
// Do the rewrite, using S.size() which contains the rewritten size.
ReplaceText(CBE->getLocStart(), S.size(), Init.c_str(), Init.size());
SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), VD->getName());
} else if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
RewriteCastExpr(CE);
}
}
} else if (VD->getType()->isFunctionPointerType()) {
CheckFunctionPointerDecl(VD->getType(), VD);
if (VD->getInit()) {
if (CastExpr *CE = dyn_cast<CastExpr>(VD->getInit())) {
RewriteCastExpr(CE);
}
}
}
return;
}
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
if (isBlockPointerType(TD->getUnderlyingType()))
RewriteBlockPointerDecl(TD);
else if (TD->getUnderlyingType()->isFunctionPointerType())
CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
return;
}
if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
if (RD->isDefinition()) {
for (RecordDecl::field_const_iterator i = RD->field_begin(),
e = RD->field_end(); i != e; ++i) {
FieldDecl *FD = *i;
if (isBlockPointerType(FD->getType()))
RewriteBlockPointerDecl(FD);
}
}
return;
}
// Nothing yet.
}
void RewriteObjC::HandleTranslationUnit(TranslationUnit& TU) {
// Get the top-level buffer that this corresponds to.
// Rewrite tabs if we care.
//RewriteTabs();
if (Diags.hasErrorOccurred())
return;
// Create the output file.
llvm::OwningPtr<llvm::raw_ostream> OwnedStream;
llvm::raw_ostream *OutFile;
if (OutFileName == "-") {
OutFile = &llvm::outs();
} else if (!OutFileName.empty()) {
std::string Err;
OutFile = new llvm::raw_fd_ostream(OutFileName.c_str(), Err);
OwnedStream.reset(OutFile);
} else if (InFileName == "-") {
OutFile = &llvm::outs();
} else {
llvm::sys::Path Path(InFileName);
Path.eraseSuffix();
Path.appendSuffix("cpp");
std::string Err;
OutFile = new llvm::raw_fd_ostream(Path.toString().c_str(), Err);
OwnedStream.reset(OutFile);
}
RewriteInclude();
InsertText(SourceLocation::getFileLoc(MainFileID, 0),
Preamble.c_str(), Preamble.size(), false);
// Rewrite Objective-c meta data*
std::string ResultStr;
RewriteImplementations(ResultStr);
// Get the buffer corresponding to MainFileID. If we haven't changed it, then
// we are done.
if (const RewriteBuffer *RewriteBuf =
Rewrite.getRewriteBufferFor(MainFileID)) {
//printf("Changed:\n");
*OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end());
} else {
fprintf(stderr, "No changes\n");
}
// Emit metadata.
*OutFile << ResultStr;
OutFile->flush();
}