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());
        }
}
Example #2
0
/// 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;
}