diff options
author | Anna Zaks <ganna@apple.com> | 2012-09-27 21:57:14 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2012-09-27 21:57:14 +0000 |
commit | 377945cc9e4f23cdbb01ade2a664acd5ff95a888 (patch) | |
tree | 50899b7fb63d603a97c0caee56ee7ad653c8b466 /lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp | |
parent | 69e431e23d95013c3401067af112da9d6dbe10e1 (diff) | |
download | clang-377945cc9e4f23cdbb01ade2a664acd5ff95a888.tar.gz |
[analyzer] IvarInvalidation: track synthesized ivars and allow escape
through property getters.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@164802 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp | 100 |
1 files changed, 69 insertions, 31 deletions
diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp index 0bf8073de9..836860e7c8 100644 --- a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp @@ -41,6 +41,8 @@ class IvarInvalidationChecker : const ObjCIvarDecl*> MethToIvarMapTy; typedef llvm::DenseMap<const ObjCPropertyDecl*, const ObjCIvarDecl*> PropToIvarMapTy; + typedef llvm::DenseMap<const ObjCIvarDecl*, + const ObjCPropertyDecl*> IvarToPropMapTy; /// Statement visitor, which walks the method body and flags the ivars /// referenced in it (either directly or via property). @@ -49,18 +51,19 @@ class IvarInvalidationChecker : /// The set of Ivars which need to be invalidated. IvarSet &IVars; - /// Property setter to ivar mapping. - MethToIvarMapTy &PropertySetterToIvarMap; + /// Property setter/getter to ivar mapping. + MethToIvarMapTy &PropertyAccessorToIvarMap; // Property to ivar mapping. PropToIvarMapTy &PropertyToIvarMap; public: MethodCrawler(const ObjCInterfaceDecl *InID, - IvarSet &InIVars, MethToIvarMapTy &InPropertySetterToIvarMap, + IvarSet &InIVars, + MethToIvarMapTy &InPropertyAccessorToIvarMap, PropToIvarMapTy &InPropertyToIvarMap) : IVars(InIVars), - PropertySetterToIvarMap(InPropertySetterToIvarMap), + PropertyAccessorToIvarMap(InPropertyAccessorToIvarMap), PropertyToIvarMap(InPropertyToIvarMap) {} void VisitStmt(const Stmt *S) { VisitChildren(S); } @@ -80,7 +83,11 @@ class IvarInvalidationChecker : /// Check if the any of the methods inside the interface are annotated with /// the invalidation annotation. - bool containsInvalidationMethod(const ObjCContainerDecl *D) const; + static bool containsInvalidationMethod(const ObjCContainerDecl *D); + + /// Check if ivar should be tracked and add to TrackedIvars if positive. + /// Returns true if ivar should be tracked. + static bool trackIvar(const ObjCIvarDecl *Iv, IvarSet &TrackedIvars); /// Given the property declaration, and the list of tracked ivars, finds /// the ivar backing the property when possible. Returns '0' when no such @@ -88,7 +95,7 @@ class IvarInvalidationChecker : static const ObjCIvarDecl *findPropertyBackingIvar( const ObjCPropertyDecl *Prop, const ObjCInterfaceDecl *InterfaceD, - IvarSet TrackedIvars); + IvarSet &TrackedIvars); public: void checkASTDecl(const ObjCMethodDecl *D, AnalysisManager& Mgr, @@ -109,7 +116,7 @@ bool isInvalidationMethod(const ObjCMethodDecl *M) { } bool IvarInvalidationChecker::containsInvalidationMethod ( - const ObjCContainerDecl *D) const { + const ObjCContainerDecl *D) { // TODO: Cache the results. @@ -152,16 +159,36 @@ bool IvarInvalidationChecker::containsInvalidationMethod ( llvm_unreachable("One of the casts above should have succeeded."); } +bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv, + IvarSet &TrackedIvars) { + QualType IvQTy = Iv->getType(); + const ObjCObjectPointerType *IvTy = IvQTy->getAs<ObjCObjectPointerType>(); + if (!IvTy) + return false; + const ObjCInterfaceDecl *IvInterf = IvTy->getInterfaceDecl(); + if (containsInvalidationMethod(IvInterf)) { + TrackedIvars[cast<ObjCIvarDecl>(Iv->getCanonicalDecl())] = false; + return true; + } + return false; +} + const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar( const ObjCPropertyDecl *Prop, const ObjCInterfaceDecl *InterfaceD, - IvarSet TrackedIvars) { + IvarSet &TrackedIvars) { const ObjCIvarDecl *IvarD = 0; // Lookup for the synthesized case. IvarD = Prop->getPropertyIvarDecl(); - if (IvarD) - return IvarD; + if (IvarD) { + if (TrackedIvars.count(IvarD)) { + return IvarD; + } + // If the ivar is synthesized we still want to track it. + if (trackIvar(IvarD, TrackedIvars)) + return IvarD; + } // Lookup IVars named "_PropName"or "PropName" among the tracked Ivars. StringRef PropName = Prop->getIdentifier()->getName(); @@ -202,19 +229,14 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCMethodDecl *D, II = InterfaceD->ivar_begin(), IE = InterfaceD->ivar_end(); II != IE; ++II) { const ObjCIvarDecl *Iv = *II; - QualType IvQTy = Iv->getType(); - const ObjCObjectPointerType *IvTy = IvQTy->getAs<ObjCObjectPointerType>(); - if (!IvTy) - continue; - const ObjCInterfaceDecl *IvInterf = IvTy->getInterfaceDecl(); - if (containsInvalidationMethod(IvInterf)) - Ivars[cast<ObjCIvarDecl>(Iv->getCanonicalDecl())] = false; + trackIvar(Iv, Ivars); } - // Construct Property/Property Setter to Ivar maps to assist checking if an + // Construct Property/Property Accessor to Ivar maps to assist checking if an // ivar which is backing a property has been reset. - MethToIvarMapTy PropSetterToIvarMap; + MethToIvarMapTy PropAccessorToIvarMap; PropToIvarMapTy PropertyToIvarMap; + IvarToPropMapTy IvarToPopertyMap; for (ObjCInterfaceDecl::prop_iterator I = InterfaceD->prop_begin(), E = InterfaceD->prop_end(); I != E; ++I) { @@ -224,24 +246,31 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCMethodDecl *D, if (!ID) { continue; } - // Find the setter. - const ObjCMethodDecl *SetterD = PD->getSetterMethodDecl(); - // If we don't know the setter, do not track this ivar. - if (!SetterD) - continue; // Store the mappings. PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl()); - SetterD = cast<ObjCMethodDecl>(SetterD->getCanonicalDecl()); PropertyToIvarMap[PD] = ID; - PropSetterToIvarMap[SetterD] = ID; + IvarToPopertyMap[ID] = PD; + + // Find the setter and the getter. + const ObjCMethodDecl *SetterD = PD->getSetterMethodDecl(); + if (SetterD) { + SetterD = cast<ObjCMethodDecl>(SetterD->getCanonicalDecl()); + PropAccessorToIvarMap[SetterD] = ID; + } + + const ObjCMethodDecl *GetterD = PD->getGetterMethodDecl(); + if (GetterD) { + GetterD = cast<ObjCMethodDecl>(GetterD->getCanonicalDecl()); + PropAccessorToIvarMap[GetterD] = ID; + } } // Check which ivars have been accessed by the method. // We assume that if ivar was at least accessed, it was not forgotten. MethodCrawler(InterfaceD, Ivars, - PropSetterToIvarMap, PropertyToIvarMap).VisitStmt(D->getBody()); + PropAccessorToIvarMap, PropertyToIvarMap).VisitStmt(D->getBody()); // Warn on the ivars that were not accessed by the method. for (IvarSet::const_iterator I = Ivars.begin(), E = Ivars.end(); I != E; ++I){ @@ -254,8 +283,17 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCMethodDecl *D, SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); - os << "Instance variable "<< IvarDecl->getName() - << " needs to be invalidated"; + + // Construct the warning message. + if (IvarDecl->getSynthesize()) { + const ObjCPropertyDecl *PD = IvarToPopertyMap[IvarDecl]; + assert(PD && + "Do we synthesize ivars for something other than properties?"); + os << "Property "<< PD->getName() << " needs to be invalidated"; + } else { + os << "Instance variable "<< IvarDecl->getName() + << " needs to be invalidated"; + } BR.EmitBasicReport(D, "Incomplete invalidation", @@ -282,7 +320,7 @@ void IvarInvalidationChecker::MethodCrawler::VisitObjCMessageExpr( const ObjCMethodDecl *MD = ME->getMethodDecl(); if (MD) { MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl()); - IVars[PropertySetterToIvarMap[MD]] = true; + IVars[PropertyAccessorToIvarMap[MD]] = true; } VisitStmt(ME); } @@ -305,7 +343,7 @@ void IvarInvalidationChecker::MethodCrawler::VisitObjCPropertyRefExpr( const ObjCMethodDecl *MD = PA->getImplicitPropertySetter(); if (MD) { MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl()); - IVars[PropertySetterToIvarMap[MD]] = true; + IVars[PropertyAccessorToIvarMap[MD]] = true; VisitStmt(PA); return; } |