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()); } }
/// CreateType - get objective-c interface type. llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, llvm::DICompileUnit Unit) { ObjCInterfaceDecl *Decl = Ty->getDecl(); unsigned Tag = llvm::dwarf::DW_TAG_structure_type; SourceManager &SM = M->getContext().getSourceManager(); // Get overall information about the record type for the debug info. std::string Name = Decl->getNameAsString(); llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(Decl->getLocation()); unsigned Line = SM.getInstantiationLineNumber(Decl->getLocation()); // To handle recursive interface, we // first generate a debug descriptor for the struct as a forward declaration. // Then (if it is a definition) we go through and get debug info for all of // its members. Finally, we create a descriptor for the complete type (which // may refer to the forward decl if the struct is recursive) and replace all // uses of the forward declaration with the final definition. llvm::DIType FwdDecl = DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, 0, 0, 0, 0, llvm::DIType(), llvm::DIArray()); // If this is just a forward declaration, return it. if (Decl->isForwardDecl()) return FwdDecl; // Otherwise, insert it into the TypeCache so that recursive uses will find // it. TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl; // Convert all the elements. llvm::SmallVector<llvm::DIDescriptor, 16> EltTys; ObjCInterfaceDecl *SClass = Decl->getSuperClass(); if (SClass) { llvm::DIType SClassTy = getOrCreateType(M->getContext().getObjCInterfaceType(SClass), Unit); llvm::DIType InhTag = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_inheritance, Unit, "", Unit, 0, 0, 0, 0 /* offset */, 0, SClassTy); EltTys.push_back(InhTag); } const ASTRecordLayout &RL = M->getContext().getASTObjCInterfaceLayout(Decl); unsigned FieldNo = 0; for (ObjCInterfaceDecl::ivar_iterator I = Decl->ivar_begin(), E = Decl->ivar_end(); I != E; ++I, ++FieldNo) { ObjCIvarDecl *Field = *I; llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); std::string FieldName = Field->getNameAsString(); // Get the location for the field. SourceLocation FieldDefLoc = Field->getLocation(); llvm::DICompileUnit FieldDefUnit = getOrCreateCompileUnit(FieldDefLoc); unsigned FieldLine = SM.getInstantiationLineNumber(FieldDefLoc); QualType FType = Field->getType(); uint64_t FieldSize = 0; unsigned FieldAlign = 0; if (!FType->isIncompleteArrayType()) { // Bit size, align and offset of the type. FieldSize = M->getContext().getTypeSize(FType); Expr *BitWidth = Field->getBitWidth(); if (BitWidth) FieldSize = BitWidth->getIntegerConstantExprValue(M->getContext()).getZExtValue(); FieldAlign = M->getContext().getTypeAlign(FType); } uint64_t FieldOffset = RL.getFieldOffset(FieldNo); unsigned Flags = 0; if (Field->getAccessControl() == ObjCIvarDecl::Protected) Flags = llvm::DIType::FlagProtected; else if (Field->getAccessControl() == ObjCIvarDecl::Private) Flags = llvm::DIType::FlagPrivate; // Create a DW_TAG_member node to remember the offset of this field in the // struct. FIXME: This is an absolutely insane way to capture this // information. When we gut debug info, this should be fixed. FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, FieldName, FieldDefUnit, FieldLine, FieldSize, FieldAlign, FieldOffset, Flags, FieldTy); EltTys.push_back(FieldTy); } llvm::DIArray Elements = DebugFactory.GetOrCreateArray(&EltTys[0], EltTys.size()); // Bit size, align and offset of the type. uint64_t Size = M->getContext().getTypeSize(Ty); uint64_t Align = M->getContext().getTypeAlign(Ty); llvm::DIType RealDecl = DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, Size, Align, 0, 0, llvm::DIType(), Elements); // Now that we have a real decl for the struct, replace anything using the // old decl with the new one. This will recursively update the debug info. FwdDecl.getGV()->replaceAllUsesWith(RealDecl.getGV()); FwdDecl.getGV()->eraseFromParent(); return RealDecl; }