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