summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2015-03-20 21:12:27 +0000
committerJordan Rose <jordan_rose@apple.com>2015-03-20 21:12:27 +0000
commit03ad616143062560de3aa1bfe41cae60d25eb548 (patch)
tree60f31ee1ffca208286904eff82144cfba4c83966 /clang/lib/StaticAnalyzer
parent063667cea267777af7855b5e9aee975c217c4997 (diff)
downloadbcm5719-llvm-03ad616143062560de3aa1bfe41cae60d25eb548.tar.gz
bcm5719-llvm-03ad616143062560de3aa1bfe41cae60d25eb548.zip
[analyzer] RetainCountChecker: Don't assume +0 for ivars backing readonly properties.
Similarly, don't assume +0 if the property's setter is manually implemented. In both cases, if the property's ownership is explicitly written, then we /do/ assume the ivar has the same ownership. rdar://problem/20218183 llvm-svn: 232849
Diffstat (limited to 'clang/lib/StaticAnalyzer')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp64
1 files changed, 52 insertions, 12 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 1991d2bad1b..6b8596efb1b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -2844,6 +2844,40 @@ static const ObjCPropertyDecl *findPropForIvar(const ObjCIvarDecl *Ivar) {
return nullptr;
}
+namespace {
+ enum Retaining_t {
+ NonRetaining,
+ Retaining
+ };
+}
+
+static Optional<Retaining_t> getRetainSemantics(const ObjCPropertyDecl *Prop) {
+ assert(Prop->getPropertyIvarDecl() &&
+ "should only be used for properties with synthesized implementations");
+
+ if (!Prop->hasWrittenStorageAttribute()) {
+ // Don't assume anything about the retain semantics of readonly properties.
+ if (Prop->isReadOnly())
+ return None;
+
+ // Don't assume anything about readwrite properties with manually-supplied
+ // setters.
+ const ObjCMethodDecl *Setter = Prop->getSetterMethodDecl();
+ bool HasManualSetter = std::any_of(Setter->redecls_begin(),
+ Setter->redecls_end(),
+ [](const Decl *SetterRedecl) -> bool {
+ return cast<ObjCMethodDecl>(SetterRedecl)->hasBody();
+ });
+ if (HasManualSetter)
+ return None;
+
+ // If the setter /is/ synthesized, we're already relying on the retain
+ // semantics of the property. Continue as normal.
+ }
+
+ return Prop->isRetaining() ? Retaining : NonRetaining;
+}
+
void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
CheckerContext &C) const {
Optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>();
@@ -2884,8 +2918,9 @@ void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
// there's no outstanding retain count for the value.
if (Kind == RetEffect::ObjC)
if (const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl()))
- if (!Prop->isRetaining())
- return;
+ if (auto retainSemantics = getRetainSemantics(Prop))
+ if (retainSemantics.getValue() == NonRetaining)
+ return;
// Note that this value has been loaded from an ivar.
C.addTransition(setRefBinding(State, Sym, RV->withIvarAccess()));
@@ -2900,18 +2935,23 @@ void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
return;
}
- // Try to find the property associated with this ivar.
- if (Kind != RetEffect::ObjC) {
- State = setRefBinding(State, Sym, PlusZero.withIvarAccess());
- } else {
- const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl());
-
- if (Prop && !Prop->isRetaining())
- State = setRefBinding(State, Sym, PlusZero);
- else
- State = setRefBinding(State, Sym, PlusZero.withIvarAccess());
+ bool didUpdateState = false;
+ if (Kind == RetEffect::ObjC) {
+ // Check if the ivar is known to be unretained. If so, we know that
+ // there's no outstanding retain count for the value.
+ if (const ObjCPropertyDecl *Prop = findPropForIvar(IRE->getDecl())) {
+ if (auto retainSemantics = getRetainSemantics(Prop)) {
+ if (retainSemantics.getValue() == NonRetaining) {
+ State = setRefBinding(State, Sym, PlusZero);
+ didUpdateState = true;
+ }
+ }
+ }
}
+ if (!didUpdateState)
+ State = setRefBinding(State, Sym, PlusZero.withIvarAccess());
+
C.addTransition(State);
}
OpenPOWER on IntegriCloud