diff --git a/pom.xml b/pom.xml
index 84e4aaabf..cef26419d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
edu.hm.hafner
analysis-model
- 4.0.1-SNAPSHOT
+ 4.1.0-SNAPSHOT
jar
diff --git a/src/main/java/edu/hm/hafner/analysis/parser/CMakeParser.java b/src/main/java/edu/hm/hafner/analysis/parser/CMakeParser.java
new file mode 100644
index 000000000..d44cd1984
--- /dev/null
+++ b/src/main/java/edu/hm/hafner/analysis/parser/CMakeParser.java
@@ -0,0 +1,52 @@
+package edu.hm.hafner.analysis.parser;
+
+import java.util.Optional;
+import java.util.regex.Matcher;
+
+import org.apache.commons.lang3.StringUtils;
+
+import edu.hm.hafner.analysis.Issue;
+import edu.hm.hafner.analysis.IssueBuilder;
+import edu.hm.hafner.analysis.Severity;
+import edu.hm.hafner.analysis.LookaheadParser;
+import edu.hm.hafner.util.LookaheadStream;
+
+/**
+ * A parser for CMake warnings.
+ *
+ * @author Uwe Brandt
+ */
+public class CMakeParser extends LookaheadParser {
+ private static final long serialVersionUID = 8149238560432255036L;
+
+ private static final String CMAKE_WARNING_PATTERN =
+ "^(?.*?)CMake\\s+(?Warning|Deprecation Warning|Error)(?:.*?(?\\S+)){0,1}(?::(?\\d+)\\s+(?\\S+)){0,1}\\s*:";
+
+ /**
+ * Creates a new instance of {@link CMakeParser}.
+ */
+ public CMakeParser() {
+ super(CMAKE_WARNING_PATTERN);
+ }
+
+ @Override
+ protected Optional createIssue(final Matcher matcher, final LookaheadStream lookahead,
+ final IssueBuilder builder) {
+ // if the category is contained in brackets, remove those brackets
+ String category = StringUtils.strip(matcher.group("category"), "()");
+ int prefixLength = matcher.group("prefix").length();
+ return builder.setFileName(matcher.group("file"))
+ .setLineStart(matcher.group("line"))
+ .setCategory(category)
+ .setMessage(readMessage(lookahead, prefixLength))
+ .setSeverity(Severity.guessFromString(matcher.group("type")))
+ .buildOptional();
+ }
+
+ private String readMessage(final LookaheadStream lookahead, final int prefixLength) {
+ if (lookahead.hasNext()) {
+ return lookahead.next().substring(prefixLength).trim();
+ }
+ return "";
+ }
+}
diff --git a/src/test/java/edu/hm/hafner/analysis/parser/CMakeParserTest.java b/src/test/java/edu/hm/hafner/analysis/parser/CMakeParserTest.java
new file mode 100644
index 000000000..6e197a7a2
--- /dev/null
+++ b/src/test/java/edu/hm/hafner/analysis/parser/CMakeParserTest.java
@@ -0,0 +1,76 @@
+package edu.hm.hafner.analysis.parser;
+
+import edu.hm.hafner.analysis.AbstractParserTest;
+import edu.hm.hafner.analysis.Severity;
+import edu.hm.hafner.analysis.Report;
+import edu.hm.hafner.analysis.assertj.SoftAssertions;
+
+/**
+ * Tests the class {@link CMakeParser}.
+ *
+ * @author Uwe Brandt
+ */
+class CMakeParserTest extends AbstractParserTest {
+ CMakeParserTest() {
+ super("cmake.txt");
+ }
+
+ @Override
+ protected void assertThatIssuesArePresent(final Report report, final SoftAssertions softly) {
+ softly.assertThat(report).hasSize(8);
+ softly.assertThat(report.get(0))
+ .hasSeverity(Severity.WARNING_NORMAL)
+ .hasCategory("")
+ .hasLineStart(0)
+ .hasMessage("Manually-specified variables were not used by the project")
+ .hasFileName("-");
+ softly.assertThat(report.get(1))
+ .hasSeverity(Severity.WARNING_NORMAL)
+ .hasCategory("")
+ .hasLineStart(0)
+ .hasMessage("The build directory is a subdirectory of the source directory.")
+ .hasFileName("CMakeLists.txt");
+ softly.assertThat(report.get(2))
+ .hasSeverity(Severity.WARNING_NORMAL)
+ .hasCategory("option")
+ .hasLineStart(10)
+ .hasMessage("I'm the message")
+ .hasFileName("tools/gtest-1.8/googlemock/CMakeLists.txt");
+ softly.assertThat(report.get(3))
+ .hasSeverity(Severity.WARNING_NORMAL)
+ .hasCategory("message")
+ .hasLineStart(423)
+ .hasMessage("Special workaround applied")
+ .hasFileName("project/utils/fancy.cmake");
+ softly.assertThat(report.get(4))
+ .hasSeverity(Severity.ERROR)
+ .hasCategory("message")
+ .hasLineStart(2)
+ .hasMessage("Uh oh !$%@!")
+ .hasFileName("error.cmake");
+ softly.assertThat(report.get(5))
+ .hasSeverity(Severity.WARNING_NORMAL)
+ .hasCategory("message")
+ .hasLineStart(23)
+ .hasMessage("function foo is deprecated, use bar instead")
+ .hasFileName("legacy.cmake");
+ softly.assertThat(report.get(6))
+ .hasSeverity(Severity.WARNING_NORMAL)
+ .hasCategory("nonexistingcategory")
+ .hasLineStart(357)
+ .hasMessage("strange things can happen")
+ .hasFileName("unlikely.cmake");
+ softly.assertThat(report.get(7))
+ .hasSeverity(Severity.WARNING_NORMAL)
+ .hasCategory("message")
+ .hasLineStart(362)
+ .hasMessage("")
+ .hasFileName("unlikely.cmake");
+ }
+
+ @Override
+ protected CMakeParser createParser() {
+ return new CMakeParser();
+ }
+}
+
diff --git a/src/test/resources/edu/hm/hafner/analysis/parser/cmake.txt b/src/test/resources/edu/hm/hafner/analysis/parser/cmake.txt
new file mode 100644
index 000000000..08541e7f2
--- /dev/null
+++ b/src/test/resources/edu/hm/hafner/analysis/parser/cmake.txt
@@ -0,0 +1,22 @@
+[step1] CMake Warning:
+[step1] Manually-specified variables were not used by the project
+
+[step2] CMake Warning in CMakeLists.txt:
+[step2] The build directory is a subdirectory of the source directory.
+
+CMake Warning (dev) at tools/gtest-1.8/googlemock/CMakeLists.txt:10 (option):
+ I'm the message
+
+CMake Warning at project/utils/fancy.cmake:423 (message):
+ Special workaround applied
+
+CMake Error at error.cmake:2 (message):
+ Uh oh !$%@!
+
+CMake Deprecation Warning at legacy.cmake:23 (message):
+ function foo is deprecated, use bar instead
+
+CMake Warning at unlikely.cmake:357 nonexistingcategory:
+ strange things can happen
+
+CMake Warning at unlikely.cmake:362 (message):
\ No newline at end of file