Skip to content

Commit 7bcab61

Browse files
committed
SONARPY-201 Stop reading files directly in checks
1 parent ada1a6b commit 7bcab61

17 files changed

Lines changed: 218 additions & 64 deletions

File tree

python-checks/src/main/java/org/sonar/python/checks/MissingNewlineAtEndOfFileCheck.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@
1919
*/
2020
package org.sonar.python.checks;
2121

22-
import com.google.common.io.Files;
2322
import com.sonar.sslr.api.AstNode;
24-
import java.io.IOException;
2523
import javax.annotation.Nullable;
2624
import org.sonar.check.Priority;
2725
import org.sonar.check.Rule;
@@ -41,14 +39,9 @@ public class MissingNewlineAtEndOfFileCheck extends PythonCheck {
4139

4240
@Override
4341
public void visitFile(@Nullable AstNode astNode) {
44-
String fileContent;
45-
try {
46-
fileContent = Files.toString(getContext().getFile(), getContext().charset());
47-
} catch (IOException e) {
48-
throw new IllegalStateException("Could not read " + getContext().getFile(), e);
49-
}
42+
String fileContent = getContext().pythonFile().content();
5043
if (fileContent.length() > 0 && !fileContent.endsWith("\n") && !fileContent.endsWith("\r")){
51-
addFileIssue(String.format(MESSAGE, getContext().getFile().getName()));
44+
addFileIssue(String.format(MESSAGE, getContext().pythonFile().file().getName()));
5245
}
5346
}
5447

python-checks/src/main/java/org/sonar/python/checks/ModuleNameCheck.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public class ModuleNameCheck extends PythonCheck {
4949

5050
@Override
5151
public void visitFile(@Nullable AstNode astNode) {
52-
String fileName = getContext().getFile().getName();
52+
String fileName = getContext().pythonFile().file().getName();
5353
int dotIndex = fileName.lastIndexOf('.');
5454
if (dotIndex > 0) {
5555
String moduleName = fileName.substring(0, dotIndex);

python-checks/src/main/java/org/sonar/python/checks/TooManyLinesInFileCheck.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public void visitNode(AstNode astNode) {
6060

6161
if (lines > maximum) {
6262
String message = "File \"{0}\" has {1} lines, which is greater than {2} authorized. Split it into smaller files.";
63-
addFileIssue(MessageFormat.format(message, getContext().getFile().getName(), lines, maximum));
63+
addFileIssue(MessageFormat.format(message, getContext().pythonFile().file().getName(), lines, maximum));
6464
}
6565
}
6666
}

python-checks/src/main/java/org/sonar/python/checks/TrailingWhitespaceCheck.java

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@
2020
package org.sonar.python.checks;
2121

2222
import com.sonar.sslr.api.AstNode;
23-
import java.io.BufferedReader;
24-
import java.io.File;
25-
import java.io.IOException;
26-
import java.nio.file.Files;
2723
import java.util.regex.Pattern;
2824
import javax.annotation.Nullable;
2925
import org.sonar.check.Priority;
@@ -46,18 +42,11 @@ public class TrailingWhitespaceCheck extends PythonCheck {
4642

4743
@Override
4844
public void visitFile(@Nullable AstNode astNode) {
49-
final File file = getContext().getFile();
50-
try (BufferedReader reader = Files.newBufferedReader(file.toPath(), getContext().charset())) {
51-
int lineNr = 0;
52-
String line;
53-
while ((line = reader.readLine()) != null) {
54-
++lineNr;
55-
if (TRAILING_WS.matcher(line).find()) {
56-
addLineIssue(MESSAGE, lineNr);
57-
}
45+
String[] lines = getContext().pythonFile().content().split("\r\n|\n|\r", -1);
46+
for (int i = 0; i < lines.length; i++) {
47+
if (TRAILING_WS.matcher(lines[i]).find()) {
48+
addLineIssue(MESSAGE, i + 1);
5849
}
59-
} catch (IOException e) {
60-
throw new IllegalStateException("Could not read " + file, e);
6150
}
6251
}
6352

python-checks/src/test/java/org/sonar/python/checks/ParsingErrorCheckTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public void test() {
4545
parser.parse(file);
4646
throw new IllegalStateException("Expected RecognitionException");
4747
} catch (RecognitionException e) {
48-
context = new PythonVisitorContext(file, StandardCharsets.UTF_8, e);
48+
context = new PythonVisitorContext(null, e);
4949
}
5050

5151
ParsingErrorCheck check = new ParsingErrorCheck();

python-squid/src/main/java/org/sonar/python/PythonCheck.java

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import com.google.common.collect.ImmutableList;
2323
import com.sonar.sslr.api.AstNode;
2424
import com.sonar.sslr.api.Token;
25-
import java.io.File;
2625
import java.util.ArrayList;
2726
import java.util.List;
2827
import javax.annotation.Nullable;
@@ -38,25 +37,25 @@ public List<PreciseIssue> scanFileForIssues(PythonVisitorContext context) {
3837
}
3938

4039
protected final PreciseIssue addIssue(AstNode node, String message) {
41-
PreciseIssue newIssue = new PreciseIssue(IssueLocation.preciseLocation(node, message), getContext().getFile());
40+
PreciseIssue newIssue = new PreciseIssue(IssueLocation.preciseLocation(node, message));
4241
issues.add(newIssue);
4342
return newIssue;
4443
}
4544

4645
protected final PreciseIssue addIssue(IssueLocation primaryLocation) {
47-
PreciseIssue newIssue = new PreciseIssue(primaryLocation, getContext().getFile());
46+
PreciseIssue newIssue = new PreciseIssue(primaryLocation);
4847
issues.add(newIssue);
4948
return newIssue;
5049
}
5150

5251
protected final PreciseIssue addLineIssue(String message, int lineNumber) {
53-
PreciseIssue newIssue = new PreciseIssue(IssueLocation.atLineLevel(message, lineNumber), getContext().getFile());
52+
PreciseIssue newIssue = new PreciseIssue(IssueLocation.atLineLevel(message, lineNumber));
5453
issues.add(newIssue);
5554
return newIssue;
5655
}
5756

5857
protected final PreciseIssue addFileIssue(String message) {
59-
PreciseIssue newIssue = new PreciseIssue(IssueLocation.atFileLevel(message), getContext().getFile());
58+
PreciseIssue newIssue = new PreciseIssue(IssueLocation.atFileLevel(message));
6059
issues.add(newIssue);
6160
return newIssue;
6261
}
@@ -67,15 +66,13 @@ protected final PreciseIssue addIssue(Token token, String message) {
6766

6867
public static class PreciseIssue {
6968

70-
private final File file;
7169
private final IssueLocation primaryLocation;
7270
private Integer cost;
7371
private final List<IssueLocation> secondaryLocations;
7472

75-
private PreciseIssue(IssueLocation primaryLocation, File file) {
73+
private PreciseIssue(IssueLocation primaryLocation) {
7674
this.primaryLocation = primaryLocation;
7775
this.secondaryLocations = new ArrayList<>();
78-
this.file = file;
7976
}
8077

8178
@Nullable
@@ -88,10 +85,6 @@ public PreciseIssue withCost(int cost) {
8885
return this;
8986
}
9087

91-
public File file() {
92-
return file;
93-
}
94-
9588
public IssueLocation primaryLocation() {
9689
return primaryLocation;
9790
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* SonarQube Python Plugin
3+
* Copyright (C) 2011-2017 SonarSource SA
4+
* mailto:info AT sonarsource DOT com
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 3 of the License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this program; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
*/
20+
package org.sonar.python;
21+
22+
import java.io.File;
23+
24+
public interface PythonFile {
25+
26+
String content();
27+
28+
@Deprecated
29+
File file();
30+
31+
}

python-squid/src/main/java/org/sonar/python/PythonVisitorContext.java

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,44 +21,37 @@
2121

2222
import com.sonar.sslr.api.AstNode;
2323
import com.sonar.sslr.api.RecognitionException;
24-
import java.io.File;
25-
import java.nio.charset.Charset;
2624

2725
public class PythonVisitorContext {
2826

2927
private final AstNode rootTree;
30-
private final File file;
31-
private final Charset charset;
28+
private final PythonFile pythonFile;
3229
private final RecognitionException parsingException;
3330

34-
public PythonVisitorContext(AstNode rootTree, File file, Charset charset) {
35-
this(rootTree, file, charset, null);
31+
public PythonVisitorContext(AstNode rootTree, PythonFile pythonFile) {
32+
this(rootTree, pythonFile, null);
3633
}
3734

38-
public PythonVisitorContext(File file, Charset charset, RecognitionException parsingException) {
39-
this(null, file, charset, parsingException);
35+
public PythonVisitorContext(PythonFile pythonFile, RecognitionException parsingException) {
36+
this(null, pythonFile, parsingException);
4037
}
4138

42-
private PythonVisitorContext(AstNode rootTree, File file, Charset charset, RecognitionException parsingException) {
39+
private PythonVisitorContext(AstNode rootTree, PythonFile pythonFile, RecognitionException parsingException) {
4340
this.rootTree = rootTree;
44-
this.file = file;
45-
this.charset = charset;
41+
this.pythonFile = pythonFile;
4642
this.parsingException = parsingException;
4743
}
4844

4945
public AstNode rootTree() {
5046
return rootTree;
5147
}
5248

53-
public File getFile() {
54-
return file;
49+
public PythonFile pythonFile() {
50+
return pythonFile;
5551
}
5652

5753
public RecognitionException parsingException() {
5854
return parsingException;
5955
}
6056

61-
public Charset charset() {
62-
return charset;
63-
}
6457
}

python-squid/src/main/java/org/sonar/python/TestPythonVisitorRunner.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
import com.sonar.sslr.api.Grammar;
2424
import com.sonar.sslr.impl.Parser;
2525
import java.io.File;
26+
import java.io.IOException;
2627
import java.nio.charset.StandardCharsets;
2728
import java.util.List;
29+
import org.sonar.api.internal.google.common.io.Files;
2830
import org.sonar.python.PythonCheck.PreciseIssue;
2931
import org.sonar.python.parser.PythonParser;
3032

@@ -46,8 +48,34 @@ public static List<PreciseIssue> scanFileForIssues(File file, PythonCheck check)
4648

4749
private static PythonVisitorContext createContext(File file) {
4850
Parser<Grammar> parser = PythonParser.create(new PythonConfiguration(StandardCharsets.UTF_8));
49-
AstNode rootTree = parser.parse(file);
50-
return new PythonVisitorContext(rootTree, file, StandardCharsets.UTF_8);
51+
TestPythonFile pythonFile = new TestPythonFile(file);
52+
AstNode rootTree = parser.parse(pythonFile.content());
53+
return new PythonVisitorContext(rootTree, pythonFile);
5154
}
5255

56+
private static class TestPythonFile implements PythonFile {
57+
58+
private final File file;
59+
60+
public TestPythonFile(File file) {
61+
this.file = file;
62+
}
63+
64+
@Override
65+
public String content() {
66+
try {
67+
return Files.toString(file, StandardCharsets.UTF_8);
68+
} catch (IOException e) {
69+
throw new IllegalStateException("Cannot read " + file, e);
70+
}
71+
}
72+
73+
@Override
74+
public File file() {
75+
return file;
76+
}
77+
78+
}
79+
80+
5381
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public void visitComment(Trivia trivia) {
141141

142142
@Override
143143
public void leaveFile(AstNode astNode) {
144-
InputFile inputFile = fileSystem.inputFile(fileSystem.predicates().is(getContext().getFile()));
144+
InputFile inputFile = fileSystem.inputFile(fileSystem.predicates().is(getContext().pythonFile().file()));
145145
if (inputFile == null){
146146
throw new IllegalStateException("InputFile is null, but it should not be.");
147147
}

0 commit comments

Comments
 (0)