2

我们想从一个类类型中找到所有的指针比较。例如,我们有一个类 A 和从 A 派生的类,如 B、C 等。

A *pa;
A *pa2;
B *pb;

所有比较,如 if (pa == pa2) 或 if (pa != pb) 都必须在我们的源代码中找到。

我知道我们可以使用 CLang 分析器来查找这些比较,但我们的源代码与 CLang 不兼容。我们正在使用 Visual Studio 2015。

请不要给出这样的解决方案;从源代码中删除 A 类,然后尝试编译它,以便从 A 类中找到它没有编译的所有用法。

有没有人找到它的解决方案?像 CppCheck(检查可能的错误)或 Visual Studio 扩展这样的工具?

编辑:

有谁知道,我怎样才能在我的代码中使用 CppDepend/CQLinq 语法找到所有比较?它也可以帮助我。CppDepend 使用 CLang,但如果它有解析错误,它会继续解析。

4

3 回答 3

2

我们的DMS Software Reengineering Toolkit及其C++14 前端可用于执行此操作。

DMS 是通用的程序分析和转换机器,可以定制以在作为插件模块提供给它的编程语言上实现所需的效果。它的 C++14 前端可配置地处理纯 ANSI、GCC/Clang 样式语法或 Visual Studio 语法。它包括一个完整的预处理器。

为了实现 OP 的目的,可以将 DMS 配置为:

  1. 解析生成 AST 的编译单元。
  2. 对于每个编译单元,执行名称和类型解析。这构建了包含类型信息的符号表,并为计算任意表达式的类型提供了基础。此功能内置于 DMS 的 C++ 前端。
  3. 爬取 AST,寻找运算符 == 和 !=
  4. 要求 DMS 计算右侧和左侧子表达式的类型
  5. 验证该类型是目标类,还是从目标类继承的类型。(推测目标类被识别为在某个源文件/行位置定义;这可以通过搜索符号表找到。检查一个类型是否从另一个派生只是递归搜索记录的可能多个父链接的问题用于符号表链接以检查父对象是否是所需的目标类型)。
  6. 报告算子的文件名、源行和列。

DMS 和 C++14 前端提供的机器/API 直接支持上述每个步骤。这可能需要在 DMS 中添加几页自定义代码才能达到效果。

于 2016-08-18T08:59:42.407 回答
1

我的解决方案是:(正如@MM所说)用模板包装类包装指针,实现运算符重载-> *(因此编译问题更少)并删除比较运算符== !=(因此找到编译错误的比较)。可以使用正则表达式替换所有指针。(A *A_Wrapper

我还发现,在地图中使用指针就像指针比较。如果您在地图中使用指针,您还应该<在包装类中删除 -Operator。

当然,我有编译错误,但这些错误并不难解决。这似乎是一定的解决方案。

我希望这对某人有所帮助。

于 2016-10-14T06:59:33.303 回答
-2

我猜我错过了这个问题。因此,您只想找到指向 A、B、C 等类型的任何指针的所有实例,其中该指针通过比较在条件表达式中使用...

所以你知道所有的类型名称。这意味着有有限数量的类型和有限数量的比较,例如 == != <= >= < > 对吗?

因此,对于所有类型创建的指针的每个实例,构建一个表。这为您提供了您正在寻找的每个指针的编码名称。

弗雷德 *myfred, *yourfred, *thefred;

帐户 *primaryacct, *secondacct; ... 等等...

您的表将是:
myfred
yourfred
thefred
primaryacct
secondacct

现在对于每个实例的每个实例 - 从第一个 'myfred' 开始找到 myfred 然后是 == 然后是 != 等等(吸收任何空格),当你找到第一个(comaprison 的左侧,例如

第二个帐户<=

然后获取右侧)并将其与您构建的表中的每个指针编码名称进行比较。当你有一个像 myfred!=primaryacct 这样的比赛时,你可以随心所欲。假设为了参数,您想对给定的比较或比较列表执行全局搜索和替换,您可以通过打开一个附加文件进行输出来随时执行此操作,并在您阅读并找到每个发生时,您可以将其输出到新的源代码文件中。

基本上只要找到每一个比较,看看它的每一面,看看两边是否有一个在你的表中的编码名称。本质上,您只是在比较字符串的有限组合的任一侧使用相同的标识符表解析代码 - 它们也是: [ == != <= >= < > ]

我不知道有什么软件工具可以做到这一点,但你可以很快地编写代码。当然,它只能达到这一目的,但它可以快速完成工作。

我当然假设您的源代码是文本形式的,并且您可以打开文件并读入以执行此操作。如果是这样,那么你可以得到你喜欢的结果,例如每个文件的列表和为每个表达的比较找到出现的行。

在读入时抓取一整行代码 -

在 C 中 - 只需使用 fgets

在 C++ 中 - 使用 getline

然后只需使用上述逻辑解析您读入的缓冲区。

-------------- 已编辑 --------------- 关于以下评论

@YusufRamazanKaragöz - 橡树 - 我为过度概括而道歉。您是否有机会提供包含其中一些问题的代码示例 - 例如,如果它涵盖多行怎么办?我的思考过程基于您所写的“必须在我们的源代码中找到所有比较,如 if (pa == pa2) 或 if (pa != pb)”,仅此而已,所以我没有扩展到函数返回,等至于构建表格 - 你知道类型正确吗?因此,对于声明了这些类型的变量的每一行都是您构建它的方式。例如,如果我想要一个包含程序所有文件的每一行代码中每个 char 定义变量的表 - 我会在所有行中搜索单词 char。然后在那行之后我会寻找逗号分隔的字符串,直到没有逗号或分号(可以继续到下一行,所以使用 fgetc 代替 fgets)。其中一些声明是直接的,一些可能是 *char,一些 char[] - 等等。然后我会有一个 char 类型的每个变量的列表。我的意思是,如果当您搜索您正在谈论的类型名称时,您看不到它所在的行以及在它之后声明的所有内容吗?如果可以,那么您可以构建索引表。或者有什么原因我不明白为什么不能这样做?查找强制转换的值会完全创建另一组解析规则,并进一步使任务复杂化,就像模板与对象的比较一样。直到现在,我才真正从最初的问题中理解您的困境。我真的很想帮忙,但也许涵盖每个解析范式的代码块可以帮助我确定是否可以。实际上,如果你能给我一个关于你为什么要这样做的想法,那会让我有一个更好的思考过程。你想全局改变一些东西吗?如果您认为努力是徒劳的,我当然会听从您的决定并停止尝试。感谢您的耐心等待,但我希望您能找到解决方案。

于 2016-08-18T09:34:47.803 回答