Skip to content

Commit

Permalink
Merge pull request #883 from evahabeeballah/polyspace-parser
Browse files Browse the repository at this point in the history
Fix parsing of line and column numbers in Polyspace parser
  • Loading branch information
uhafner authored Feb 2, 2023
2 parents c336bd6 + e16ece1 commit 9286ec4
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 35 deletions.
59 changes: 35 additions & 24 deletions src/main/java/edu/hm/hafner/analysis/parser/PolyspaceParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
import edu.hm.hafner.analysis.ReaderFactory;
import edu.hm.hafner.analysis.Report;
import edu.hm.hafner.analysis.Severity;
import edu.hm.hafner.util.IntegerParser;

import static org.apache.commons.lang3.StringUtils.*;

/**
* A parser for Polyspace Bug Finder and Code Prover results.
* Used for .csv files generated from Bugfinder and CodeProver tools
* A parser for Polyspace Bug Finder and Code Prover results. Used for .csv files generated from Bugfinder and
* CodeProver tools
*
* @author Eva Habeeb
*/
Expand All @@ -31,45 +32,30 @@ public class PolyspaceParser extends IssueParser {

@Override
public Report parse(final ReaderFactory reader) throws ParsingException {
try (Stream<String> lines = reader.readStream().skip(1)) {
try (Stream<String> lines = reader.readStream()) {
return parse(lines);
}
}

private Report parse(final Stream<String> lines) {
try (IssueBuilder builder = new IssueBuilder()) {
int lineNumber;
int colNumber;
int limit;
Report report = new Report();

Iterator<String> lineIterator = lines.iterator();
int offset = detectLineOffset(lineIterator);

while (lineIterator.hasNext()) {
String line = lineIterator.next();
/* Checks whether "CWE" field is found, which defines the difference between
a BugFinder file and a CodeProver report */
if (line.contains("CWE")) {
// BugFinder result file has 16 columns
limit = 16;
lineNumber = 14;
colNumber = 15;
}
else {
// CodePRover file has 15 columns
limit = 15;
lineNumber = 13;
colNumber = 14;
}

String[] attributes = line.split("\\t", limit);
String[] attributes = line.split("\\t", 15 + offset);
if (containsAnyIgnoreCase(attributes[9], "Unreviewed", "To investigate", "To fix", "Other")) {
builder.setFileName(attributes[8]);
builder.setCategory(attributes[2]);
builder.setDescription(attributes[1]);
builder.setMessage("Check: " + attributes[5] + " " + attributes[6]);
builder.setModuleName(attributes[7]);
builder.setColumnStart(attributes[colNumber]);
builder.setLineStart(attributes[lineNumber]);
builder.setColumnStart(IntegerParser.parseInt(attributes[14 + offset]));
builder.setLineStart(IntegerParser.parseInt(attributes[13 + offset]));
builder.setSeverity(mapPriority(attributes));
builder.setAdditionalProperties(attributes[0]);

Expand All @@ -80,7 +66,32 @@ private Report parse(final Stream<String> lines) {
}
}

@SuppressWarnings({"PMD.UseVarargs", "PMD.CyclomaticComplexity" })
/**
* Checks whether the "CWE" field is found in the header, which defines the difference between BugFinder file and a
* CodeProver reports.
*
* @param lineIterator
* the iterator to read the lines
*
* @return the offset to the line and column index (1 for BugFinder, 0 for CodeProver)
*/
private int detectLineOffset(final Iterator<String> lineIterator) {
if (readHeader(lineIterator).contains("CWE ID")) {
return 1; // BugFinder result file has 16 columns
}
else {
return 0; // CodeProver file has 15 columns
}
}

private String readHeader(final Iterator<String> lineIterator) {
if (lineIterator.hasNext()) {
return lineIterator.next();
}
return EMPTY;
}

@SuppressWarnings({"PMD.UseVarargs", "PMD.CyclomaticComplexity"})
private Severity mapPriority(final String[] attributes) {
if (equalsIgnoreCase(attributes[SEVERITY_INDEX], "Unset")) {
if (equalsIgnoreCase(attributes[FAMILY_INDEX], "Defect")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package edu.hm.hafner.analysis.parser;

import org.junit.jupiter.api.Test;

import edu.hm.hafner.analysis.AbstractParserTest;
import edu.hm.hafner.analysis.Report;
import edu.hm.hafner.analysis.Severity;
import edu.hm.hafner.analysis.assertions.SoftAssertions;

import static edu.hm.hafner.analysis.assertions.Assertions.*;

/**
* Tests the class {@link PolyspaceParser}.
*
* @author Eva Habeeb
*/
class PolyspaceParserTest extends AbstractParserTest {
/**
* Creates a new instance of {@link PolyspaceParserTest}.
*/
protected PolyspaceParserTest() {
PolyspaceParserTest() {
super("polyspace.csv");
}

Expand All @@ -32,6 +33,7 @@ protected void assertThatIssuesArePresent(final Report report, final SoftAsserti
.hasMessage("Check: Null pointer Impact: High")
.hasModuleName("calculate()")
.hasCategory("memory")
.hasColumnStart(49)
.hasDescription("Defect")
.hasSeverity(Severity.WARNING_HIGH);
softly.assertThat(report.get(1))
Expand All @@ -53,5 +55,42 @@ protected void assertThatIssuesArePresent(final Report report, final SoftAsserti
.hasModuleName("tester()")
.hasSeverity(Severity.WARNING_NORMAL);
}

@Test
void polyspaceCPTest() {
Report warnings = parse("polyspace_cp.csv");
assertThat(warnings).hasSize(4);

try (SoftAssertions softly = new SoftAssertions()) {
softly.assertThat(warnings.get(0)).hasLineStart(30)
.hasFileName("D:/workspace/math.c")
.hasCategory("Data flow")
.hasDescription("Run-time Check")
.hasMessage("Check: Unreachable code")
.hasModuleName("xinitialize()")
.hasColumnStart(4)
.hasSeverity(Severity.WARNING_HIGH);
softly.assertThat(warnings.get(1)).hasLineStart(34)
.hasFileName("D:/sample.h")
.hasCategory("Data flow")
.hasDescription("Run-time Check")
.hasModuleName("method_a()")
.hasColumnStart(4)
.hasSeverity(Severity.WARNING_NORMAL);
softly.assertThat(warnings.get(2)).hasLineStart(66)
.hasDescription("Run-time Check")
.hasModuleName("errorCheck()")
.hasColumnStart(4)
.hasSeverity(Severity.WARNING_HIGH);
softly.assertThat(warnings.get(3)).hasLineStart(217)
.hasDescription("MISRA C:2012")
.hasMessage("Check: 10.1 Operands shall not be of an inappropriate essential type. Category: Required")
.hasFileName("/file/SERVICE.c")
.hasModuleName("a_message()")
.hasColumnStart(27)
.hasCategory("10 The essential type model")
.hasSeverity(Severity.WARNING_NORMAL);
}
}
}

14 changes: 7 additions & 7 deletions src/test/resources/edu/hm/hafner/analysis/parser/polyspace.csv
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
ID Family Group Color New Check Information Function File Status Severity Comment CWE ID Key Line Col
3547 Defect memory Red yes Null pointer Impact: High calculate() D:\Jenkins\workspace\example.c Unreviewed Unset CWE-476 CWE-690 123456789 222 49
1320 Defect Programming Red yes Qualifier removed in conversion Impact: Low D:\example/test.c Unreviewed Unset CWE-704 123456789 276 5
184 Custom Rule 4 Structs Not Applicable yes 4.3 All struct fields must follow the specified pattern. File() D:\sample.h Unreviewed High 123456789 631 16
5630 Run-time Check memory Red yes Out of bounds array index tester() /jenkins/example.c Unreviewed Medium 123456789 468 55
15484 Run-time Check Data flow Gray yes Unreachable code init() /jenkins/example.c Unreviewed Low 123456789 27 4
420 MISRA C:2012 11 Pointer type conversions Not Applicable yes 11.1 Conversions shall not be performed between a pointer to a function and any other type. Category: Required tester() /example/myinit.c Unreviewed Unset 123456789 512 48
421 MISRA C:2012 11 Pointer type conversions Not Applicable yes 11.8 A cast shall not remove any const or volatile qualification from the type pointed to by a pointer. Category: Required calculate() /jenkins/main.c Unreviewed Unset 123456789 70 5
3528 Guidelines Software Complexity Not Applicable no 123 Depth of call nesting exceeds threshold Category: HIS init() D:\workspace/math.c Unreviewed Unset 123456789 406 10
3529 Guidelines Software Complexity Not Applicable no 123 Number of calling functions exceeds threshold Category: HIS main() D:\Jenkins\main.c Unreviewed Unset 123456789 131 10
184 Custom Rule 4 Structs Not Applicable yes 4.3 All struct fields must follow the specified pattern. File() D:\sample.h Unreviewed High CWE-74 123456789 631 16
5630 Run-time Check memory Red yes Out of bounds array index tester() /jenkins/example.c Unreviewed Medium CWE-864 1236789 468 55
15484 Run-time Check Data flow Gray yes Unreachable code init() /jenkins/example.c Unreviewed Low CWE-149 1236089 27 4
420 MISRA C:2012 11 Pointer type conversions Not Applicable yes 11.1 Conversions shall not be performed between a pointer to a function and any other type. Category: Required tester() /example/myinit.c Unreviewed Unset CWE-4135 733913 512 48
421 MISRA C:2012 11 Pointer type conversions Not Applicable yes 11.8 A cast shall not remove any const or volatile qualification from the type pointed to by a pointer. Category: Required calculate() /jenkins/main.c Unreviewed Unset CWE-317 013751 70 5
3528 Guidelines Software Complexity Not Applicable no 123 Depth of call nesting exceeds threshold Category: HIS init() D:\workspace/math.c Unreviewed Unset CWE-612 9155 406 10
3529 Guidelines Software Complexity Not Applicable no 123 Number of calling functions exceeds threshold Category: HIS main() D:\Jenkins\main.c Unreviewed Unset CWE-554 9991112 131 10
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ID Family Group Color New Check Information Function File Status Severity Comment Key Line Col
16153 Run-time Check Data flow Red yes Unreachable code xinitialize() D:\workspace/math.c Unreviewed Unset CC1849A44441 30 4
16155 Run-time Check Data flow Gray yes Unreachable code method_a() D:\sample.h Unreviewed Medium CC10009C49A1 34 4
16144 Run-time Check Data flow Gray yes Unreachable code errorCheck() D:\Jenkins\main.c Unreviewed High 81111559C49A1 66 4
2436 MISRA C:2012 10 The essential type model Not Applicable yes 10.1 Operands shall not be of an inappropriate essential type. Category: Required a_message() /file/SERVICE.c Unreviewed Unset 844C182E62C8B9 217 27

0 comments on commit 9286ec4

Please sign in to comment.