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