ObjCPropertyChecker.cpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. //==- ObjCPropertyChecker.cpp - Check ObjC properties ------------*- C++ -*-==//
  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. // This checker finds issues with Objective-C properties.
  10. // Currently finds only one kind of issue:
  11. // - Find synthesized properties with copy attribute of mutable NS collection
  12. // types. Calling -copy on such collections produces an immutable copy,
  13. // which contradicts the type of the property.
  14. //
  15. //===----------------------------------------------------------------------===//
  16. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  17. #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
  18. #include "clang/StaticAnalyzer/Core/Checker.h"
  19. using namespace clang;
  20. using namespace ento;
  21. namespace {
  22. class ObjCPropertyChecker
  23. : public Checker<check::ASTDecl<ObjCPropertyDecl>> {
  24. void checkCopyMutable(const ObjCPropertyDecl *D, BugReporter &BR) const;
  25. public:
  26. void checkASTDecl(const ObjCPropertyDecl *D, AnalysisManager &Mgr,
  27. BugReporter &BR) const;
  28. };
  29. } // end anonymous namespace.
  30. void ObjCPropertyChecker::checkASTDecl(const ObjCPropertyDecl *D,
  31. AnalysisManager &Mgr,
  32. BugReporter &BR) const {
  33. checkCopyMutable(D, BR);
  34. }
  35. void ObjCPropertyChecker::checkCopyMutable(const ObjCPropertyDecl *D,
  36. BugReporter &BR) const {
  37. if (D->isReadOnly() || D->getSetterKind() != ObjCPropertyDecl::Copy)
  38. return;
  39. QualType T = D->getType();
  40. if (!T->isObjCObjectPointerType())
  41. return;
  42. const std::string &PropTypeName(T->getPointeeType().getCanonicalType()
  43. .getUnqualifiedType()
  44. .getAsString());
  45. if (!StringRef(PropTypeName).startswith("NSMutable"))
  46. return;
  47. const ObjCImplDecl *ImplD = nullptr;
  48. if (const ObjCInterfaceDecl *IntD =
  49. dyn_cast<ObjCInterfaceDecl>(D->getDeclContext())) {
  50. ImplD = IntD->getImplementation();
  51. } else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(D->getDeclContext())) {
  52. ImplD = CatD->getClassInterface()->getImplementation();
  53. }
  54. if (!ImplD || ImplD->HasUserDeclaredSetterMethod(D))
  55. return;
  56. SmallString<128> Str;
  57. llvm::raw_svector_ostream OS(Str);
  58. OS << "Property of mutable type '" << PropTypeName
  59. << "' has 'copy' attribute; an immutable object will be stored instead";
  60. BR.EmitBasicReport(
  61. D, this, "Objective-C property misuse", "Logic error", OS.str(),
  62. PathDiagnosticLocation::createBegin(D, BR.getSourceManager()),
  63. D->getSourceRange());
  64. }
  65. void ento::registerObjCPropertyChecker(CheckerManager &Mgr) {
  66. Mgr.registerChecker<ObjCPropertyChecker>();
  67. }
  68. bool ento::shouldRegisterObjCPropertyChecker(const CheckerManager &mgr) {
  69. return true;
  70. }