]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / llvm / tools / clang / lib / ARCMigrate / ObjCMT.cpp
1 //===--- ObjCMT.cpp - ObjC Migrate Tool -----------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "clang/ARCMigrate/ARCMTActions.h"
11 #include "clang/AST/ASTConsumer.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/NSAPI.h"
14 #include "clang/AST/ParentMap.h"
15 #include "clang/AST/RecursiveASTVisitor.h"
16 #include "clang/Basic/FileManager.h"
17 #include "clang/Edit/Commit.h"
18 #include "clang/Edit/EditedSource.h"
19 #include "clang/Edit/EditsReceiver.h"
20 #include "clang/Edit/Rewriters.h"
21 #include "clang/Frontend/CompilerInstance.h"
22 #include "clang/Frontend/MultiplexConsumer.h"
23 #include "clang/Lex/PPConditionalDirectiveRecord.h"
24 #include "clang/Lex/Preprocessor.h"
25 #include "clang/Rewrite/Core/Rewriter.h"
26 #include "llvm/ADT/SmallString.h"
27
28 using namespace clang;
29 using namespace arcmt;
30
31 namespace {
32
33 class ObjCMigrateASTConsumer : public ASTConsumer {
34   void migrateDecl(Decl *D);
35
36 public:
37   std::string MigrateDir;
38   bool MigrateLiterals;
39   bool MigrateSubscripting;
40   OwningPtr<NSAPI> NSAPIObj;
41   OwningPtr<edit::EditedSource> Editor;
42   FileRemapper &Remapper;
43   FileManager &FileMgr;
44   const PPConditionalDirectiveRecord *PPRec;
45   bool IsOutputFile;
46
47   ObjCMigrateASTConsumer(StringRef migrateDir,
48                          bool migrateLiterals,
49                          bool migrateSubscripting,
50                          FileRemapper &remapper,
51                          FileManager &fileMgr,
52                          const PPConditionalDirectiveRecord *PPRec,
53                          bool isOutputFile = false)
54   : MigrateDir(migrateDir),
55     MigrateLiterals(migrateLiterals),
56     MigrateSubscripting(migrateSubscripting),
57     Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec),
58     IsOutputFile(isOutputFile) { }
59
60 protected:
61   virtual void Initialize(ASTContext &Context) {
62     NSAPIObj.reset(new NSAPI(Context));
63     Editor.reset(new edit::EditedSource(Context.getSourceManager(),
64                                         Context.getLangOpts(),
65                                         PPRec));
66   }
67
68   virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
69     for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
70       migrateDecl(*I);
71     return true;
72   }
73   virtual void HandleInterestingDecl(DeclGroupRef DG) {
74     // Ignore decls from the PCH.
75   }
76   virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
77     ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
78   }
79
80   virtual void HandleTranslationUnit(ASTContext &Ctx);
81 };
82
83 }
84
85 ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
86                              StringRef migrateDir,
87                              bool migrateLiterals,
88                              bool migrateSubscripting)
89   : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir),
90     MigrateLiterals(migrateLiterals), MigrateSubscripting(migrateSubscripting),
91     CompInst(0) {
92   if (MigrateDir.empty())
93     MigrateDir = "."; // user current directory if none is given.
94 }
95
96 ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
97                                                   StringRef InFile) {
98   PPConditionalDirectiveRecord *
99     PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager());
100   CompInst->getPreprocessor().addPPCallbacks(PPRec);
101   ASTConsumer *
102     WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
103   ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir,
104                                                        MigrateLiterals,
105                                                        MigrateSubscripting,
106                                                        Remapper,
107                                                     CompInst->getFileManager(),
108                                                        PPRec);
109   ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer };
110   return new MultiplexConsumer(Consumers);
111 }
112
113 bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
114   Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(),
115                         /*ignoreIfFilesChanges=*/true);
116   CompInst = &CI;
117   CI.getDiagnostics().setIgnoreAllWarnings(true);
118   return true;
119 }
120
121 namespace {
122 class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
123   ObjCMigrateASTConsumer &Consumer;
124   ParentMap &PMap;
125
126 public:
127   ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap)
128     : Consumer(consumer), PMap(PMap) { }
129
130   bool shouldVisitTemplateInstantiations() const { return false; }
131   bool shouldWalkTypesOfTypeLocs() const { return false; }
132
133   bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
134     if (Consumer.MigrateLiterals) {
135       edit::Commit commit(*Consumer.Editor);
136       edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
137       Consumer.Editor->commit(commit);
138     }
139
140     if (Consumer.MigrateSubscripting) {
141       edit::Commit commit(*Consumer.Editor);
142       edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit);
143       Consumer.Editor->commit(commit);
144     }
145
146     return true;
147   }
148
149   bool TraverseObjCMessageExpr(ObjCMessageExpr *E) {
150     // Do depth first; we want to rewrite the subexpressions first so that if
151     // we have to move expressions we will move them already rewritten.
152     for (Stmt::child_range range = E->children(); range; ++range)
153       if (!TraverseStmt(*range))
154         return false;
155
156     return WalkUpFromObjCMessageExpr(E);
157   }
158 };
159
160 class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
161   ObjCMigrateASTConsumer &Consumer;
162   OwningPtr<ParentMap> PMap;
163
164 public:
165   BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
166
167   bool shouldVisitTemplateInstantiations() const { return false; }
168   bool shouldWalkTypesOfTypeLocs() const { return false; }
169
170   bool TraverseStmt(Stmt *S) {
171     PMap.reset(new ParentMap(S));
172     ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
173     return true;
174   }
175 };
176 }
177
178 void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
179   if (!D)
180     return;
181   if (isa<ObjCMethodDecl>(D))
182     return; // Wait for the ObjC container declaration.
183
184   BodyMigrator(*this).TraverseDecl(D);
185 }
186
187 namespace {
188
189 class RewritesReceiver : public edit::EditsReceiver {
190   Rewriter &Rewrite;
191
192 public:
193   RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
194
195   virtual void insert(SourceLocation loc, StringRef text) {
196     Rewrite.InsertText(loc, text);
197   }
198   virtual void replace(CharSourceRange range, StringRef text) {
199     Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
200   }
201 };
202
203 }
204
205 void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
206   Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
207   RewritesReceiver Rec(rewriter);
208   Editor->applyRewrites(Rec);
209
210   for (Rewriter::buffer_iterator
211         I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
212     FileID FID = I->first;
213     RewriteBuffer &buf = I->second;
214     const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
215     assert(file);
216     SmallString<512> newText;
217     llvm::raw_svector_ostream vecOS(newText);
218     buf.write(vecOS);
219     vecOS.flush();
220     llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
221                    StringRef(newText.data(), newText.size()), file->getName());
222     SmallString<64> filePath(file->getName());
223     FileMgr.FixupRelativePath(filePath);
224     Remapper.remap(filePath.str(), memBuf);
225   }
226
227   if (IsOutputFile) {
228     Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics());
229   } else {
230     Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics());
231   }
232 }
233
234 bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
235   CI.getDiagnostics().setIgnoreAllWarnings(true);
236   return true;
237 }
238
239 ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
240                                                   StringRef InFile) {
241   PPConditionalDirectiveRecord *
242     PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager());
243   CI.getPreprocessor().addPPCallbacks(PPRec);
244   return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile,
245                                     /*MigrateLiterals=*/true,
246                                     /*MigrateSubscripting=*/true,
247                                     Remapper,
248                                     CI.getFileManager(),
249                                     PPRec,
250                                     /*isOutputFile=*/true); 
251 }