[cfe-commits] r164868 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp test/Analysis/objc_invalidation.m
Anna Zaks
ganna at apple.com
Mon Oct 1 11:03:29 PDT 2012
On Sep 28, 2012, at 6:51 PM, Jordan Rose <jordan_rose at apple.com> wrote:
> Comments (fewer this time):
>
> On Sep 28, 2012, at 17:20 , Anna Zaks <ganna at apple.com> wrote:
>
>>
>> /// Statement visitor, which walks the method body and flags the ivars
>> /// referenced in it (either directly or via property).
>> class MethodCrawler : public ConstStmtVisitor<MethodCrawler> {
>> + const ObjCMethodDecl *EnclosingMethod;
>>
>> /// The set of Ivars which need to be invalidated.
>> IvarSet &IVars;
>>
>> - /// Property setter/getter to ivar mapping.
>> - MethToIvarMapTy &PropertyAccessorToIvarMap;
>> + /// Flag is set as the result of a message send to another
>> + /// invalidation method.
>> + bool &CalledAnotherInvalidationMethod;
>> +
>> + /// Property setter to ivar mapping.
>> + const MethToIvarMapTy &PropertySetterToIvarMap;
>> +
>> + /// Property getter to ivar mapping.
>> + const MethToIvarMapTy &PropertyGetterToIvarMap;
>> +
>> + /// Property to ivar mapping.
>> + const PropToIvarMapTy &PropertyToIvarMap;
>> +
>> + /// The invalidation method being currently processed.
>> + const ObjCMethodDecl *InvalidationMethod;
>> +
>> + /// Peel off parents, casts, OpaqueValueExpr, and PseudoObjectExpr.
>> + const Expr *peel(const Expr *E) const;
>
> Typo: "parens".
>
>
>
>> +const Expr *IvarInvalidationChecker::MethodCrawler::peel(const Expr *E) const {
>> + E = E->IgnoreParenCasts();
>> + if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
>> + E = POE->getSyntacticForm()->IgnoreParenCasts();
>> + if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
>> + E = OVE->getSourceExpr()->IgnoreParenCasts();
>> + return E;
>> +}
>
>
>
>
>> +
>> +bool IvarInvalidationChecker::MethodCrawler::isZero(const Expr *E) const {
>> + E = peel(E);
>> + if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E))
>> + return IL->getValue() == 0;
>> +
>> + if (const CastExpr *ICE = dyn_cast<CastExpr>(E))
>> + return ICE->getCastKind() == CK_NullToPointer;
>> +
>> + return false;
>> +}
>
> The more robust form of this is Expr::isNullPointerConstant.
>
isNullPointerConstant seems to do type checking, determining which type of null pointer we have. Why is it more robust to use here (all the typechecking has been done already)?
>
>> +void IvarInvalidationChecker::MethodCrawler::check(const Expr *E) {
>> + E = peel(E);
>> +
>> + if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
>> + E = OVE->getSourceExpr();
>
> This should have been checked by peel already?
leftover from internal refactor, thanks
>
>
>> + if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
>> + checkObjCIvarRefExpr(IvarRef);
>> + return;
>> + }
>> +
>> + if (const ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E)) {
>> + checkObjCPropertyRefExpr(PropRef);
>> + return;
>> + }
>> +
>> + if (const ObjCMessageExpr *MsgExpr = dyn_cast<ObjCMessageExpr>(E)) {
>> + checkObjCMessageExpr(MsgExpr);
>> + return;
>> + }
>> +}
>> +
>> +void IvarInvalidationChecker::MethodCrawler::VisitBinaryOperator(
>> + const BinaryOperator *BO) {
>> + if (!BO->isAssignmentOp())
>> + return;
>
> You could probably be even more aggressive here and look for = specifically, since += and such aren't valid on ObjC objects.
yes, we should check only for '='.
>
>> + // Do we assign zero?
>> + if (!isZero(BO->getRHS()))
>> + return;
>> +
>> + // Check the variable we are assigning to.
>> + check(BO->getLHS());
>> +
>> + VisitStmt(BO);
>> +}
>
> This VisitStmt is after two early returns. It seems like it should be first.
yes. Thanks
>
>
>> +void IvarInvalidationChecker::MethodCrawler::VisitObjCMessageExpr(
>> + const ObjCMessageExpr *ME) {
>> + const ObjCMethodDecl *MD = ME->getMethodDecl();
>> + const Expr *Receiver = ME->getInstanceReceiver();
>> +
>> + // Stop if we are calling '[self invalidate]'.
>> + if (Receiver && isInvalidationMethod(MD))
>> + if (const DeclRefExpr *RD =
>> + dyn_cast<DeclRefExpr>(Receiver->IgnoreParenCasts())) {
>> + if (RD->getDecl() == EnclosingMethod->getSelfDecl()) {
>> + CalledAnotherInvalidationMethod = true;
>> + return;
>> + }
>> + }
>> +
>> + // Check if we call a setter and set the property to 'nil'.
>> + if (MD && (ME->getNumArgs() == 1) && isZero(ME->getArg(0))) {
>> + MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl());
>> + MethToIvarMapTy::const_iterator IvI = PropertySetterToIvarMap.find(MD);
>> + if (IvI != PropertySetterToIvarMap.end()) {
>> + markInvalidated(IvI->second);
>> + return;
>> + }
>> + }
>> +
>> + // Check if we call the 'invalidation' routine on the ivar.
>> + if (Receiver) {
>> + InvalidationMethod = MD;
>> + check(Receiver->IgnoreParenCasts());
>> + InvalidationMethod = 0;
>
> Passing state around like this does not make me happy.
It does not make me happy either.:) It does not make me more happy to pass this as a parameter through a bunch of calls.
> In particular, [[a foo] bar] will not work because the check() method calls back to VisitObjCMessageExpr.
It does not.
> Then again, no one will write an invalidation method like this.
More information about the cfe-commits
mailing list