找到未使用的结构和结构成员

Fre*_*ihl 5 c linux gcc

前一段时间我们接管了遗留代码库的责任.

这个非常糟糕的结构/编写代码的一个怪癖是它包含许多非常庞大的结构,每个结构包含数百个成员.我们所做的许多步骤之一是清除尽可能多的未使用的代码,因此需要找到未使用的结构/结构成员.

关于结构,我想出了python,GNU Globalctags的组合来列出未使用的结构成员.

基本上,我正在做的是用来ctags生成一个标签文件,下面的python脚本解析该文件以找到所有结构成员,然后使用GNU Global在先前生成的全局数据库中查找以查看是否使用该成员在代码中.

这种方法存在许多相当严重的缺陷,但它解决了我们面临的问题,并为我们进一步清理提供了良好的开端.

必须有更好的方法来做到这一点!

问题是:如何在代码库中找到未使用的结构和结构成员?

#!/usr/bin/env python

import os
import string
import sys
import operator

def printheader(word):
    """generate a nice header string"""
    print "\n%s\n%s" % (word, "-" * len(word))

class StructFreqAnalysis:
    """ add description"""
    def __init__(self):
        self.path2hfile=''
        self.name=''
        self.id=''
        self.members=[]

    def show(self):
        print 'path2hfile:',self.path2hfile
        print 'name:',self.name
        print 'members:',self.members
        print

    def sort(self):
        return sorted(self.members, key=operator.itemgetter(1))

    def prettyprint(self):
        '''display a sorted list'''
        print 'struct:',self.name
        print 'path:',self.path2hfile
        for i in self.sort():
            print '    ',i[0],':',i[1]
        print

f=open('tags','r')

x={} # struct_name -> class
y={} # internal tags id -> class

for i in f:
    i=i.strip()
    if 'typeref:struct:' in i:
        line=i.split()
        x[line[0]]=StructFreqAnalysis()
        x[line[0]].name=line[0]
        x[line[0]].path2hfile=line[1]
        for j in line:
            if 'typeref' in j:
                s=j.split(':')
                x[line[0]].id=s[-1]
                y[s[-1]]=x[line[0]]

f.seek(0)
for i in f:
    i=i.strip()
    if 'struct:' in i:
        items=i.split()
        name=items[0]
        id=items[-1].split(':')[-1]
        if id:
            if id in y:
                key=y[id]
                key.members.append([name,0])
f.close()

# do frequency count
for k,v in x.iteritems():
    for i in v.members:
        cmd='global -a -s %s'%i[0]     # -a absolute path. use global to give src-file for member
        g=os.popen(cmd)
        for gout in g:
            if '.c' in gout:
                gout=gout.strip()
                f=open(gout,'r')
                for line in f:
                    if '->'+i[0] in line or '.'+i[0] in line:
                        i[1]=i[1]+1
                f.close()

printheader('All structures')
for k,v in x.iteritems():
    v.prettyprint()

#show which structs that can be removed
printheader('These structs could perhaps be removed')
for k,v in x.iteritems():
    if len(v.members)==0:
        v.show()

printheader('Total number of probably unused members')
cnt=0
for k,v in x.iteritems():
    for i in v.members:
        if i[1]==0:
            cnt=cnt+1
print cnt
Run Code Online (Sandbox Code Playgroud)

编辑

正如@Jens-Gustedt所提出的,使用编译器是一种很好的方法.在使用编译器方法之前,我正在采用一种可以进行某种"高级"过滤的方法.

Jen*_*edt 1

如果这些只是少数struct,并且代码没有struct通过另一种类型访问 a 的不良行为......那么您可以注释掉第一个类型的所有字段struct,然后让编译器告诉您。

一个接一个地取消注释已使用的字段,直到编译器满意为止。然后,一旦编译完成,就进行良好的测试,以确保没有黑客入侵的前提。

迭代所有struct

绝对不漂亮,但最终你至少会有一个对代码有所了解的人。