TransAPIUses.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. //===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // checkAPIUses:
  10. //
  11. // Emits error/fix with some API uses that are obsolete or not safe in ARC mode:
  12. //
  13. // - NSInvocation's [get/set]ReturnValue and [get/set]Argument are only safe
  14. // with __unsafe_unretained objects.
  15. // - Calling -zone gets replaced with 'nil'.
  16. //
  17. //===----------------------------------------------------------------------===//
  18. #include "Transforms.h"
  19. #include "Internals.h"
  20. #include "clang/AST/ASTContext.h"
  21. #include "clang/Sema/SemaDiagnostic.h"
  22. using namespace clang;
  23. using namespace arcmt;
  24. using namespace trans;
  25. namespace {
  26. class APIChecker : public RecursiveASTVisitor<APIChecker> {
  27. MigrationPass &Pass;
  28. Selector getReturnValueSel, setReturnValueSel;
  29. Selector getArgumentSel, setArgumentSel;
  30. Selector zoneSel;
  31. public:
  32. APIChecker(MigrationPass &pass) : Pass(pass) {
  33. SelectorTable &sels = Pass.Ctx.Selectors;
  34. IdentifierTable &ids = Pass.Ctx.Idents;
  35. getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue"));
  36. setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue"));
  37. IdentifierInfo *selIds[2];
  38. selIds[0] = &ids.get("getArgument");
  39. selIds[1] = &ids.get("atIndex");
  40. getArgumentSel = sels.getSelector(2, selIds);
  41. selIds[0] = &ids.get("setArgument");
  42. setArgumentSel = sels.getSelector(2, selIds);
  43. zoneSel = sels.getNullarySelector(&ids.get("zone"));
  44. }
  45. bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
  46. // NSInvocation.
  47. if (E->isInstanceMessage() &&
  48. E->getReceiverInterface() &&
  49. E->getReceiverInterface()->getName() == "NSInvocation") {
  50. StringRef selName;
  51. if (E->getSelector() == getReturnValueSel)
  52. selName = "getReturnValue";
  53. else if (E->getSelector() == setReturnValueSel)
  54. selName = "setReturnValue";
  55. else if (E->getSelector() == getArgumentSel)
  56. selName = "getArgument";
  57. else if (E->getSelector() == setArgumentSel)
  58. selName = "setArgument";
  59. else
  60. return true;
  61. Expr *parm = E->getArg(0)->IgnoreParenCasts();
  62. QualType pointee = parm->getType()->getPointeeType();
  63. if (pointee.isNull())
  64. return true;
  65. if (pointee.getObjCLifetime() > Qualifiers::OCL_ExplicitNone)
  66. Pass.TA.report(parm->getBeginLoc(),
  67. diag::err_arcmt_nsinvocation_ownership,
  68. parm->getSourceRange())
  69. << selName;
  70. return true;
  71. }
  72. // -zone.
  73. if (E->isInstanceMessage() &&
  74. E->getInstanceReceiver() &&
  75. E->getSelector() == zoneSel &&
  76. Pass.TA.hasDiagnostic(diag::err_unavailable,
  77. diag::err_unavailable_message,
  78. E->getSelectorLoc(0))) {
  79. // Calling -zone is meaningless in ARC, change it to nil.
  80. Transaction Trans(Pass.TA);
  81. Pass.TA.clearDiagnostic(diag::err_unavailable,
  82. diag::err_unavailable_message,
  83. E->getSelectorLoc(0));
  84. Pass.TA.replace(E->getSourceRange(), getNilString(Pass));
  85. }
  86. return true;
  87. }
  88. };
  89. } // anonymous namespace
  90. void trans::checkAPIUses(MigrationPass &pass) {
  91. APIChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
  92. }