Skip to content

Commit 76d1aa3

Browse files
SONARPY-896 NOSONAR annotation should silence issues on multiline strings (#1060)
1 parent ac00be6 commit 76d1aa3

File tree

3 files changed

+45
-7
lines changed

3 files changed

+45
-7
lines changed

python-frontend/src/main/java/org/sonar/python/metrics/FileLinesVisitor.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.sonar.plugins.python.api.PythonVisitorContext;
3232
import org.sonar.plugins.python.api.SubscriptionContext;
3333
import org.sonar.plugins.python.api.tree.ClassDef;
34+
import org.sonar.plugins.python.api.tree.ExpressionStatement;
3435
import org.sonar.plugins.python.api.tree.FileInput;
3536
import org.sonar.plugins.python.api.tree.FunctionDef;
3637
import org.sonar.plugins.python.api.tree.StringLiteral;
@@ -130,16 +131,16 @@ private void visitToken(Token token) {
130131
}
131132

132133
for (Trivia trivia : token.trivia()) {
133-
visitComment(trivia);
134+
visitComment(trivia, token);
134135
}
135136
}
136137

137-
private void visitComment(Trivia trivia) {
138+
private void visitComment(Trivia trivia, Token parentToken) {
138139
String commentLine = getContents(trivia.token().value());
139140
int line = trivia.token().line();
140141
if (commentLine.contains("NOSONAR")) {
141142
linesOfComments.remove(line);
142-
noSonar.add(line);
143+
addNoSonarLines(trivia, parentToken);
143144
} else if (!isBlank(commentLine)) {
144145
linesOfComments.add(line);
145146
}
@@ -185,6 +186,23 @@ private static String getContents(String comment) {
185186
return comment.substring(comment.indexOf('#'));
186187
}
187188

189+
private void addNoSonarLines(Trivia trivia, Token parentToken) {
190+
int line = trivia.token().line();
191+
if (parentToken.parent().is(Tree.Kind.EXPRESSION_STMT)) {
192+
ExpressionStatement expressionStatement = (ExpressionStatement) parentToken.parent();
193+
if (!expressionStatement.expressions().isEmpty() && expressionStatement.expressions().get(0).is(Tree.Kind.STRING_LITERAL)) {
194+
// Count every line of a string literal as part of the "NOSONAR" scope
195+
StringLiteral stringLiteral = (StringLiteral) expressionStatement.expressions().get(0);
196+
int firstLine = stringLiteral.firstToken().line();
197+
for (int i = firstLine; i < line + 1; i++) {
198+
noSonar.add(i);
199+
}
200+
return;
201+
}
202+
}
203+
noSonar.add(line);
204+
}
205+
188206
public int getStatements() {
189207
return statements;
190208
}

python-frontend/src/test/java/org/sonar/python/FileLinesVisitorTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ public void test() {
3535

3636
TestPythonVisitorRunner.scanFile(new File(BASE_DIR, "file_lines.py"), visitor);
3737

38-
assertThat(visitor.getLinesOfCode()).hasSize(12);
39-
assertThat(visitor.getLinesOfCode()).containsOnly(6, 8, 11, 12, 13, 14, 15, 16, 18, 19, 21, 25);
38+
assertThat(visitor.getLinesOfCode()).hasSize(24);
39+
assertThat(visitor.getLinesOfCode()).containsOnly(6, 8, 11, 12, 13, 14, 15, 16, 18, 19, 21, 25, 28, 32, 34, 36, 37, 38, 39, 40, 41, 43, 44, 45);
4040

41-
assertThat(visitor.getCommentLineCount()).isEqualTo(13);
41+
assertThat(visitor.getCommentLineCount()).isEqualTo(16);
4242

43-
assertThat(visitor.getLinesWithNoSonar()).containsOnly(15);
43+
assertThat(visitor.getLinesWithNoSonar()).containsOnly(15, 29, 30, 31, 34, 37, 38, 39, 40, 41, 45);
4444
}
4545

4646
@Test

python-frontend/src/test/resources/metrics/file_lines.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,23 @@ def foo1(x,y,z,): # end of line comment
2323
3 lines of docstring
2424
"""
2525
pass
26+
27+
28+
def foo2(x,y,z,):
29+
"""
30+
3 lines of docstring
31+
""" # NOSONAR
32+
pass
33+
34+
"some string literal" # NOSONAR
35+
36+
def foo3():
37+
"""
38+
some tuple
39+
""", """
40+
of multiline strings
41+
""" # NOSONAR
42+
43+
def foo4():
44+
(multine,
45+
expression) # NOSONAR

0 commit comments

Comments
 (0)