44
55import edu .hm .hafner .analysis .Issue ;
66import edu .hm .hafner .analysis .IssueBuilder ;
7- import edu .hm .hafner .analysis .Location ;
87import edu .hm .hafner .analysis .LookaheadParser ;
9- import edu .hm .hafner .analysis .Severity ;
108import edu .hm .hafner .analysis .util .IntegerParser ;
119import edu .hm .hafner .util .LookaheadStream ;
12- import edu .hm .hafner .util .TreeStringBuilder ;
1310
1411import java .io .Serial ;
12+ import java .util .ArrayList ;
1513import java .util .Optional ;
1614import java .util .regex .Matcher ;
1715import java .util .regex .Pattern ;
@@ -25,12 +23,13 @@ public class Gcc4CompilerParser extends LookaheadParser {
2523 @ Serial
2624 private static final long serialVersionUID = 5490211629355204910L ;
2725
26+ private static final String LOCATION = "(?<file>.+?):(?<line>\\ d+):(?:(?<column>\\ d+):)?" ;
2827 private static final String GCC_WARNING_PATTERN =
29- ANT_TASK + "(.+?):( \\ d+):(?:( \\ d+):)? ?( [wW]arning|.*[Ee]rror|[Nn]ote ): (.*)$" ;
28+ ANT_TASK + LOCATION + " ?(?<severity> [wW]arning|.*[Ee]rror): (?<message> .*)$" ;
3029 private static final Pattern CLASS_PATTERN = Pattern .compile ("\\ [-W(.+)]$" );
3130 private static final Pattern GCC_OPTION_PATTERN = Pattern .compile ("\\ [-(f[^\\ ]]+)]$" );
3231 private static final Pattern CLANG_TIDY_PATTERN = Pattern .compile ("\\ [[^\\ s\\ ]]+\\ ]$" );
33- private static final Pattern NOTE_PATTERN = Pattern .compile ("^(?<file>.+?):(?<line> \\ d+):(?:(?<column> \\ d+):)? ?[Nn]ote: (?<message>.*)$" );
32+ private static final Pattern NOTE_PATTERN = Pattern .compile ("^" + LOCATION + " ?[Nn]ote: (?<message>.*)$" );
3433
3534 /**
3635 * Creates a new instance of {@link Gcc4CompilerParser}.
@@ -40,8 +39,10 @@ public Gcc4CompilerParser() {
4039 }
4140
4241 /**
43- * Creates a new instance of {@link Gcc4CompilerParser} with specified pattern.
44- * @param pattern a regex pattern to be used instead of the default one
42+ * Creates a new instance of {@link Gcc4CompilerParser} with the specified pattern.
43+ *
44+ * @param pattern
45+ * a regex pattern to be used instead of the default one
4546 */
4647 Gcc4CompilerParser (final String pattern ) {
4748 super (pattern );
@@ -55,64 +56,69 @@ protected boolean isLineInteresting(final String line) {
5556 @ Override
5657 protected Optional <Issue > createIssue (final Matcher matcher , final LookaheadStream lookahead ,
5758 final IssueBuilder builder ) {
58- if (isNoteMessage (matcher )) {
59+ var originalMessage = matcher .group ("message" );
60+ if (isClangTidyWarning (originalMessage )) {
5961 return Optional .empty ();
6062 }
6163
62- var message = new StringBuilder (matcher .group (5 ));
63- var originalMessage = message .toString ();
64-
65- setCategory (builder , originalMessage );
64+ addLocation (matcher , builder );
6665
66+ var message = new StringBuilder (originalMessage );
6767 boolean hasCodeSnippet = false ;
6868 while (lookahead .hasNext () && isMessageContinuation (lookahead , hasCodeSnippet )) {
6969 var continuation = lookahead .next ();
70- if (continuation .length () > 0 && Character .isWhitespace (continuation .charAt (0 ))) {
70+ if (! continuation .isEmpty () && Character .isWhitespace (continuation .charAt (0 ))) {
7171 hasCodeSnippet = true ;
7272 }
7373 message .append ('\n' );
7474 message .append (continuation );
7575 }
7676
77- var treeStringBuilder = new TreeStringBuilder ();
78- var notes = collectNotes (lookahead , builder , treeStringBuilder );
77+ var notes = collectNotes (lookahead , builder );
7978 if (!notes .isEmpty ()) {
8079 message .append ('\n' );
8180 message .append (notes );
8281 }
8382
84- // Reject clang-tidy warnings that have [check-name] but not [-Wwarning-name]
85- // clang-tidy warnings should be handled by ClangTidyParser
86- var messageStr = message .toString ();
87- if (CLANG_TIDY_PATTERN .matcher (messageStr ).find () && !CLASS_PATTERN .matcher (messageStr ).find ()) {
88- return Optional .empty ();
89- }
90-
91- return builder .setFileName (matcher .group (1 ))
92- .setLineStart (matcher .group (2 ))
93- .setColumnStart (matcher .group (3 ))
94- .setMessage (messageStr )
95- .setSeverity (Severity .guessFromString (matcher .group (4 )))
83+ setCategory (builder , originalMessage );
84+ return builder .setMessage (message )
85+ .guessSeverity (matcher .group ("severity" ))
9686 .buildOptional ();
9787 }
9888
89+ private void addLocation (final Matcher matcher , final IssueBuilder builder ) {
90+ var fileName = matcher .group ("file" );
91+ var line = toInt (matcher .group ("line" ));
92+ var column = toInt (matcher .group ("column" ));
93+
94+ builder .addLocation (fileName , line , line , column , column );
95+ }
96+
97+ private int toInt (final String number ) {
98+ return IntegerParser .parseInt (number );
99+ }
100+
99101 /**
100- * Checks if the matched line is a note message.
102+ * Check if the warning is from clang-tidy. Those warnings are quite similar and have [check-name] but not
103+ * [-Wwarning-name] or [-fcompiler-option]. Since a separate parser handles clang-tidy warnings, we can skip them
104+ * here.
101105 *
102- * @param matcher the matcher for the current line
103- * @return true if the line is a note message, false otherwise
106+ * @return {@code true} if the message is a clang-tidy warning, {@code false} otherwise
104107 */
105- private boolean isNoteMessage (final Matcher matcher ) {
106- var messageType = matcher .group (4 );
107- return "note" .equals (messageType ) || "Note" .equals (messageType );
108+ private boolean isClangTidyWarning (final String message ) {
109+ return CLANG_TIDY_PATTERN .matcher (message ).find ()
110+ && !CLASS_PATTERN .matcher (message ).find ()
111+ && !GCC_OPTION_PATTERN .matcher (message ).find ();
108112 }
109113
110114 /**
111- * Sets the category based on the original message content.
112- * Checks for GCC warning categories (e.g., [-Wunused-variable]) or compiler options (e.g., [-fpermissive]).
115+ * Sets the category based on the original message content. Checks for GCC warning categories (e.g.,
116+ * [-Wunused-variable]) or compiler options (e.g., [-fpermissive]).
113117 *
114- * @param builder the issue builder
115- * @param originalMessage the original message to extract the category from
118+ * @param builder
119+ * the issue builder
120+ * @param originalMessage
121+ * the original message to extract the category from
116122 */
117123 private void setCategory (final IssueBuilder builder , final String originalMessage ) {
118124 var classMatcher = CLASS_PATTERN .matcher (originalMessage );
@@ -128,38 +134,27 @@ private void setCategory(final IssueBuilder builder, final String originalMessag
128134 }
129135
130136 /**
131- * Collects any subsequent note lines from the lookahead stream and adds them as additional locations.
137+ * Collects any further note lines from the lookahead stream and adds them as additional locations.
132138 *
133- * @param lookahead the lookahead stream
134- * @param builder the issue builder to add locations to
135- * @param treeStringBuilder the tree string builder for interning file names
139+ * @param lookahead
140+ * the lookahead stream
141+ * @param builder
142+ * the issue builder to add locations to
136143 * @return a string containing all collected note lines, or an empty string if no notes were found
137144 */
138- private String collectNotes (final LookaheadStream lookahead , final IssueBuilder builder ,
139- final TreeStringBuilder treeStringBuilder ) {
140- var notes = new StringBuilder ();
145+ private String collectNotes (final LookaheadStream lookahead , final IssueBuilder builder ) {
146+ var notes = new ArrayList <String >();
141147 while (lookahead .hasNext ()) {
142- var nextLine = lookahead .peekNext ();
143- var noteMatcher = NOTE_PATTERN .matcher (nextLine );
148+ var noteMatcher = NOTE_PATTERN .matcher (lookahead .peekNext ());
144149 if (noteMatcher .matches ()) {
145- if (!notes .isEmpty ()) {
146- notes .append ('\n' );
147- }
148- notes .append (lookahead .next ());
149-
150- // Add the note as an additional location
151- var file = noteMatcher .group ("file" );
152- var line = IntegerParser .parseInt (noteMatcher .group ("line" ));
153- var column = IntegerParser .parseInt (noteMatcher .group ("column" ));
154-
155- var fileName = treeStringBuilder .intern (file );
156- builder .addLocation (new Location (fileName , line , line , column , column ));
150+ notes .add (lookahead .next ());
151+ addLocation (noteMatcher , builder );
157152 }
158153 else {
159154 break ;
160155 }
161156 }
162- return notes . toString ( );
157+ return String . join ( " \n " , notes );
163158 }
164159
165160 @ SuppressWarnings ("PMD.AvoidLiteralsInIfCondition" )
0 commit comments