Integrate an external code checker into Eclipse CDT

Execute C/C++ code analysis tools with Codan in Eclipse

Codan is the Eclipse CDT (C/C++ Development Tooling) built-in code analysis framework for C/C++ projects. Codan provides infrastructure to perform static code analysis and comes with ready-to-use problem checkers. With the Eclipse Juno release, Codan was extended to enable developers to automatically execute external code analysis tools. Alex Ruiz explains why the update is good news for users of Eclipse CDT, then shows you how to use Java™ code and a little bit of XML to quickly integrate your favorite code checker into your Eclipse C/C++ development environment.

Share:

Alex Ruiz (alruiz@google.com), Software engineer, Google

Alex RuizAlex Ruiz works in the Engineering Tools organization at Google Inc. He spends his spare time working on open source projects, blogging, writing technical articles, and speaking at international conferences. Check out Alex's blog. The opinions expressed in this article represent his own and not those of his employer.



22 August 2012

Also available in Chinese Russian Japanese Portuguese

Codan is a code analysis framework that performs code checks on C/C++ projects. Part of the Eclipse CDT (C/C++ Development Tooling) suite since 2011, Codan not only provides all the infrastructure necessary to perform static code analysis, but also some useful, ready-to-use problem checkers (see Resources).

Codan was updated with the Eclipse Juno release in June 2012 to enable developers to automatically execute external code analysis tools within Eclipse. This is an exciting advance for Eclipse CDT and for C/C++ developers. While the previously provided problem checkers were good, many more were needed to give Codan feature-parity with existing external code analysis tools. Codan now easily integrates with mature external tools such as Cppcheck and clang_check.

Related tutorials on developerWorks

More about application development with Eclipse CDT:

Integrating external code analysis tools with Eclipse CDT enables more and better code checks than developers were able to do with Codan alone. It should also greatly improve overall development productivity. We can now configure external code analysis tools from Codan's Preferences pages. Once integrated with Codan, the tools are invoked automatically and their outputs are displayed as editor markers.

In this article, I'll show you how to use Java code and a little bit of XML to integrate your favorite code analysis tool into your Eclipse C/C++ development environment. My example will be based on integrating Cppcheck with Codan, but the process should be applicable to the tool of your choice.

Install Eclipse Juno and CDT

You will need to have both Eclipse Juno and CDT installed in order to follow the examples in this article. If you haven't installed Eclipse yet, you can install a version that comes with CDT pre-installed. To do this, simply select Eclipse IDE for C/C++ Developers from the Eclipse downloads page.

If you already have an Eclipse installation that does not include CDT, follow these instructions to update your development environment:

  1. Inside Eclipse, select the menu Help > Install New Software....
  2. In the Install dialog, select Juno from the drop-down list.
  3. In the Programming Languages category, select C/C++ Development Tools SDK.
Figure 1. Installing CDT
A screenshot of the Eclipse plug-in installation page.

In addition to CDT, you will need the standard GNU C/C++ development tools for compiling, building, and debugging your code. See Resources for instructions on how to install these tools.

Start up Codan

Most Codan code checks are enabled by default. You can individually configure Codan code checks at the workspace or project levels using Eclipse's Preferences or Project Property pages, respectively.

From Codan's Preferences page, shown in Figure 2, you can see all of the code checkers available and the code problems each one reports on.

Figure 2. Code checkers on Codan's Preferences page
A screenshot of Codan's Preferences page.

From this page you can enable, disable, or change the severity of a problem. If you want to configure other properties of individual problems you can select a problem and click the Customize Selected... button. Figure 3 shows the configuration options for the problem "Name convention for function."

Figure 3. Configuring a problem
A screenshot showing the path to configure a problem using Codan.

The third tab in Figure 3 allows you to specify how a problem check should be launched:

  • Run as you type: When a user makes changes to a file in a CDT editor.
  • Run on file open: When a file is opened in a CDT editor.
  • Run on file save: When unsaved changes on a CDT editor are saved.
  • Run on incremental build: When an incremental build is issued (usually when a file is saved and the project-level option "Build Automatically" is enabled). If you enable this option and "Run on file save" together, then a code check will run twice.
  • Run on full build: When a full build is issued (e.g., when a project is cleaned).
  • Run on demand: When a user manually triggers a code check from the context menu item "Run C/C++ Code Analysis."

Code checks with Codan

So that you can see Codan at work, I'll create a C++ project with a short C++ file. In this file, I'll assign a variable to itself. Codan includes the code check "Assignment to itself," which is enabled by default with the severity level of "error." It is configured to run as you type, so the error will pop up immediately.

Figure 4. Codan executing a code check
A screenshot showing Codan executing code checks.

