static void Scan(IvarUsageMap& M, const Stmt *S) { if (!S) return; if (const ObjCIvarRefExpr *Ex = dyn_cast<ObjCIvarRefExpr>(S)) { const ObjCIvarDecl *D = Ex->getDecl(); IvarUsageMap::iterator I = M.find(D); if (I != M.end()) I->second = Used; return; } // Blocks can reference an instance variable of a class. if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) { Scan(M, BE->getBody()); return; } if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(S)) for (PseudoObjectExpr::const_semantics_iterator i = POE->semantics_begin(), e = POE->semantics_end(); i != e; ++i) { const Expr *sub = *i; if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub)) sub = OVE->getSourceExpr(); Scan(M, sub); } for (Stmt::const_child_iterator I=S->child_begin(),E=S->child_end(); I!=E;++I) Scan(M, *I); }
void clang::CheckObjCUnusedIvar(ObjCImplementationDecl* D, BugReporter& BR) { ObjCInterfaceDecl* ID = D->getClassInterface(); IvarUsageMap M; ASTContext &Ctx = BR.getContext(); // Iterate over the ivars. for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end(); I!=E; ++I) { ObjCIvarDecl* ID = *I; // Ignore ivars that aren't private. if (ID->getAccessControl() != ObjCIvarDecl::Private) continue; // Skip IB Outlets. if (ID->getAttr<IBOutletAttr>()) continue; M[ID] = Unused; } if (M.empty()) return; // Now scan the methods for accesses. for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(Ctx), E = D->instmeth_end(Ctx); I!=E; ++I) Scan(M, (*I)->getBody(Ctx)); // Scan for @synthesized property methods that act as setters/getters // to an ivar. for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(Ctx), E = D->propimpl_end(Ctx); I!=E; ++I) Scan(M, *I); // Find ivars that are unused. for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) if (I->second == Unused) { std::ostringstream os; os << "Instance variable '" << I->first->getNameAsString() << "' in class '" << ID->getNameAsString() << "' is never used by the methods in its @implementation " "(although it may be used by category methods)."; BR.EmitBasicReport("Unused instance variable", "Optimization", os.str().c_str(), I->first->getLocation()); } }
static void Scan(IvarUsageMap& M, ObjCPropertyImplDecl* D) { if (!D) return; ObjCIvarDecl* ID = D->getPropertyIvarDecl(); if (!ID) return; IvarUsageMap::iterator I = M.find(ID); if (I != M.end()) I->second = Used; }
static void Scan(IvarUsageMap& M, Stmt* S) { if (!S) return; if (ObjCIvarRefExpr* Ex = dyn_cast<ObjCIvarRefExpr>(S)) { ObjCIvarDecl* D = Ex->getDecl(); IvarUsageMap::iterator I = M.find(D); if (I != M.end()) I->second = Used; return; } for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) Scan(M, *I); }
static void Scan(IvarUsageMap& M, const Stmt* S) { if (!S) return; if (const ObjCIvarRefExpr *Ex = dyn_cast<ObjCIvarRefExpr>(S)) { const ObjCIvarDecl *D = Ex->getDecl(); IvarUsageMap::iterator I = M.find(D); if (I != M.end()) I->second = Used; return; } // Blocks can reference an instance variable of a class. if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) { Scan(M, BE->getBody()); return; } for (Stmt::const_child_iterator I=S->child_begin(),E=S->child_end(); I!=E;++I) Scan(M, *I); }
static void checkObjCUnusedIvar(const ObjCImplementationDecl *D, BugReporter &BR) { const ObjCInterfaceDecl *ID = D->getClassInterface(); IvarUsageMap M; // Iterate over the ivars. for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end(); I!=E; ++I) { const ObjCIvarDecl *ID = *I; // Ignore ivars that... // (a) aren't private // (b) explicitly marked unused // (c) are iboutlets // (d) are unnamed bitfields if (ID->getAccessControl() != ObjCIvarDecl::Private || ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>() || ID->getAttr<IBOutletCollectionAttr>() || ID->isUnnamedBitfield()) continue; M[ID] = Unused; } if (M.empty()) return; // Now scan the implementation declaration. Scan(M, D); // Any potentially unused ivars? bool hasUnused = false; for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) if (I->second == Unused) { hasUnused = true; break; } if (!hasUnused) return; // We found some potentially unused ivars. Scan the entire translation unit // for functions inside the @implementation that reference these ivars. // FIXME: In the future hopefully we can just use the lexical DeclContext // to go from the ObjCImplementationDecl to the lexically "nested" // C functions. SourceManager &SM = BR.getSourceManager(); Scan(M, D->getDeclContext(), SM.getFileID(D->getLocation()), SM); // Find ivars that are unused. for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I) if (I->second == Unused) { std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "Instance variable '" << *I->first << "' in class '" << *ID << "' is never used by the methods in its @implementation " "(although it may be used by category methods)."; PathDiagnosticLocation L = PathDiagnosticLocation::create(I->first, BR.getSourceManager()); BR.EmitBasicReport(D, "Unused instance variable", "Optimization", os.str(), L); } }