]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.cpp
Merge ^/head r288035 through r288099.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / ARCMigrate / Transforms.cpp
1 //===--- Transforms.cpp - Transformations 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 //===----------------------------------------------------------------------===//
9
10 #include "Transforms.h"
11 #include "Internals.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/RecursiveASTVisitor.h"
14 #include "clang/AST/StmtVisitor.h"
15 #include "clang/Analysis/DomainSpecific/CocoaConventions.h"
16 #include "clang/Basic/SourceManager.h"
17 #include "clang/Basic/TargetInfo.h"
18 #include "clang/Lex/Lexer.h"
19 #include "clang/Lex/Preprocessor.h"
20 #include "clang/Sema/Sema.h"
21 #include "clang/Sema/SemaDiagnostic.h"
22 #include "llvm/ADT/DenseSet.h"
23 #include "llvm/ADT/StringSwitch.h"
24 #include <map>
25
26 using namespace clang;
27 using namespace arcmt;
28 using namespace trans;
29
30 ASTTraverser::~ASTTraverser() { }
31
32 bool MigrationPass::CFBridgingFunctionsDefined() {
33   if (!EnableCFBridgeFns.hasValue())
34     EnableCFBridgeFns = SemaRef.isKnownName("CFBridgingRetain") &&
35                         SemaRef.isKnownName("CFBridgingRelease");
36   return *EnableCFBridgeFns;
37 }
38
39 //===----------------------------------------------------------------------===//
40 // Helpers.
41 //===----------------------------------------------------------------------===//
42
43 bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
44                          bool AllowOnUnknownClass) {
45   if (!Ctx.getLangOpts().ObjCARCWeak)
46     return false;
47
48   QualType T = type;
49   if (T.isNull())
50     return false;
51
52   // iOS is always safe to use 'weak'.
53   if (Ctx.getTargetInfo().getTriple().isiOS())
54     AllowOnUnknownClass = true;
55
56   while (const PointerType *ptr = T->getAs<PointerType>())
57     T = ptr->getPointeeType();
58   if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
59     ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
60     if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject"))
61       return false; // id/NSObject is not safe for weak.
62     if (!AllowOnUnknownClass && !Class->hasDefinition())
63       return false; // forward classes are not verifiable, therefore not safe.
64     if (Class && Class->isArcWeakrefUnavailable())
65       return false;
66   }
67
68   return true;
69 }
70
71 bool trans::isPlusOneAssign(const BinaryOperator *E) {
72   if (E->getOpcode() != BO_Assign)
73     return false;
74
75   return isPlusOne(E->getRHS());
76 }
77
78 bool trans::isPlusOne(const Expr *E) {
79   if (!E)
80     return false;
81   if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E))
82     E = EWC->getSubExpr();
83
84   if (const ObjCMessageExpr *
85         ME = dyn_cast<ObjCMessageExpr>(E->IgnoreParenCasts()))
86     if (ME->getMethodFamily() == OMF_retain)
87       return true;
88
89   if (const CallExpr *
90         callE = dyn_cast<CallExpr>(E->IgnoreParenCasts())) {
91     if (const FunctionDecl *FD = callE->getDirectCallee()) {
92       if (FD->hasAttr<CFReturnsRetainedAttr>())
93         return true;
94
95       if (FD->isGlobal() &&
96           FD->getIdentifier() &&
97           FD->getParent()->isTranslationUnit() &&
98           FD->isExternallyVisible() &&
99           ento::cocoa::isRefType(callE->getType(), "CF",
100                                  FD->getIdentifier()->getName())) {
101         StringRef fname = FD->getIdentifier()->getName();
102         if (fname.endswith("Retain") ||
103             fname.find("Create") != StringRef::npos ||
104             fname.find("Copy") != StringRef::npos) {
105           return true;
106         }
107       }
108     }
109   }
110
111   const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E);
112   while (implCE && implCE->getCastKind() ==  CK_BitCast)
113     implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
114
115   if (implCE && implCE->getCastKind() == CK_ARCConsumeObject)
116     return true;
117
118   return false;
119 }
120
121 /// \brief 'Loc' is the end of a statement range. This returns the location
122 /// immediately after the semicolon following the statement.
123 /// If no semicolon is found or the location is inside a macro, the returned
124 /// source location will be invalid.
125 SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
126                                             ASTContext &Ctx, bool IsDecl) {
127   SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx, IsDecl);
128   if (SemiLoc.isInvalid())
129     return SourceLocation();
130   return SemiLoc.getLocWithOffset(1);
131 }
132
133 /// \brief \arg Loc is the end of a statement range. This returns the location
134 /// of the semicolon following the statement.
135 /// If no semicolon is found or the location is inside a macro, the returned
136 /// source location will be invalid.
137 SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
138                                             ASTContext &Ctx,
139                                             bool IsDecl) {
140   SourceManager &SM = Ctx.getSourceManager();
141   if (loc.isMacroID()) {
142     if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOpts(), &loc))
143       return SourceLocation();
144   }
145   loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOpts());
146
147   // Break down the source location.
148   std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
149
150   // Try to load the file buffer.
151   bool invalidTemp = false;
152   StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
153   if (invalidTemp)
154     return SourceLocation();
155
156   const char *tokenBegin = file.data() + locInfo.second;
157
158   // Lex from the start of the given location.
159   Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
160               Ctx.getLangOpts(),
161               file.begin(), tokenBegin, file.end());
162   Token tok;
163   lexer.LexFromRawLexer(tok);
164   if (tok.isNot(tok::semi)) {
165     if (!IsDecl)
166       return SourceLocation();
167     // Declaration may be followed with other tokens; such as an __attribute,
168     // before ending with a semicolon.
169     return findSemiAfterLocation(tok.getLocation(), Ctx, /*IsDecl*/true);
170   }
171
172   return tok.getLocation();
173 }
174
175 bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) {
176   if (!E || !E->HasSideEffects(Ctx))
177     return false;
178
179   E = E->IgnoreParenCasts();
180   ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
181   if (!ME)
182     return true;
183   switch (ME->getMethodFamily()) {
184   case OMF_autorelease:
185   case OMF_dealloc:
186   case OMF_release:
187   case OMF_retain:
188     switch (ME->getReceiverKind()) {
189     case ObjCMessageExpr::SuperInstance:
190       return false;
191     case ObjCMessageExpr::Instance:
192       return hasSideEffects(ME->getInstanceReceiver(), Ctx);
193     default:
194       break;
195     }
196     break;
197   default:
198     break;
199   }
200
201   return true;
202 }
203
204 bool trans::isGlobalVar(Expr *E) {
205   E = E->IgnoreParenCasts();
206   if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
207     return DRE->getDecl()->getDeclContext()->isFileContext() &&
208            DRE->getDecl()->isExternallyVisible();
209   if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
210     return isGlobalVar(condOp->getTrueExpr()) &&
211            isGlobalVar(condOp->getFalseExpr());
212
213   return false;  
214 }
215
216 StringRef trans::getNilString(MigrationPass &Pass) {
217   return Pass.SemaRef.PP.isMacroDefined("nil") ? "nil" : "0";
218 }
219
220 namespace {
221
222 class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
223   ExprSet &Refs;
224 public:
225   ReferenceClear(ExprSet &refs) : Refs(refs) { }
226   bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; }
227 };
228
229 class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> {
230   ValueDecl *Dcl;
231   ExprSet &Refs;
232
233 public:
234   ReferenceCollector(ValueDecl *D, ExprSet &refs)
235     : Dcl(D), Refs(refs) { }
236
237   bool VisitDeclRefExpr(DeclRefExpr *E) {
238     if (E->getDecl() == Dcl)
239       Refs.insert(E);
240     return true;
241   }
242 };
243
244 class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
245   ExprSet &Removables;
246
247 public:
248   RemovablesCollector(ExprSet &removables)
249   : Removables(removables) { }
250   
251   bool shouldWalkTypesOfTypeLocs() const { return false; }
252   
253   bool TraverseStmtExpr(StmtExpr *E) {
254     CompoundStmt *S = E->getSubStmt();
255     for (CompoundStmt::body_iterator
256         I = S->body_begin(), E = S->body_end(); I != E; ++I) {
257       if (I != E - 1)
258         mark(*I);
259       TraverseStmt(*I);
260     }
261     return true;
262   }
263   
264   bool VisitCompoundStmt(CompoundStmt *S) {
265     for (auto *I : S->body())
266       mark(I);
267     return true;
268   }
269   
270   bool VisitIfStmt(IfStmt *S) {
271     mark(S->getThen());
272     mark(S->getElse());
273     return true;
274   }
275   
276   bool VisitWhileStmt(WhileStmt *S) {
277     mark(S->getBody());
278     return true;
279   }
280   
281   bool VisitDoStmt(DoStmt *S) {
282     mark(S->getBody());
283     return true;
284   }
285   
286   bool VisitForStmt(ForStmt *S) {
287     mark(S->getInit());
288     mark(S->getInc());
289     mark(S->getBody());
290     return true;
291   }
292   
293 private:
294   void mark(Stmt *S) {
295     if (!S) return;
296     
297     while (LabelStmt *Label = dyn_cast<LabelStmt>(S))
298       S = Label->getSubStmt();
299     S = S->IgnoreImplicit();
300     if (Expr *E = dyn_cast<Expr>(S))
301       Removables.insert(E);
302   }
303 };
304
305 } // end anonymous namespace
306
307 void trans::clearRefsIn(Stmt *S, ExprSet &refs) {
308   ReferenceClear(refs).TraverseStmt(S);
309 }
310
311 void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) {
312   ReferenceCollector(D, refs).TraverseStmt(S);
313 }
314
315 void trans::collectRemovables(Stmt *S, ExprSet &exprs) {
316   RemovablesCollector(exprs).TraverseStmt(S);
317 }
318
319 //===----------------------------------------------------------------------===//
320 // MigrationContext
321 //===----------------------------------------------------------------------===//
322
323 namespace {
324
325 class ASTTransform : public RecursiveASTVisitor<ASTTransform> {
326   MigrationContext &MigrateCtx;
327   typedef RecursiveASTVisitor<ASTTransform> base;
328
329 public:
330   ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { }
331
332   bool shouldWalkTypesOfTypeLocs() const { return false; }
333
334   bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
335     ObjCImplementationContext ImplCtx(MigrateCtx, D);
336     for (MigrationContext::traverser_iterator
337            I = MigrateCtx.traversers_begin(),
338            E = MigrateCtx.traversers_end(); I != E; ++I)
339       (*I)->traverseObjCImplementation(ImplCtx);
340
341     return base::TraverseObjCImplementationDecl(D);
342   }
343
344   bool TraverseStmt(Stmt *rootS) {
345     if (!rootS)
346       return true;
347
348     BodyContext BodyCtx(MigrateCtx, rootS);
349     for (MigrationContext::traverser_iterator
350            I = MigrateCtx.traversers_begin(),
351            E = MigrateCtx.traversers_end(); I != E; ++I)
352       (*I)->traverseBody(BodyCtx);
353
354     return true;
355   }
356 };
357
358 }
359
360 MigrationContext::~MigrationContext() {
361   for (traverser_iterator
362          I = traversers_begin(), E = traversers_end(); I != E; ++I)
363     delete *I;
364 }
365
366 bool MigrationContext::isGCOwnedNonObjC(QualType T) {
367   while (!T.isNull()) {
368     if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
369       if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
370         return !AttrT->getModifiedType()->isObjCRetainableType();
371     }
372
373     if (T->isArrayType())
374       T = Pass.Ctx.getBaseElementType(T);
375     else if (const PointerType *PT = T->getAs<PointerType>())
376       T = PT->getPointeeType();
377     else if (const ReferenceType *RT = T->getAs<ReferenceType>())
378       T = RT->getPointeeType();
379     else
380       break;
381   }
382
383   return false;
384 }
385
386 bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr,
387                                                 StringRef toAttr,
388                                                 SourceLocation atLoc) {
389   if (atLoc.isMacroID())
390     return false;
391
392   SourceManager &SM = Pass.Ctx.getSourceManager();
393
394   // Break down the source location.
395   std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
396
397   // Try to load the file buffer.
398   bool invalidTemp = false;
399   StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
400   if (invalidTemp)
401     return false;
402
403   const char *tokenBegin = file.data() + locInfo.second;
404
405   // Lex from the start of the given location.
406   Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
407               Pass.Ctx.getLangOpts(),
408               file.begin(), tokenBegin, file.end());
409   Token tok;
410   lexer.LexFromRawLexer(tok);
411   if (tok.isNot(tok::at)) return false;
412   lexer.LexFromRawLexer(tok);
413   if (tok.isNot(tok::raw_identifier)) return false;
414   if (tok.getRawIdentifier() != "property")
415     return false;
416   lexer.LexFromRawLexer(tok);
417   if (tok.isNot(tok::l_paren)) return false;
418   
419   Token BeforeTok = tok;
420   Token AfterTok;
421   AfterTok.startToken();
422   SourceLocation AttrLoc;
423   
424   lexer.LexFromRawLexer(tok);
425   if (tok.is(tok::r_paren))
426     return false;
427
428   while (1) {
429     if (tok.isNot(tok::raw_identifier)) return false;
430     if (tok.getRawIdentifier() == fromAttr) {
431       if (!toAttr.empty()) {
432         Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
433         return true;
434       }
435       // We want to remove the attribute.
436       AttrLoc = tok.getLocation();
437     }
438
439     do {
440       lexer.LexFromRawLexer(tok);
441       if (AttrLoc.isValid() && AfterTok.is(tok::unknown))
442         AfterTok = tok;
443     } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
444     if (tok.is(tok::r_paren))
445       break;
446     if (AttrLoc.isInvalid())
447       BeforeTok = tok;
448     lexer.LexFromRawLexer(tok);
449   }
450
451   if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) {
452     // We want to remove the attribute.
453     if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) {
454       Pass.TA.remove(SourceRange(BeforeTok.getLocation(),
455                                  AfterTok.getLocation()));
456     } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) {
457       Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation()));
458     } else {
459       Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc));
460     }
461
462     return true;
463   }
464   
465   return false;
466 }
467
468 bool MigrationContext::addPropertyAttribute(StringRef attr,
469                                             SourceLocation atLoc) {
470   if (atLoc.isMacroID())
471     return false;
472
473   SourceManager &SM = Pass.Ctx.getSourceManager();
474
475   // Break down the source location.
476   std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
477
478   // Try to load the file buffer.
479   bool invalidTemp = false;
480   StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
481   if (invalidTemp)
482     return false;
483
484   const char *tokenBegin = file.data() + locInfo.second;
485
486   // Lex from the start of the given location.
487   Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
488               Pass.Ctx.getLangOpts(),
489               file.begin(), tokenBegin, file.end());
490   Token tok;
491   lexer.LexFromRawLexer(tok);
492   if (tok.isNot(tok::at)) return false;
493   lexer.LexFromRawLexer(tok);
494   if (tok.isNot(tok::raw_identifier)) return false;
495   if (tok.getRawIdentifier() != "property")
496     return false;
497   lexer.LexFromRawLexer(tok);
498
499   if (tok.isNot(tok::l_paren)) {
500     Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") ");
501     return true;
502   }
503   
504   lexer.LexFromRawLexer(tok);
505   if (tok.is(tok::r_paren)) {
506     Pass.TA.insert(tok.getLocation(), attr);
507     return true;
508   }
509
510   if (tok.isNot(tok::raw_identifier)) return false;
511
512   Pass.TA.insert(tok.getLocation(), std::string(attr) + ", ");
513   return true;
514 }
515
516 void MigrationContext::traverse(TranslationUnitDecl *TU) {
517   for (traverser_iterator
518          I = traversers_begin(), E = traversers_end(); I != E; ++I)
519     (*I)->traverseTU(*this);
520
521   ASTTransform(*this).TraverseDecl(TU);
522 }
523
524 static void GCRewriteFinalize(MigrationPass &pass) {
525   ASTContext &Ctx = pass.Ctx;
526   TransformActions &TA = pass.TA;
527   DeclContext *DC = Ctx.getTranslationUnitDecl();
528   Selector FinalizeSel =
529    Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));
530   
531   typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
532   impl_iterator;
533   for (impl_iterator I = impl_iterator(DC->decls_begin()),
534        E = impl_iterator(DC->decls_end()); I != E; ++I) {
535     for (const auto *MD : I->instance_methods()) {
536       if (!MD->hasBody())
537         continue;
538       
539       if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
540         const ObjCMethodDecl *FinalizeM = MD;
541         Transaction Trans(TA);
542         TA.insert(FinalizeM->getSourceRange().getBegin(), 
543                   "#if !__has_feature(objc_arc)\n");
544         CharSourceRange::getTokenRange(FinalizeM->getSourceRange());
545         const SourceManager &SM = pass.Ctx.getSourceManager();
546         const LangOptions &LangOpts = pass.Ctx.getLangOpts();
547         bool Invalid;
548         std::string str = "\n#endif\n";
549         str += Lexer::getSourceText(
550                   CharSourceRange::getTokenRange(FinalizeM->getSourceRange()), 
551                                     SM, LangOpts, &Invalid);
552         TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str);
553         
554         break;
555       }
556     }
557   }
558 }
559
560 //===----------------------------------------------------------------------===//
561 // getAllTransformations.
562 //===----------------------------------------------------------------------===//
563
564 static void traverseAST(MigrationPass &pass) {
565   MigrationContext MigrateCtx(pass);
566
567   if (pass.isGCMigration()) {
568     MigrateCtx.addTraverser(new GCCollectableCallsTraverser);
569     MigrateCtx.addTraverser(new GCAttrsTraverser());
570   }
571   MigrateCtx.addTraverser(new PropertyRewriteTraverser());
572   MigrateCtx.addTraverser(new BlockObjCVariableTraverser());
573   MigrateCtx.addTraverser(new ProtectedScopeTraverser());
574
575   MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl());
576 }
577
578 static void independentTransforms(MigrationPass &pass) {
579   rewriteAutoreleasePool(pass);
580   removeRetainReleaseDeallocFinalize(pass);
581   rewriteUnusedInitDelegate(pass);
582   removeZeroOutPropsInDeallocFinalize(pass);
583   makeAssignARCSafe(pass);
584   rewriteUnbridgedCasts(pass);
585   checkAPIUses(pass);
586   traverseAST(pass);
587 }
588
589 std::vector<TransformFn> arcmt::getAllTransformations(
590                                                LangOptions::GCMode OrigGCMode,
591                                                bool NoFinalizeRemoval) {
592   std::vector<TransformFn> transforms;
593
594   if (OrigGCMode ==  LangOptions::GCOnly && NoFinalizeRemoval)
595     transforms.push_back(GCRewriteFinalize);
596   transforms.push_back(independentTransforms);
597   // This depends on previous transformations removing various expressions.
598   transforms.push_back(removeEmptyStatementsAndDeallocFinalize);
599
600   return transforms;
601 }