diff --git a/src/main/java/edu/hm/hafner/analysis/parser/IarCstatParser.java b/src/main/java/edu/hm/hafner/analysis/parser/IarCstatParser.java new file mode 100644 index 000000000..befa8d092 --- /dev/null +++ b/src/main/java/edu/hm/hafner/analysis/parser/IarCstatParser.java @@ -0,0 +1,61 @@ +package edu.hm.hafner.analysis.parser; + +import edu.hm.hafner.analysis.Issue; +import edu.hm.hafner.analysis.IssueBuilder; +import edu.hm.hafner.analysis.RegexpLineParser; +import edu.hm.hafner.analysis.Severity; + +import java.util.Optional; +import java.util.regex.Matcher; + +/** + * A parser for the IAR CSTAT warnings. + * + * @author Lorenz Aebi + */ +public class IarCstatParser extends RegexpLineParser { + private static final long serialVersionUID = 7695540852439013425L; + + private static final String IAR_WARNING_PATTERN = ANT_TASK + + "(?:\"?(.*?)\"?[\\(,](\\d+)\\)?\\s+)?(Severity-(?:Low|Medium|High))\\[(\\S+)\\]:(.*)$"; + + /** + * Creates a new instance of {@link IarCstatParser}. + */ + public IarCstatParser() { + super(IAR_WARNING_PATTERN); + } + + @Override + protected boolean isLineInteresting(final String line) { + return line.contains("Severity-"); + } + + @Override + protected Optional createIssue(final Matcher matcher, final IssueBuilder builder) { + return builder.setSeverity(mapSeverity(matcher.group(3))) + .setMessage(normalizeWhitespaceInMessage(matcher.group(5))) + .setFileName(matcher.group(1)) + .setLineStart(matcher.group(2)) + .setCategory(matcher.group(4)) + .buildOptional(); + } + + private Severity mapSeverity(final String category) { + Severity severity; + if (category.equals("Severity-Low")) { + severity = Severity.WARNING_LOW; + } + else if (category.equals("Severity-High")) { + severity = Severity.WARNING_HIGH; + } + else { + severity = Severity.WARNING_NORMAL; + } + return severity; + } + + private String normalizeWhitespaceInMessage(final String message) { + return message.replaceAll("\\s+", " "); + } +} diff --git a/src/test/java/edu/hm/hafner/analysis/parser/IarCstatParserTest.java b/src/test/java/edu/hm/hafner/analysis/parser/IarCstatParserTest.java new file mode 100644 index 000000000..14db5b6d1 --- /dev/null +++ b/src/test/java/edu/hm/hafner/analysis/parser/IarCstatParserTest.java @@ -0,0 +1,74 @@ +package edu.hm.hafner.analysis.parser; + +import edu.hm.hafner.analysis.AbstractParserTest; +import edu.hm.hafner.analysis.Report; +import edu.hm.hafner.analysis.Severity; +import edu.hm.hafner.analysis.assertj.SoftAssertions; +import org.junit.jupiter.api.Test; + +import static edu.hm.hafner.analysis.assertj.Assertions.assertThat; +import static edu.hm.hafner.analysis.assertj.SoftAssertions.assertSoftly; + +/** + * Tests the class {@link IarCstatParser}. + * + * @author Lorenz Aebi + */ +class IarCstatParserTest extends AbstractParserTest { + IarCstatParserTest() { + super("iar-cstat.txt"); + } + + @Override + protected IarCstatParser createParser() { + return new IarCstatParser(); + } + + @Override + protected void assertThatIssuesArePresent(final Report report, final SoftAssertions softly) { + assertThat(report).hasSize(6).hasDuplicatesSize(0); + + softly.assertThat(report.get(0)) + .hasSeverity(Severity.WARNING_LOW) + .hasCategory("MISRAC2012-Rule-14.4_c") + .hasLineStart(129) + .hasLineEnd(129) + .hasMessage("Type of if condition is not boolean. MISRAC2012-Rule-14.4") + .hasFileName("src/main/hal/HalAdc.c"); + softly.assertThat(report.get(1)) + .hasSeverity(Severity.WARNING_LOW) + .hasCategory("MISRAC2012-Rule-8.4") + .hasLineStart(145) + .hasLineEnd(145) + .hasMessage("Definition of externally-linked `ADC0_IRQHandler()' has no compatible declaration. MISRAC2012-Rule-8.4") + .hasFileName("src/main/hal/HalAdcLS.c"); + softly.assertThat(report.get(2)) + .hasSeverity(Severity.WARNING_NORMAL) + .hasCategory("MISRAC2012-Rule-14.3_a") + .hasLineStart(131) + .hasLineEnd(131) + .hasMessage("Conditional expression `0!=PalLog_GetUpdateRate()' is always true. CERT-EXP17-C,MISRAC2012-Rule-14.3") + .hasFileName("src/main/pal/PalLog.c"); + softly.assertThat(report.get(3)) + .hasSeverity(Severity.WARNING_HIGH) + .hasCategory("PTR-null-fun-pos") + .hasLineStart(15) + .hasLineEnd(15) + .hasMessage("Function call `f1()' is immediately dereferenced, without checking for NULL. CERT-EXP34-C,CWE-476") + .hasFileName("cstat1.c"); + softly.assertThat(report.get(4)) + .hasSeverity(Severity.WARNING_LOW) + .hasCategory("RED-unused-assign") + .hasLineStart(18) + .hasLineEnd(18) + .hasMessage("Value assigned to variable `ch' is never used. CERT-MSC13-C,CWE-563") + .hasFileName("cstat1.c"); + softly.assertThat(report.get(5)) + .hasSeverity(Severity.WARNING_HIGH) + .hasCategory("ARR-inv-index") + .hasLineStart(16) + .hasLineEnd(16) + .hasMessage("Array `arr' 1st subscript 20 is out of bounds [0,9]. CERT-ARR33-C,CWE-119,CWE-120,CWE-121,CWE-124,CWE-126,CWE-127,CWE-129,MISRAC++2008-5-0-16,MISRAC2012-Rule-18.1") + .hasFileName("cstat2.c"); + } +} diff --git a/src/test/resources/edu/hm/hafner/analysis/parser/iar-cstat.txt b/src/test/resources/edu/hm/hafner/analysis/parser/iar-cstat.txt new file mode 100644 index 000000000..304ae53cf --- /dev/null +++ b/src/test/resources/edu/hm/hafner/analysis/parser/iar-cstat.txt @@ -0,0 +1,6 @@ +"src\main\hal\HalAdc.c",129 Severity-Low[MISRAC2012-Rule-14.4_c]:Type of if condition is not boolean. MISRAC2012-Rule-14.4 +"src\main\hal\HalAdcLS.c",145 Severity-Low[MISRAC2012-Rule-8.4]:Definition of externally-linked `ADC0_IRQHandler()' has no compatible declaration. MISRAC2012-Rule-8.4 +"src\main\pal\PalLog.c",131 Severity-Medium[MISRAC2012-Rule-14.3_a]:Conditional expression `0!=PalLog_GetUpdateRate()' is always true. CERT-EXP17-C,MISRAC2012-Rule-14.3 +"cstat1.c",15 Severity-High[PTR-null-fun-pos]: Function call `f1()' is immediately dereferenced, without checking for NULL. CERT-EXP34-C,CWE-476 +"cstat1.c",18 Severity-Low[RED-unused-assign]: Value assigned to variable `ch' is never used. CERT-MSC13-C,CWE-563 +"cstat2.c",16 Severity-High[ARR-inv-index]: Array `arr' 1st subscript 20 is out of bounds [0,9]. CERT-ARR33-C,CWE-119,CWE-120,CWE-121,CWE-124,CWE-126,CWE-127,CWE-129,MISRAC++2008-5-0-16,MISRAC2012-Rule-18.1