diff options
author | Artem Dergachev <artem.dergachev@gmail.com> | 2016-12-13 17:19:18 +0000 |
---|---|---|
committer | Artem Dergachev <artem.dergachev@gmail.com> | 2016-12-13 17:19:18 +0000 |
commit | e69d2e47e5142c3a60eab90f39f62e3e44c67ad7 (patch) | |
tree | 8e97f726e6faa8c5d05e821cfde045925e4d993e /clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp | |
parent | 26dab1283f97d67e20c07c5ed9797a0c35e2bb8e (diff) | |
download | bcm5719-llvm-e69d2e47e5142c3a60eab90f39f62e3e44c67ad7.tar.gz bcm5719-llvm-e69d2e47e5142c3a60eab90f39f62e3e44c67ad7.zip |
[analyzer] Detect ObjC properties that are both (copy) and Mutable.
When an Objective-C property has a (copy) attribute, the default setter
for this property performs a -copy on the object assigned.
Calling -copy on a mutable NS object such as NSMutableString etc.
produces an immutable object, NSString in our example.
Hence the getter becomes type-incorrect.
rdar://problem/21022397
Differential Revision: https://reviews.llvm.org/D27535
llvm-svn: 289554
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp new file mode 100644 index 00000000000..b9857e51f3e --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp @@ -0,0 +1,82 @@ +//==- 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<check::ASTDecl<ObjCPropertyDecl>> { + 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<ObjCInterfaceDecl>(D->getDeclContext())) { + ImplD = IntD->getImplementation(); + } else { + const ObjCCategoryDecl *CatD = cast<ObjCCategoryDecl>(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<ObjCPropertyChecker>(); +} |