Index: include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- include/clang/StaticAnalyzer/Checkers/Checkers.td +++ include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -478,18 +478,19 @@ let ParentPackage = OSX in { +def ObjCPropertyChecker : Checker<"ObjCProperty">, + HelpText<"Find various issues with Objective-C properties">, + DescFile<"ObjCPropertyChecker.cpp">; + def NumberObjectConversionChecker : Checker<"NumberObjectConversion">, - InPackage, HelpText<"Check for erroneous conversions of objects representing numbers into numbers">, DescFile<"NumberObjectConversionChecker.cpp">; def MacOSXAPIChecker : Checker<"API">, - InPackage, HelpText<"Check for proper uses of various Apple APIs">, DescFile<"MacOSXAPIChecker.cpp">; def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">, - InPackage, HelpText<"Check for proper uses of Secure Keychain APIs">, DescFile<"MacOSKeychainAPIChecker.cpp">; Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt =================================================================== --- lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -59,6 +59,7 @@ ObjCContainersASTChecker.cpp ObjCContainersChecker.cpp ObjCMissingSuperCallChecker.cpp + ObjCPropertyChecker.cpp ObjCSelfInitChecker.cpp ObjCSuperDeallocChecker.cpp ObjCUnusedIVarsChecker.cpp Index: lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp =================================================================== --- /dev/null +++ lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp @@ -0,0 +1,79 @@ +//==- 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 autosynthesized 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> { +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 { + if (D->getSetterKind() != ObjCPropertyDecl::Copy) + return; + + QualType T = D->getType(); + if (!T->isObjCObjectPointerType()) + return; + + StringRef PropTypeName(T->getPointeeType() + .getCanonicalType() + .getUnqualifiedType() + .getAsString()); + if (!PropTypeName.startswith("NSMutable")) + return; + + const ObjCInterfaceDecl *IntD = + dyn_cast(D->getDeclContext()); + if (!IntD) + return; + + const ObjCImplDecl *IntImplD = IntD->getImplementation(); + if (!IntImplD) + return; + + ObjCPropertyImplDecl *ImplD = IntImplD->FindPropertyImplDecl( + D->getIdentifier(), D->isClassProperty() + ? ObjCPropertyQueryKind::OBJC_PR_query_class + : ObjCPropertyQueryKind::OBJC_PR_query_instance); + if (!ImplD || + ImplD->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + return; + + BR.EmitBasicReport( + D, this, "Objective-C property misuse", "Logic error", + "Property of mutable type has copy attribute; " + "an immutable object will be returned instead", + PathDiagnosticLocation::createBegin(D, BR.getSourceManager()), + D->getSourceRange()); +} + +void ento::registerObjCPropertyChecker(CheckerManager &Mgr) { + Mgr.registerChecker(); +} Index: test/Analysis/ObjCPropertiesSyntaxChecks.m =================================================================== --- /dev/null +++ test/Analysis/ObjCPropertiesSyntaxChecks.m @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -w -fblocks -analyze -analyzer-checker=osx.ObjCProperty %s -verify + +#include "Inputs/system-header-simulator-objc.h" + +@interface I : NSObject { + NSMutableString *_mutableExplicitStr; + NSMutableString *_trulyMutableStr; + NSMutableString *_trulyMutableExplicitStr; +} +@property(copy) NSString *str; // no-warning +@property(copy) NSMutableString *mutableStr; // expected-warning{{Property of mutable type has copy attribute; an immutable object will be returned instead}} +@property(copy) NSMutableString *mutableExplicitStr; // expected-warning{{Property of mutable type has copy attribute; an immutable object will be returned instead}} +@property(copy) NSMutableString *trulyMutableStr; // no-warning +@property(copy) NSMutableString *trulyMutableExplicitStr; // no-warning +@end + +@implementation I +@synthesize mutableExplicitStr = _mutableExplicitStr; +- (NSMutableString *)trulyMutableStr { + return _trulyMutableStr; +} +- (void)setTrulyMutableStr: (NSMutableString *) S { + _trulyMutableStr = [S mutableCopy]; +} +@dynamic trulyMutableExplicitStr; +- (NSMutableString *)trulyMutableExplicitStr { + return _trulyMutableExplicitStr; +} +- (void)setTrulyMutableExplicitStr: (NSMutableString *) S { + _trulyMutableExplicitStr = [S mutableCopy]; +} +@end + +void Foo(I *i) { + i.trulyMutableStr = @"hello world"; +}