Skip to content

Commit f925834

Browse files
SONARPY-1785 Run the new symbol table builder and type inference engine during regular analysis
1 parent b710d18 commit f925834

File tree

4 files changed

+120
-15
lines changed

4 files changed

+120
-15
lines changed

python-frontend/src/main/java/org/sonar/plugins/python/api/PythonVisitorContext.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
import org.sonar.python.caching.CacheContextImpl;
3232
import org.sonar.python.semantic.ProjectLevelSymbolTable;
3333
import org.sonar.python.semantic.SymbolTableBuilder;
34+
import org.sonar.python.semantic.v2.ProjectLevelTypeTable;
35+
import org.sonar.python.semantic.v2.SymbolTableBuilderV2;
36+
import org.sonar.python.semantic.v2.TypeInferenceV2;
3437

3538
public class PythonVisitorContext extends PythonInputFileContext {
3639

@@ -44,6 +47,9 @@ public PythonVisitorContext(FileInput rootTree, PythonFile pythonFile, @Nullable
4447
this.parsingException = null;
4548
SymbolTableBuilder symbolTableBuilder = packageName != null ? new SymbolTableBuilder(packageName, pythonFile) : new SymbolTableBuilder(pythonFile);
4649
symbolTableBuilder.visitFileInput(rootTree);
50+
SymbolTableBuilderV2 symbolTableBuilderV2 = new SymbolTableBuilderV2();
51+
symbolTableBuilderV2.visitFileInput(rootTree);
52+
rootTree.accept(new TypeInferenceV2(new ProjectLevelTypeTable(ProjectLevelSymbolTable.empty())));
4753
}
4854

4955
public PythonVisitorContext(FileInput rootTree, PythonFile pythonFile, @Nullable File workingDirectory, String packageName,
@@ -52,6 +58,9 @@ public PythonVisitorContext(FileInput rootTree, PythonFile pythonFile, @Nullable
5258
this.rootTree = rootTree;
5359
this.parsingException = null;
5460
new SymbolTableBuilder(packageName, pythonFile, projectLevelSymbolTable).visitFileInput(rootTree);
61+
SymbolTableBuilderV2 symbolTableBuilderV2 = new SymbolTableBuilderV2();
62+
symbolTableBuilderV2.visitFileInput(rootTree);
63+
rootTree.accept(new TypeInferenceV2(new ProjectLevelTypeTable(ProjectLevelSymbolTable.empty())));
5564
}
5665

5766
public PythonVisitorContext(FileInput rootTree, PythonFile pythonFile, @Nullable File workingDirectory, String packageName,
@@ -60,6 +69,9 @@ public PythonVisitorContext(FileInput rootTree, PythonFile pythonFile, @Nullable
6069
this.rootTree = rootTree;
6170
this.parsingException = null;
6271
new SymbolTableBuilder(packageName, pythonFile, projectLevelSymbolTable).visitFileInput(rootTree);
72+
SymbolTableBuilderV2 symbolTableBuilderV2 = new SymbolTableBuilderV2();
73+
symbolTableBuilderV2.visitFileInput(rootTree);
74+
rootTree.accept(new TypeInferenceV2(new ProjectLevelTypeTable(projectLevelSymbolTable)));
6375
}
6476

6577
public PythonVisitorContext(PythonFile pythonFile, RecognitionException parsingException) {

python-frontend/src/main/java/org/sonar/python/semantic/v2/FunctionTypeBuilder.java

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
import static org.sonar.python.tree.TreeUtils.locationInFile;
3939

40-
public class FunctionTypeBuilder {
40+
public class FunctionTypeBuilder implements TypeBuilder<FunctionType> {
4141

4242
private boolean hasVariadicParameter;
4343
private String name;
@@ -66,6 +66,48 @@ public FunctionTypeBuilder fromFunctionDef(FunctionDef functionDef) {
6666
return this;
6767
}
6868

69+
public FunctionTypeBuilder(String name) {
70+
this.name = name;
71+
}
72+
73+
public FunctionTypeBuilder() {
74+
}
75+
76+
public FunctionTypeBuilder withHasVariadicParameter(boolean hasVariadicParameter) {
77+
this.hasVariadicParameter = hasVariadicParameter;
78+
return this;
79+
}
80+
81+
public FunctionTypeBuilder withAttributes(List<PythonType> attributes) {
82+
this.attributes = attributes;
83+
return this;
84+
}
85+
86+
public FunctionTypeBuilder withParameters(List<ParameterV2> parameters) {
87+
this.parameters = parameters;
88+
return this;
89+
}
90+
91+
public FunctionTypeBuilder withAsynchronous(boolean asynchronous) {
92+
isAsynchronous = asynchronous;
93+
return this;
94+
}
95+
96+
public FunctionTypeBuilder withHasDecorators(boolean hasDecorators) {
97+
this.hasDecorators = hasDecorators;
98+
return this;
99+
}
100+
101+
public FunctionTypeBuilder withInstanceMethod(boolean instanceMethod) {
102+
isInstanceMethod = instanceMethod;
103+
return this;
104+
}
105+
106+
public FunctionTypeBuilder withReturnType(PythonType returnType) {
107+
this.returnType = returnType;
108+
return this;
109+
}
110+
69111
public FunctionType build() {
70112
return new FunctionType(name, attributes, parameters, returnType, isAsynchronous, hasDecorators, isInstanceMethod, hasVariadicParameter, owner);
71113
}
@@ -77,8 +119,9 @@ private static boolean isInstanceMethod(FunctionDef functionDef) {
77119
.noneMatch(decorator -> decorator.equals(STATIC_METHOD_DECORATOR) || decorator.equals(CLASS_METHOD_DECORATOR));
78120
}
79121

80-
public void setOwner(PythonType owner) {
122+
public FunctionTypeBuilder withOwner(PythonType owner) {
81123
this.owner = owner;
124+
return this;
82125
}
83126

84127
private void createParameterNames(List<AnyParameter> parameterTrees, @Nullable String fileId) {

python-frontend/src/main/java/org/sonar/python/semantic/v2/SymbolsModuleTypeProvider.java

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ private static ModuleType createEmptyModule(String moduleName, ModuleType parent
8484
private ModuleType createModuleFromSymbols(String name, ModuleType parent, Collection<Symbol> symbols) {
8585
var members = new HashMap<String, PythonType>();
8686
symbols.forEach(symbol -> {
87-
var type = convertToType(symbol);
87+
var type = convertToType(symbol, new HashMap<>());
8888
members.put(symbol.name(), type);
8989
});
9090
var module = new ModuleType(name, parent);
@@ -99,26 +99,49 @@ private static PythonType convertToObjectType(Symbol symbol) {
9999
return PythonType.UNKNOWN;
100100
}
101101

102-
private static PythonType convertToFunctionType(FunctionSymbol symbol) {
103-
return new FunctionType(symbol.name(), List.of(), List.of(), PythonType.UNKNOWN, false, false, false, false, null);
102+
private static PythonType convertToFunctionType(FunctionSymbol symbol, Map<Symbol, PythonType> createdTypesBySymbol) {
103+
// TODO: ensure we don't build twice
104+
if (createdTypesBySymbol.containsKey(symbol)) {
105+
return createdTypesBySymbol.get(symbol);
106+
}
107+
FunctionTypeBuilder functionTypeBuilder =
108+
new FunctionTypeBuilder(symbol.name())
109+
.withAttributes(List.of())
110+
.withParameters(List.of())
111+
.withReturnType(PythonType.UNKNOWN)
112+
.withAsynchronous(false)
113+
.withHasDecorators(false)
114+
.withInstanceMethod(false)
115+
.withHasVariadicParameter(false)
116+
.withOwner(null);
117+
FunctionType functionType = functionTypeBuilder.build();
118+
createdTypesBySymbol.put(symbol, functionType);
119+
return functionType;
104120
}
105121

106-
private PythonType convertToClassType(ClassSymbol symbol) {
107-
Set<Member> members = symbol.declaredMembers().stream().map(m -> new Member(m.name(), convertToType(m))).collect(Collectors.toSet());
108-
List<PythonType> superClasses = symbol.superClasses().stream().map(this::convertToType).toList();
109-
return new ClassType(symbol.name(), members, List.of(), superClasses);
122+
private PythonType convertToClassType(ClassSymbol symbol, Map<Symbol, PythonType> createdTypesBySymbol) {
123+
if (createdTypesBySymbol.containsKey(symbol)) {
124+
return createdTypesBySymbol.get(symbol);
125+
}
126+
ClassType classType = new ClassType(symbol.name());
127+
createdTypesBySymbol.put(symbol, classType);
128+
Set<Member> members = symbol.declaredMembers().stream().map(m -> new Member(m.name(), convertToType(m, createdTypesBySymbol))).collect(Collectors.toSet());
129+
classType.members().addAll(members);
130+
List<PythonType> superClasses = symbol.superClasses().stream().map(s -> convertToType(s, createdTypesBySymbol)).toList();
131+
classType.superClasses().addAll(superClasses);
132+
return classType;
110133
}
111134

112-
private PythonType convertToUnionType(AmbiguousSymbol ambiguousSymbol) {
113-
List<PythonType> pythonTypes = ambiguousSymbol.alternatives().stream().map(this::convertToType).toList();
135+
private PythonType convertToUnionType(AmbiguousSymbol ambiguousSymbol, Map<Symbol, PythonType> createdTypesBySymbol) {
136+
List<PythonType> pythonTypes = ambiguousSymbol.alternatives().stream().map(a -> convertToType(a, createdTypesBySymbol)).toList();
114137
return new UnionType(pythonTypes);
115138
}
116139

117-
private PythonType convertToType(Symbol symbol) {
140+
private PythonType convertToType(Symbol symbol, Map<Symbol, PythonType> createdTypesBySymbol) {
118141
return switch (symbol.kind()) {
119-
case CLASS -> convertToClassType((ClassSymbol) symbol);
120-
case FUNCTION -> convertToFunctionType((FunctionSymbol) symbol);
121-
case AMBIGUOUS -> convertToUnionType((AmbiguousSymbol) symbol);
142+
case CLASS -> convertToClassType((ClassSymbol) symbol, createdTypesBySymbol);
143+
case FUNCTION -> convertToFunctionType((FunctionSymbol) symbol, createdTypesBySymbol);
144+
case AMBIGUOUS -> convertToUnionType((AmbiguousSymbol) symbol, createdTypesBySymbol);
122145
case OTHER -> convertToObjectType(symbol);
123146
};
124147
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* SonarQube Python Plugin
3+
* Copyright (C) 2011-2024 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.semantic.v2;
21+
22+
import org.sonar.python.types.v2.PythonType;
23+
24+
public interface TypeBuilder<T extends PythonType> {
25+
26+
T build();
27+
}

0 commit comments

Comments
 (0)