1249423Sdim//===--- TransARCAssign.cpp - Transformations to ARC mode -----------------===//
2224135Sdim//
3224135Sdim//                     The LLVM Compiler Infrastructure
4224135Sdim//
5224135Sdim// This file is distributed under the University of Illinois Open Source
6224135Sdim// License. See LICENSE.TXT for details.
7224135Sdim//
8224135Sdim//===----------------------------------------------------------------------===//
9224135Sdim//
10224135Sdim// makeAssignARCSafe:
11224135Sdim//
12224135Sdim// Add '__strong' where appropriate.
13224135Sdim//
14224135Sdim//  for (id x in collection) {
15224135Sdim//    x = 0;
16224135Sdim//  }
17224135Sdim// ---->
18224135Sdim//  for (__strong id x in collection) {
19224135Sdim//    x = 0;
20224135Sdim//  }
21224135Sdim//
22224135Sdim//===----------------------------------------------------------------------===//
23224135Sdim
24224135Sdim#include "Transforms.h"
25224135Sdim#include "Internals.h"
26239462Sdim#include "clang/AST/ASTContext.h"
27224135Sdim#include "clang/Sema/SemaDiagnostic.h"
28224135Sdim
29224135Sdimusing namespace clang;
30224135Sdimusing namespace arcmt;
31224135Sdimusing namespace trans;
32224135Sdim
33224135Sdimnamespace {
34224135Sdim
35224135Sdimclass ARCAssignChecker : public RecursiveASTVisitor<ARCAssignChecker> {
36224135Sdim  MigrationPass &Pass;
37224135Sdim  llvm::DenseSet<VarDecl *> ModifiedVars;
38224135Sdim
39224135Sdimpublic:
40224135Sdim  ARCAssignChecker(MigrationPass &pass) : Pass(pass) { }
41224135Sdim
42224135Sdim  bool VisitBinaryOperator(BinaryOperator *Exp) {
43234353Sdim    if (Exp->getType()->isDependentType())
44234353Sdim      return true;
45234353Sdim
46224135Sdim    Expr *E = Exp->getLHS();
47224135Sdim    SourceLocation OrigLoc = E->getExprLoc();
48224135Sdim    SourceLocation Loc = OrigLoc;
49224135Sdim    DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
50224135Sdim    if (declRef && isa<VarDecl>(declRef->getDecl())) {
51224135Sdim      ASTContext &Ctx = Pass.Ctx;
52224135Sdim      Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(Ctx, &Loc);
53224135Sdim      if (IsLV != Expr::MLV_ConstQualified)
54224135Sdim        return true;
55224135Sdim      VarDecl *var = cast<VarDecl>(declRef->getDecl());
56224135Sdim      if (var->isARCPseudoStrong()) {
57224135Sdim        Transaction Trans(Pass.TA);
58224135Sdim        if (Pass.TA.clearDiagnostic(diag::err_typecheck_arr_assign_enumeration,
59224135Sdim                                    Exp->getOperatorLoc())) {
60224135Sdim          if (!ModifiedVars.count(var)) {
61224135Sdim            TypeLoc TLoc = var->getTypeSourceInfo()->getTypeLoc();
62224135Sdim            Pass.TA.insert(TLoc.getBeginLoc(), "__strong ");
63224135Sdim            ModifiedVars.insert(var);
64224135Sdim          }
65224135Sdim        }
66224135Sdim      }
67224135Sdim    }
68224135Sdim
69224135Sdim    return true;
70224135Sdim  }
71224135Sdim};
72224135Sdim
73224135Sdim} // anonymous namespace
74224135Sdim
75224135Sdimvoid trans::makeAssignARCSafe(MigrationPass &pass) {
76224135Sdim  ARCAssignChecker assignCheck(pass);
77224135Sdim  assignCheck.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
78224135Sdim}
79