1//===--- TransARCAssign.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// makeAssignARCSafe:
11//
12// Add '__strong' where appropriate.
13//
14//  for (id x in collection) {
15//    x = 0;
16//  }
17// ---->
18//  for (__strong id x in collection) {
19//    x = 0;
20//  }
21//
22//===----------------------------------------------------------------------===//
23
24#include "Transforms.h"
25#include "Internals.h"
26#include "clang/AST/ASTContext.h"
27#include "clang/Sema/SemaDiagnostic.h"
28
29using namespace clang;
30using namespace arcmt;
31using namespace trans;
32
33namespace {
34
35class ARCAssignChecker : public RecursiveASTVisitor<ARCAssignChecker> {
36  MigrationPass &Pass;
37  llvm::DenseSet<VarDecl *> ModifiedVars;
38
39public:
40  ARCAssignChecker(MigrationPass &pass) : Pass(pass) { }
41
42  bool VisitBinaryOperator(BinaryOperator *Exp) {
43    if (Exp->getType()->isDependentType())
44      return true;
45
46    Expr *E = Exp->getLHS();
47    SourceLocation OrigLoc = E->getExprLoc();
48    SourceLocation Loc = OrigLoc;
49    DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
50    if (declRef && isa<VarDecl>(declRef->getDecl())) {
51      ASTContext &Ctx = Pass.Ctx;
52      Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(Ctx, &Loc);
53      if (IsLV != Expr::MLV_ConstQualified)
54        return true;
55      VarDecl *var = cast<VarDecl>(declRef->getDecl());
56      if (var->isARCPseudoStrong()) {
57        Transaction Trans(Pass.TA);
58        if (Pass.TA.clearDiagnostic(diag::err_typecheck_arr_assign_enumeration,
59                                    Exp->getOperatorLoc())) {
60          if (!ModifiedVars.count(var)) {
61            TypeLoc TLoc = var->getTypeSourceInfo()->getTypeLoc();
62            Pass.TA.insert(TLoc.getBeginLoc(), "__strong ");
63            ModifiedVars.insert(var);
64          }
65        }
66      }
67    }
68
69    return true;
70  }
71};
72
73} // anonymous namespace
74
75void trans::makeAssignARCSafe(MigrationPass &pass) {
76  ARCAssignChecker assignCheck(pass);
77  assignCheck.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
78}
79