NoQ created this revision.
NoQ added reviewers: zaks.anna, dcoughlin.
NoQ added a subscriber: cfe-commits.
Herald added a subscriber: mgorny.

When an ObjC property is declared as `(copy)`, and the type of the property is 
mutable (eg. `NSMutableSomething`), the autosynthesized code for the setter, 
which as usual copies the object by calling `-copy`, produces an immutable 
object (eg. `NSSomething`; cf. `-mutableCopy` which would actually produce 
`NSMutableSomething`), which would lead to unexpected results.

The checker is named to be a bit more generic, even though i have no particular 
plans for other checks at the moment.

Testing in progress.


https://reviews.llvm.org/D27535

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp
  test/Analysis/ObjCPropertiesSyntaxChecks.m

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";
+}
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<check::ASTDecl<ObjCPropertyDecl>> {
+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<ObjCInterfaceDecl>(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<ObjCPropertyChecker>();
+}
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: 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<OSX>,
   HelpText<"Check for erroneous conversions of objects representing numbers into numbers">,
   DescFile<"NumberObjectConversionChecker.cpp">;
 
 def MacOSXAPIChecker : Checker<"API">,
-  InPackage<OSX>,
   HelpText<"Check for proper uses of various Apple APIs">,
   DescFile<"MacOSXAPIChecker.cpp">;
 
 def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">,
-  InPackage<OSX>,
   HelpText<"Check for proper uses of Secure Keychain APIs">,
   DescFile<"MacOSKeychainAPIChecker.cpp">;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to