Skip to content

Commit 0a146e5

Browse files
SONARPY-2129 Implement VariableDescriptorToPythonTypeConverter (#1973)
1 parent ea4a0e0 commit 0a146e5

File tree

6 files changed

+111
-4
lines changed

6 files changed

+111
-4
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ public AnyDescriptorToPythonTypeConverter(LazyTypesContext lazyTypesContext) {
3535
this.lazyTypesContext = lazyTypesContext;
3636
converters = new EnumMap<>(Map.of(
3737
Descriptor.Kind.CLASS, new ClassDescriptorToPythonTypeConverter(),
38-
Descriptor.Kind.FUNCTION, new FunctionDescriptorToPythonTypeConverter()
38+
Descriptor.Kind.FUNCTION, new FunctionDescriptorToPythonTypeConverter(),
39+
Descriptor.Kind.VARIABLE, new VariableDescriptorToPythonTypeConverter()
3940
));
4041
}
4142

@@ -52,5 +53,4 @@ private DescriptorToPythonTypeConverter converterFor(Descriptor descriptor) {
5253
return converters.getOrDefault(descriptor.kind(), UNKNOWN_DESCRIPTOR_CONVERTER);
5354
}
5455

55-
5656
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,4 @@ public interface DescriptorToPythonTypeConverter {
2626

2727
PythonType convert(ConversionContext ctx, Descriptor from);
2828

29-
3029
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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.converter;
21+
22+
import java.util.Optional;
23+
import org.sonar.python.index.Descriptor;
24+
import org.sonar.python.index.VariableDescriptor;
25+
import org.sonar.python.types.v2.ObjectType;
26+
import org.sonar.python.types.v2.PythonType;
27+
import org.sonar.python.types.v2.TypeWrapper;
28+
29+
public class VariableDescriptorToPythonTypeConverter implements DescriptorToPythonTypeConverter {
30+
31+
public PythonType convert(ConversionContext ctx, VariableDescriptor from) {
32+
var typeWrapper = Optional.ofNullable(from.annotatedType())
33+
.map(fqn -> ctx.lazyTypesContext().getOrCreateLazyTypeWrapper(fqn))
34+
.orElse(TypeWrapper.UNKNOWN_TYPE_WRAPPER);
35+
return new ObjectType(typeWrapper);
36+
}
37+
38+
@Override
39+
public PythonType convert(ConversionContext ctx, Descriptor from) {
40+
if (from instanceof VariableDescriptor variableDescriptor) {
41+
return convert(ctx, variableDescriptor);
42+
}
43+
throw new IllegalArgumentException("Unsupported Descriptor");
44+
}
45+
}

python-frontend/src/test/java/org/sonar/python/semantic/v2/converter/ConversionContextTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,5 +72,4 @@ void convertTest() {
7272
Assertions.assertSame(expectedType, type);
7373
}
7474

75-
7675
}

python-frontend/src/test/java/org/sonar/python/semantic/v2/converter/DescriptorToPythonTypeConverterTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,15 @@
2828
import org.sonar.python.index.ClassDescriptor;
2929
import org.sonar.python.index.Descriptor;
3030
import org.sonar.python.index.FunctionDescriptor;
31+
import org.sonar.python.index.VariableDescriptor;
3132
import org.sonar.python.semantic.v2.ClassTypeBuilder;
3233
import org.sonar.python.semantic.v2.LazyTypesContext;
3334
import org.sonar.python.types.v2.ClassType;
3435
import org.sonar.python.types.v2.FunctionType;
3536
import org.sonar.python.types.v2.LazyType;
37+
import org.sonar.python.types.v2.LazyTypeWrapper;
3638
import org.sonar.python.types.v2.Member;
39+
import org.sonar.python.types.v2.ObjectType;
3740
import org.sonar.python.types.v2.PythonType;
3841
import org.sonar.python.types.v2.TypeWrapper;
3942

@@ -142,5 +145,29 @@ void functionDescriptorConversionTest() {
142145
.isSameAs(resolvedReturnType);
143146
}
144147

148+
@Test
149+
void variableDescriptorConversionTest() {
150+
var lazyTypesContext = Mockito.mock(LazyTypesContext.class);
151+
var converter = new AnyDescriptorToPythonTypeConverter(lazyTypesContext);
152+
var descriptor = Mockito.mock(VariableDescriptor.class);
153+
154+
var variableTypeName = "Returned";
155+
var resolvedVariableType = new ClassTypeBuilder().withName(variableTypeName).build();
156+
157+
Mockito.when(descriptor.kind()).thenReturn(Descriptor.Kind.VARIABLE);
158+
Mockito.when(descriptor.name()).thenReturn("variable");
159+
Mockito.when(descriptor.annotatedType()).thenReturn(variableTypeName);
160+
161+
Mockito.when(lazyTypesContext.getOrCreateLazyTypeWrapper(variableTypeName))
162+
.thenReturn(new LazyTypeWrapper(new LazyType(variableTypeName, lazyTypesContext)));
163+
164+
Mockito.when(lazyTypesContext.resolveLazyType(Mockito.argThat(lt -> variableTypeName.equals(lt.fullyQualifiedName()))))
165+
.thenReturn(resolvedVariableType);
166+
167+
var type = (ObjectType) converter.convert(descriptor);
168+
Assertions.assertThat(type)
169+
.extracting(PythonType::unwrappedType)
170+
.isSameAs(resolvedVariableType);
171+
}
145172

146173
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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.converter;
21+
22+
import org.assertj.core.api.Assertions;
23+
import org.junit.jupiter.api.Test;
24+
import org.mockito.Mockito;
25+
import org.sonar.python.index.ClassDescriptor;
26+
27+
class VariableDescriptorToPythonTypeConverterTest {
28+
@Test
29+
void unsupportedClassTest() {
30+
var ctx = Mockito.mock(ConversionContext.class);
31+
var descriptor = Mockito.mock(ClassDescriptor.class);
32+
var converter = new VariableDescriptorToPythonTypeConverter();
33+
Assertions.assertThatThrownBy(() -> converter.convert(ctx, descriptor))
34+
.isInstanceOf(IllegalArgumentException.class)
35+
.hasMessage("Unsupported Descriptor");
36+
}
37+
}

0 commit comments

Comments
 (0)