diff options
author | Devin Coughlin <dcoughlin@apple.com> | 2016-02-18 19:13:30 +0000 |
---|---|---|
committer | Devin Coughlin <dcoughlin@apple.com> | 2016-02-18 19:13:30 +0000 |
commit | 069a1073ddbd9fd605a98189edd682e3cc083fad (patch) | |
tree | e125797f3335ae20bfad896280aae5c5a2cf1a89 /clang/lib/StaticAnalyzer/Core/CallEvent.cpp | |
parent | d70a6e71a9f04d12b155ca561f8ef92b3b227a40 (diff) | |
download | bcm5719-llvm-069a1073ddbd9fd605a98189edd682e3cc083fad.tar.gz bcm5719-llvm-069a1073ddbd9fd605a98189edd682e3cc083fad.zip |
[analyzer] Improve modeling of ObjC synthesized property setters.
When modeling a call to a setter for a property that is synthesized to be
backed by an instance variable, don't invalidate the entire instance
but rather only the storage for the updated instance variable itself.
This still doesn't model the effect of the setter completely. It doesn't
bind the set value to the ivar storage location because doing so would cause
the set value to escape, removing valuable diagnostics about potential
leaks of the value from the retain count checker.
llvm-svn: 261243
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/CallEvent.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 63 |
1 files changed, 54 insertions, 9 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 59b90b5ce98..2c7b5302dd6 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -678,9 +678,26 @@ ArrayRef<ParmVarDecl*> ObjCMethodCall::parameters() const { return D->parameters(); } -void -ObjCMethodCall::getExtraInvalidatedValues(ValueList &Values, - RegionAndSymbolInvalidationTraits *ETraits) const { +void ObjCMethodCall::getExtraInvalidatedValues( + ValueList &Values, RegionAndSymbolInvalidationTraits *ETraits) const { + + // If the method call is a setter for property known to be backed by + // an instance variable, don't invalidate the entire receiver, just + // the storage for that instance variable. + if (const ObjCPropertyDecl *PropDecl = getAccessedProperty()) { + if (const ObjCIvarDecl *PropIvar = PropDecl->getPropertyIvarDecl()) { + SVal IvarLVal = getState()->getLValue(PropIvar, getReceiverSVal()); + const MemRegion *IvarRegion = IvarLVal.getAsRegion(); + ETraits->setTrait( + IvarRegion, + RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion); + ETraits->setTrait(IvarRegion, + RegionAndSymbolInvalidationTraits::TK_SuppressEscape); + Values.push_back(IvarLVal); + return; + } + } + Values.push_back(getReceiverSVal()); } @@ -740,6 +757,18 @@ const PseudoObjectExpr *ObjCMethodCall::getContainingPseudoObjectExpr() const { return ObjCMessageDataTy::getFromOpaqueValue(Data).getPointer(); } +static const Expr * +getSyntacticFromForPseudoObjectExpr(const PseudoObjectExpr *POE) { + const Expr *Syntactic = POE->getSyntacticForm(); + + // This handles the funny case of assigning to the result of a getter. + // This can happen if the getter returns a non-const reference. + if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(Syntactic)) + Syntactic = BO->getLHS(); + + return Syntactic; +} + ObjCMessageKind ObjCMethodCall::getMessageKind() const { if (!Data) { @@ -749,12 +778,7 @@ ObjCMessageKind ObjCMethodCall::getMessageKind() const { // Check if parent is a PseudoObjectExpr. if (const PseudoObjectExpr *POE = dyn_cast_or_null<PseudoObjectExpr>(S)) { - const Expr *Syntactic = POE->getSyntacticForm(); - - // This handles the funny case of assigning to the result of a getter. - // This can happen if the getter returns a non-const reference. - if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(Syntactic)) - Syntactic = BO->getLHS(); + const Expr *Syntactic = getSyntacticFromForPseudoObjectExpr(POE); ObjCMessageKind K; switch (Syntactic->getStmtClass()) { @@ -790,6 +814,27 @@ ObjCMessageKind ObjCMethodCall::getMessageKind() const { return static_cast<ObjCMessageKind>(Info.getInt()); } +const ObjCPropertyDecl *ObjCMethodCall::getAccessedProperty() const { + // Look for properties accessed with property syntax (foo.bar = ...) + if ( getMessageKind() == OCM_PropertyAccess) { + const PseudoObjectExpr *POE = getContainingPseudoObjectExpr(); + assert(POE && "Property access without PseudoObjectExpr?"); + + const Expr *Syntactic = getSyntacticFromForPseudoObjectExpr(POE); + auto *RefExpr = cast<ObjCPropertyRefExpr>(Syntactic); + + if (RefExpr->isExplicitProperty()) + return RefExpr->getExplicitProperty(); + } + + // Look for properties accessed with method syntax ([foo setBar:...]). + const ObjCMethodDecl *MD = getDecl(); + if (!MD || !MD->isPropertyAccessor()) + return nullptr; + + // Note: This is potentially quite slow. + return MD->findPropertyDecl(); +} bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl, Selector Sel) const { |