In Figure 4, you can see that Codan found the self-assignment error and reported it before I had a chance to save the file. Perfect!

To learn more about using Codan, visit the project's homepage (see Resources).

Integrate Cppcheck into Eclipse CDT

To integrate an external code-analysis tool with Codan, we need to write a special kind of checker that knows how to invoke that tool. A checker is an implementation of Codan's IChecker interface that performs some kind of code check on a given IResource (typically an IFile).

To demonstrate how easy it is to create an external-tool-based checker, we'll create a checker that invokes the popular tool Cppcheck (see Resources). Here's what we'll do:

  • Create an Eclipse plug-in project and add Codan as a dependency.
  • Create an error parser to parse the output of Cppcheck and create editor markers if necessary.
  • Create the code checker, which is the class responsible for invoking Cppcheck.

Step 1. Create an Eclipse plug-in project

To create a Codan checker, we start by creating a new Eclipse plug-in project:

  1. Select the menu File > New > Project....
  2. In the category Plug-in Development, select Plug-in Project.
  3. Enter a name for the project (mine is "CppcheckChecker") and click Next.
  4. Accept defaults and click Finish.
Figure 5. Creating a plug-in project
A screenshot showing how to create a Plug-in project.

Right after creating the new plug-in project, Eclipse will automatically open the MANIFEST.MF file. This is the file where we'll add Codan's dependencies.

In the editor, select the Dependencies tab and add the following to the Required Plug-ins list:

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

Eclipse plug-ins

I won't cover all the details of writing an Eclipse plug-in in this article because Eclipse isn't the focus of my discussion. See Resources for an introduction to writing Eclipse plug-ins.

Step 2. Create an error parser

We'll need an error parser to create editor markers from Cppcheck's output, so our next step is to extend Eclipse's C/C++ tooling with a plug in. We'll use Java code for this purpose because Eclipse itself is a Java application.

First, we'll create a class, CppcheckErrorParser, that implements org.eclipse.cdt.core.IErrorParser. We start by finding the pattern that Cppcheck uses when reporting code problems. The error parser will use this pattern to identify a line of output that represents a problem report, then extract from that output the information it needs to create an editor marker.

Listing 1. A pattern that matches Cppcheck's output
  // 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*(.*)");

Listing 2 shows how the error parser uses the pattern to extract the path and name of the file being checked, as well as the location, description, and severity of the found error. With this information, the error parser creates a new ProblemMarkerInfo and passes it to the given ErrorParserManager. ErrorParserManager is the class responsible for creating editor markers.

Listing 2. Processing Cppcheck's output
  @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;
  }
}

Mapping problem severities

Cppcheck defines its own problem severities, which are not the same as the ones used by editor markers. For example, the Cppcheck severity "style" does not have a counterpart in the Eclipse world. To overcome this issue, we need to create a mapping between the two kinds of problem severities. The method findSeverityCode (shown in Listing 3) demonstrates a straightforward way to implement this mapping:

Listing 3. Mapping problem severities
  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;
  }

After we've created the mapping, any problem reported by Cppcheck with severity "style" will be displayed in Eclipse using severity SEVERITY_INFO. This mapping defines only the default values for problem severities. As you will see later, it is possible to configure this mapping from the Codan Preferences page.

For CppcheckErrorParser to be recognized by Codan, it needs to be registered in the plugin.xml file, using the extension point org.eclipse.cdt.core.ErrorParser:

Listing 4. Registering the error parser
  <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>

Note in Listing 4 that the ErrorParser extension point was originally created for registering parsers for CDT's build tools. It is not specific to Codan. To indicate that CppcheckErrorParser should be used with Codan only, we add the context "codan."

Step 3. Create the code checker

AbstractExternalToolBasedChecker is the superclass for any external-tool-based Codan code checker. It provides most of the infrastructure necessary to invoke an external code-analysis tool. Because we're integrating Cppcheck, we'll call this class CppcheckChecker.

The first thing we need to do is specify the default values for the information, related to the external tool, which will be displayed on the Codan Preferences page.

This information, which should be passed to the checker's constructor, includes the following:

  • The name of the external code analysis tool, in this case Cppcheck.
  • The name of the tool's executable, which is cppcheck. We don't need to specify a path for the executable because we're assuming it is in the system's PATH.
  • The arguments to pass to the executable, which are contained in a single String. We specify "--enable=all" in order to enable all of Cppcheck's checks.
Listing 5. Default Cppcheck information
  public CppCheckChecker() {
    super(new ConfigurationSettings("Cppcheck", new File("cppcheck"), "--enable=all"));
  }

Note that Codan's Preferences page lets us modify both the executable path and the arguments to pass.

Mapping problem severities to problem IDs

