//==- ObjCPropertyChecker.cpp - Check ObjC properties ------------*- C++ -*-==// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This checker finds issues with Objective-C properties. // Currently finds only one kind of issue: // - Find synthesized properties with copy attribute of mutable NS collection // types. Calling -copy on such collections produces an immutable copy, // which contradicts the type of the property. // //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/Checker.h" using namespace clang; using namespace ento; namespace { class ObjCPropertyChecker : public Checker> { void checkCopyMutable(const ObjCPropertyDecl *D, BugReporter &BR) const; public: void checkASTDecl(const ObjCPropertyDecl *D, AnalysisManager &Mgr, BugReporter &BR) const; }; } // end anonymous namespace. void ObjCPropertyChecker::checkASTDecl(const ObjCPropertyDecl *D, AnalysisManager &Mgr, BugReporter &BR) const { checkCopyMutable(D, BR); } void ObjCPropertyChecker::checkCopyMutable(const ObjCPropertyDecl *D, BugReporter &BR) const { if (D->isReadOnly() || D->getSetterKind() != ObjCPropertyDecl::Copy) return; QualType T = D->getType(); if (!T->isObjCObjectPointerType()) return; const std::string &PropTypeName(T->getPointeeType().getCanonicalType() .getUnqualifiedType() .getAsString()); if (!StringRef(PropTypeName).startswith("NSMutable")) return; const ObjCImplDecl *ImplD = nullptr; if (const ObjCInterfaceDecl *IntD = dyn_cast(D->getDeclContext())) { ImplD = IntD->getImplementation(); } else if (auto *CatD = dyn_cast(D->getDeclContext())) { ImplD = CatD->getClassInterface()->getImplementation(); } if (!ImplD || ImplD->HasUserDeclaredSetterMethod(D)) return; SmallString<128> Str; llvm::raw_svector_ostream OS(Str); OS << "Property of mutable type '" << PropTypeName << "' has 'copy' attribute; an immutable object will be stored instead"; BR.EmitBasicReport( D, this, "Objective-C property misuse", "Logic error", OS.str(), PathDiagnosticLocation::createBegin(D, BR.getSourceManager()), D->getSourceRange()); } void ento::registerObjCPropertyChecker(CheckerManager &Mgr) { Mgr.registerChecker(); }