Skip to content

Commit

Permalink
remove Cppcheck XML format V1 support
Browse files Browse the repository at this point in the history
- V1 report support is deprecated: use XML V2 format instead (--xml-version=2)
- support Cppcheck V1.69++ (remove messages from former versions)
- close #1247
  • Loading branch information
guwirth committed Mar 29, 2020
1 parent 53c4fb9 commit 044c183
Show file tree
Hide file tree
Showing 23 changed files with 2,647 additions and 4,446 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,173 @@
package org.sonar.cxx.sensors.cppcheck;

import java.io.File;
import java.nio.file.Paths;
import javax.annotation.Nullable;
import javax.xml.stream.XMLStreamException;
import org.codehaus.staxmate.in.SMHierarchicCursor;
import org.codehaus.staxmate.in.SMInputCursor;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.cxx.sensors.utils.EmptyReportException;
import org.sonar.cxx.sensors.utils.StaxParser;
import org.sonar.cxx.utils.CxxReportIssue;
import org.sonar.cxx.utils.CxxReportLocation;

public interface CppcheckParser {
public class CppcheckParser {

private static final Logger LOG = Loggers.get(CppcheckParser.class);

private final CxxCppCheckSensor sensor;

public CppcheckParser(CxxCppCheckSensor sensor) {
this.sensor = sensor;
}

private static String requireAttributeSet(@Nullable String attributeValue, String errorMsg) {
if (attributeValue == null || attributeValue.isEmpty()) {
throw new IllegalArgumentException(errorMsg);
}
return attributeValue;
}

private static String createIssueText(String msg, boolean isInconclusive) {
if (isInconclusive) {
return "[inconclusive] " + msg;
}
return msg;
}

public void processReport(final SensorContext context, File report)
throws javax.xml.stream.XMLStreamException {
LOG.debug("Parsing 'Cppcheck V2' format");
var parser = new StaxParser(new StaxParser.XmlStreamHandler() {
/**
* {@inheritDoc}
*/
@Override
public void stream(SMHierarchicCursor rootCursor) throws XMLStreamException {
boolean parsed = false;

try {
rootCursor.advance();
} catch (com.ctc.wstx.exc.WstxEOFException eofExc) {
throw new EmptyReportException("Cannot read cppcheck report (format V2)", eofExc);
}

try {
String version = rootCursor.getAttrValue("version");
if ("2".equals(version)) {
SMInputCursor errorsCursor = rootCursor.childElementCursor("errors");
if (errorsCursor.getNext() != null) {
parsed = true;
SMInputCursor errorCursor = errorsCursor.childElementCursor("error");

while (errorCursor.getNext() != null) {
processErrorTag(context, errorCursor);
}
}
}
} catch (RuntimeException e) {
throw new XMLStreamException("processReport failed", e);
}

if (!parsed) {
throw new XMLStreamException();
}
}

private void processErrorTag(final SensorContext context, SMInputCursor errorCursor) throws XMLStreamException {
String id = requireAttributeSet(errorCursor.getAttrValue("id"),
"Missing mandatory attribute /results/errors/error[@id]");
String msg = requireAttributeSet(errorCursor.getAttrValue("msg"),
"Missing mandatory attribute /results/errors/error[@msg]");
boolean isInconclusive = "true".equals(errorCursor.getAttrValue("inconclusive"));
String issueText = createIssueText(msg, isInconclusive);
CxxReportIssue issue = null;

SMInputCursor locationCursor = errorCursor.childElementCursor("location");
while (locationCursor.getNext() != null) {
String file = locationCursor.getAttrValue("file");
String line = locationCursor.getAttrValue("line");
String info = locationCursor.getAttrValue("info");

if (file != null) {
file = file.replace('\\', '/');
}

if ("*".equals(file)) {
// findings on project level
file = null;
line = null;
info = null;
}

final boolean isLocationInProject = isLocationInProject(file, context);
if (issue == null) {
// primary location
// if primary location cannot be found in the current project (in
// the current module) we are not interested in this <error>
if (!isLocationInProject) {
LOG.debug("Cannot find the file '{}', skipping violations", file);
return;
}

issue = new CxxReportIssue(id, file, line, issueText);
// add the same <file>:<line> second time if there is additional
// information about the flow/analysis
if (info != null && !msg.equals(info)) {
issue.addLocation(file, line, info);
}
} else if (info != null) {
// secondary location
// secondary location cannot reference a file, which is missing in
// the current project (in the current module). If such case occurs
// we'll use a primary location and move the affected path to the
// info
if (isLocationInProject) {
issue.addLocation(file, line, info);
} else {
CxxReportLocation primaryLocation = issue.getLocations().get(0);
String primaryFile = primaryLocation.getFile();
String primaryLine = primaryLocation.getLine();

var extendedInfo = new StringBuilder(512);
extendedInfo.append(makeRelativePath(file, primaryFile)).append(":").append(line).append(" ")
.append(info);
issue.addLocation(primaryFile, primaryLine, extendedInfo.toString());
}
}
}

// no <location> tags: issue raised on the whole module/project
if (issue == null) {
issue = new CxxReportIssue(id, null, null, issueText);
}
sensor.saveUniqueViolation(context, issue);
}

private String makeRelativePath(String path, String basePath) {
try {
return Paths.get(basePath).relativize(Paths.get(path)).toString();
} catch (IllegalArgumentException e) {
return path;
}
}

private boolean isLocationInProject(@Nullable String file, final SensorContext context) {
// file == null means that we are dealing with a warning for the whole
// project/module
return (file == null) || (sensor.getInputFileIfInProject(context, file) != null);
}
});

parser.parse(report);
}

@Override
public String toString() {
return getClass().getSimpleName();
}

void processReport(SensorContext context, File report)
throws javax.xml.stream.XMLStreamException;
}

This file was deleted.

Loading

0 comments on commit 044c183

Please sign in to comment.