Skip to content

Commit 02affce

Browse files
pynicolasalban-auzeill
authored andcommitted
SONARPY-179 Feed metric executable_lines_data
1 parent d09a973 commit 02affce

5 files changed

Lines changed: 74 additions & 6 deletions

File tree

its/plugin/src/test/java/com/sonar/python/it/plugin/MetricsTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ public void should_be_compatible_with_DevCockpit() {
150150
assertThat(getFileMeasure("comment_lines_data").getValue())
151151
.contains("2=1")
152152
.doesNotContain("4=1");
153+
assertThat(getFileMeasure("executable_lines_data").getValue())
154+
.doesNotContain("1=1")
155+
.contains("5=1");
153156
}
154157

155158
/* Helper methods */

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

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import org.sonar.python.DocstringExtractor;
3232
import org.sonar.python.PythonVisitor;
3333
import org.sonar.python.TokenLocation;
34+
import org.sonar.python.api.PythonGrammar;
35+
import org.sonar.python.api.PythonKeyword;
3436
import org.sonar.python.api.PythonTokenType;
3537

3638
/**
@@ -39,6 +41,7 @@
3941
public class FileLinesVisitor extends PythonVisitor {
4042

4143
private static final PythonCommentAnalyser COMMENT_ANALYSER = new PythonCommentAnalyser();
44+
private static final Set<AstNodeType> EXECUTABLE_LINE_KINDS = executableLineKinds();
4245

4346
private boolean seenFirstToken;
4447

@@ -48,14 +51,26 @@ public class FileLinesVisitor extends PythonVisitor {
4851
private Set<Integer> linesOfCode = new HashSet<>();
4952
private Set<Integer> linesOfComments = new HashSet<>();
5053
private Set<Integer> linesOfDocstring = new HashSet<>();
54+
private Set<Integer> executableLines = new HashSet<>();
5155

5256
public FileLinesVisitor(boolean ignoreHeaderComments) {
5357
this.ignoreHeaderComments = ignoreHeaderComments;
5458
}
5559

60+
private static Set<AstNodeType> executableLineKinds() {
61+
Set<AstNodeType> kinds = new HashSet<>();
62+
kinds.add(PythonGrammar.STATEMENT);
63+
kinds.add(PythonKeyword.ELIF);
64+
kinds.add(PythonKeyword.EXCEPT);
65+
return Collections.unmodifiableSet(kinds);
66+
}
67+
5668
@Override
5769
public Set<AstNodeType> subscribedKinds() {
58-
return DocstringExtractor.DOCUMENTABLE_NODE_TYPES;
70+
Set<AstNodeType> kinds = new HashSet<>();
71+
kinds.addAll(DocstringExtractor.DOCUMENTABLE_NODE_TYPES);
72+
kinds.addAll(EXECUTABLE_LINE_KINDS);
73+
return kinds;
5974
}
6075

6176
@Override
@@ -64,18 +79,24 @@ public void visitFile(AstNode astNode) {
6479
linesOfCode.clear();
6580
linesOfComments.clear();
6681
linesOfDocstring.clear();
82+
executableLines.clear();
6783
seenFirstToken = false;
6884
}
6985

7086
@Override
7187
public void visitNode(AstNode astNode) {
72-
Token docstringToken = DocstringExtractor.extractDocstring(astNode);
73-
if (docstringToken != null) {
74-
TokenLocation location = new TokenLocation(docstringToken);
75-
for (int line = location.startLine(); line <= location.endLine(); line++) {
76-
linesOfDocstring.add(line);
88+
if (DocstringExtractor.DOCUMENTABLE_NODE_TYPES.contains(astNode.getType())) {
89+
Token docstringToken = DocstringExtractor.extractDocstring(astNode);
90+
if (docstringToken != null) {
91+
TokenLocation location = new TokenLocation(docstringToken);
92+
for (int line = location.startLine(); line <= location.endLine(); line++) {
93+
linesOfDocstring.add(line);
94+
}
7795
}
7896
}
97+
if (EXECUTABLE_LINE_KINDS.contains(astNode.getType())) {
98+
executableLines.add(astNode.getTokenLine());
99+
}
79100
}
80101

81102
/**
@@ -128,6 +149,7 @@ public void visitComment(Trivia trivia) {
128149
public void leaveFile(AstNode astNode) {
129150
// account for the docstring lines
130151
for (Integer line : linesOfDocstring) {
152+
executableLines.remove(line);
131153
linesOfCode.remove(line);
132154
linesOfComments.add(line);
133155
}
@@ -145,6 +167,10 @@ public Set<Integer> getLinesOfComments() {
145167
return Collections.unmodifiableSet(new HashSet<>(linesOfComments));
146168
}
147169

170+
public Set<Integer> getExecutableLines() {
171+
return Collections.unmodifiableSet(new HashSet<>(executableLines));
172+
}
173+
148174
private static class PythonCommentAnalyser {
149175

150176
public boolean isBlank(String line) {

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,11 @@ public void test_ignoreHeaderComments() {
5454
assertThat(visitor.getLinesOfComments()).containsOnly(4);
5555
}
5656

57+
@Test
58+
public void executable_lines() throws Exception {
59+
FileLinesVisitor visitor = new FileLinesVisitor(false);
60+
TestPythonVisitorRunner.scanFile(new File(BASE_DIR, "executable_lines.py"), visitor);
61+
assertThat(visitor.getExecutableLines()).containsOnly(1, 2, 4, 7, 11, 13, 14, 15, 16, 18, 20, 21, 22, 23, 25, 27, 28, 29);
62+
}
63+
5764
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import a
2+
from x.y import z
3+
4+
multiline_statement(
5+
'abc')
6+
7+
def f1():
8+
"""
9+
docstring
10+
"""
11+
return 42
12+
13+
if x:
14+
print 1
15+
elif y:
16+
print 2
17+
else:
18+
print 3
19+
20+
try:
21+
import x
22+
except ImportError:
23+
pass
24+
else:
25+
print('error')
26+
27+
class class1:
28+
def method1():
29+
pass

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ private void saveMeasures(InputFile inputFile, PythonVisitorContext visitorConte
179179
for (int line : linesOfComments) {
180180
fileLinesContext.setIntValue(CoreMetrics.COMMENT_LINES_DATA_KEY, line, 1);
181181
}
182+
for (int line : fileLinesVisitor.getExecutableLines()) {
183+
fileLinesContext.setIntValue(CoreMetrics.EXECUTABLE_LINES_DATA_KEY, line, 1);
184+
}
182185
fileLinesContext.save();
183186

184187
linesOfCodeByFile.put(inputFile, linesOfCode);

0 commit comments

Comments
 (0)