Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SONARPY-2346 Remove usage of old ProjectLevelSymbolTable#from using V1 symbols #2199

Merged
merged 4 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
Seppli11 marked this conversation as resolved.
Show resolved Hide resolved

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
Loading