130660a898545416f0fea2d717f16f75640001e38Ted Kremenek//===--- ObjCMT.cpp - ObjC Migrate Tool -----------------------------------===// 230660a898545416f0fea2d717f16f75640001e38Ted Kremenek// 330660a898545416f0fea2d717f16f75640001e38Ted Kremenek// The LLVM Compiler Infrastructure 430660a898545416f0fea2d717f16f75640001e38Ted Kremenek// 530660a898545416f0fea2d717f16f75640001e38Ted Kremenek// This file is distributed under the University of Illinois Open Source 630660a898545416f0fea2d717f16f75640001e38Ted Kremenek// License. See LICENSE.TXT for details. 730660a898545416f0fea2d717f16f75640001e38Ted Kremenek// 830660a898545416f0fea2d717f16f75640001e38Ted Kremenek//===----------------------------------------------------------------------===// 930660a898545416f0fea2d717f16f75640001e38Ted Kremenek 1030660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/ARCMigrate/ARCMTActions.h" 1130660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Frontend/CompilerInstance.h" 1230660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Frontend/MultiplexConsumer.h" 1330660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/AST/RecursiveASTVisitor.h" 1430660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/AST/NSAPI.h" 1530660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/AST/ASTConsumer.h" 1630660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Edit/Rewriters.h" 1730660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Edit/EditedSource.h" 1830660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Edit/Commit.h" 1930660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Edit/EditsReceiver.h" 2030660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Rewrite/Rewriter.h" 2130660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Lex/Preprocessor.h" 2230660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "clang/Basic/FileManager.h" 2330660a898545416f0fea2d717f16f75640001e38Ted Kremenek#include "llvm/ADT/SmallString.h" 2430660a898545416f0fea2d717f16f75640001e38Ted Kremenek 2530660a898545416f0fea2d717f16f75640001e38Ted Kremenekusing namespace clang; 2630660a898545416f0fea2d717f16f75640001e38Ted Kremenekusing namespace arcmt; 2730660a898545416f0fea2d717f16f75640001e38Ted Kremenek 2830660a898545416f0fea2d717f16f75640001e38Ted Kremeneknamespace { 2930660a898545416f0fea2d717f16f75640001e38Ted Kremenek 3030660a898545416f0fea2d717f16f75640001e38Ted Kremenekclass ObjCMigrateASTConsumer : public ASTConsumer { 3130660a898545416f0fea2d717f16f75640001e38Ted Kremenek void migrateDecl(Decl *D); 3230660a898545416f0fea2d717f16f75640001e38Ted Kremenek 3330660a898545416f0fea2d717f16f75640001e38Ted Kremenekpublic: 3430660a898545416f0fea2d717f16f75640001e38Ted Kremenek std::string MigrateDir; 3530660a898545416f0fea2d717f16f75640001e38Ted Kremenek bool MigrateLiterals; 3630660a898545416f0fea2d717f16f75640001e38Ted Kremenek bool MigrateSubscripting; 3730660a898545416f0fea2d717f16f75640001e38Ted Kremenek llvm::OwningPtr<NSAPI> NSAPIObj; 3830660a898545416f0fea2d717f16f75640001e38Ted Kremenek llvm::OwningPtr<edit::EditedSource> Editor; 3930660a898545416f0fea2d717f16f75640001e38Ted Kremenek FileRemapper &Remapper; 4030660a898545416f0fea2d717f16f75640001e38Ted Kremenek FileManager &FileMgr; 4130660a898545416f0fea2d717f16f75640001e38Ted Kremenek const PreprocessingRecord *PPRec; 4230660a898545416f0fea2d717f16f75640001e38Ted Kremenek bool IsOutputFile; 4330660a898545416f0fea2d717f16f75640001e38Ted Kremenek 4430660a898545416f0fea2d717f16f75640001e38Ted Kremenek ObjCMigrateASTConsumer(StringRef migrateDir, 4530660a898545416f0fea2d717f16f75640001e38Ted Kremenek bool migrateLiterals, 4630660a898545416f0fea2d717f16f75640001e38Ted Kremenek bool migrateSubscripting, 4730660a898545416f0fea2d717f16f75640001e38Ted Kremenek FileRemapper &remapper, 4830660a898545416f0fea2d717f16f75640001e38Ted Kremenek FileManager &fileMgr, 4930660a898545416f0fea2d717f16f75640001e38Ted Kremenek const PreprocessingRecord *PPRec, 5030660a898545416f0fea2d717f16f75640001e38Ted Kremenek bool isOutputFile = false) 5130660a898545416f0fea2d717f16f75640001e38Ted Kremenek : MigrateDir(migrateDir), 5230660a898545416f0fea2d717f16f75640001e38Ted Kremenek MigrateLiterals(migrateLiterals), 5330660a898545416f0fea2d717f16f75640001e38Ted Kremenek MigrateSubscripting(migrateSubscripting), 5430660a898545416f0fea2d717f16f75640001e38Ted Kremenek Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), 5530660a898545416f0fea2d717f16f75640001e38Ted Kremenek IsOutputFile(isOutputFile) { } 5630660a898545416f0fea2d717f16f75640001e38Ted Kremenek 5730660a898545416f0fea2d717f16f75640001e38Ted Kremenekprotected: 5830660a898545416f0fea2d717f16f75640001e38Ted Kremenek virtual void Initialize(ASTContext &Context) { 5930660a898545416f0fea2d717f16f75640001e38Ted Kremenek NSAPIObj.reset(new NSAPI(Context)); 6030660a898545416f0fea2d717f16f75640001e38Ted Kremenek Editor.reset(new edit::EditedSource(Context.getSourceManager(), 614e4d08403ca5cfd4d558fa2936215d3a4e5a528dDavid Blaikie Context.getLangOpts(), 6230660a898545416f0fea2d717f16f75640001e38Ted Kremenek PPRec)); 6330660a898545416f0fea2d717f16f75640001e38Ted Kremenek } 6430660a898545416f0fea2d717f16f75640001e38Ted Kremenek 6530660a898545416f0fea2d717f16f75640001e38Ted Kremenek virtual bool HandleTopLevelDecl(DeclGroupRef DG) { 6630660a898545416f0fea2d717f16f75640001e38Ted Kremenek for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) 6730660a898545416f0fea2d717f16f75640001e38Ted Kremenek migrateDecl(*I); 6830660a898545416f0fea2d717f16f75640001e38Ted Kremenek return true; 6930660a898545416f0fea2d717f16f75640001e38Ted Kremenek } 7030660a898545416f0fea2d717f16f75640001e38Ted Kremenek virtual void HandleInterestingDecl(DeclGroupRef DG) { 7130660a898545416f0fea2d717f16f75640001e38Ted Kremenek // Ignore decls from the PCH. 7230660a898545416f0fea2d717f16f75640001e38Ted Kremenek } 7330660a898545416f0fea2d717f16f75640001e38Ted Kremenek virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) { 7430660a898545416f0fea2d717f16f75640001e38Ted Kremenek ObjCMigrateASTConsumer::HandleTopLevelDecl(DG); 7530660a898545416f0fea2d717f16f75640001e38Ted Kremenek } 7630660a898545416f0fea2d717f16f75640001e38Ted Kremenek 7730660a898545416f0fea2d717f16f75640001e38Ted Kremenek virtual void HandleTranslationUnit(ASTContext &Ctx); 7830660a898545416f0fea2d717f16f75640001e38Ted Kremenek}; 7930660a898545416f0fea2d717f16f75640001e38Ted Kremenek 8030660a898545416f0fea2d717f16f75640001e38Ted Kremenek} 8130660a898545416f0fea2d717f16f75640001e38Ted Kremenek 8230660a898545416f0fea2d717f16f75640001e38Ted KremenekObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction, 8330660a898545416f0fea2d717f16f75640001e38Ted Kremenek StringRef migrateDir, 8430660a898545416f0fea2d717f16f75640001e38Ted Kremenek bool migrateLiterals, 8530660a898545416f0fea2d717f16f75640001e38Ted Kremenek bool migrateSubscripting) 8630660a898545416f0fea2d717f16f75640001e38Ted Kremenek : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir), 8730660a898545416f0fea2d717f16f75640001e38Ted Kremenek MigrateLiterals(migrateLiterals), MigrateSubscripting(migrateSubscripting), 8830660a898545416f0fea2d717f16f75640001e38Ted Kremenek CompInst(0) { 8930660a898545416f0fea2d717f16f75640001e38Ted Kremenek if (MigrateDir.empty()) 9030660a898545416f0fea2d717f16f75640001e38Ted Kremenek MigrateDir = "."; // user current directory if none is given. 9130660a898545416f0fea2d717f16f75640001e38Ted Kremenek} 9230660a898545416f0fea2d717f16f75640001e38Ted Kremenek 9330660a898545416f0fea2d717f16f75640001e38Ted KremenekASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, 9430660a898545416f0fea2d717f16f75640001e38Ted Kremenek StringRef InFile) { 9530660a898545416f0fea2d717f16f75640001e38Ted Kremenek ASTConsumer * 9630660a898545416f0fea2d717f16f75640001e38Ted Kremenek WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile); 9730660a898545416f0fea2d717f16f75640001e38Ted Kremenek ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir, 9830660a898545416f0fea2d717f16f75640001e38Ted Kremenek MigrateLiterals, 9930660a898545416f0fea2d717f16f75640001e38Ted Kremenek MigrateSubscripting, 10030660a898545416f0fea2d717f16f75640001e38Ted Kremenek Remapper, 10130660a898545416f0fea2d717f16f75640001e38Ted Kremenek CompInst->getFileManager(), 10230660a898545416f0fea2d717f16f75640001e38Ted Kremenek CompInst->getPreprocessor().getPreprocessingRecord()); 10330660a898545416f0fea2d717f16f75640001e38Ted Kremenek ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer }; 10430660a898545416f0fea2d717f16f75640001e38Ted Kremenek return new MultiplexConsumer(Consumers); 10530660a898545416f0fea2d717f16f75640001e38Ted Kremenek} 10630660a898545416f0fea2d717f16f75640001e38Ted Kremenek 10730660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) { 10830660a898545416f0fea2d717f16f75640001e38Ted Kremenek Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(), 10930660a898545416f0fea2d717f16f75640001e38Ted Kremenek /*ignoreIfFilesChanges=*/true); 11030660a898545416f0fea2d717f16f75640001e38Ted Kremenek CompInst = &CI; 11130660a898545416f0fea2d717f16f75640001e38Ted Kremenek CI.getDiagnostics().setIgnoreAllWarnings(true); 11230660a898545416f0fea2d717f16f75640001e38Ted Kremenek CI.getPreprocessorOpts().DetailedRecord = true; 11330660a898545416f0fea2d717f16f75640001e38Ted Kremenek CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true; 11430660a898545416f0fea2d717f16f75640001e38Ted Kremenek return true; 11530660a898545416f0fea2d717f16f75640001e38Ted Kremenek} 11630660a898545416f0fea2d717f16f75640001e38Ted Kremenek 11730660a898545416f0fea2d717f16f75640001e38Ted Kremeneknamespace { 11830660a898545416f0fea2d717f16f75640001e38Ted Kremenekclass ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> { 11930660a898545416f0fea2d717f16f75640001e38Ted Kremenek ObjCMigrateASTConsumer &Consumer; 12030660a898545416f0fea2d717f16f75640001e38Ted Kremenek 12130660a898545416f0fea2d717f16f75640001e38Ted Kremenekpublic: 12230660a898545416f0fea2d717f16f75640001e38Ted Kremenek ObjCMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { } 12330660a898545416f0fea2d717f16f75640001e38Ted Kremenek 12430660a898545416f0fea2d717f16f75640001e38Ted Kremenek bool shouldVisitTemplateInstantiations() const { return false; } 12530660a898545416f0fea2d717f16f75640001e38Ted Kremenek bool shouldWalkTypesOfTypeLocs() const { return false; } 12630660a898545416f0fea2d717f16f75640001e38Ted Kremenek 12730660a898545416f0fea2d717f16f75640001e38Ted Kremenek bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 12830660a898545416f0fea2d717f16f75640001e38Ted Kremenek if (Consumer.MigrateLiterals) { 12930660a898545416f0fea2d717f16f75640001e38Ted Kremenek edit::Commit commit(*Consumer.Editor); 13030660a898545416f0fea2d717f16f75640001e38Ted Kremenek edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit); 13130660a898545416f0fea2d717f16f75640001e38Ted Kremenek Consumer.Editor->commit(commit); 13230660a898545416f0fea2d717f16f75640001e38Ted Kremenek } 13330660a898545416f0fea2d717f16f75640001e38Ted Kremenek 13430660a898545416f0fea2d717f16f75640001e38Ted Kremenek if (Consumer.MigrateSubscripting) { 13530660a898545416f0fea2d717f16f75640001e38Ted Kremenek edit::Commit commit(*Consumer.Editor); 13630660a898545416f0fea2d717f16f75640001e38Ted Kremenek edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit); 13730660a898545416f0fea2d717f16f75640001e38Ted Kremenek Consumer.Editor->commit(commit); 13830660a898545416f0fea2d717f16f75640001e38Ted Kremenek } 13930660a898545416f0fea2d717f16f75640001e38Ted Kremenek 14030660a898545416f0fea2d717f16f75640001e38Ted Kremenek return true; 14130660a898545416f0fea2d717f16f75640001e38Ted Kremenek } 14230660a898545416f0fea2d717f16f75640001e38Ted Kremenek 14330660a898545416f0fea2d717f16f75640001e38Ted Kremenek bool TraverseObjCMessageExpr(ObjCMessageExpr *E) { 14430660a898545416f0fea2d717f16f75640001e38Ted Kremenek // Do depth first; we want to rewrite the subexpressions first so that if 14530660a898545416f0fea2d717f16f75640001e38Ted Kremenek // we have to move expressions we will move them already rewritten. 14630660a898545416f0fea2d717f16f75640001e38Ted Kremenek for (Stmt::child_range range = E->children(); range; ++range) 14730660a898545416f0fea2d717f16f75640001e38Ted Kremenek if (!TraverseStmt(*range)) 14830660a898545416f0fea2d717f16f75640001e38Ted Kremenek return false; 14930660a898545416f0fea2d717f16f75640001e38Ted Kremenek 15030660a898545416f0fea2d717f16f75640001e38Ted Kremenek return WalkUpFromObjCMessageExpr(E); 15130660a898545416f0fea2d717f16f75640001e38Ted Kremenek } 15230660a898545416f0fea2d717f16f75640001e38Ted Kremenek}; 15330660a898545416f0fea2d717f16f75640001e38Ted Kremenek} 15430660a898545416f0fea2d717f16f75640001e38Ted Kremenek 15530660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid ObjCMigrateASTConsumer::migrateDecl(Decl *D) { 15630660a898545416f0fea2d717f16f75640001e38Ted Kremenek if (!D) 15730660a898545416f0fea2d717f16f75640001e38Ted Kremenek return; 15830660a898545416f0fea2d717f16f75640001e38Ted Kremenek if (isa<ObjCMethodDecl>(D)) 15930660a898545416f0fea2d717f16f75640001e38Ted Kremenek return; // Wait for the ObjC container declaration. 16030660a898545416f0fea2d717f16f75640001e38Ted Kremenek 16130660a898545416f0fea2d717f16f75640001e38Ted Kremenek ObjCMigrator(*this).TraverseDecl(D); 16230660a898545416f0fea2d717f16f75640001e38Ted Kremenek} 16330660a898545416f0fea2d717f16f75640001e38Ted Kremenek 16430660a898545416f0fea2d717f16f75640001e38Ted Kremeneknamespace { 16530660a898545416f0fea2d717f16f75640001e38Ted Kremenek 16630660a898545416f0fea2d717f16f75640001e38Ted Kremenekclass RewritesReceiver : public edit::EditsReceiver { 16730660a898545416f0fea2d717f16f75640001e38Ted Kremenek Rewriter &Rewrite; 16830660a898545416f0fea2d717f16f75640001e38Ted Kremenek 16930660a898545416f0fea2d717f16f75640001e38Ted Kremenekpublic: 17030660a898545416f0fea2d717f16f75640001e38Ted Kremenek RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { } 17130660a898545416f0fea2d717f16f75640001e38Ted Kremenek 17230660a898545416f0fea2d717f16f75640001e38Ted Kremenek virtual void insert(SourceLocation loc, StringRef text) { 17330660a898545416f0fea2d717f16f75640001e38Ted Kremenek Rewrite.InsertText(loc, text); 17430660a898545416f0fea2d717f16f75640001e38Ted Kremenek } 17530660a898545416f0fea2d717f16f75640001e38Ted Kremenek virtual void replace(CharSourceRange range, StringRef text) { 17630660a898545416f0fea2d717f16f75640001e38Ted Kremenek Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text); 17730660a898545416f0fea2d717f16f75640001e38Ted Kremenek } 17830660a898545416f0fea2d717f16f75640001e38Ted Kremenek}; 17930660a898545416f0fea2d717f16f75640001e38Ted Kremenek 18030660a898545416f0fea2d717f16f75640001e38Ted Kremenek} 18130660a898545416f0fea2d717f16f75640001e38Ted Kremenek 18230660a898545416f0fea2d717f16f75640001e38Ted Kremenekvoid ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { 1834e4d08403ca5cfd4d558fa2936215d3a4e5a528dDavid Blaikie Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts()); 18430660a898545416f0fea2d717f16f75640001e38Ted Kremenek RewritesReceiver Rec(rewriter); 18530660a898545416f0fea2d717f16f75640001e38Ted Kremenek Editor->applyRewrites(Rec); 18630660a898545416f0fea2d717f16f75640001e38Ted Kremenek 18730660a898545416f0fea2d717f16f75640001e38Ted Kremenek for (Rewriter::buffer_iterator 18830660a898545416f0fea2d717f16f75640001e38Ted Kremenek I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { 18930660a898545416f0fea2d717f16f75640001e38Ted Kremenek FileID FID = I->first; 19030660a898545416f0fea2d717f16f75640001e38Ted Kremenek RewriteBuffer &buf = I->second; 19130660a898545416f0fea2d717f16f75640001e38Ted Kremenek const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); 19230660a898545416f0fea2d717f16f75640001e38Ted Kremenek assert(file); 19330660a898545416f0fea2d717f16f75640001e38Ted Kremenek llvm::SmallString<512> newText; 19430660a898545416f0fea2d717f16f75640001e38Ted Kremenek llvm::raw_svector_ostream vecOS(newText); 19530660a898545416f0fea2d717f16f75640001e38Ted Kremenek buf.write(vecOS); 19630660a898545416f0fea2d717f16f75640001e38Ted Kremenek vecOS.flush(); 19730660a898545416f0fea2d717f16f75640001e38Ted Kremenek llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( 19830660a898545416f0fea2d717f16f75640001e38Ted Kremenek StringRef(newText.data(), newText.size()), file->getName()); 19930660a898545416f0fea2d717f16f75640001e38Ted Kremenek llvm::SmallString<64> filePath(file->getName()); 20030660a898545416f0fea2d717f16f75640001e38Ted Kremenek FileMgr.FixupRelativePath(filePath); 20130660a898545416f0fea2d717f16f75640001e38Ted Kremenek Remapper.remap(filePath.str(), memBuf); 20230660a898545416f0fea2d717f16f75640001e38Ted Kremenek } 20330660a898545416f0fea2d717f16f75640001e38Ted Kremenek 20430660a898545416f0fea2d717f16f75640001e38Ted Kremenek if (IsOutputFile) { 20530660a898545416f0fea2d717f16f75640001e38Ted Kremenek Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics()); 20630660a898545416f0fea2d717f16f75640001e38Ted Kremenek } else { 20730660a898545416f0fea2d717f16f75640001e38Ted Kremenek Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics()); 20830660a898545416f0fea2d717f16f75640001e38Ted Kremenek } 20930660a898545416f0fea2d717f16f75640001e38Ted Kremenek} 21030660a898545416f0fea2d717f16f75640001e38Ted Kremenek 21130660a898545416f0fea2d717f16f75640001e38Ted Kremenekbool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) { 21230660a898545416f0fea2d717f16f75640001e38Ted Kremenek CI.getPreprocessorOpts().DetailedRecord = true; 21330660a898545416f0fea2d717f16f75640001e38Ted Kremenek CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true; 21430660a898545416f0fea2d717f16f75640001e38Ted Kremenek return true; 21530660a898545416f0fea2d717f16f75640001e38Ted Kremenek} 21630660a898545416f0fea2d717f16f75640001e38Ted Kremenek 21730660a898545416f0fea2d717f16f75640001e38Ted KremenekASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, 21830660a898545416f0fea2d717f16f75640001e38Ted Kremenek StringRef InFile) { 21930660a898545416f0fea2d717f16f75640001e38Ted Kremenek return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile, 22030660a898545416f0fea2d717f16f75640001e38Ted Kremenek /*MigrateLiterals=*/true, 22130660a898545416f0fea2d717f16f75640001e38Ted Kremenek /*MigrateSubscripting=*/true, 22230660a898545416f0fea2d717f16f75640001e38Ted Kremenek Remapper, 22330660a898545416f0fea2d717f16f75640001e38Ted Kremenek CI.getFileManager(), 22430660a898545416f0fea2d717f16f75640001e38Ted Kremenek CI.getPreprocessor().getPreprocessingRecord(), 22530660a898545416f0fea2d717f16f75640001e38Ted Kremenek /*isOutputFile=*/true); 22630660a898545416f0fea2d717f16f75640001e38Ted Kremenek} 227