Skip to content

Commit

Permalink
SONARPY-2346 Remove usage of old ProjectLevelSymbolTable#from using V…
Browse files Browse the repository at this point in the history
…1 symbols (#2199)
  • Loading branch information
ghislainpiot authored Dec 4, 2024
1 parent efcd828 commit 33ea204
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 289 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public static PythonVisitorContext createNotebookContext(File file, Map<Integer,
}

public static ProjectLevelSymbolTable globalSymbols(List<File> files, File baseDir) {
ProjectLevelSymbolTable projectLevelSymbolTable = new ProjectLevelSymbolTable();
ProjectLevelSymbolTable projectLevelSymbolTable = ProjectLevelSymbolTable.empty();
for (File file : files) {
var pythonFile = new TestPythonFile(file);
if (pythonFile.isIPython()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,10 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.sonar.plugins.python.api.symbols.AmbiguousSymbol;
import org.sonar.plugins.python.api.symbols.ClassSymbol;
import org.sonar.plugins.python.api.symbols.FunctionSymbol;
import org.sonar.plugins.python.api.symbols.Symbol;
import org.sonar.plugins.python.api.types.InferredType;
import org.sonar.python.semantic.AmbiguousSymbolImpl;
Expand All @@ -45,76 +40,6 @@ public class DescriptorUtils {

private DescriptorUtils() {}

public static Descriptor descriptor(Symbol symbol) {
switch (symbol.kind()) {
case FUNCTION:
return functionDescriptor(((FunctionSymbol) symbol));
case CLASS:
return classDescriptor((ClassSymbol) symbol);
case AMBIGUOUS:
return ambiguousDescriptor((AmbiguousSymbol) symbol);
default:
return new VariableDescriptor(symbol.name(), symbol.fullyQualifiedName(), symbol.annotatedTypeName());
}
}

private static ClassDescriptor classDescriptor(ClassSymbol classSymbol) {
ClassDescriptor.ClassDescriptorBuilder classDescriptor = new ClassDescriptor.ClassDescriptorBuilder()
.withName(classSymbol.name())
.withFullyQualifiedName(classSymbol.fullyQualifiedName())
.withMembers(classSymbol.declaredMembers().stream().map(DescriptorUtils::descriptor).collect(Collectors.toSet()))
.withSuperClasses(classSymbol.superClasses().stream().map(Symbol::fullyQualifiedName).filter(Objects::nonNull).toList())
.withDefinitionLocation(classSymbol.definitionLocation())
.withHasMetaClass(((ClassSymbolImpl) classSymbol).hasMetaClass())
.withHasSuperClassWithoutDescriptor(((ClassSymbolImpl) classSymbol).hasSuperClassWithoutSymbol() ||
// Setting hasSuperClassWithoutDescriptor if a parent has a null FQN as it would be impossible to retrieve it without one, even if the parent exists.
classSymbol.superClasses().stream().anyMatch(s -> s.fullyQualifiedName() == null))
.withMetaclassFQN(((ClassSymbolImpl) classSymbol).metaclassFQN())
.withHasDecorators(classSymbol.hasDecorators())
.withSupportsGenerics(((ClassSymbolImpl) classSymbol).supportsGenerics());

return classDescriptor.build();
}

private static FunctionDescriptor functionDescriptor(FunctionSymbol functionSymbol) {
return new FunctionDescriptor.FunctionDescriptorBuilder()
.withName(functionSymbol.name())
.withFullyQualifiedName(functionSymbol.fullyQualifiedName())
.withParameters(parameters(functionSymbol.parameters()))
.withHasDecorators(functionSymbol.hasDecorators())
.withDecorators(functionSymbol.decorators())
.withIsAsynchronous(functionSymbol.isAsynchronous())
.withIsInstanceMethod(functionSymbol.isInstanceMethod())
.withAnnotatedReturnTypeName(functionSymbol.annotatedReturnTypeName())
.withDefinitionLocation(functionSymbol.definitionLocation())
.build();
}

private static AmbiguousDescriptor ambiguousDescriptor(AmbiguousSymbol ambiguousSymbol) {
return ambiguousDescriptor(ambiguousSymbol, null);
}

public static AmbiguousDescriptor ambiguousDescriptor(AmbiguousSymbol ambiguousSymbol, @Nullable String overriddenFQN) {
String fullyQualifiedName = overriddenFQN != null ? overriddenFQN : ambiguousSymbol.fullyQualifiedName();
Set<Descriptor> alternatives = ambiguousSymbol.alternatives().stream()
.map(DescriptorUtils::descriptor)
.collect(Collectors.toSet());
return new AmbiguousDescriptor(ambiguousSymbol.name(), fullyQualifiedName, alternatives);
}

private static List<FunctionDescriptor.Parameter> parameters(List<FunctionSymbol.Parameter> parameters) {
return parameters.stream().map(parameter -> new FunctionDescriptor.Parameter(
parameter.name(),
((FunctionSymbolImpl.ParameterImpl) parameter).annotatedTypeName(),
parameter.hasDefaultValue(),
parameter.isKeywordOnly(),
parameter.isPositionalOnly(),
parameter.isPositionalVariadic(),
parameter.isKeywordVariadic(),
parameter.location()
)).toList();
}

// TODO SONARPY-958: Cleanup the symbol construction from descriptors by extracting this logic in a builder class
public static Symbol symbolFromDescriptor(Descriptor descriptor, ProjectLevelSymbolTable projectLevelSymbolTable,
@Nullable String localSymbolName, Map<Descriptor, Symbol> createdSymbolsByDescriptor, Map<String, Symbol> createdSymbolsByFqn) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,25 +61,22 @@ public class ProjectLevelSymbolTable {
private TypeShedDescriptorsProvider typeShedDescriptorsProvider = null;

public static ProjectLevelSymbolTable empty() {
return new ProjectLevelSymbolTable(Collections.emptyMap());
return new ProjectLevelSymbolTable();
}

public static ProjectLevelSymbolTable from(Map<String, Set<Symbol>> globalSymbolsByModuleName) {
return new ProjectLevelSymbolTable(globalSymbolsByModuleName);
}
public static ProjectLevelSymbolTable from(Map<String, Set<Descriptor>> globalDescriptorsByModuleName) {
var projectLevelSymbolTable = ProjectLevelSymbolTable.empty();

public ProjectLevelSymbolTable() {
this.globalDescriptorsByModuleName = new HashMap<>();
for (var entry : globalDescriptorsByModuleName.entrySet()) {
var descriptors = entry.getValue();
projectLevelSymbolTable.globalDescriptorsByModuleName.put(entry.getKey(), descriptors);
}

return projectLevelSymbolTable;
}

private ProjectLevelSymbolTable(Map<String, Set<Symbol>> globalSymbolsByModuleName) {
private ProjectLevelSymbolTable() {
this.globalDescriptorsByModuleName = new HashMap<>();
globalSymbolsByModuleName.entrySet().forEach(entry -> {
String moduleName = entry.getKey();
Set<Symbol> symbols = entry.getValue();
Set<Descriptor> globalDescriptors = symbols.stream().map(DescriptorUtils::descriptor).collect(Collectors.toSet());
globalDescriptorsByModuleName.put(moduleName, globalDescriptors);
});
}

public void removeModule(String packageName, String fileName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@

import com.sonar.sslr.api.RecognitionException;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.Test;
Expand All @@ -33,9 +30,10 @@
import org.sonar.plugins.python.api.tree.Tree;
import org.sonar.python.PythonTestUtils;
import org.sonar.python.caching.CacheContextImpl;
import org.sonar.python.index.Descriptor;
import org.sonar.python.index.VariableDescriptor;
import org.sonar.python.parser.PythonParser;
import org.sonar.python.semantic.ProjectLevelSymbolTable;
import org.sonar.python.semantic.SymbolImpl;
import org.sonar.python.tree.FileInputImpl;
import org.sonar.python.tree.PythonTreeMaker;

Expand Down Expand Up @@ -82,9 +80,11 @@ void globalSymbols() {
String code = "from mod import a, b";
FileInput fileInput = new PythonTreeMaker().fileInput(PythonParser.create().parse(code));
PythonFile pythonFile = pythonFile("my_module.py");
List<Symbol> modSymbols = Arrays.asList(new SymbolImpl("a", null), new SymbolImpl("b", null));
Map<String, Set<Symbol>> globalSymbols = Collections.singletonMap("mod", new HashSet<>(modSymbols));
new PythonVisitorContext(fileInput, pythonFile, null, "my_package", ProjectLevelSymbolTable.from(globalSymbols), null);

Set<Descriptor> descriptors = Set.of(new VariableDescriptor("a", "mod.a", null), new VariableDescriptor("b", "mod.b", null));
Map<String, Set<Descriptor>> globalDescriptors = Collections.singletonMap("mod", descriptors);

new PythonVisitorContext(fileInput, pythonFile, null, "my_package", ProjectLevelSymbolTable.from(globalDescriptors), CacheContextImpl.dummyCache());
assertThat(fileInput.globalVariables()).extracting(Symbol::name).containsExactlyInAnyOrder("a", "b");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.sonar.plugins.python.api.tree.Name;
import org.sonar.python.semantic.SymbolImpl;
import org.sonar.python.semantic.v2.SymbolV2;
import org.sonar.python.semantic.v2.converter.PythonTypeToDescriptorConverter;
import org.sonar.python.types.v2.PythonType;
Expand All @@ -30,7 +29,6 @@
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.sonar.python.index.ClassDescriptorTest.lastClassDescriptor;
import static org.sonar.python.index.DescriptorToProtobufTestUtils.assertDescriptorToProtobuf;
import static org.sonar.python.index.DescriptorUtils.descriptor;
import static org.sonar.python.index.FunctionDescriptorTest.lastFunctionDescriptor;
import static org.sonar.python.types.v2.TypesTestUtils.lastName;

Expand Down Expand Up @@ -110,10 +108,8 @@ void test_different_names_illegal_argument() {

@Test
void ambiguous_descriptor_creation_different_name_same_fqn() {
SymbolImpl foo = new SymbolImpl("foo", "mod.bar");
SymbolImpl bar = new SymbolImpl("bar", "mod.bar");
Descriptor fooDesc = descriptor(foo);
Descriptor barDesc = descriptor(bar);
Descriptor fooDesc = new VariableDescriptor("foo", "mod.bar", null, false);
Descriptor barDesc = new VariableDescriptor("bar", "mod.bar", null, false);
assertThatThrownBy(() -> AmbiguousDescriptor.create(fooDesc, barDesc)).isInstanceOf(IllegalArgumentException.class);
}

Expand Down
Loading

0 comments on commit 33ea204

Please sign in to comment.