diff options
author | Devin Coughlin <dcoughlin@apple.com> | 2016-10-12 23:57:05 +0000 |
---|---|---|
committer | Devin Coughlin <dcoughlin@apple.com> | 2016-10-12 23:57:05 +0000 |
commit | 0bd37a1a367dffdf4513a3068c2f51290366e3f3 (patch) | |
tree | 810a173ae3dcc60f2be38e238bc062c0e04401f8 /clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp | |
parent | 1255c1965655d9200559ba33ddd7bd2b11847dab (diff) | |
download | bcm5719-llvm-0bd37a1a367dffdf4513a3068c2f51290366e3f3.tar.gz bcm5719-llvm-0bd37a1a367dffdf4513a3068c2f51290366e3f3.zip |
[analyzer] DeallocChecker: Don't warn about directly-set IBOutlet ivars on macOS
On macOS (but not iOS), if an ObjC property has no setter, the nib-loading code
for an IBOutlet is documented as directly setting the backing ivar without
retaining the value -- even if the property is 'retain'.
This resulted in false positives from the DeallocChecker for code that did not
release such ivars in -dealloc.
To avoid these false positives, treat IBOutlet ivars that back a property
without a setter as having an unknown release requirement in macOS.
rdar://problem/28507353
llvm-svn: 284084
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index 4fece1c7fff..1c8ca0f4295 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp @@ -34,6 +34,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetInfo.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" @@ -180,6 +181,7 @@ private: bool classHasSeparateTeardown(const ObjCInterfaceDecl *ID) const; bool isReleasedByCIFilterDealloc(const ObjCPropertyImplDecl *PropImpl) const; + bool isNibLoadedIvarWithoutRetain(const ObjCPropertyImplDecl *PropImpl) const; }; } // End anonymous namespace. @@ -935,6 +937,9 @@ ReleaseRequirement ObjCDeallocChecker::getDeallocReleaseRequirement( if (isReleasedByCIFilterDealloc(PropImpl)) return ReleaseRequirement::MustNotReleaseDirectly; + if (isNibLoadedIvarWithoutRetain(PropImpl)) + return ReleaseRequirement::Unknown; + return ReleaseRequirement::MustRelease; case ObjCPropertyDecl::Weak: @@ -1091,6 +1096,32 @@ bool ObjCDeallocChecker::isReleasedByCIFilterDealloc( return false; } +/// Returns whether the ivar backing the property is an IBOutlet that +/// has its value set by nib loading code without retaining the value. +/// +/// On macOS, if there is no setter, the nib-loading code sets the ivar +/// directly, without retaining the value, +/// +/// On iOS and its derivatives, the nib-loading code will call +/// -setValue:forKey:, which retains the value before directly setting the ivar. +bool ObjCDeallocChecker::isNibLoadedIvarWithoutRetain( + const ObjCPropertyImplDecl *PropImpl) const { + const ObjCIvarDecl *IvarDecl = PropImpl->getPropertyIvarDecl(); + if (!IvarDecl->hasAttr<IBOutletAttr>()) + return false; + + const llvm::Triple &Target = + IvarDecl->getASTContext().getTargetInfo().getTriple(); + + if (!Target.isMacOSX()) + return false; + + if (PropImpl->getPropertyDecl()->getSetterMethodDecl()) + return false; + + return true; +} + void ento::registerObjCDeallocChecker(CheckerManager &Mgr) { const LangOptions &LangOpts = Mgr.getLangOpts(); // These checker only makes sense under MRR. |