blob: 0650e3b94fbc8aaeb7189abc8f1566fd92ff9cfd [file] [log] [blame]
John McCall8f0e8d22011-06-15 23:25:17 +00001//===--- Tranforms.cpp - Tranformations to ARC mode -----------------------===//
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//===----------------------------------------------------------------------===//
John McCall8f0e8d22011-06-15 23:25:17 +00009
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000010#include "Transforms.h"
John McCall8f0e8d22011-06-15 23:25:17 +000011#include "Internals.h"
12#include "clang/Sema/SemaDiagnostic.h"
13#include "clang/AST/RecursiveASTVisitor.h"
14#include "clang/AST/StmtVisitor.h"
15#include "clang/AST/ParentMap.h"
16#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
17#include "clang/Lex/Lexer.h"
18#include "clang/Basic/SourceManager.h"
19#include "llvm/ADT/StringSwitch.h"
20#include "llvm/ADT/DenseSet.h"
21#include <map>
22
23using namespace clang;
24using namespace arcmt;
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000025using namespace trans;
John McCall8f0e8d22011-06-15 23:25:17 +000026using llvm::StringRef;
27
28//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000029// Helpers.
John McCall8f0e8d22011-06-15 23:25:17 +000030//===----------------------------------------------------------------------===//
31
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000032/// \brief 'Loc' is the end of a statement range. This returns the location
33/// immediately after the semicolon following the statement.
34/// If no semicolon is found or the location is inside a macro, the returned
35/// source location will be invalid.
36SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
37 ASTContext &Ctx) {
38 SourceManager &SM = Ctx.getSourceManager();
39 if (loc.isMacroID()) {
40 if (!SM.isAtEndOfMacroInstantiation(loc))
41 return SourceLocation();
42 loc = SM.getInstantiationRange(loc).second;
43 }
44 loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions());
45
46 // Break down the source location.
47 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
48
49 // Try to load the file buffer.
50 bool invalidTemp = false;
51 llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
52 if (invalidTemp)
53 return SourceLocation();
54
55 const char *tokenBegin = file.data() + locInfo.second;
56
57 // Lex from the start of the given location.
58 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
59 Ctx.getLangOptions(),
60 file.begin(), tokenBegin, file.end());
61 Token tok;
62 lexer.LexFromRawLexer(tok);
63 if (tok.isNot(tok::semi))
64 return SourceLocation();
65
66 return tok.getLocation().getFileLocWithOffset(1);
67}
68
69bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) {
70 if (!E || !E->HasSideEffects(Ctx))
71 return false;
72
73 E = E->IgnoreParenCasts();
74 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
75 if (!ME)
76 return true;
77 switch (ME->getMethodFamily()) {
78 case OMF_autorelease:
79 case OMF_dealloc:
80 case OMF_release:
81 case OMF_retain:
82 switch (ME->getReceiverKind()) {
83 case ObjCMessageExpr::SuperInstance:
84 return false;
85 case ObjCMessageExpr::Instance:
86 return hasSideEffects(ME->getInstanceReceiver(), Ctx);
87 default:
88 break;
89 }
90 break;
91 default:
92 break;
93 }
94
95 return true;
96}
97
John McCall8f0e8d22011-06-15 23:25:17 +000098namespace {
99
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000100class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
101 ExprSet &Refs;
102public:
103 ReferenceClear(ExprSet &refs) : Refs(refs) { }
104 bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; }
105 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Refs.erase(E); return true; }
106};
107
108class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> {
109 ValueDecl *Dcl;
110 ExprSet &Refs;
John McCall8f0e8d22011-06-15 23:25:17 +0000111
112public:
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000113 ReferenceCollector(ValueDecl *D, ExprSet &refs)
114 : Dcl(D), Refs(refs) { }
115
116 bool VisitDeclRefExpr(DeclRefExpr *E) {
117 if (E->getDecl() == Dcl)
118 Refs.insert(E);
119 return true;
120 }
121
122 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
123 if (E->getDecl() == Dcl)
124 Refs.insert(E);
125 return true;
126 }
127};
128
129class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
130 ExprSet &Removables;
131
132public:
133 RemovablesCollector(ExprSet &removables)
John McCall8f0e8d22011-06-15 23:25:17 +0000134 : Removables(removables) { }
135
136 bool shouldWalkTypesOfTypeLocs() const { return false; }
137
138 bool TraverseStmtExpr(StmtExpr *E) {
139 CompoundStmt *S = E->getSubStmt();
140 for (CompoundStmt::body_iterator
141 I = S->body_begin(), E = S->body_end(); I != E; ++I) {
142 if (I != E - 1)
143 mark(*I);
144 TraverseStmt(*I);
145 }
146 return true;
147 }
148
149 bool VisitCompoundStmt(CompoundStmt *S) {
150 for (CompoundStmt::body_iterator
151 I = S->body_begin(), E = S->body_end(); I != E; ++I)
152 mark(*I);
153 return true;
154 }
155
156 bool VisitIfStmt(IfStmt *S) {
157 mark(S->getThen());
158 mark(S->getElse());
159 return true;
160 }
161
162 bool VisitWhileStmt(WhileStmt *S) {
163 mark(S->getBody());
164 return true;
165 }
166
167 bool VisitDoStmt(DoStmt *S) {
168 mark(S->getBody());
169 return true;
170 }
171
172 bool VisitForStmt(ForStmt *S) {
173 mark(S->getInit());
174 mark(S->getInc());
175 mark(S->getBody());
176 return true;
177 }
178
179private:
180 void mark(Stmt *S) {
181 if (!S) return;
182
183 if (LabelStmt *Label = dyn_cast<LabelStmt>(S))
184 return mark(Label->getSubStmt());
185 if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(S))
186 return mark(CE->getSubExpr());
187 if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S))
188 return mark(EWC->getSubExpr());
189 if (Expr *E = dyn_cast<Expr>(S))
190 Removables.insert(E);
191 }
192};
193
John McCall8f0e8d22011-06-15 23:25:17 +0000194} // end anonymous namespace
195
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000196void trans::clearRefsIn(Stmt *S, ExprSet &refs) {
197 ReferenceClear(refs).TraverseStmt(S);
John McCall8f0e8d22011-06-15 23:25:17 +0000198}
199
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000200void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) {
201 ReferenceCollector(D, refs).TraverseStmt(S);
John McCall8f0e8d22011-06-15 23:25:17 +0000202}
203
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000204void trans::collectRemovables(Stmt *S, ExprSet &exprs) {
205 RemovablesCollector(exprs).TraverseStmt(S);
John McCall8f0e8d22011-06-15 23:25:17 +0000206}
207
208//===----------------------------------------------------------------------===//
209// getAllTransformations.
210//===----------------------------------------------------------------------===//
211
212static void independentTransforms(MigrationPass &pass) {
213 rewriteAutoreleasePool(pass);
214 changeIvarsOfAssignProperties(pass);
215 removeRetainReleaseDealloc(pass);
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000216 rewriteUnusedInitDelegate(pass);
217 removeZeroOutPropsInDealloc(pass);
John McCall8f0e8d22011-06-15 23:25:17 +0000218 makeAssignARCSafe(pass);
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000219 rewriteUnbridgedCasts(pass);
John McCall8f0e8d22011-06-15 23:25:17 +0000220 rewriteBlockObjCVariable(pass);
221 rewriteAllocCopyWithZone(pass);
222}
223
224std::vector<TransformFn> arcmt::getAllTransformations() {
225 std::vector<TransformFn> transforms;
226
227 // This must come first since rewriteAutoreleasePool depends on -release
228 // calls being present to determine the @autorelease ending scope.
229 transforms.push_back(independentTransforms);
230
231 transforms.push_back(removeEmptyStatements);
232 transforms.push_back(removeDeallocMethod);
233
234 return transforms;
235}