Skip to content

Commit

Permalink
SONARPY-2242 TypeInferenceV2 should resolve stubs with variable descr…
Browse files Browse the repository at this point in the history
…iptors pointing to submodules (#2094)
  • Loading branch information
ghislainpiot authored Oct 25, 2024
1 parent a95937e commit a91a2d5
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,17 @@ public class VariableDescriptor implements Descriptor {
private final String name;
private final String fullyQualifiedName;
private final String annotatedType;
private final boolean isImportedModule;

public VariableDescriptor(String name, @Nullable String fullyQualifiedName, @Nullable String annotatedType) {
public VariableDescriptor(String name, @Nullable String fullyQualifiedName, @Nullable String annotatedType, boolean isImportedModule) {
this.name = name;
this.fullyQualifiedName = fullyQualifiedName;
this.annotatedType = annotatedType;
this.isImportedModule = isImportedModule;
}

public VariableDescriptor(String name, @Nullable String fullyQualifiedName, @Nullable String annotatedType) {
this(name, fullyQualifiedName, annotatedType, false);
}

@Override
Expand All @@ -52,4 +58,8 @@ public Kind kind() {
public String annotatedType() {
return annotatedType;
}

public boolean isImportedModule() {
return isImportedModule;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,12 @@ public PythonType getType(List<String> typeFqnParts) {
if (parent instanceof ModuleType moduleType) {
TypeWrapper typeWrapper = moduleType.members().get(part);
if (typeWrapper instanceof LazyTypeWrapper lazyTypeWrapper && !lazyTypeWrapper.isResolved()) {
if (i == typeFqnParts.size() - 1) {
// this is the name we are looking for, resolve it
if (shouldResolveImmediately(lazyTypeWrapper, typeFqnParts, i)) {
// We try to resolve the type of the member if it points to a different module.
// If it points to the same module, we try to resolve the submodule of the same name
return typeWrapper.type();
}

// The member of the module is a LazyType, which means it's a re-exported type from a submodule
// We try to resolve the submodule instead
Optional<PythonType> subModule = moduleType.resolveSubmodule(part);
Expand All @@ -90,6 +92,10 @@ public PythonType getType(List<String> typeFqnParts) {
return parent;
}

private static boolean shouldResolveImmediately(LazyTypeWrapper lazyTypeWrapper, List<String> typeFqnParts, int i) {
return i == typeFqnParts.size() - 1 && !(lazyTypeWrapper.hasImportPath(String.join(".", typeFqnParts)));
}

/**
* This method returns a module type for a given FQN, or unknown if it cannot be resolved.
* It is to be used to retrieve modules referenced in the "from" clause of an "import from" statement,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
public class VariableDescriptorToPythonTypeConverter implements DescriptorToPythonTypeConverter {

public PythonType convert(ConversionContext ctx, VariableDescriptor from) {
if (from.isImportedModule()) {
var fqn = from.fullyQualifiedName();
if (fqn != null) {
return ctx.lazyTypesContext().getOrCreateLazyType(fqn);
}
}
return Optional.ofNullable(from.annotatedType())
.map(fqn -> ctx.lazyTypesContext().getOrCreateLazyTypeWrapper(fqn))
.map(t -> (PythonType) new ObjectType(t))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ public class VarSymbolToDescriptorConverter {
public Descriptor convert(SymbolsProtos.VarSymbol varSymbol) {
var fullyQualifiedName = TypeShedUtils.normalizedFqn(varSymbol.getFullyQualifiedName());
var typeAnnotation = TypeShedUtils.getTypesNormalizedFqn(varSymbol.getTypeAnnotation());
var isImportedModule = varSymbol.getIsImportedModule();
if (isTypeAnnotationKnownToBeIncorrect(fullyQualifiedName)) {
return new VariableDescriptor(varSymbol.getName(), fullyQualifiedName, null);
return new VariableDescriptor(varSymbol.getName(), fullyQualifiedName, null, isImportedModule);
}
return new VariableDescriptor(varSymbol.getName(), fullyQualifiedName, typeAnnotation);
return new VariableDescriptor(varSymbol.getName(), fullyQualifiedName, typeAnnotation, isImportedModule);
}

private static boolean isTypeAnnotationKnownToBeIncorrect(String fullyQualifiedName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public boolean isResolved() {
return !(type instanceof LazyType);
}

public boolean hasImportPath(String importPath) {
return ((LazyType) type).importPath().equals(importPath);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,4 +253,14 @@ class lib: ...
// SONARPY-2176 lib should be resolved as the renamed class "A" here
assertThat(aType.name()).isEqualTo("A");
}

@Test
void resolveStubsWithImportedModuleVariableDescriptor() {
var symbolTable = ProjectLevelSymbolTable.empty();
var table = new ProjectLevelTypeTable(symbolTable);

var nnModuleType = table.getType("torch.nn");

Assertions.assertThat(nnModuleType).isNotNull().isInstanceOf(ModuleType.class);
}
}

0 comments on commit a91a2d5

Please sign in to comment.