1234287Sdim//===--- ObjCMT.cpp - ObjC Migrate Tool -----------------------------------===// 2234287Sdim// 3234287Sdim// The LLVM Compiler Infrastructure 4234287Sdim// 5234287Sdim// This file is distributed under the University of Illinois Open Source 6234287Sdim// License. See LICENSE.TXT for details. 7234287Sdim// 8234287Sdim//===----------------------------------------------------------------------===// 9234287Sdim 10234287Sdim#include "clang/ARCMigrate/ARCMTActions.h" 11249423Sdim#include "clang/AST/ASTConsumer.h" 12239462Sdim#include "clang/AST/ASTContext.h" 13249423Sdim#include "clang/AST/NSAPI.h" 14249423Sdim#include "clang/AST/ParentMap.h" 15234287Sdim#include "clang/AST/RecursiveASTVisitor.h" 16249423Sdim#include "clang/Basic/FileManager.h" 17249423Sdim#include "clang/Edit/Commit.h" 18234287Sdim#include "clang/Edit/EditedSource.h" 19234287Sdim#include "clang/Edit/EditsReceiver.h" 20249423Sdim#include "clang/Edit/Rewriters.h" 21249423Sdim#include "clang/Frontend/CompilerInstance.h" 22249423Sdim#include "clang/Frontend/MultiplexConsumer.h" 23249423Sdim#include "clang/Lex/PPConditionalDirectiveRecord.h" 24249423Sdim#include "clang/Lex/Preprocessor.h" 25243830Sdim#include "clang/Rewrite/Core/Rewriter.h" 26234287Sdim#include "llvm/ADT/SmallString.h" 27234287Sdim 28234287Sdimusing namespace clang; 29234287Sdimusing namespace arcmt; 30234287Sdim 31234287Sdimnamespace { 32234287Sdim 33234287Sdimclass ObjCMigrateASTConsumer : public ASTConsumer { 34234287Sdim void migrateDecl(Decl *D); 35234287Sdim 36234287Sdimpublic: 37234287Sdim std::string MigrateDir; 38234287Sdim bool MigrateLiterals; 39234287Sdim bool MigrateSubscripting; 40249423Sdim OwningPtr<NSAPI> NSAPIObj; 41249423Sdim OwningPtr<edit::EditedSource> Editor; 42234287Sdim FileRemapper &Remapper; 43234287Sdim FileManager &FileMgr; 44249423Sdim const PPConditionalDirectiveRecord *PPRec; 45234287Sdim bool IsOutputFile; 46234287Sdim 47234287Sdim ObjCMigrateASTConsumer(StringRef migrateDir, 48234287Sdim bool migrateLiterals, 49234287Sdim bool migrateSubscripting, 50234287Sdim FileRemapper &remapper, 51234287Sdim FileManager &fileMgr, 52249423Sdim const PPConditionalDirectiveRecord *PPRec, 53234287Sdim bool isOutputFile = false) 54234287Sdim : MigrateDir(migrateDir), 55234287Sdim MigrateLiterals(migrateLiterals), 56234287Sdim MigrateSubscripting(migrateSubscripting), 57234287Sdim Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), 58234287Sdim IsOutputFile(isOutputFile) { } 59234287Sdim 60234287Sdimprotected: 61234287Sdim virtual void Initialize(ASTContext &Context) { 62234287Sdim NSAPIObj.reset(new NSAPI(Context)); 63234287Sdim Editor.reset(new edit::EditedSource(Context.getSourceManager(), 64234287Sdim Context.getLangOpts(), 65234287Sdim PPRec)); 66234287Sdim } 67234287Sdim 68234287Sdim virtual bool HandleTopLevelDecl(DeclGroupRef DG) { 69234287Sdim for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) 70234287Sdim migrateDecl(*I); 71234287Sdim return true; 72234287Sdim } 73234287Sdim virtual void HandleInterestingDecl(DeclGroupRef DG) { 74234287Sdim // Ignore decls from the PCH. 75234287Sdim } 76234287Sdim virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) { 77234287Sdim ObjCMigrateASTConsumer::HandleTopLevelDecl(DG); 78234287Sdim } 79234287Sdim 80234287Sdim virtual void HandleTranslationUnit(ASTContext &Ctx); 81234287Sdim}; 82234287Sdim 83234287Sdim} 84234287Sdim 85234287SdimObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction, 86234287Sdim StringRef migrateDir, 87234287Sdim bool migrateLiterals, 88234287Sdim bool migrateSubscripting) 89234287Sdim : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir), 90234287Sdim MigrateLiterals(migrateLiterals), MigrateSubscripting(migrateSubscripting), 91234287Sdim CompInst(0) { 92234287Sdim if (MigrateDir.empty()) 93234287Sdim MigrateDir = "."; // user current directory if none is given. 94234287Sdim} 95234287Sdim 96234287SdimASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, 97234287Sdim StringRef InFile) { 98249423Sdim PPConditionalDirectiveRecord * 99249423Sdim PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager()); 100249423Sdim CompInst->getPreprocessor().addPPCallbacks(PPRec); 101234287Sdim ASTConsumer * 102234287Sdim WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile); 103234287Sdim ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir, 104234287Sdim MigrateLiterals, 105234287Sdim MigrateSubscripting, 106234287Sdim Remapper, 107234287Sdim CompInst->getFileManager(), 108249423Sdim PPRec); 109234287Sdim ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer }; 110234287Sdim return new MultiplexConsumer(Consumers); 111234287Sdim} 112234287Sdim 113234287Sdimbool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) { 114234287Sdim Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(), 115234287Sdim /*ignoreIfFilesChanges=*/true); 116234287Sdim CompInst = &CI; 117234287Sdim CI.getDiagnostics().setIgnoreAllWarnings(true); 118234287Sdim return true; 119234287Sdim} 120234287Sdim 121234287Sdimnamespace { 122234287Sdimclass ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> { 123234287Sdim ObjCMigrateASTConsumer &Consumer; 124249423Sdim ParentMap &PMap; 125234287Sdim 126234287Sdimpublic: 127249423Sdim ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap) 128249423Sdim : Consumer(consumer), PMap(PMap) { } 129234287Sdim 130234287Sdim bool shouldVisitTemplateInstantiations() const { return false; } 131234287Sdim bool shouldWalkTypesOfTypeLocs() const { return false; } 132234287Sdim 133234287Sdim bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 134234287Sdim if (Consumer.MigrateLiterals) { 135234287Sdim edit::Commit commit(*Consumer.Editor); 136249423Sdim edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap); 137234287Sdim Consumer.Editor->commit(commit); 138234287Sdim } 139234287Sdim 140234287Sdim if (Consumer.MigrateSubscripting) { 141234287Sdim edit::Commit commit(*Consumer.Editor); 142234287Sdim edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit); 143234287Sdim Consumer.Editor->commit(commit); 144234287Sdim } 145234287Sdim 146234287Sdim return true; 147234287Sdim } 148234287Sdim 149234287Sdim bool TraverseObjCMessageExpr(ObjCMessageExpr *E) { 150234287Sdim // Do depth first; we want to rewrite the subexpressions first so that if 151234287Sdim // we have to move expressions we will move them already rewritten. 152234287Sdim for (Stmt::child_range range = E->children(); range; ++range) 153234287Sdim if (!TraverseStmt(*range)) 154234287Sdim return false; 155234287Sdim 156234287Sdim return WalkUpFromObjCMessageExpr(E); 157234287Sdim } 158234287Sdim}; 159249423Sdim 160249423Sdimclass BodyMigrator : public RecursiveASTVisitor<BodyMigrator> { 161249423Sdim ObjCMigrateASTConsumer &Consumer; 162249423Sdim OwningPtr<ParentMap> PMap; 163249423Sdim 164249423Sdimpublic: 165249423Sdim BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { } 166249423Sdim 167249423Sdim bool shouldVisitTemplateInstantiations() const { return false; } 168249423Sdim bool shouldWalkTypesOfTypeLocs() const { return false; } 169249423Sdim 170249423Sdim bool TraverseStmt(Stmt *S) { 171249423Sdim PMap.reset(new ParentMap(S)); 172249423Sdim ObjCMigrator(Consumer, *PMap).TraverseStmt(S); 173249423Sdim return true; 174249423Sdim } 175249423Sdim}; 176234287Sdim} 177234287Sdim 178234287Sdimvoid ObjCMigrateASTConsumer::migrateDecl(Decl *D) { 179234287Sdim if (!D) 180234287Sdim return; 181234287Sdim if (isa<ObjCMethodDecl>(D)) 182234287Sdim return; // Wait for the ObjC container declaration. 183234287Sdim 184249423Sdim BodyMigrator(*this).TraverseDecl(D); 185234287Sdim} 186234287Sdim 187234287Sdimnamespace { 188234287Sdim 189234287Sdimclass RewritesReceiver : public edit::EditsReceiver { 190234287Sdim Rewriter &Rewrite; 191234287Sdim 192234287Sdimpublic: 193234287Sdim RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { } 194234287Sdim 195234287Sdim virtual void insert(SourceLocation loc, StringRef text) { 196234287Sdim Rewrite.InsertText(loc, text); 197234287Sdim } 198234287Sdim virtual void replace(CharSourceRange range, StringRef text) { 199234287Sdim Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text); 200234287Sdim } 201234287Sdim}; 202234287Sdim 203234287Sdim} 204234287Sdim 205234287Sdimvoid ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { 206234287Sdim Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts()); 207234287Sdim RewritesReceiver Rec(rewriter); 208234287Sdim Editor->applyRewrites(Rec); 209234287Sdim 210234287Sdim for (Rewriter::buffer_iterator 211234287Sdim I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { 212234287Sdim FileID FID = I->first; 213234287Sdim RewriteBuffer &buf = I->second; 214234287Sdim const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); 215234287Sdim assert(file); 216249423Sdim SmallString<512> newText; 217234287Sdim llvm::raw_svector_ostream vecOS(newText); 218234287Sdim buf.write(vecOS); 219234287Sdim vecOS.flush(); 220234287Sdim llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( 221234287Sdim StringRef(newText.data(), newText.size()), file->getName()); 222249423Sdim SmallString<64> filePath(file->getName()); 223234287Sdim FileMgr.FixupRelativePath(filePath); 224234287Sdim Remapper.remap(filePath.str(), memBuf); 225234287Sdim } 226234287Sdim 227234287Sdim if (IsOutputFile) { 228234287Sdim Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics()); 229234287Sdim } else { 230234287Sdim Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics()); 231234287Sdim } 232234287Sdim} 233234287Sdim 234234287Sdimbool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) { 235239462Sdim CI.getDiagnostics().setIgnoreAllWarnings(true); 236234287Sdim return true; 237234287Sdim} 238234287Sdim 239234287SdimASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, 240234287Sdim StringRef InFile) { 241249423Sdim PPConditionalDirectiveRecord * 242249423Sdim PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager()); 243249423Sdim CI.getPreprocessor().addPPCallbacks(PPRec); 244234287Sdim return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile, 245234287Sdim /*MigrateLiterals=*/true, 246234287Sdim /*MigrateSubscripting=*/true, 247234287Sdim Remapper, 248234287Sdim CI.getFileManager(), 249249423Sdim PPRec, 250234287Sdim /*isOutputFile=*/true); 251234287Sdim} 252