def get_diagnostics(self): local_cursors = [c for c in self.cursors\ if c.location.file.name == self.filename] def is_local_category(cur): return cur.kind == ci.CursorKind.OBJC_CATEGORY_DECL\ and cur.displayname == '' local_categories = [c for c in local_cursors if is_local_category(c)] class Extension(object): def __init__(self, classname, ivars): self.classname = classname self.ivars = ivars exts = [] for lc in local_categories: class_cursor = list(lc.get_children())[0] ivars = [i for i in lc.get_children()\ if i.kind == ci.CursorKind.OBJC_IVAR_DECL] exts.append(Extension(class_cursor.displayname, ivars)) result = [] for ext in exts: class_impl = [c for c in local_cursors\ if c.kind == ci.CursorKind.OBJC_IMPLEMENTATION_DECL and\ c.displayname == ext.classname][0] ivar_usages = dict([(i.displayname, 0) for i in ext.ivars]) method_impls = [c for c in class_impl.get_children()\ if c.kind == ci.CursorKind.OBJC_INSTANCE_METHOD_DECL] def collect_ivar_usages(cur): ivar_set = set() def go(cur): if cur.kind == ci.CursorKind.MEMBER_REF_EXPR: ivar_set.add(cur.displayname) for child in cur.get_children(): go(child) go(cur) return ivar_set for mi in method_impls: ivar_usages_in_method = collect_ivar_usages(mi) for usage in ivar_usages_in_method: if usage in ivar_usages: ivar_usages[usage] += 1 for ivar in ext.ivars: if ivar_usages[ivar.displayname] == 0: d = LintDiagnostic() d.category = self.category d.filename = self.filename d.line = ivar.location.line d.context = full_text_for_cursor(ivar) d.message = 'unused ivar ' + ivar.displayname result.append(d) elif ivar_usages[ivar.displayname] == 1 and self.has_arc: # FIXME: false positive if ivar is used as a storage # to fix this, we need to check if read access is possible # before write access in this method d = LintDiagnostic() d.category = self.category d.filename = self.filename d.line = ivar.location.line d.context = full_text_for_cursor(ivar) d.message = 'ivar {0} is used in only one method'.format( ivar.displayname) result.append(d) return result
def get_diagnostics(self): local_cursors = [c for c in self.cursors\ if c.location.file.name == self.filename] def is_local_category(cur): return cur.kind == ci.CursorKind.OBJC_CATEGORY_DECL\ and cur.displayname == '' local_categories = [c for c in local_cursors if is_local_category(c)] class Extension(object): def __init__(self, filename, methods): self.filename = filename self.methods = methods exts = [] for lc in local_categories: class_cursor = list(lc.get_children())[0] ivars = [i for i in lc.get_children()\ if i.kind == ci.CursorKind.OBJC_INSTANCE_METHOD_DECL] exts.append(Extension(class_cursor.displayname, ivars)) result = [] for ext in exts: class_impls = [c for c in local_cursors\ if c.kind == ci.CursorKind.OBJC_IMPLEMENTATION_DECL and\ c.displayname == ext.filename] yet_unused_method_names = [i.displayname for i in ext.methods] def traverse(cur): if cur.kind == ci.CursorKind.OBJC_MESSAGE_EXPR\ and cur.displayname in yet_unused_method_names: yet_unused_method_names.remove(cur.displayname) if cur.kind == ci.CursorKind.OBJC_SELECTOR_EXPR: # '@selector(foo)' -> 'foo' selector_name = full_text_for_cursor(cur)[10:-1] if selector_name in yet_unused_method_names: yet_unused_method_names.remove(selector_name) if not yet_unused_method_names: return for child in cur.get_children(): traverse(child) for class_impl in class_impls: traverse(class_impl) for method in ext.methods: if method.displayname in yet_unused_method_names: d = LintDiagnostic() d.category = self.category d.filename = self.filename d.line = method.location.line d.context = full_text_for_cursor(method) d.message = 'unused method ' + method.displayname result.append(d) return result