C++ Klocwork(或其他工具)能识别类型、typedef和#define指令吗?

C++ Klocwork(或其他工具)能识别类型、typedef和#define指令吗?,c++,static-analysis,klocwork,C++,Static Analysis,Klocwork,我发现了一些错误,这些错误阻止程序以64位代码的形式正常运行。最近,我一直在玩弄Klocwork及其自定义checkers特性,它让我可以使用XPath以树的形式浏览源代码。作为正则表达式的“更智能”的替代方案,这是很有用的,但我还不能让它知道类型 例如,假设我想找到使用int或long计数的For循环的每个实例。下面的代码很容易找到 for (int i = 0; i < 10; i++) // ... 查找第一个循环,因为i的类型显式定义为int。但是,找不到第二个循环,因为

我发现了一些错误,这些错误阻止程序以64位代码的形式正常运行。最近,我一直在玩弄Klocwork及其自定义checkers特性,它让我可以使用XPath以树的形式浏览源代码。作为正则表达式的“更智能”的替代方案,这是很有用的,但我还不能让它知道类型

例如,假设我想找到使用
int
long
计数的
For
循环的每个实例。下面的代码很容易找到

for (int i = 0; i < 10; i++)
    // ...

查找第一个循环,因为
i
的类型显式定义为
int
。但是,找不到第二个循环,因为typedef模糊了底层类型。哪些工具可以跟踪类型,从而将第二个循环变量
j
识别为确实是
int

我工作的公司Semantic Designs Inc.提供工具 用于分析和转换程序和数据的通用基础结构 各种编程语言的特定分析组件。 它们一起被称为DMS。在C++的情况下,DMS包括 集成的词法分析器、预处理器、解析器以及名称和类型 每个GCC3、GCC4、ISO14882c1998(ANSI)的分辨率组件, Visual C++ 6和非托管Visual Studio 2005 C++。对于各种 方言的C,也存在控制流分析,有副作用 analyzer和符号依赖关系分析器,使用这些分析器可以使用 指针检查器、非活动代码移除器、函数探查器和程序 切片器已经实现

名称和类型解析组件提供完整的符号表 信息和查找功能,以便 标识符可以很容易地与其类型和其他类型相关联 声明性信息。这些信息就像是被捕获和保存的一样 由编译器使用,但与抽象语法树一起保留 以可由任何包含以下内容的工具自适应重复使用的形式: 组成部分

语义设计最近构建了一个定制工具 与循环中的索引变量类型特别相关 声明,例如您的示例中的声明。在这种情况下,问题是 要升级使用-fno作为作用域编译器开关的GCC2代码, 它为循环变量提供了一个范围解析规则,而循环变量不是 在以后的GCC方言中支持。该工具必须转换循环, 将循环变量的声明移动到外部上下文中 这保留了-fno的作用域范围规则。这些变化在哪里 没有必要,没有进行任何更改

因此,该工具必须识别与每个引用关联的类型 到循环变量,在屏蔽作用域的情况下进行区分,以及 重新构造代码,以便GCC3和GCC4名称解析 产生与GCC2相同的语义解释,带有 -fno适用于范围。这需要能够访问符号表 与每个变量引用相关的信息,以及 在代码移动的位置,为 已移动其声明的任何变量的类型声明。 DMS提供的符号表和标识符参考表 包含所有需要的C++名称和类型解析组件 信息,以及用于重构指定类型语法的模块 允许合成正确的新类型声明

例如,考虑例子:

// loop variable hides variable in global scope
// will change meaning without -fno-for-scope
// fix: move decl. of cnt before for-loop
//   optionally rename globcnt loop variable

float globcnt = 0.0;

int Foo::foo3() {
    for (int globcnt = 0; globcnt < 5; globcnt++) {
        globalInt += globcnt;
    }
    globalInt += 2*globcnt + 1;
    return 0;
}
//循环变量隐藏全局范围内的变量
//将更改含义,范围不使用-fno
//修正:移动decl。碳纳米管在for环前的应用
//可选地重命名globcnt循环变量
浮球Cnt=0.0;
intfoo::foo3(){
对于(int globcnt=0;globcnt<5;globcnt++){
globalInt+=globcnt;
}
globalInt+=2*globcnt+1;
返回0;
}
范围语义的GCC2-fno表示对globcnt的引用 在循环之外的是循环变量,即使GCC3 考虑超出范围的循环变量并解析引用 全局变量。该工具将此代码转换为:

float globcnt = 0.0;

int Foo::foo3() {
    int globcnt = 0;
    for (; globcnt < 5; globcnt++) {
        globalInt += globcnt;
    }
    globalInt += 2*globcnt + 1;
    return 0;
}
float globcnt=0.0;
intfoo::foo3(){
int globcnt=0;
对于(;globcnt<5;globcnt++){
globalInt+=globcnt;
}
globalInt+=2*globcnt+1;
返回0;
}
如果代码没有被转换,GCC4将始终返回 来自Foo:foo3的值1。不过,转换后的值会 受到最初设计的循环迭代的影响 GCC2。该工具必须认识到,对globcnt的最终引用 是指向int类型的局部变量,而不是指向int类型的全局变量 输入float,它可以通过符号表查找来执行,并执行操作 因此

另一方面,以下代码中识别的工具 在循环之外没有对i的引用,因此可以接受 (和首选)保持循环变量声明不变

int Foo::foo0() {
    for (int i = 0; i < 10; i++) {
        globalInt += i*i;
    }
    return 0;
}
intfoo::foo0(){
对于(int i=0;i<10;i++){
globalInt+=i*i;
}
返回0;
}

您可以使用Clang()甚至Elsa()在类型传播和模板实例化之后生成AST。两者都提供了一个不错的C++ API和一些将AST倾倒到可读文本中的方法。这两个选项都是免费的。

不完全确定这是否是您想要的,但您可以使用内置函数轻松解析类型。例如,回答您的问题(尽管可能不是您的基本需求):

这将非常方便地找到使用“int”或“long int”计数器类型的“for”循环,并且显然可以应用于基于表达式语句的任何元素

无论是程序员定义的还是语言定义的,类型定义都适合这种操作。但是,预处理器定义只会产生其本机语言类型(即宏本身不可用于操作)
float globcnt = 0.0;

int Foo::foo3() {
    int globcnt = 0;
    for (; globcnt < 5; globcnt++) {
        globalInt += globcnt;
    }
    globalInt += 2*globcnt + 1;
    return 0;
}
int Foo::foo0() {
    for (int i = 0; i < 10; i++) {
        globalInt += i*i;
    }
    return 0;
}
//ForStmt / Init::ExprStmt / Expr::BinaryExpr [ $type := Left.getTypeName() ] [ $type = 'int' | $type.contains('long') ]