Skip to content

Commit 5677230

Browse files
joke1196sonartech
authored andcommitted
SONARPY-2745: Take into account the end column of mypy reports (#343)
GitOrigin-RevId: 5bcc6490f7636703f51fad91e915af86d966791b
1 parent 5a7b985 commit 5677230

4 files changed

Lines changed: 38 additions & 12 deletions

File tree

python-commons/src/main/java/org/sonar/plugins/python/ExternalIssuesSensor.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
*/
1717
package org.sonar.plugins.python;
1818

19-
2019
import java.io.File;
2120
import java.io.IOException;
2221
import java.util.HashSet;
@@ -104,7 +103,7 @@ protected void saveIssue(SensorContext context, TextReportReader.Issue issue, Se
104103
.message(issue.message)
105104
.on(inputFile);
106105
if (issue.columnNumber != null && issue.columnNumber < inputFile.selectLine(issue.lineNumber).end().lineOffset()) {
107-
primaryLocation.at(inputFile.newRange(issue.lineNumber, issue.columnNumber, issue.lineNumber, issue.columnNumber + 1));
106+
primaryLocation.at(inputFile.newRange(issue.lineNumber, issue.columnNumber, issue.endLineNumber.orElse(issue.lineNumber), issue.endColNumber.orElse(issue.columnNumber + 1)));
108107
} else {
109108
// Pylint formatted issues might not provide column information
110109
primaryLocation.at(inputFile.selectLine(issue.lineNumber));

python-commons/src/main/java/org/sonar/plugins/python/TextReportReader.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.io.IOException;
2121
import java.util.ArrayList;
2222
import java.util.List;
23+
import java.util.Optional;
2324
import java.util.Scanner;
2425
import java.util.regex.Matcher;
2526
import java.util.regex.Pattern;
@@ -81,7 +82,7 @@ private Issue extractDefaultStyleIssue(Matcher m) {
8182
columnNumber -= this.reportOffset;
8283
String ruleKey = m.group(4);
8384
String message = m.group(5);
84-
return new Issue(filePath, ruleKey, message, lineNumber, columnNumber);
85+
return new Issue(filePath, ruleKey, message, lineNumber, columnNumber, null, null);
8586
}
8687

8788
private static Issue extractLegacyStyleIssue(Matcher m) {
@@ -93,7 +94,7 @@ private static Issue extractLegacyStyleIssue(Matcher m) {
9394
ruleKey = ruleKey.substring(0, keyLastIndex);
9495
}
9596
String message = m.group(4);
96-
return new Issue(filePath, ruleKey, message, lineNumber, null);
97+
return new Issue(filePath, ruleKey, message, lineNumber, null, null, null);
9798
}
9899

99100
public static class Issue {
@@ -108,12 +109,20 @@ public static class Issue {
108109

109110
public final Integer columnNumber;
110111

111-
public Issue(String filePath, String ruleKey, String message, Integer lineNumber, @Nullable Integer columnNumber) {
112+
public final Optional<Integer> endLineNumber;
113+
114+
public final Optional<Integer> endColNumber;
115+
116+
public Issue(String filePath, String ruleKey, String message, Integer lineNumber, @Nullable Integer columnNumber, @Nullable Integer endLineNumber,
117+
@Nullable Integer endColNumber) {
112118
this.filePath = filePath;
113119
this.ruleKey = ruleKey;
114120
this.message = message;
115121
this.lineNumber = lineNumber;
116122
this.columnNumber = columnNumber;
123+
this.endLineNumber = Optional.ofNullable(endLineNumber);
124+
this.endColNumber = Optional.ofNullable(endColNumber);
117125
}
126+
118127
}
119128
}

python-commons/src/main/java/org/sonar/plugins/python/mypy/MypySensor.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,13 @@ public class MypySensor extends ExternalIssuesSensor {
4444
private static final String FALLBACK_RULE_KEY = "unknown_mypy_rule";
4545

4646
// Pattern -> Location ': ' Severity ':' Message '['Code']'
47-
// Location -> File ':' StartLine
48-
private static final Pattern PATTERN =
49-
Pattern.compile("^(?<file>[^:]+):(?<startLine>\\d+)(?::(?<startCol>\\d+))?(?::\\d+:\\d+)?: (?<severity>\\S+[^:]): (?<message>.*?)(?: \\[(?<code>.*)])?\\s*$");
47+
// Location -> File ':' StartLine (':' StartCol (':' EndLine ':' EndCol))
48+
49+
private static final String START_LOCATION = "(?<startLine>\\d+)(?::(?<startCol>\\d+))?";
50+
private static final String END_LOCATION = "(?::(?<endLine>\\d+):(?<endCol>\\d+))?";
51+
52+
private static final Pattern PATTERN = Pattern
53+
.compile(String.format("^(?<file>[^:]+):%s%s: (?<severity>\\S+[^:]): (?<message>.*?)(?: \\[(?<code>.*)])?\\s*$", START_LOCATION, END_LOCATION));
5054

5155
@Override
5256
protected void importReport(File reportPath, SensorContext context, Set<String> unresolvedInputFiles) throws IOException {
@@ -99,7 +103,21 @@ private static TextReportReader.Issue extractIssue(Matcher m) {
99103
.map(i -> i - 1)
100104
.orElse(null);
101105

102-
return new TextReportReader.Issue(filePath, errorCode, message, lineNumber, columnNumber);
106+
Integer endLineNumber = Optional.ofNullable(m.group("endLine"))
107+
.map(Integer::parseInt)
108+
.orElse(null);
109+
110+
111+
// Start and end column should be different as this is a requirement from our issue location.
112+
// If they are the same ExternalIssuesSensor will use start column + 1
113+
Integer endColNumber = Optional.ofNullable(m.group("endCol"))
114+
.map(Integer::parseInt)
115+
.map(i -> i - 1)
116+
.filter(i -> !i.equals(columnNumber))
117+
.orElse(null);
118+
119+
120+
return new TextReportReader.Issue(filePath, errorCode, message, lineNumber, columnNumber, endLineNumber, endColNumber);
103121
}
104122

105123
@Override

python-commons/src/test/java/org/sonar/plugins/python/mypy/MypySensorTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,19 +135,19 @@ void issues_with_sonarqube_79_error_end() throws IOException {
135135
assertIssue(externalIssues.get(0),
136136
"arg-type",
137137
"Argument 1 to \"greet_all\" has incompatible type \"List[int]\"; expected \"List[str]\"",
138-
11, 10, 11, 11);
138+
11, 10, 11, 13);
139139
assertIssue(externalIssues.get(1),
140140
"no-untyped-def",
141141
"Function is missing a type annotation",
142-
13, 0, 13, 1);
142+
13, 0, 14, 13);
143143
assertIssue(externalIssues.get(2),
144144
"import",
145145
"Cannot find implementation or library stub for module named \"unknown\"",
146146
16, 0, 16, 1);
147147
assertIssue(externalIssues.get(3),
148148
"no-untyped-call",
149149
"Call to untyped function \"no_type_hints\" in typed context",
150-
19, 10, 19, 11);
150+
19, 10, 19, 25);
151151
assertIssue(externalIssues.get(4),
152152
"unknown_mypy_rule",
153153
"Unused \"type: ignore\" comment",

0 commit comments

Comments
 (0)