xref: /llvm-project/clang/lib/ARCMigrate/TransARCAssign.cpp (revision 2946cd701067404b99c39fb29dc9c74bd7193eb3)
1d81108f0SBenjamin Kramer //===--- TransARCAssign.cpp - Transformations to ARC mode -----------------===//
2e5b475c6SArgyrios Kyrtzidis //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5b475c6SArgyrios Kyrtzidis //
7e5b475c6SArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
8e5b475c6SArgyrios Kyrtzidis //
9e5b475c6SArgyrios Kyrtzidis // makeAssignARCSafe:
10e5b475c6SArgyrios Kyrtzidis //
11e5b475c6SArgyrios Kyrtzidis // Add '__strong' where appropriate.
12e5b475c6SArgyrios Kyrtzidis //
13e5b475c6SArgyrios Kyrtzidis //  for (id x in collection) {
14e5b475c6SArgyrios Kyrtzidis //    x = 0;
15e5b475c6SArgyrios Kyrtzidis //  }
16e5b475c6SArgyrios Kyrtzidis // ---->
17e5b475c6SArgyrios Kyrtzidis //  for (__strong id x in collection) {
18e5b475c6SArgyrios Kyrtzidis //    x = 0;
19e5b475c6SArgyrios Kyrtzidis //  }
20e5b475c6SArgyrios Kyrtzidis //
21e5b475c6SArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
22e5b475c6SArgyrios Kyrtzidis 
23e5b475c6SArgyrios Kyrtzidis #include "Transforms.h"
24e5b475c6SArgyrios Kyrtzidis #include "Internals.h"
254ab984e7SBenjamin Kramer #include "clang/AST/ASTContext.h"
26e5b475c6SArgyrios Kyrtzidis #include "clang/Sema/SemaDiagnostic.h"
27e5b475c6SArgyrios Kyrtzidis 
28e5b475c6SArgyrios Kyrtzidis using namespace clang;
29e5b475c6SArgyrios Kyrtzidis using namespace arcmt;
30e5b475c6SArgyrios Kyrtzidis using namespace trans;
31e5b475c6SArgyrios Kyrtzidis 
32e5b475c6SArgyrios Kyrtzidis namespace {
33e5b475c6SArgyrios Kyrtzidis 
34e5b475c6SArgyrios Kyrtzidis class ARCAssignChecker : public RecursiveASTVisitor<ARCAssignChecker> {
35e5b475c6SArgyrios Kyrtzidis   MigrationPass &Pass;
36e5b475c6SArgyrios Kyrtzidis   llvm::DenseSet<VarDecl *> ModifiedVars;
37e5b475c6SArgyrios Kyrtzidis 
38e5b475c6SArgyrios Kyrtzidis public:
ARCAssignChecker(MigrationPass & pass)39e5b475c6SArgyrios Kyrtzidis   ARCAssignChecker(MigrationPass &pass) : Pass(pass) { }
40e5b475c6SArgyrios Kyrtzidis 
VisitBinaryOperator(BinaryOperator * Exp)41e5b475c6SArgyrios Kyrtzidis   bool VisitBinaryOperator(BinaryOperator *Exp) {
42aed9bd7cSArgyrios Kyrtzidis     if (Exp->getType()->isDependentType())
43aed9bd7cSArgyrios Kyrtzidis       return true;
44aed9bd7cSArgyrios Kyrtzidis 
45e5b475c6SArgyrios Kyrtzidis     Expr *E = Exp->getLHS();
46e5b475c6SArgyrios Kyrtzidis     SourceLocation OrigLoc = E->getExprLoc();
47e5b475c6SArgyrios Kyrtzidis     SourceLocation Loc = OrigLoc;
48e5b475c6SArgyrios Kyrtzidis     DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
49e5b475c6SArgyrios Kyrtzidis     if (declRef && isa<VarDecl>(declRef->getDecl())) {
50e5b475c6SArgyrios Kyrtzidis       ASTContext &Ctx = Pass.Ctx;
51e5b475c6SArgyrios Kyrtzidis       Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(Ctx, &Loc);
52e5b475c6SArgyrios Kyrtzidis       if (IsLV != Expr::MLV_ConstQualified)
53e5b475c6SArgyrios Kyrtzidis         return true;
54e5b475c6SArgyrios Kyrtzidis       VarDecl *var = cast<VarDecl>(declRef->getDecl());
55e5b475c6SArgyrios Kyrtzidis       if (var->isARCPseudoStrong()) {
56e5b475c6SArgyrios Kyrtzidis         Transaction Trans(Pass.TA);
57e5b475c6SArgyrios Kyrtzidis         if (Pass.TA.clearDiagnostic(diag::err_typecheck_arr_assign_enumeration,
58e5b475c6SArgyrios Kyrtzidis                                     Exp->getOperatorLoc())) {
59e5b475c6SArgyrios Kyrtzidis           if (!ModifiedVars.count(var)) {
60e5b475c6SArgyrios Kyrtzidis             TypeLoc TLoc = var->getTypeSourceInfo()->getTypeLoc();
61e5b475c6SArgyrios Kyrtzidis             Pass.TA.insert(TLoc.getBeginLoc(), "__strong ");
62e5b475c6SArgyrios Kyrtzidis             ModifiedVars.insert(var);
63e5b475c6SArgyrios Kyrtzidis           }
64e5b475c6SArgyrios Kyrtzidis         }
65e5b475c6SArgyrios Kyrtzidis       }
66e5b475c6SArgyrios Kyrtzidis     }
67e5b475c6SArgyrios Kyrtzidis 
68e5b475c6SArgyrios Kyrtzidis     return true;
69e5b475c6SArgyrios Kyrtzidis   }
70e5b475c6SArgyrios Kyrtzidis };
71e5b475c6SArgyrios Kyrtzidis 
72e5b475c6SArgyrios Kyrtzidis } // anonymous namespace
73e5b475c6SArgyrios Kyrtzidis 
makeAssignARCSafe(MigrationPass & pass)74e5b475c6SArgyrios Kyrtzidis void trans::makeAssignARCSafe(MigrationPass &pass) {
75e5b475c6SArgyrios Kyrtzidis   ARCAssignChecker assignCheck(pass);
76e5b475c6SArgyrios Kyrtzidis   assignCheck.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
77e5b475c6SArgyrios Kyrtzidis }
78