1//===--- TransUnusedInitDelegate.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// Transformations:
10//===----------------------------------------------------------------------===//
11//
12// rewriteUnusedInitDelegate:
13//
14// Rewrites an unused result of calling a delegate initialization, to assigning
15// the result to self.
16// e.g
17//  [self init];
18// ---->
19//  self = [self init];
20//
21//===----------------------------------------------------------------------===//
22
23#include "Transforms.h"
24#include "Internals.h"
25#include "clang/AST/ASTContext.h"
26#include "clang/Sema/SemaDiagnostic.h"
27
28using namespace clang;
29using namespace arcmt;
30using namespace trans;
31
32namespace {
33
34class UnusedInitRewriter : public RecursiveASTVisitor<UnusedInitRewriter> {
35  Stmt *Body;
36  MigrationPass &Pass;
37
38  ExprSet Removables;
39
40public:
41  UnusedInitRewriter(MigrationPass &pass)
42    : Body(nullptr), Pass(pass) { }
43
44  void transformBody(Stmt *body, Decl *ParentD) {
45    Body = body;
46    collectRemovables(body, Removables);
47    TraverseStmt(body);
48  }
49
50  bool VisitObjCMessageExpr(ObjCMessageExpr *ME) {
51    if (ME->isDelegateInitCall() &&
52        isRemovable(ME) &&
53        Pass.TA.hasDiagnostic(diag::err_arc_unused_init_message,
54                              ME->getExprLoc())) {
55      Transaction Trans(Pass.TA);
56      Pass.TA.clearDiagnostic(diag::err_arc_unused_init_message,
57                              ME->getExprLoc());
58      SourceRange ExprRange = ME->getSourceRange();
59      Pass.TA.insert(ExprRange.getBegin(), "if (!(self = ");
60      std::string retStr = ")) return ";
61      retStr += getNilString(Pass.Ctx);
62      Pass.TA.insertAfterToken(ExprRange.getEnd(), retStr);
63    }
64    return true;
65  }
66
67private:
68  bool isRemovable(Expr *E) const {
69    return Removables.count(E);
70  }
71};
72
73} // anonymous namespace
74
75void trans::rewriteUnusedInitDelegate(MigrationPass &pass) {
76  BodyTransform<UnusedInitRewriter> trans(pass);
77  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
78}
79