Skip to content

show some Cppcheck messages on file-level #60

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 52 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,59 @@ See

## Known Issues

### Analyzing header files

`cppcheck` is not designed to be run on header files (`.h`) directly, as must be done for this
plugin, and as a result may have false positives.

When run on header files directly, `cppcheck` defaults to C as the language, which will generate
false positives for C++ projects. C++ projects should append `--language=c++` to the
`cppcheck` options.
false positives for C++ projects. So `--language=c++` is implicitly added as option when analyzing header files.

It will also provide `unusedFunction` and `unusedStructMember` false positives so these findings are being suppressed.

### Analyzing multiple configurations

By default `cppcheck` tries to determine all the available configurations for a file (i.e. all combination of the used
preprocessor defines). As the plugin doesn't get the current list of defines this may lead to findings shown in code
which is shown as disabled in the editor. To check just a specific configuration you can either add defines using `-D`
to the options. Or you can limit the configurations to a single one adding `--max-configs=1`.

By default Limiting the configurations also decreases the time of the analysis.

By default a maximum of 12 configurations is checked. This may lead to some code which might actually be active not to
show any findings. This can also be controlled by the `--max-configs=<n>` option.

### Multiple include paths

No additional includes path are being passed to `cppcheck` for the analysis which might result in false positives or not
all findings being shown.

You can add additional include path using the `-I <path>` options.

### Batch analysis

The batch analysis passes the files individually to `cppcheck` just like the highlighting inspections. So if you pass a
folder to the batch analysis it might not show the same findings as when passing a folder to `cppcheck` itself.

It will also pass all the contents of the folder to the analysis and not just project files. This might lead to
unexpected findings.

Also some findings in headers files triggered by the analysis of a source files are not being shown.

### Showing raw output

Currently there is no way to view the raw output of the `cppcheck` execution.

### External libraries / System includes

`cppcheck` does not support analyzing of external library or system includes. It provides profiles for several external
libraries which describe the contents and behavior of the includes which allows it to finding issues with usage of them
in the code. To add such a profile to your analysis you need to specify it via the `--library=<name>` option. The
available profile can be found in the `cfg` folder of your `cppcheck` installation.

### Global options

Currently the configured options are global and not per project.

## Development

Expand All @@ -60,6 +107,9 @@ Deployment.

## Releases