Next we want to specify the IDs of the error parsers we'll be using, shown in Listing 6. The IDs must be the same as the ones used in the plugin.xml file.

Listing 6. Specifying the IDs of the error parser to use
  @Override
  protected String[] getParserIDs() {
    return new String[] { "com.dw.cdt.checkers.CppcheckErrorParser" };
  }

Back in Listing 2, we created a ProblemMarkerInfo and passed it to the given ErrorParserManager in order to create editor markers. ErrorParserManager will delegate the creation of editor markers to our newly created checker.

To have the checker create an editor marker, we need to override the method addMarker(ProblemMarkerInfo) (whose job it is to find another type of mismatch). Codan checkers cannot create editor markers directly from ProblemMarkerInfos. They have their own mechanism that uses problem IDs to figure out the appropriate severity for the created editor marker.

A problem ID is a unique ID that Codan uses to identify a code problem that is reported by a code checker. All code problems are displayed on Codan's Preferences page (see Figure 2).

Listing 7. Creating error markers
  @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);
  }

To find the problem ID that corresponds to a ProblemMarkerInfo's severity, we need to create a mapping between severities and problem IDs. Listing 8 shows how the mapping is implemented:

Listing 8. Mapping problem severities to problem IDs
  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");
  }

Code checkers that use an external code analysis tool need to indicate which of their problem IDs is considered the "reference." The reference problem ID is used to obtain the preference values of the checker (for example, the name of the external tool, as shown in Listing 5). It doesn't matter which problem ID is the reference because all the problems will share preferences.

Listing 9. Specifying the reference problem ID
  @Override
  protected String getReferenceProblemId() {
    return ERROR_PROBLEM_ID;
  }

The constant ERROR_PROBLEM_ID is defined in Listing 8.

Registering the checker

So that the code checker and all the problems it reports will show up on Codan's Preferences page (and thus be accessible to users), we need to register the checker with Codan's plugin.xml file.

Because we don't know all the problems that Cppcheck can report, and because we can't prevent Cppcheck from adding or removing code checks in future versions, we won't be able to register each individual problem. Instead, we'll group problems by severity and treat each group as an individual problem. In Listing 10 we register errors, warnings, and style violations as three individual problems:

Listing 10. Registering the checker and problem reports
  <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>

We specify the name of the checker that will be displayed to users in the category element. The IDs of the problems should be the same as the ones used in the checker (see Listing 8).

In the plugin.xml file, we specify the following about all three problems:

  • They are enabled by default.
  • They have the default severities "Error," "Warning," and "Info," respectively.
  • They have the message pattern: "{0},," which forces Codan to use the problem description as it was reported by Cppcheck.

Using Cppcheck in Codan

We can now see CppcheckChecker on the Codan Preferences page, as shown in Figure 6:

Figure 6. Cppcheck displayed on Codan's Preferences page
A screenshot of CppcheckChecker listed on the Codan Preferences page.

Figure 7 shows options for configuring how Cppcheck should report code errors:

Figure 7. Configure Cppcheck's error reporting
Options for configuring Cppcheck errors.

Figure 8 shows how Cppcheck reports code problems. Note that Cppcheck was automatically invoked after the file was saved.

Figure 8. A Cppcheck report
A screenshot of Cppcheck reporting code problems.

A downside to integration

One limitation of integrating Codan with external code analysis tools is that external-tool-based checkers cannot run while the user types. This is simply because an external tool cannot see a file's unsaved changes. So an external checker needs to be run when a file is open and when a file is saved.

This limitation is outweighed by the benefits of using a mature code-analysis tool, however. Integrating an external tool with Codan is also a lot easier and simpler than creating a regular checker, which requires deep knowledge of the C or C++ languages and CDT's AST implementation. By contrast, we were able to write CppcheckChecker with about 100 lines of simple Java code (contained in two classes) and 30 lines of XML.

In conclusion

Prior to the Eclipse Juno release, creating custom code checks for Codan required a good understanding of the C/C++ languages and CDT's own AST implementation. The Juno release of Eclipse CDT resolves that issue by letting developers create Codan code checkers, which can then delegate the heavy lifting to an external code-analysis tool.

In this article, we used just a little bit of Java code and XML to integrate Cppcheck with Codan, bringing together this popular C/C++ code analysis tool with the built-in code analysis framework for C/C++ programs in Eclipse. As I previously mentioned, you should be able to apply the process demonstrated here to your favorite code analysis tool. See Resources to learn more.

Resources

Learn

Get products and technologies

Discuss

  • Get involved in the developerWorks community. Connect with other developerWorks users while exploring dW's developer-driven blogs, forums, groups, and wikis.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology, Open source, XML
ArticleID=830239
ArticleTitle=Integrate an external code checker into Eclipse CDT
publish-date=08222012