Skip to content

Commit ae9fcb8

Browse files
SONARPY-845 Introduce PythonIndexer wrapper for ProjectLevelSymbolTable (#916)
1 parent 87e8c06 commit ae9fcb8

File tree

2 files changed

+98
-44
lines changed

2 files changed

+98
-44
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* SonarQube Python Plugin
3+
* Copyright (C) 2011-2021 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.plugins.python;
21+
22+
import com.sonar.sslr.api.AstNode;
23+
import java.io.IOException;
24+
import java.net.URI;
25+
import java.util.HashMap;
26+
import java.util.List;
27+
import java.util.Map;
28+
import org.sonar.api.batch.fs.InputFile;
29+
import org.sonar.api.batch.sensor.SensorContext;
30+
import org.sonar.api.utils.log.Logger;
31+
import org.sonar.api.utils.log.Loggers;
32+
import org.sonar.plugins.python.api.PythonFile;
33+
import org.sonar.plugins.python.api.tree.FileInput;
34+
import org.sonar.python.parser.PythonParser;
35+
import org.sonar.python.semantic.ProjectLevelSymbolTable;
36+
import org.sonar.python.tree.PythonTreeMaker;
37+
38+
import static org.sonar.python.semantic.SymbolUtils.pythonPackageName;
39+
40+
public class PythonIndexer {
41+
42+
private static final Logger LOG = Loggers.get(PythonIndexer.class);
43+
44+
private final Map<URI, String> packageNames = new HashMap<>();
45+
private final PythonParser parser = PythonParser.create();
46+
private final ProjectLevelSymbolTable projectLevelSymbolTable = new ProjectLevelSymbolTable();
47+
48+
49+
void buildOnce(SensorContext context, List<InputFile> files) {
50+
LOG.debug("Input files for indexing: " + files);
51+
// computes "globalSymbolsByModuleName"
52+
long startTime = System.currentTimeMillis();
53+
GlobalSymbolsScanner globalSymbolsStep = new GlobalSymbolsScanner(context);
54+
globalSymbolsStep.execute(files, context);
55+
long stopTime = System.currentTimeMillis() - startTime;
56+
LOG.debug("Time to build the project level symbol table: " + stopTime + "ms");
57+
}
58+
59+
String packageName(URI uri) {
60+
return packageNames.get(uri);
61+
}
62+
63+
ProjectLevelSymbolTable projectLevelSymbolTable() {
64+
return projectLevelSymbolTable;
65+
}
66+
67+
private class GlobalSymbolsScanner extends Scanner {
68+
69+
private GlobalSymbolsScanner(SensorContext context) {
70+
super(context);
71+
}
72+
73+
@Override
74+
protected String name() {
75+
return "global symbols computation";
76+
}
77+
78+
@Override
79+
protected void scanFile(InputFile inputFile) throws IOException {
80+
AstNode astNode = parser.parse(inputFile.contents());
81+
FileInput astRoot = new PythonTreeMaker().fileInput(astNode);
82+
String packageName = pythonPackageName(inputFile.file(), context.fileSystem().baseDir());
83+
packageNames.put(inputFile.uri(), packageName);
84+
PythonFile pythonFile = SonarQubePythonFile.create(inputFile);
85+
projectLevelSymbolTable.addModule(astRoot, packageName, pythonFile);
86+
}
87+
88+
@Override
89+
protected void processException(Exception e, InputFile file) {
90+
LOG.debug("Unable to construct project-level symbol table for file: " + file.toString());
91+
LOG.debug(e.getMessage());
92+
}
93+
}
94+
}

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

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,10 @@
2222
import com.sonar.sslr.api.AstNode;
2323
import com.sonar.sslr.api.RecognitionException;
2424
import java.io.File;
25-
import java.io.IOException;
2625
import java.util.ArrayDeque;
2726
import java.util.ArrayList;
2827
import java.util.Deque;
29-
import java.util.HashMap;
3028
import java.util.List;
31-
import java.util.Map;
3229
import java.util.Set;
3330
import javax.annotation.CheckForNull;
3431
import org.sonar.api.SonarProduct;
@@ -57,22 +54,18 @@
5754
import org.sonar.python.metrics.FileLinesVisitor;
5855
import org.sonar.python.metrics.FileMetrics;
5956
import org.sonar.python.parser.PythonParser;
60-
import org.sonar.python.semantic.ProjectLevelSymbolTable;
6157
import org.sonar.python.tree.PythonTreeMaker;
6258

63-
import static org.sonar.python.semantic.SymbolUtils.pythonPackageName;
64-
6559
public class PythonScanner extends Scanner {
6660

6761
private static final Logger LOG = Loggers.get(PythonScanner.class);
6862

6963
private final PythonParser parser;
70-
private final Map<InputFile, String> packageNames = new HashMap<>();
7164
private final PythonChecks checks;
7265
private final FileLinesContextFactory fileLinesContextFactory;
7366
private final NoSonarFilter noSonarFilter;
7467
private final PythonCpdAnalyzer cpdAnalyzer;
75-
private final ProjectLevelSymbolTable projectLevelSymbolTable = new ProjectLevelSymbolTable();
68+
private final PythonIndexer indexer;
7669

7770

7871
public PythonScanner(
@@ -85,13 +78,8 @@ public PythonScanner(
8578
this.noSonarFilter = noSonarFilter;
8679
this.cpdAnalyzer = new PythonCpdAnalyzer(context);
8780
this.parser = PythonParser.create();
88-
89-
// computes "globalSymbolsByModuleName"
90-
long startTime = System.currentTimeMillis();
91-
GlobalSymbolsScanner globalSymbolsStep = new GlobalSymbolsScanner(context);
92-
globalSymbolsStep.execute(files, context);
93-
long stopTime = System.currentTimeMillis() - startTime;
94-
LOG.debug("Time to build the project level symbol table: " + stopTime + "ms");
81+
this.indexer = new PythonIndexer();
82+
this.indexer.buildOnce(context, files);
9583
}
9684

9785
@Override
@@ -106,7 +94,7 @@ protected void scanFile(InputFile inputFile) {
10694
try {
10795
AstNode astNode = parser.parse(pythonFile.content());
10896
FileInput parse = new PythonTreeMaker().fileInput(astNode);
109-
visitorContext = new PythonVisitorContext(parse, pythonFile, getWorkingDirectory(context), packageNames.get(inputFile), projectLevelSymbolTable);
97+
visitorContext = new PythonVisitorContext(parse, pythonFile, getWorkingDirectory(context), indexer.packageName(inputFile.uri()), indexer.projectLevelSymbolTable());
11098
saveMeasures(inputFile, visitorContext);
11199
} catch (RecognitionException e) {
112100
visitorContext = new PythonVisitorContext(pythonFile, e);
@@ -245,32 +233,4 @@ private void saveMetricOnFile(InputFile inputFile, Metric<Integer> metric, Integ
245233
.on(inputFile)
246234
.save();
247235
}
248-
249-
private class GlobalSymbolsScanner extends Scanner {
250-
251-
private GlobalSymbolsScanner(SensorContext context) {
252-
super(context);
253-
}
254-
255-
@Override
256-
protected String name() {
257-
return "global symbols computation";
258-
}
259-
260-
@Override
261-
protected void scanFile(InputFile inputFile) throws IOException {
262-
AstNode astNode = parser.parse(inputFile.contents());
263-
FileInput astRoot = new PythonTreeMaker().fileInput(astNode);
264-
String packageName = pythonPackageName(inputFile.file(), context.fileSystem().baseDir());
265-
packageNames.put(inputFile, packageName);
266-
PythonFile pythonFile = SonarQubePythonFile.create(inputFile);
267-
projectLevelSymbolTable.addModule(astRoot, packageName, pythonFile);
268-
}
269-
270-
@Override
271-
protected void processException(Exception e, InputFile file) {
272-
LOG.debug("Unable to construct project-level symbol table for file: " + file.toString());
273-
LOG.debug(e.getMessage());
274-
}
275-
}
276236
}

0 commit comments

Comments
 (0)