删除未使用或冗余的代码

时间:2015-10-19 07:56:36

标签: c++ algorithm data-structures

如何检测永远不会被调用的函数定义并将其从文件中删除然后保存?

假设我现在只有1个CPP文件,它有main()函数和许多其他函数定义(函数定义也可以在main() 内)。如果我要编写一个程序来解析这个CPP文件,并检查一个函数是否被调用,如果没有被调用则删除,那么这样做的方式是什么?

我想到的方法很少:

  1. 我会找到main()开头和结尾的行号。我可以通过维持一堆打开和关闭大括号{}来实现。
  2. main之后的任何内容都是函数定义。然后我可以解析函数定义。为此,我可以通过以下方式解析它:

    < string >< open paren >< comma separated string(s) for arguments >< closing paren >
    
  3. 一旦我拥有了(2)中描述的所有函数的名称,我就可以创建一个名称为key和value的映射为bool,表示函数是否被调用一次或不。

  4. 最后再次解析文件以检查是否有任何名称与此地图相同的函数调用。函数调用可以来自main或来自其他一些函数。可以根据函数是否被调用来标记键的值(即函数名称)。

  5. 我觉得我的逻辑很复杂,可以用更聪明的方式完成。根据上述逻辑,很难找到所有的角落情况(会有很多)。此外,可能存在函数指针以使解析逻辑变得困难。如果这还不够,那么函数指针也可以typedef

    如何设计我的程序?是一个地图(维护文件名)和堆栈(维护大括号)正确的数据结构还是还有其他更适合处理它的东西?

    注意:我不是在寻找任何工具来执行此操作。我也不想使用任何库(如果它存在以使事情变得容易)。

4 个答案:

答案 0 :(得分:1)

我认为你不应该尝试从头开始构建一个C ++解析器,因为其他人在评论中说这真的很难。恕我直言,你最好从CLang库开始,而不是为你做低级解析,直接使用抽象语法树。

您甚至可以使用crange作为如何使用它们来生成交叉引用表的示例。

或者,您可以直接使用GNU global,因为它的if (Robot.IsConnected) { if (GamePad.GetState(PlayerIndex.One).IsButtonDown(Buttons.A) || GamePad.GetState(PlayerIndex.One).IsButtonDown(Buttons.B) || GamePad.GetState(PlayerIndex.One).IsButtonDown(Buttons.Y) || GamePad.GetState(PlayerIndex.One).IsButtonDown(Buttons.X)) { if (GamePad.GetState(PlayerIndex.One).Buttons.Y == ButtonState.Pressed) { Robot.SendMessage(driveRobot, straight); } if (Robot2.IsConnected) { if (GamePad.GetState(PlayerIndex.Two).IsButtonDown(Buttons.A) || GamePad.GetState(PlayerIndex.Two).IsButtonDown(Buttons.B) || GamePad.GetState(PlayerIndex.Two).IsButtonDown(Buttons.Y) || GamePad.GetState(PlayerIndex.Two).IsButtonDown(Buttons.X)) { if (GamePad.GetState(PlayerIndex.Two).Buttons.Y == ButtonState.Pressed) { Robot.SendMessage(driveRobot2, straight); } 命令直接生成您必须分析的定义和参考数据库。

恕我直言,这两种方式比从头创建C ++解析器更简单。

答案 1 :(得分:1)

  • 这是评论,而不是答案,但我在此发布,因为评论空间太长了。

您应该考虑很多问题。首先,您不应该假设main()是源文件中的第一个函数。

即使它是,在main()之前应该有一些函数头声明,以便编译器可以在main中识别它们的调用。

接下来,函数的开始和结束括号不需要在单独的行中,它们也不必是它们行中的唯一字符。通常,几乎整个C ++代码可以放在一行中!

此外,函数可能因参数类型不同而具有相同的名称(重载),因此如果不将整个代码解析为,则不能识别调用哪个函数参数的类型。甚至更多:您必须执行与标准转换/强制转换匹配的类型列表,可能需要考虑内联构造函数调用。当然你不应该忘记默认参数。例如,resolving overloaded function call的Google会看到大纲here

此外,可能存在未使用功能链。例如,如果a()调用b()b()调用c()d(),但a()本身未调用,那么整个四个都未使用,即使存在b()c()d()的“来电”。

还有可能通过指针调用函数,在这种情况下,您可能无法找到调用。例如:

int (*testfun)(int) = whattotest ? TestFun1 : TestFun2;  // no call
int testResult = testfun(paramToTest);  // unknown function called

最后,代码可能会被#define - s。

混淆

结论:您可能必须编写自己的C ++编译器(机器代码生成器除外)才能实现目标。

答案 2 :(得分:1)

我能想到的最简单的方法是:

  • 编写一个可以识别函数的最小解析器。它只需要检测函数的起始和结束行。
  • 以编程方式注释掉第一个函数,保存到临时文件。
  • 尝试通过调用编译器来编译文件。
  • 检查是否存在编译错误,如果是,则调用该函数,如果没有,则不使用。
  • 继续下一个功能。

答案 3 :(得分:0)

这是一个非常粗略的想法,我怀疑它是非常有效的,但也许它可以帮助你开始。首先遍历文件一次,挑选出任何函数名称(我不完全确定你会怎么做)。但是一旦你有这些名字,再次遍历文件,在文件的任何地方,主要和其他功能中查找函数名称。如果您发现多于1个实例,则意味着正在调用该函数并且应该保留该函数。