20
20
package org .sonar .python .types ;
21
21
22
22
import com .sonar .sslr .api .AstNode ;
23
+ import java .io .IOException ;
23
24
import java .io .InputStream ;
24
25
import java .util .Arrays ;
25
26
import java .util .Collection ;
33
34
import java .util .stream .Collectors ;
34
35
import javax .annotation .CheckForNull ;
35
36
import javax .annotation .Nullable ;
37
+ import org .sonar .api .utils .log .Logger ;
38
+ import org .sonar .api .utils .log .Loggers ;
36
39
import org .sonar .plugins .python .api .PythonFile ;
40
+ import org .sonar .plugins .python .api .symbols .AmbiguousSymbol ;
37
41
import org .sonar .plugins .python .api .symbols .ClassSymbol ;
38
42
import org .sonar .plugins .python .api .symbols .FunctionSymbol ;
39
43
import org .sonar .plugins .python .api .symbols .Symbol ;
54
58
import org .sonar .python .semantic .SymbolTableBuilder ;
55
59
import org .sonar .python .tree .FunctionDefImpl ;
56
60
import org .sonar .python .tree .PythonTreeMaker ;
61
+ import org .sonar .python .types .protobuf .SymbolsProtos .ModuleSymbol ;
62
+ import org .sonar .python .types .protobuf .SymbolsProtos .OverloadedFunctionSymbol ;
57
63
58
64
import static org .sonar .plugins .python .api .types .BuiltinTypes .NONE_TYPE ;
59
65
@@ -62,7 +68,7 @@ public class TypeShed {
62
68
private static final String TYPING = "typing" ;
63
69
private static final String TYPING_EXTENSIONS = "typing_extensions" ;
64
70
private static Map <String , Symbol > builtins ;
65
- private static final Map <String , Set < Symbol >> typeShedSymbols = new HashMap <>();
71
+ private static final Map <String , Map < String , Symbol >> typeShedSymbols = new HashMap <>();
66
72
private static final Map <String , Set <Symbol >> builtinGlobalSymbols = new HashMap <>();
67
73
private static final Set <String > modulesInProgress = new HashSet <>();
68
74
@@ -73,6 +79,9 @@ public class TypeShed {
73
79
private static final String THIRD_PARTY_2 = "typeshed/third_party/2/" ;
74
80
private static final String THIRD_PARTY_3 = "typeshed/third_party/3/" ;
75
81
private static final String CUSTOM_THIRD_PARTY = "custom/" ;
82
+ private static final String PROTOBUF = "protobuf/" ;
83
+
84
+ private static final Logger LOG = Loggers .get (TypeShed .class );
76
85
77
86
private TypeShed () {
78
87
}
@@ -161,10 +170,11 @@ static Set<Symbol> typingExtensionsSymbols(Map<String, Set<Symbol>> typingSymbol
161
170
public static Set <Symbol > symbolsForModule (String moduleName ) {
162
171
if (!TypeShed .typeShedSymbols .containsKey (moduleName )) {
163
172
Set <Symbol > symbols = searchTypeShedForModule (moduleName );
164
- typeShedSymbols .put (moduleName , symbols );
173
+ Map <String , Symbol > symbolsByFqn = symbols .stream ().collect (Collectors .toMap (Symbol ::fullyQualifiedName , s -> s ));
174
+ typeShedSymbols .put (moduleName , symbolsByFqn );
165
175
return symbols ;
166
176
}
167
- return TypeShed .typeShedSymbols .get (moduleName );
177
+ return new HashSet <>( TypeShed .typeShedSymbols .get (moduleName ). values () );
168
178
}
169
179
170
180
@ CheckForNull
@@ -195,6 +205,11 @@ private static Set<Symbol> searchTypeShedForModule(String moduleName) {
195
205
return new HashSet <>();
196
206
}
197
207
modulesInProgress .add (moduleName );
208
+ Collection <Symbol > symbolsFromProtobuf = getSymbolsFromProtobufModule (moduleName );
209
+ if (!symbolsFromProtobuf .isEmpty ()) {
210
+ modulesInProgress .remove (moduleName );
211
+ return new HashSet <>(symbolsFromProtobuf );
212
+ }
198
213
Set <Symbol > customSymbols = new HashSet <>(getModuleSymbols (moduleName , CUSTOM_THIRD_PARTY , builtinGlobalSymbols ).values ());
199
214
if (!customSymbols .isEmpty ()) {
200
215
modulesInProgress .remove (moduleName );
@@ -268,7 +283,7 @@ public static ClassSymbol typeShedClass(String fullyQualifiedName) {
268
283
269
284
public static Collection <Symbol > stubFilesSymbols () {
270
285
Set <Symbol > symbols = new HashSet <>(TypeShed .builtinSymbols ().values ());
271
- typeShedSymbols .values ().forEach (symbols :: addAll );
286
+ typeShedSymbols .values ().forEach (symbolsByFqn -> symbols . addAll ( symbolsByFqn . values ()) );
272
287
return symbols ;
273
288
}
274
289
@@ -340,4 +355,57 @@ private static class ModuleDescription {
340
355
}
341
356
}
342
357
358
+
359
+ private static Collection <Symbol > getSymbolsFromProtobufModule (String moduleName ) {
360
+ InputStream resource = TypeShed .class .getResourceAsStream (PROTOBUF + moduleName + ".protobuf" );
361
+ if (resource == null ) {
362
+ return Collections .emptySet ();
363
+ }
364
+ return getSymbolsFromProtobufModule (deserializedModule (moduleName , resource )).values ();
365
+ }
366
+
367
+ @ CheckForNull
368
+ static ModuleSymbol deserializedModule (String moduleName , InputStream resource ) {
369
+ try {
370
+ return ModuleSymbol .parseFrom (resource );
371
+ } catch (IOException e ) {
372
+ LOG .debug ("Error while deserializing protobuf for module " + moduleName , e );
373
+ return null ;
374
+ }
375
+ }
376
+
377
+ static Map <String , Symbol > getSymbolsFromProtobufModule (@ Nullable ModuleSymbol moduleSymbol ) {
378
+ if (moduleSymbol == null ) {
379
+ return Collections .emptyMap ();
380
+ }
381
+ Map <String , Symbol > deserializedSymbols = new HashMap <>();
382
+ moduleSymbol .getClassesList ().forEach (proto -> deserializedSymbols .put (proto .getFullyQualifiedName (), new ClassSymbolImpl (proto )));
383
+ moduleSymbol .getFunctionsList ().forEach (proto -> deserializedSymbols .put (proto .getFullyQualifiedName (), new FunctionSymbolImpl (proto )));
384
+ moduleSymbol .getOverloadedFunctionsList ().forEach (proto -> deserializedSymbols .put (proto .getFullname (), fromOverloadedFunction (proto )));
385
+ return deserializedSymbols ;
386
+ }
387
+
388
+ private static AmbiguousSymbol fromOverloadedFunction (OverloadedFunctionSymbol overloadedFunctionSymbol ) {
389
+ Set <Symbol > overloadedSymbols = overloadedFunctionSymbol .getDefinitionsList ().stream ()
390
+ .map (FunctionSymbolImpl ::new )
391
+ .collect (Collectors .toSet ());
392
+ return AmbiguousSymbolImpl .create (overloadedSymbols );
393
+ }
394
+
395
+ @ CheckForNull
396
+ public static Symbol symbolWithFQN (String fullyQualifiedName ) {
397
+ String [] fqnSplittedByDot = fullyQualifiedName .split ("\\ ." );
398
+ String localName = fqnSplittedByDot [fqnSplittedByDot .length - 1 ];
399
+ if (fqnSplittedByDot .length == 2 && fqnSplittedByDot [0 ].equals ("builtins" ) && builtins .containsKey (localName )) {
400
+ return builtins .get (localName );
401
+ }
402
+ for (Map <String , Symbol > symbolsByFqn : typeShedSymbols .values ()) {
403
+ Symbol symbol = symbolsByFqn .get (fullyQualifiedName );
404
+ if (symbol != null ) {
405
+ return symbol ;
406
+ }
407
+ }
408
+ return null ;
409
+ }
410
+
343
411
}
0 commit comments