Skip to content

Commit ce6ff92

Browse files
joke1196ghislainpiot
authored andcommitted
SONARPY-2045: Fix incorrect count of escaped chars (#1897)
1 parent fb40b95 commit ce6ff92

File tree

4 files changed

+25
-20
lines changed

4 files changed

+25
-20
lines changed

python-frontend/src/main/java/org/sonar/python/tree/TokenEnricher.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public static TokenImpl enrichToken(Token token, Map<Integer, IPythonLocation> o
5656
}
5757

5858
private static int computeColWithEscapes(int currentCol, Map<Integer, Integer> escapes, int offsetColumn) {
59-
return (int) escapes.keySet().stream().filter(k -> k < currentCol).count() + offsetColumn + currentCol;
59+
return (int) escapes.keySet().stream().filter(k -> k > 0 && k < currentCol).count() + offsetColumn + currentCol;
6060
}
6161

6262
}

sonar-python-plugin/src/main/java/org/sonar/plugins/python/IpynbNotebookParser.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,10 @@ private boolean parseSourceMultilineString(JsonParser jParser, JsonToken jsonTok
159159
var previousExtraChars = 0;
160160

161161
for (String line : sourceLine.lines().toList()) {
162-
var countEscapedChar = countEscapeCharacters(line, new LinkedHashMap<>(), tokenLocation.getColumnNr());
162+
var countEscapedChar = countEscapeCharacters(line, new LinkedHashMap<>(), previousLen + previousExtraChars + tokenLocation.getColumnNr());
163163
var currentCount = countEscapedChar.get(-1);
164164
addLineToSource(line, new IPythonLocation(tokenLocation.getLineNr(),
165-
tokenLocation.getColumnNr() + previousLen + previousExtraChars + 1, countEscapedChar));
165+
tokenLocation.getColumnNr() + previousLen + previousExtraChars, countEscapedChar));
166166
aggregatedSource.append("\n");
167167
previousLen = line.length() + 2;
168168
previousExtraChars = currentCount;
@@ -200,16 +200,14 @@ private static Map<Integer, Integer> countEscapeCharacters(String sourceLine, Ma
200200
for (int i = 1; i < sourceLine.length(); ++i) {
201201
char c = arr[i];
202202
switch (c) {
203-
case '"', '\'', '/':
204-
// + 1 as we do have to count the open quote.
205-
colMap.put(i, i + colOffSet + count + 1);
206-
if (c != '/') {
207-
numberOfExtraChars++;
208-
}
209-
break;
210-
case '\\', '\b', '\f', '\n', '\r', '\t':
211-
count += 2;
203+
case '"', '\'', '\\':
212204
numberOfExtraChars++;
205+
colMap.put(i, i + colOffSet + count + numberOfExtraChars);
206+
break;
207+
// we never encounter \n or \r as the lines are split at these characters
208+
case '\b', '\f', '\t':
209+
// we increase the count of one char as we count the \ but not the t or b
210+
count += 1;
213211
break;
214212
default:
215213
break;

sonar-python-plugin/src/test/java/org/sonar/plugins/python/IpynbNotebookParserTest.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,21 @@ void testParseNotebook() throws IOException {
4848
assertThat(result.contents()).hasLineCount(27);
4949
assertThat(StringUtils.countMatches(result.contents(), IpynbNotebookParser.SONAR_PYTHON_NOTEBOOK_CELL_DELIMITER))
5050
.isEqualTo(7);
51-
assertThat(result.locationMap()).extracting(map -> map.get(17)).isEqualTo(new IPythonLocation(64, 27, Map.of(6, 21, 20, 37, -1, 3)));
52-
53-
assertThat(result.locationMap()).extracting(map -> map.get(22)).isEqualTo(new IPythonLocation(83, 15, Map.of(6, 21, 15, 32, -1, 3)));
54-
assertThat(result.locationMap()).extracting(map -> map.get(23)).isEqualTo(new IPythonLocation(83, 37, Map.of(6, 21, 23, 40, -1, 3)));
55-
51+
assertThat(result.locationMap()).extracting(map -> map.get(1)).isEqualTo(new IPythonLocation(17, 5, Map.of(-1, 0)));
52+
//" print \"not none\"\n"
53+
assertThat(result.locationMap()).extracting(map -> map.get(3)).isEqualTo(new IPythonLocation(19, 5, Map.of(10, 16, 19, 26, -1, 2)));
54+
//"source": "#Some code\nprint(\"hello world\\n\")",
55+
assertThat(result.locationMap()).extracting(map -> map.get(16)).isEqualTo(new IPythonLocation(64, 14, Map.of(-1, 0)));
56+
assertThat(result.locationMap()).extracting(map -> map.get(17)).isEqualTo(new IPythonLocation(64, 26, Map.of(6, 33, 18, 46, 20, 49, -1, 3)));
57+
58+
//"source": "print(\"My\\ntext\")\nprint(\"Something else\\n\")"
59+
assertThat(result.locationMap()).extracting(map -> map.get(22)).isEqualTo(new IPythonLocation(83, 14, Map.of(6, 21, 9, 25, 15, 32, -1, 3)));
60+
assertThat(result.locationMap()).extracting(map -> map.get(23)).isEqualTo(new IPythonLocation(83, 36, Map.of(6, 43, 21, 59, 23, 62, -1, 3)));
61+
62+
//"source": "a = \"A bunch of characters \\n \\f \\r \\ \t \"\nb = None"
5663
assertThat(result.locationMap()).extracting(map -> map.get(25))
57-
.isEqualTo(new IPythonLocation(90, 15, Map.of(4, 19, 39, 62, 41, 64, 42, 65, 46, 71, -1, 7)));
58-
assertThat(result.locationMap()).extracting(map -> map.get(26)).isEqualTo(new IPythonLocation(90, 71, Map.of(-1, 0)));
64+
.isEqualTo(new IPythonLocation(90, 14, Map.of(4, 19, 27, 43, 30, 47, 33, 51, 36, 55, 40, 61, -1, 6)));
65+
assertThat(result.locationMap()).extracting(map -> map.get(26)).isEqualTo(new IPythonLocation(90, 63, Map.of(-1, 0)));
5966
// last line with the cell delimiter which contains the EOF token
6067
assertThat(result.locationMap()).extracting(map -> map.get(27)).isEqualTo(new IPythonLocation(90, 14, Map.of(-1, 0)));
6168
}

sonar-python-plugin/src/test/resources/org/sonar/plugins/python/notebook.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
"execution_count": 1,
8888
"metadata": {},
8989
"outputs": [],
90-
"source": "a = \"A bunch of characters \\n \\t \\f \\r / // \\ \"\nb = None"
90+
"source": "a = \"A bunch of characters \\n \\f \\r \\ \t \"\nb = None"
9191
}
9292
],
9393
"metadata": {

0 commit comments

Comments
 (0)