Skip to content

Commit f754d80

Browse files
SONARPY-2155 Implement FunctionSymbolToDescriptorConverter
1 parent 88f3919 commit f754d80

File tree

2 files changed

+167
-0
lines changed

2 files changed

+167
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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.typeshed;
21+
22+
import java.util.Collection;
23+
import java.util.Optional;
24+
import org.sonar.python.index.FunctionDescriptor;
25+
import org.sonar.python.types.protobuf.SymbolsProtos;
26+
27+
public class FunctionSymbolToDescriptorConverter {
28+
29+
private final ParameterSymbolToDescriptorConverter parameterConverter;
30+
31+
public FunctionSymbolToDescriptorConverter() {
32+
parameterConverter = new ParameterSymbolToDescriptorConverter();
33+
}
34+
35+
public FunctionDescriptor convert(SymbolsProtos.FunctionSymbol functionSymbol) {
36+
return convert(functionSymbol, false);
37+
}
38+
39+
public FunctionDescriptor convert(SymbolsProtos.FunctionSymbol functionSymbol, boolean isParentIsAClass) {
40+
var fullyQualifiedName = TypeShedUtils.normalizedFqn(functionSymbol.getFullyQualifiedName());
41+
var returnType = TypeShedUtils.getTypesNormalizedFqn(functionSymbol.getReturnAnnotation());
42+
var decorators = Optional.of(functionSymbol)
43+
.map(SymbolsProtos.FunctionSymbol::getResolvedDecoratorNamesList)
44+
.stream()
45+
.flatMap(Collection::stream)
46+
.map(TypeShedUtils::normalizedFqn)
47+
.toList();
48+
var parameters = functionSymbol.getParametersList().stream()
49+
.map(parameterConverter::convert)
50+
.toList();
51+
var isInstanceMethod = isParentIsAClass && !functionSymbol.getIsStatic() && !functionSymbol.getIsClassMethod();
52+
return new FunctionDescriptor.FunctionDescriptorBuilder()
53+
.withName(functionSymbol.getName())
54+
.withFullyQualifiedName(fullyQualifiedName)
55+
.withIsAsynchronous(functionSymbol.getIsAsynchronous())
56+
.withIsInstanceMethod(isInstanceMethod)
57+
.withHasDecorators(functionSymbol.getHasDecorators())
58+
.withAnnotatedReturnTypeName(returnType)
59+
.withDecorators(decorators)
60+
.withParameters(parameters)
61+
.build();
62+
}
63+
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
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.typeshed;
21+
22+
import org.assertj.core.api.Assertions;
23+
import org.junit.jupiter.api.Test;
24+
import org.sonar.python.types.protobuf.SymbolsProtos;
25+
26+
class FunctionSymbolToDescriptorConverterTest {
27+
28+
@Test
29+
void test() {
30+
var converter = new FunctionSymbolToDescriptorConverter();
31+
32+
var symbol = SymbolsProtos.FunctionSymbol.newBuilder()
33+
.setName("foo")
34+
.setFullyQualifiedName("module.foo")
35+
.setIsAsynchronous(false)
36+
.setIsClassMethod(false)
37+
.setIsStatic(false)
38+
.setHasDecorators(true)
39+
.addResolvedDecoratorNames("decorator")
40+
.setReturnAnnotation(
41+
SymbolsProtos.Type.newBuilder()
42+
.setFullyQualifiedName("builtins.int")
43+
.build()
44+
)
45+
.addParameters(
46+
SymbolsProtos.ParameterSymbol.newBuilder()
47+
.setName("p1")
48+
.build()
49+
)
50+
.build();
51+
var descriptor = converter.convert(symbol);
52+
53+
Assertions.assertThat(descriptor.name()).isEqualTo("foo");
54+
Assertions.assertThat(descriptor.fullyQualifiedName()).isEqualTo("module.foo");
55+
Assertions.assertThat(descriptor.isAsynchronous()).isFalse();
56+
Assertions.assertThat(descriptor.isInstanceMethod()).isFalse();
57+
Assertions.assertThat(descriptor.hasDecorators()).isTrue();
58+
Assertions.assertThat(descriptor.annotatedReturnTypeName()).isEqualTo("int");
59+
Assertions.assertThat(descriptor.parameters()).hasSize(1);
60+
Assertions.assertThat(descriptor.parameters().get(0).name()).isEqualTo("p1");
61+
}
62+
63+
@Test
64+
void instanceMethodTest() {
65+
var converter = new FunctionSymbolToDescriptorConverter();
66+
67+
var symbol = SymbolsProtos.FunctionSymbol.newBuilder()
68+
.setIsClassMethod(false)
69+
.setIsStatic(false)
70+
.build();
71+
var descriptor = converter.convert(symbol, true);
72+
Assertions.assertThat(descriptor.isInstanceMethod()).isTrue();
73+
74+
symbol = SymbolsProtos.FunctionSymbol.newBuilder()
75+
.setIsClassMethod(true)
76+
.setIsStatic(false)
77+
.build();
78+
descriptor = converter.convert(symbol, true);
79+
Assertions.assertThat(descriptor.isInstanceMethod()).isFalse();
80+
81+
symbol = SymbolsProtos.FunctionSymbol.newBuilder()
82+
.setIsClassMethod(false)
83+
.setIsStatic(true)
84+
.build();
85+
descriptor = converter.convert(symbol, true);
86+
Assertions.assertThat(descriptor.isInstanceMethod()).isFalse();
87+
88+
symbol = SymbolsProtos.FunctionSymbol.newBuilder()
89+
.setIsClassMethod(true)
90+
.setIsStatic(true)
91+
.build();
92+
descriptor = converter.convert(symbol, true);
93+
Assertions.assertThat(descriptor.isInstanceMethod()).isFalse();
94+
95+
symbol = SymbolsProtos.FunctionSymbol.newBuilder()
96+
.setIsClassMethod(true)
97+
.setIsStatic(true)
98+
.build();
99+
descriptor = converter.convert(symbol, false);
100+
Assertions.assertThat(descriptor.isInstanceMethod()).isFalse();
101+
}
102+
103+
}

0 commit comments

Comments
 (0)