NSAutoreleasePoolChecker.cpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. //=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==//
  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. // This file defines a NSAutoreleasePoolChecker, a small checker that warns
  11. // about subpar uses of NSAutoreleasePool. Note that while the check itself
  12. // (in its current form) could be written as a flow-insensitive check, in
  13. // can be potentially enhanced in the future with flow-sensitive information.
  14. // It is also a good example of the CheckerVisitor interface.
  15. //
  16. //===----------------------------------------------------------------------===//
  17. #include "ClangSACheckers.h"
  18. #include "clang/AST/Decl.h"
  19. #include "clang/AST/DeclObjC.h"
  20. #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
  21. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  22. #include "clang/StaticAnalyzer/Core/Checker.h"
  23. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  24. #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
  25. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  26. #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
  27. using namespace clang;
  28. using namespace ento;
  29. namespace {
  30. class NSAutoreleasePoolChecker
  31. : public Checker<check::PreObjCMessage> {
  32. mutable std::unique_ptr<BugType> BT;
  33. mutable Selector releaseS;
  34. public:
  35. void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
  36. };
  37. } // end anonymous namespace
  38. void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
  39. CheckerContext &C) const {
  40. if (!msg.isInstanceMessage())
  41. return;
  42. const ObjCInterfaceDecl *OD = msg.getReceiverInterface();
  43. if (!OD)
  44. return;
  45. if (!OD->getIdentifier()->isStr("NSAutoreleasePool"))
  46. return;
  47. if (releaseS.isNull())
  48. releaseS = GetNullarySelector("release", C.getASTContext());
  49. // Sending 'release' message?
  50. if (msg.getSelector() != releaseS)
  51. return;
  52. if (!BT)
  53. BT.reset(new BugType(this, "Use -drain instead of -release",
  54. "API Upgrade (Apple)"));
  55. ExplodedNode *N = C.addTransition();
  56. if (!N) {
  57. assert(0);
  58. return;
  59. }
  60. auto Report = llvm::make_unique<BugReport>(
  61. *BT, "Use -drain instead of -release when using NSAutoreleasePool and "
  62. "garbage collection", N);
  63. Report->addRange(msg.getSourceRange());
  64. C.emitReport(std::move(Report));
  65. }
  66. void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) {
  67. if (mgr.getLangOpts().getGC() != LangOptions::NonGC)
  68. mgr.registerChecker<NSAutoreleasePoolChecker>();
  69. }