Skip to content

Commit 214b742

Browse files
SONARPY-2157 Implement OverloadedFunctionSymbolToDescriptorConverter
1 parent f754d80 commit 214b742

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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.stream.Collectors;
23+
import org.sonar.python.index.AmbiguousDescriptor;
24+
import org.sonar.python.index.Descriptor;
25+
import org.sonar.python.types.protobuf.SymbolsProtos;
26+
27+
public class OverloadedFunctionSymbolToDescriptorConverter {
28+
29+
private final FunctionSymbolToDescriptorConverter functionConverter;
30+
31+
public OverloadedFunctionSymbolToDescriptorConverter(FunctionSymbolToDescriptorConverter functionConverter2) {
32+
functionConverter = functionConverter2;
33+
}
34+
35+
public AmbiguousDescriptor convert(SymbolsProtos.OverloadedFunctionSymbol overloadedFunctionSymbol) {
36+
return convert(overloadedFunctionSymbol, false);
37+
}
38+
39+
public AmbiguousDescriptor convert(SymbolsProtos.OverloadedFunctionSymbol overloadedFunctionSymbol, boolean isParentIsAClass) {
40+
if (overloadedFunctionSymbol.getDefinitionsList().size() < 2) {
41+
throw new IllegalStateException("Overloaded function symbols should have at least two definitions.");
42+
}
43+
var name = overloadedFunctionSymbol.getName();
44+
var fullyQualifiedName = TypeShedUtils.normalizedFqn(overloadedFunctionSymbol.getFullname());
45+
var descriptors = overloadedFunctionSymbol.getDefinitionsList().stream()
46+
.map(fs -> functionConverter.convert(fs, isParentIsAClass))
47+
.map(Descriptor.class::cast)
48+
.collect(Collectors.toSet());
49+
return new AmbiguousDescriptor(name, fullyQualifiedName, descriptors);
50+
}
51+
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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.function.Function;
23+
import java.util.stream.Collectors;
24+
import org.assertj.core.api.Assertions;
25+
import org.junit.jupiter.api.Test;
26+
import org.sonar.python.index.Descriptor;
27+
import org.sonar.python.index.FunctionDescriptor;
28+
import org.sonar.python.types.protobuf.SymbolsProtos;
29+
30+
class OverloadedFunctionSymbolToDescriptorConverterTest {
31+
32+
33+
@Test
34+
void test() {
35+
var symbol = SymbolsProtos.OverloadedFunctionSymbol.newBuilder()
36+
.setName("something")
37+
.setFullname("module.something")
38+
.addDefinitions(SymbolsProtos.FunctionSymbol.newBuilder()
39+
.setName("f1")
40+
.setIsStatic(true)
41+
.build())
42+
.addDefinitions(SymbolsProtos.FunctionSymbol.newBuilder()
43+
.setName("f2")
44+
.build())
45+
.build();
46+
var converter = new OverloadedFunctionSymbolToDescriptorConverter(new FunctionSymbolToDescriptorConverter());
47+
48+
var descriptor = converter.convert(symbol, true);
49+
Assertions.assertThat(descriptor.name()).isEqualTo("something");
50+
Assertions.assertThat(descriptor.fullyQualifiedName()).isEqualTo("module.something");
51+
Assertions.assertThat(descriptor.alternatives()).hasSize(2);
52+
53+
var candidatesByName = descriptor.alternatives()
54+
.stream()
55+
.collect(Collectors.toMap(Descriptor::name, Function.identity()));
56+
57+
var f1 = (FunctionDescriptor) candidatesByName.get("f1");
58+
var f2 = (FunctionDescriptor) candidatesByName.get("f2");
59+
Assertions.assertThat(f1.isInstanceMethod()).isFalse();
60+
Assertions.assertThat(f2.isInstanceMethod()).isTrue();
61+
}
62+
63+
@Test
64+
void builtinTest() {
65+
var symbol = SymbolsProtos.OverloadedFunctionSymbol.newBuilder()
66+
.setName("int")
67+
.setFullname("builtins.int")
68+
.addDefinitions(SymbolsProtos.FunctionSymbol.newBuilder().build())
69+
.addDefinitions(SymbolsProtos.FunctionSymbol.newBuilder().build())
70+
.build();
71+
var converter = new OverloadedFunctionSymbolToDescriptorConverter(new FunctionSymbolToDescriptorConverter());
72+
73+
var descriptor = converter.convert(symbol);
74+
Assertions.assertThat(descriptor.name()).isEqualTo("int");
75+
Assertions.assertThat(descriptor.fullyQualifiedName()).isEqualTo("int");
76+
Assertions.assertThat(descriptor.alternatives()).hasSize(2);
77+
}
78+
79+
@Test
80+
void singleCandidateExceptionTest() {
81+
var symbol = SymbolsProtos.OverloadedFunctionSymbol.newBuilder()
82+
.addDefinitions(SymbolsProtos.FunctionSymbol.newBuilder().build())
83+
.build();
84+
var converter = new OverloadedFunctionSymbolToDescriptorConverter(new FunctionSymbolToDescriptorConverter());
85+
86+
Assertions.assertThatThrownBy(() -> converter.convert(symbol))
87+
.isInstanceOf(IllegalStateException.class)
88+
.hasMessage("Overloaded function symbols should have at least two definitions.");
89+
}
90+
91+
}

0 commit comments

Comments
 (0)