Codan是一个代码分析框架,可对C / C ++项目执行代码检查。 自2011年以来,Codan已成为Eclipse CDT(C / C ++开发工具)套件的一部分,它不仅提供执行静态代码分析所需的所有基础结构,而且还提供了一些有用的即用型问题检查器(请参阅参考资料 )。
Codan在2012年6月的Eclipse Juno版本中进行了更新,以使开发人员能够在Eclipse中自动执行外部代码分析工具。 对于Eclipse CDT和C / C ++开发人员而言,这是令人激动的进步。 尽管先前提供的问题检查器很好,但是需要更多的东西来使Codan与现有的外部代码分析工具保持功能相同。 Codan现在可以轻松地与成熟的外部工具(例如Cppcheck和clang_check)集成。
将外部代码分析工具与Eclipse CDT集成在一起,比开发人员仅使用Codan就能完成更多,更好的代码检查。 它还应该大大提高整体开发效率。 现在,我们可以从Codan的“首选项”页面配置外部代码分析工具。 与Codan集成后,将自动调用这些工具,并将其输出显示为编辑器标记。
在本文中,我将向您展示如何使用Java代码和一点点XML将您喜欢的代码分析工具集成到Eclipse C / C ++开发环境中。 我的示例将基于Cppcheck与Codan的集成,但是该过程应适用于您选择的工具。
安装Eclipse Juno和CDT
为了遵循本文中的示例,您将需要同时安装Eclipse Juno和CDT。 如果尚未安装Eclipse,则可以安装CDT附带的版本。 为此,只需从Eclipse下载页面中选择C / C ++开发人员的Eclipse IDE 。
如果您已经安装了不包含CDT的Eclipse,请按照以下说明更新您的开发环境:
- 在Eclipse中,选择菜单帮助>安装新软件...。
- 在“安装”对话框中,从下拉列表中选择Juno 。
- 在“编程语言”类别中,选择“ C / C ++开发工具SDK” 。
图1.安装CDT
除了CDT,您还需要标准的GNU C / C ++开发工具来编译,构建和调试代码。 请参阅相关主题有关如何安装这些工具的说明。
启动科丹
默认情况下,大多数Codan代码检查均处于启用状态。 您可以分别使用Eclipse的“首选项”或“项目属性”页面在工作区或项目级别分别配置Codan代码检查。
在Codan的Preferences页面(如图2所示)中,您可以看到所有可用的代码检查器以及每个报告的代码问题。
图2. Codan的Preferences页面上的代码检查器
在此页面上,您可以启用,禁用或更改问题的严重性。 如果要配置单个问题的其他属性,则可以选择一个问题,然后单击“ 定制选定的...”按钮。 图3显示了问题“函数的名称约定”的配置选项。
图3.配置问题
图3中的第三个选项卡允许您指定应该如何启动问题检查:
- 键入时运行 :当用户在CDT编辑器中对文件进行更改时。
- 在文件打开时运行 :在CDT编辑器中打开文件时。
- 在文件保存上运行 :保存CDT编辑器上未保存的更改时。
- 在增量构建上运行 :发出增量构建时(通常在保存文件并启用项目级选项“自动构建”时)。 如果同时启用此选项和“在文件保存时运行”,则代码检查将运行两次。
- 在完整版本上运行 :发出完整版本时(例如,在清理项目时)。
- 按需运行 :当用户从上下文菜单项“运行C / C ++代码分析”手动触发代码检查时。
与Codan进行代码检查
为了让您看到Codan在工作,我将用一个简短的C ++文件创建一个C ++项目。 在此文件中,我将为其分配一个变量。 Codan包含代码检查“对自身的分配”,默认情况下,其严重性级别为“错误”启用。 它被配置为在您键入时运行,因此错误将立即弹出。
图4. Codan执行代码检查
在图4中 ,您可以看到Codan在我有机会保存文件之前发现了自我分配错误并报告了该错误。 完善!
要了解有关使用Codan的更多信息,请访问项目的主页(请参阅参考资料 )。
将Cppcheck集成到Eclipse CDT中
为了将外部代码分析工具与Codan集成,我们需要编写一种特殊的检查程序,该检查程序知道如何调用该工具。 检查器是Codan IChecker
接口的实现, IChecker
接口对给定的IResource
(通常是IFile
)执行某种代码检查。
为了证明它是多么容易地创建一个基于外部工具检查,我们将创建一个调用常用的工具Cppcheck(见检查相关主题 )。 这是我们要做的:
- 创建一个Eclipse插件项目,并将Codan添加为依赖项。
- 创建一个错误分析器以分析Cppcheck的输出,并在必要时创建编辑器标记。
- 创建代码检查器,它是负责调用Cppcheck的类。
步骤1.创建一个Eclipse插件项目
要创建Codan检查器,我们首先创建一个新的Eclipse插件项目:
- 选择菜单文件>新建>项目...。
- 在“插件开发”类别中,选择“ 插件项目” 。
- 输入项目的名称(我的名称为“ CppcheckChecker”),然后单击“ 下一步” 。
- 接受默认值,然后单击完成 。
图5.创建一个插件项目
创建新的插件项目后,Eclipse将立即自动打开MANIFEST.MF
文件。 这是我们将添加Codan依赖项的文件。
在编辑器中,选择“依赖关系”选项卡,并将以下内容添加到“必需的插件”列表中:
org.eclipse.cdt.codan.core
org.eclipse.cdt.codan.core.cxx
org.eclipse.cdt.codan.ui
org.eclipse.cdt.codan.ui.cxx
org.eclipse.cdt.core
org.eclipse.cdt.ui
org.eclipse.core.resources
org.eclipse.core.runtime
org.eclipse.ui
步骤2.创建一个错误解析器
我们将需要一个错误解析器来根据Cppcheck的输出创建编辑器标记,因此下一步是使用插件扩展Eclipse的C / C ++工具。我们将为此目的使用Java代码,因为Eclipse本身就是Java应用程序。
首先,我们将创建一个实现org.eclipse.cdt.core.IErrorParser
的类CppcheckErrorParser
。 我们首先找到在报告代码问题时Cppcheck使用的模式。 错误分析器将使用此模式来识别代表问题报告的输出行,然后从该输出中提取创建编辑器标记所需的信息。
清单1.与Cppcheck的输出匹配的模式
// sample line to parse:
//
// [/src/HelloWorld.cpp:19]: (style) The scope of the variable 'i' can be reduced
// ----------1--------- -2 --3-- ------------------4-------------------------
//
// groups:
// 1: file path and name
// 2: line where problem was found
// 3: problem severity
// 4: problem description
private static Pattern pattern =
Pattern.compile("\\[(.*):(\\d+)\\]:\\s*\\((.*)\\)\\s*(.*)");
清单2显示了错误解析器如何使用该模式提取要检查的文件的路径和名称,以及找到的错误的位置,描述和严重性。 利用此信息,错误分析器将创建一个新的ProblemMarkerInfo
并将其传递给给定的ErrorParserManager
。 ErrorParserManager
是负责创建编辑器标记的类。
清单2.处理Cppcheck的输出
@Override
public boolean processLine(String line, ErrorParserManager parserManager) {
Matcher matcher = pattern.matcher(line);
if (!matcher.matches()) {
return false;
}
IFile fileName = parserManager.findFileName(matcher.group(1));
if (fileName != null) {
int lineNumber = Integer.parseInt(matcher.group(2));
String description = matcher.group(4);
int severity = findSeverityCode(matcher.group(3));
ProblemMarkerInfo info =
new ProblemMarkerInfo(fileName, lineNumber, description, severity, null);
parserManager.addProblemMarker(info);
return true;
}
return false;
}
}
映射问题严重性
Cppcheck定义了自己的问题严重性,与编辑器标记使用的严重性不同。 例如,Cppcheck严重性“样式”在Eclipse世界中没有对应的严重性。 为了克服这个问题,我们需要在两种问题严重性之间建立映射。 方法findSeverityCode
(如清单3所示)演示了实现此映射的直接方法:
清单3.映射问题严重性
private static Map<String, Integer> SEVERITY_MAPPING = new HashMap<String, Integer>();
static {
SEVERITY_MAPPING.put("error", IMarkerGenerator.SEVERITY_ERROR_RESOURCE);
SEVERITY_MAPPING.put("warning", IMarkerGenerator.SEVERITY_WARNING);
SEVERITY_MAPPING.put("style", IMarkerGenerator.SEVERITY_INFO);
}
private int findSeverityCode(String text) {
Integer code = SEVERITY_MAPPING.get(text);
if (code != null) {
return code;
}
return IMarkerGenerator.SEVERITY_INFO;
}
创建映射后,由Cppcheck报告的严重性为“样式”的任何问题都将使用严重性SEVERITY_INFO
在Eclipse中显示。 此映射仅定义问题严重性的默认值。 如您将在后面看到的,可以从“ Codan首选项”页面配置此映射。
为了使CppcheckErrorParser
能够识别CppcheckErrorParser
,需要使用扩展点org.eclipse.cdt.core.ErrorParser
将其注册在plugin.xml文件中:
清单4.注册错误解析器
<extension id="com.developerworks.cdt.checkers" name="Cppcheck error parsers"
point="org.eclipse.cdt.core.ErrorParser">
<errorparser class="cppcheckchecker.CppcheckErrorParser"
id="com.dw.cdt.checkers.CppcheckErrorParser"
name="Cppcheck">
<context type="codan" />
</errorparser>
</extension>
请注意,在清单4中, ErrorParser
扩展点最初是为注册CDT的构建工具的解析器而创建的。 它不特定于Codan。 为了表明CppcheckErrorParser
应与Codan一起使用,我们添加上下文“ codan
。
步骤3.创建代码检查器
AbstractExternalToolBasedChecker
是任何基于外部工具的Codan代码检查器的超类。 它提供了调用外部代码分析工具所需的大多数基础结构。 因为我们正在集成Cppcheck,所以我们将其称为CppcheckChecker
类。
我们需要做的第一件事是为信息指定与外部工具有关的默认值,该默认值将显示在“ Codan首选项”页面上。
该信息应传递给检查器的构造函数,包括以下内容:
- 外部代码分析工具的名称,在本例中为Cppcheck。
- 工具可执行文件的名称,即
cppcheck
。 我们不需要为可执行文件指定路径,因为我们假设它位于系统的PATH
。 - 传递给可执行文件的参数,包含在单个
String
。 我们指定“--enable=all
”以启用所有Cppcheck的检查。
清单5.默认的Cppcheck信息
public CppCheckChecker() {
super(new ConfigurationSettings("Cppcheck", new File("cppcheck"), "--enable=all"));
}
请注意,Codan的“首选项”页面允许我们修改可执行路径和要传递的参数。
将问题严重性映射到问题ID
接下来,我们要指定将要使用的错误解析器的ID,如清单6所示。这些ID必须与plugin.xml文件中使用的ID相同。
清单6.指定要使用的错误解析器的ID
@Override
protected String[] getParserIDs() {
return new String[] { "com.dw.cdt.checkers.CppcheckErrorParser" };
}
返回清单2 ,我们创建了ProblemMarkerInfo
并将其传递给给定的ErrorParserManager
,以创建编辑器标记。 ErrorParserManager
将把编辑器标记的创建委派给我们新创建的检查器。
要使检查器创建编辑器标记,我们需要重写addMarker(ProblemMarkerInfo)
方法(其工作是查找另一种不匹配类型)。 Codan检查器无法直接从ProblemMarkerInfo
创建编辑器标记。 他们有自己的机制,该机制使用问题ID来为创建的编辑器标记找出适当的严重性。
问题ID是Codan用来标识代码检查程序报告的代码问题的唯一ID。 所有代码问题都显示在Codan的“首选项”页面上(请参见图2 )。
清单7.创建错误标记
@Override
public void addMarker(ProblemMarkerInfo info) {
String problemId = PROBLEM_IDS.get(info.severity);
String description = String.format("[cppcheck] %s", info.description);
reportProblem(problemId, createProblemLocation(info), description);
}
为了找到与ProblemMarkerInfo
的严重性相对应的问题ID,我们需要在严重性和问题ID之间创建映射。 清单8显示了如何实现映射:
清单8.将问题严重性映射到问题ID
private static final String ERROR_PROBLEM_ID =
"com.dw.cdt.checkers.cppcheck.error";
private static final Map<Integer, String> PROBLEM_IDS =
new HashMap<Integer, String>();
static {
PROBLEM_IDS.put(
IMarkerGenerator.SEVERITY_ERROR_RESOURCE, ERROR_PROBLEM_ID);
PROBLEM_IDS.put(
IMarkerGenerator.SEVERITY_WARNING, "com.dw.cdt.checkers.cppcheck.warning");
PROBLEM_IDS.put(
IMarkerGenerator.SEVERITY_INFO, "com.dw.cdt.checkers.cppcheck.style");
}
使用外部代码分析工具的代码检查器需要指出他们的哪个问题ID被视为“参考”。 参考问题ID用于获取检查器的首选项值(例如,外部工具的名称,如清单5所示)。 哪个问题ID是参考都没有关系,因为所有问题都将共享首选项。
清单9.指定参考问题ID
@Override
protected String getReferenceProblemId() {
return ERROR_PROBLEM_ID;
}
清单8中定义了常量ERROR_PROBLEM_ID
。
注册检查器
为了使代码检查器及其报告的所有问题都显示在Codan的“首选项”页面上(因此用户可以访问),我们需要在Codan的plugin.xml文件中注册检查器。
因为我们不知道Cppcheck可以报告的所有问题,并且因为我们不能阻止Cppcheck在将来的版本中添加或删除代码检查,所以我们将无法注册每个问题。 相反,我们将按严重性对问题进行分组,并将每个组视为一个单独的问题。 在清单10中,我们将错误 , 警告和样式冲突注册为三个独立的问题:
清单10.注册检查器和问题报告
<extension point="org.eclipse.cdt.codan.core.checkers">
<category id="cppcheckChecker.category" name="Cppcheck" />
<checker class="cppcheckchecker.CppcheckChecker" id="cppcheckChecker.cppChecker"
name="CppcheckChecker">
<problem id="com.dw.cdt.checkers.cppcheck.error" name="Error"
defaultEnabled="true" defaultSeverity="Error" messagePattern="{0}"
category="cppcheckChecker.category"/>
<problem id="com.dw.cdt.checkers.cppcheck.warning" name="Warning"
defaultEnabled="true" defaultSeverity="Warning" messagePattern="{0}"
category="cppcheckChecker.category"/>
<problem id="com.dw.cdt.checkers.cppcheck.style" name="Style"
defaultEnabled="true" defaultSeverity="Info" messagePattern="{0}"
category="cppcheckChecker.category"/>
</checker>
</extension>
我们在category
元素中指定将显示给用户的检查器的名称。 问题的ID应该与检查器中使用的ID相同(请参见清单8 )。
在plugin.xml文件中,我们针对所有三个问题指定以下内容:
- 默认情况下启用它们。
- 它们分别具有默认严重性“错误”,“警告”和“信息”。
- 它们具有消息模式:“
{0},
”,它迫使Codan使用Cppcheck报告的问题描述。
在Codan中使用Cppcheck
现在,我们可以在Codan Preferences页面上看到CppcheckChecker
, 如图6所示:
图6. Codan的Preferences页面上显示的Cppcheck
![“ Codan首选项”页面上列出的CppcheckChecker的屏幕截图。](https://i-blog.csdnimg.cn/blog_migrate/4ff2b8f45865eaa9451cc364ff4e86f8.png)
图7显示了用于配置Cppcheck如何报告代码错误的选项:
图7.配置Cppcheck的错误报告
图8显示了Cppcheck如何报告代码问题。 请注意,保存文件后会自动调用Cppcheck。
图8. Cppcheck报告
整合的弊端
将Codan与外部代码分析工具集成的局限性在于,当用户键入内容时,基于外部工具的检查器无法运行。 这仅仅是因为外部工具无法看到文件的未保存更改。 因此,当打开文件并保存文件时,需要运行外部检查器。
但是,使用成熟的代码分析工具所带来的好处却远远超过了这种限制。 与创建常规检查器相比,将外部工具与Codan集成起来也容易得多,也很简单,后者需要对C或C ++语言以及CDT的AST实现有深入的了解。 相比之下,我们能够用大约100行简单的Java代码(包含在两个类中)和30行XML来编写CppcheckChecker
。
结论
在Eclipse Juno发行版之前,为Codan创建自定义代码检查需要充分了解C / C ++语言和CDT自己的AST实现。 Eclipse CDT的Juno版本通过允许开发人员创建Codan代码检查器来解决此问题,然后将繁重的工作委托给外部代码分析工具。
在本文中,我们仅使用了少量Java代码和XML即可将Cppcheck与Codan集成在一起,将流行的C / C ++代码分析工具与Eclipse中C / C ++程序的内置代码分析框架结合在一起。 如前所述,您应该能够将此处演示的过程应用于您喜欢的代码分析工具。 请参阅相关主题 ,以了解更多信息。
翻译自: https://www.ibm.com/developerworks/java/library/j-codan/index.html