summaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-09-27 21:57:14 +0000
committerAnna Zaks <ganna@apple.com>2012-09-27 21:57:14 +0000
commit377945cc9e4f23cdbb01ade2a664acd5ff95a888 (patch)
tree50899b7fb63d603a97c0caee56ee7ad653c8b466 /lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
parent69e431e23d95013c3401067af112da9d6dbe10e1 (diff)
downloadclang-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.cpp100
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;
}