### 1.7.0 - XXXX-XX-XX
- Show some Cppcheck messages (`toomanyconfigs`, `missingInclude`, `noValidConfiguration`) on file-level. See [Known Issues](#known-issues) on how to fix these. (Contribution by @firewave)

### 1.6.2 - 2022-01-25

- Fixed `NullPointerException` with Cppcheck < 1.89 caused by missing `column` attribute in XML result.
Expand Down
10 changes: 3 additions & 7 deletions resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<idea-plugin>
<id>com.github.johnthagen.cppcheck</id>
<name>cppcheck</name>
<version>1.6.2</version>
<version>1.7.0</version>
<vendor email="[email protected]" url="http://github.com/johnthagen">johnthagen</vendor>

<description><![CDATA[
Expand Down Expand Up @@ -52,15 +52,11 @@
<br/>

<b>Known issues:</b><br/>
Cppcheck is not designed to be run on header files (.h) directly, as must be done for this
plugin, and as a result may have false positives.<br/>
When run on header files directly, Cppcheck defaults to C as the language, which will
generate false positives for C++ projects. C++ projects should leave --language=c++ appended to the
Cppcheck options.<br/>
Please refer to <a href="https://github.com/johnthagen/clion-cppcheck#known-issues">Known Issues</a>.<br/>
]]></description>

<change-notes><![CDATA[
- Fixed `NullPointerException` with Cppcheck < 1.89 caused by missing 'column' attribute in XML result.
- Show some Cppcheck messages (toomanyconfigs, missingInclude, noValidConfiguration) on file-level. See <a href="https://github.com/johnthagen/clion-cppcheck#known-issues">Known Issues</a> on how to fix these. (Contribution by @firewave)
]]>
</change-notes>

Expand Down
104 changes: 65 additions & 39 deletions src/com/github/johnthagen/cppcheck/CppCheckInspectionImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,6 @@ public static List<ProblemDescriptor> parseOutput(@NotNull final PsiFile psiFile

final String id = attributes.getNamedItem("id").getNodeValue();

// Skip the "toomanyconfigs" error
/*
<error id="toomanyconfigs" severity="information" msg="Too many #ifdef configurations - cppcheck only checks 1 of 12 configurations. Use --force to check all configurations." verbose="The checking of the file will be interrupted because there are too many #ifdef configurations. Checking of all #ifdef configurations can be forced by --force command line option or from GUI preferences. However that may increase the checking time." cwe="398">
<location file="C:\Users\Name\AppData\Local\Temp\___valueflow.cpp" line="0" column="0"/>
</error>
*/
if (id.equals("toomanyconfigs")) {
continue;
}

// Skip the "missingIncludeSystem" error
/*
<error id="missingIncludeSystem" severity="information" msg="Cppcheck cannot find all the include files (use --check-config for details)" verbose="Cppcheck cannot find all the include files. Cppcheck can check the code without the include files found. But the results will probably be more accurate if all the include files are found. Please check your project&apos;s include directories and add all of them as include directories for Cppcheck. To see what files Cppcheck cannot find use --check-config."/>
Expand All @@ -116,11 +106,6 @@ public static List<ProblemDescriptor> parseOutput(@NotNull final PsiFile psiFile
continue;
}

// suppress this warnings for now - will be properly handled in an upcoming patch
if (id.equals("noValidConfiguration") || id.equals("missingInclude")) {
continue;
}

// we are never interested in these
if (id.equals("unmatchedSuppression") || id.equals("purgedConfiguration")) {
continue;
Expand Down Expand Up @@ -148,49 +133,90 @@ public static List<ProblemDescriptor> parseOutput(@NotNull final PsiFile psiFile
}
}

String fileName = null;
int lineNumber = 0;
int column = 0;

/*
<error id="missingInclude" severity="information" msg="Cppcheck cannot find all the include files (use --check-config for details)" verbose="Cppcheck cannot find all the include files. Cppcheck can check the code without the include files found. But the results will probably be more accurate if all the include files are found. Please check your project&apos;s include directories and add all of them as include directories for Cppcheck. To see what files Cppcheck cannot find use --check-config."/>
*/
// TODO: handle like any warning when Cppcheck provides the --check-config results with the normal analysis
if (id.equals("missingInclude")) {
// is a global warning without location information
}
// ignore entries without location e.g. missingIncludeSystem
if (location == null) {
else if (location == null) {
CppcheckNotification.send("no location for " + psiFile.getVirtualFile().getCanonicalPath(),
id + " " + severity + " " + inconclusive + " " + errorMessage,
NotificationType.ERROR);
continue;
}
else {
final NamedNodeMap locationAttributes = location.getAttributes();
fileName = new File(locationAttributes.getNamedItem("file").getNodeValue()).getName();
lineNumber = Integer.parseInt(locationAttributes.getNamedItem("line").getNodeValue());
final Node columnAttr = locationAttributes.getNamedItem("column");
// TODO: use in ProblemDescriptor
column = -1;
// the "column" attribute was added in Cppcheck 1.89
if (columnAttr != null) {
column = Integer.parseInt(columnAttr.getNodeValue());
}

final NamedNodeMap locationAttributes = location.getAttributes();
final String fileName = new File(locationAttributes.getNamedItem("file").getNodeValue()).getName();
int lineNumber = Integer.parseInt(locationAttributes.getNamedItem("line").getNodeValue());
final Node columnAttr = locationAttributes.getNamedItem("column");
// TODO: use in ProblemDescriptor
int column = -1;
// the "column" attribute was added in Cppcheck 1.89
if (columnAttr != null) {
column = Integer.parseInt(columnAttr.getNodeValue());
// If a file #include's header files, Cppcheck will also run on the header files and print
// any errors. These errors don't apply to the current file and should not be drawn. They can
// be distinguished by checking the file name.
if (!fileName.equals(sourceFileName)) {
continue;
}
}

// If a file #include's header files, Cppcheck will also run on the header files and print
// any errors. These errors don't apply to the current file and should not be drawn. They can
// be distinguished by checking the file name.
if (!fileName.equals(sourceFileName)) {
continue;
}
// leaving it at null will report it for the whole file
TextRange range = null;

// Cppcheck error
if (lineNumber <= 0 || lineNumber > document.getLineCount()) {
/*
<error id="toomanyconfigs" severity="information" msg="Too many #ifdef configurations - cppcheck only checks 1 of 12 configurations. Use --force to check all configurations." verbose="The checking of the file will be interrupted because there are too many #ifdef configurations. Checking of all #ifdef configurations can be forced by --force command line option or from GUI preferences. However that may increase the checking time." cwe="398">
<location file="C:\Users\Name\AppData\Local\Temp\___valueflow.cpp" line="0" column="0"/>
</error>
*/
if (id.equals("toomanyconfigs")) {
// show as message for the file
}
// TODO: handle like any warning when Cppcheck provides the --check-config results with the normal analysis
else if (id.equals("missingInclude")) {
// show as message for the file
}
/*
<error id="noValidConfiguration" severity="information" msg="This file is not analyzed. Cppcheck failed to extract a valid configuration. Use -v for more details." verbose="This file is not analyzed. Cppcheck failed to extract a valid configuration. The tested configurations have these preprocessor errors:\012&apos;&apos; : [/mnt/s/GitHub/cppcheck-fw/gui/temp/moc_platforms.cpp:13] #error &quot;The header file &apos;platforms.h&apos; doesn&apos;t include &lt;QObject&gt;.&quot;\012Q_MOC_OUTPUT_REVISION : [/mnt/s/GitHub/cppcheck-fw/gui/temp/moc_platforms.cpp:15] #error &quot;This file was generated using the moc from 5.12.5. It&quot;">
<location file="/mnt/s/GitHub/cppcheck-fw/gui/temp/moc_platforms.cpp" line="0" column="0"/>
</error>
*/
else if (id.equals("noValidConfiguration")) {
// show as message for the file
// show the verbose message as notification since it contains important details
final String verboseMessage = attributes.getNamedItem("verbose").getNodeValue();
CppcheckNotification.send("noValidConfiguration for "+ psiFile.getVirtualFile().getCanonicalPath(),
verboseMessage,
NotificationType.INFORMATION);
}
else if (lineNumber <= 0 || lineNumber > document.getLineCount()) {
CppcheckNotification.send("line number out-of-bounds for " + psiFile.getVirtualFile().getCanonicalPath(),
id + " " + severity + " " + inconclusive + " " + errorMessage + " " + fileName + " " + lineNumber + " " + column,
NotificationType.ERROR);
continue;
}
else {
// Document counts lines starting at 0, rather than 1 like in cppcheck.
lineNumber -= 1;

// Document counts lines starting at 0, rather than 1 like in cppcheck.
lineNumber -= 1;

final int lineStartOffset = DocumentUtil.getFirstNonSpaceCharOffset(document, lineNumber);
final int lineEndOffset = document.getLineEndOffset(lineNumber);
final int lineStartOffset = DocumentUtil.getFirstNonSpaceCharOffset(document, lineNumber);
final int lineEndOffset = document.getLineEndOffset(lineNumber);
range = TextRange.create(lineStartOffset, lineEndOffset);
}

final ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
psiFile,
TextRange.create(lineStartOffset, lineEndOffset),
range,
"Cppcheck: (" + severity + (inconclusive ? INCONCLUSIVE_TEXT : "") + ") " + id + ": " + errorMessage,
severityToHighlightType(severity),
true);
Expand Down