Skip to content

Commit 71ed57b

Browse files
andreaguarinoguillaume-dequenne
authored andcommitted
SONARPY-957 Deserialize typeshed variable symbols from protobuf. Fix FN on S4423
1 parent 47480ab commit 71ed57b

File tree

6 files changed

+63
-1
lines changed

6 files changed

+63
-1
lines changed

its/ruling/src/test/resources/expected/python-S4423.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@
77
174,
88
213,
99
],
10+
'project:tornado-2.3/tornado/simple_httpclient.py':[
11+
210,
12+
],
13+
'project:tornado-2.3/tornado/test/httpserver_test.py':[
14+
110,
15+
115,
16+
120,
17+
125,
18+
],
1019
'project:twisted-12.1.0/doc/core/examples/echoserv_ssl.py':[
1120
15,
1221
],

python-checks/src/test/java/org/sonar/python/checks/WeakSSLProtocolCheckTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,8 @@ public void test() {
2929
PythonCheckVerifier.verify("src/test/resources/checks/weakSSLProtocol.py", new WeakSSLProtocolCheck());
3030
}
3131

32+
@Test
33+
public void test_fallback_import() {
34+
PythonCheckVerifier.verify("src/test/resources/checks/weakSSLProtocol_fallback_import.py", new WeakSSLProtocolCheck());
35+
}
3236
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
try:
2+
import ssl
3+
except ImportError:
4+
ssl = None
5+
6+
if ssl is not None:
7+
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv2) # Noncompliant

python-frontend/src/main/java/org/sonar/python/semantic/SymbolImpl.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.ArrayList;
2323
import java.util.Collections;
2424
import java.util.HashMap;
25+
import java.util.HashSet;
2526
import java.util.List;
2627
import java.util.Map;
2728
import java.util.Optional;
@@ -39,6 +40,8 @@
3940
import org.sonar.plugins.python.api.types.InferredType;
4041
import org.sonar.python.tree.NameImpl;
4142
import org.sonar.python.types.InferredTypes;
43+
import org.sonar.python.types.TypeShed;
44+
import org.sonar.python.types.protobuf.SymbolsProtos;
4245

4346
public class SymbolImpl implements Symbol {
4447

@@ -65,6 +68,17 @@ public SymbolImpl(String name, @Nullable String fullyQualifiedName, @Nullable St
6568
this.kind = Kind.OTHER;
6669
}
6770

71+
public SymbolImpl(SymbolsProtos.VarSymbol varSymbol) {
72+
this.name = varSymbol.getName();
73+
this.fullyQualifiedName = TypeShed.normalizedFqn(varSymbol.getFullyQualifiedName());
74+
String fqn = varSymbol.getTypeAnnotation().getFullyQualifiedName();
75+
if (!fqn.isEmpty()) {
76+
this.annotatedTypeName = TypeShed.normalizedFqn(fqn);
77+
}
78+
this.validForPythonVersions = new HashSet<>(varSymbol.getValidForList());
79+
this.kind = Kind.OTHER;
80+
}
81+
6882
@Override
6983
public String name() {
7084
return name;

python-frontend/src/main/java/org/sonar/python/types/TypeShed.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,13 +403,17 @@ static Map<String, Symbol> getSymbolsFromProtobufModule(@Nullable ModuleSymbol m
403403
moduleSymbol.getOverloadedFunctionsList().stream()
404404
.filter(d -> isValidForProjectPythonVersion(d.getValidForList()))
405405
.forEach(proto -> descriptorsByName.computeIfAbsent(proto.getName(), d -> new HashSet<>()).add(proto));
406+
moduleSymbol.getVarsList().stream()
407+
.filter(d -> isValidForProjectPythonVersion(d.getValidForList()))
408+
.forEach(proto -> descriptorsByName.computeIfAbsent(proto.getName(), d -> new HashSet<>()).add(proto));
406409

407410
Map<String, Symbol> deserializedSymbols = new HashMap<>();
408411

409412
for (Map.Entry<String, Set<Object>> entry : descriptorsByName.entrySet()) {
410413
String name = entry.getKey();
411414
Set<Symbol> symbols = symbolsFromDescriptor(entry.getValue(), false);
412-
deserializedSymbols.put(name, disambiguateSymbolsWithSameName(name, symbols, moduleSymbol.getFullyQualifiedName()));
415+
Symbol disambiguatedSymbol = disambiguateSymbolsWithSameName(name, symbols, moduleSymbol.getFullyQualifiedName());
416+
deserializedSymbols.put(name, disambiguatedSymbol);
413417
}
414418
return deserializedSymbols;
415419
}
@@ -465,6 +469,9 @@ public static Set<Symbol> symbolsFromDescriptor(Set<Object> descriptors, boolean
465469
}
466470
symbols.add(fromOverloadedFunction(((OverloadedFunctionSymbol) descriptor), isInsideClass));
467471
}
472+
if (descriptor instanceof SymbolsProtos.VarSymbol) {
473+
symbols.add(new SymbolImpl((SymbolsProtos.VarSymbol) descriptor));
474+
}
468475
}
469476
return symbols;
470477
}

python-frontend/src/test/java/org/sonar/python/types/TypeShedTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,4 +466,25 @@ private static Map<String, Symbol> symbolsForModule(String moduleName) {
466466
assertThat(symbols.stream().map(Symbol::name)).doesNotHaveDuplicates();
467467
return symbols.stream().collect(Collectors.toMap(Symbol::name, Function.identity()));
468468
}
469+
470+
@Test
471+
public void variables_from_protobuf() throws TextFormat.ParseException {
472+
SymbolsProtos.ModuleSymbol moduleSymbol = moduleSymbol(
473+
"fully_qualified_name: \"mod\"\n" +
474+
"vars {\n" +
475+
" name: \"foo\"\n" +
476+
" fully_qualified_name: \"mod.foo\"\n" +
477+
" type_annotation {\n" +
478+
" pretty_printed_name: \"builtins.str\"\n" +
479+
" fully_qualified_name: \"builtins.str\"\n" +
480+
" }\n" +
481+
"}\n" +
482+
"vars {\n" +
483+
" name: \"bar\"\n" +
484+
" fully_qualified_name: \"mod.bar\"\n" +
485+
"}\n");
486+
Map<String, Symbol> symbols = TypeShed.getSymbolsFromProtobufModule(moduleSymbol);
487+
assertThat(symbols.values()).extracting(Symbol::kind, Symbol::fullyQualifiedName, Symbol::annotatedTypeName)
488+
.containsExactlyInAnyOrder(tuple(Kind.OTHER, "mod.foo", "str"), tuple(Kind.OTHER, "mod.bar", null));
489+
}
469490
}

0 commit comments

Comments
 (0)