1616 */
1717package org .sonar .python .types ;
1818
19+ import com .google .common .annotations .VisibleForTesting ;
1920import java .io .IOException ;
2021import java .io .InputStream ;
2122import java .util .Arrays ;
2627import java .util .List ;
2728import java .util .Map ;
2829import java .util .Set ;
30+ import java .util .concurrent .ConcurrentHashMap ;
31+ import java .util .concurrent .locks .ReentrantLock ;
2932import java .util .stream .Collectors ;
3033import javax .annotation .CheckForNull ;
3134import javax .annotation .Nullable ;
5962
6063public class TypeShed {
6164
62- private static Map <String , Symbol > builtins ;
63- private static final Map <String , Map <String , Symbol >> typeShedSymbols = new HashMap <>();
64- private static final Map <String , Set <Symbol >> builtinGlobalSymbols = new HashMap <>();
65+ private static volatile Map <String , Symbol > builtins ;
66+ private static final Map <String , Map <String , Symbol >> typeShedSymbols = new ConcurrentHashMap <>();
67+ private static final Map <String , Set <Symbol >> builtinGlobalSymbols = new ConcurrentHashMap <>();
68+ private static final ReentrantLock resolutionLock = new ReentrantLock ();
6569
6670 private static final String PROTOBUF_CUSTOM_STUBS = "custom_protobuf/" ;
6771 private static final String PROTOBUF = "stdlib_protobuf/" ;
@@ -87,8 +91,8 @@ public class TypeShed {
8791 }
8892
8993 private static final Logger LOG = LoggerFactory .getLogger (TypeShed .class );
90- private static Set <String > supportedPythonVersions ;
91- private static ProjectLevelSymbolTable projectLevelSymbolTable ;
94+ private static volatile Set <String > supportedPythonVersions ;
95+ private static volatile ProjectLevelSymbolTable projectLevelSymbolTable ;
9296
9397 private TypeShed () {
9498 }
@@ -102,20 +106,23 @@ public static void setProjectLevelSymbolTable(ProjectLevelSymbolTable projectLev
102106 }
103107
104108 public static Map <String , Symbol > builtinSymbols () {
105- if ((TypeShed .builtins == null )) {
106- supportedPythonVersions = ProjectPythonVersion .currentVersions ().stream ().map (PythonVersionUtils .Version ::serializedValue ).collect (Collectors .toSet ());
107- Map <String , Symbol > builtins = getSymbolsFromProtobufModule (BUILTINS_FQN , PROTOBUF );
108- builtins .put (NONE_TYPE , new ClassSymbolImpl (NONE_TYPE , NONE_TYPE ));
109- TypeShed .builtins = Collections .unmodifiableMap (builtins );
110- TypeShed .builtinGlobalSymbols .put ("" , new HashSet <>(builtins .values ()));
109+ if (builtins == null ) {
110+ resolutionLock .lock ();
111+ try {
112+ if (builtins == null ) {
113+ supportedPythonVersions = ProjectPythonVersion .currentVersions ().stream ().map (PythonVersionUtils .Version ::serializedValue ).collect (Collectors .toSet ());
114+ Map <String , Symbol > builtinMap = getSymbolsFromProtobufModule (BUILTINS_FQN , PROTOBUF );
115+ builtinMap .put (NONE_TYPE , new ClassSymbolImpl (NONE_TYPE , NONE_TYPE ));
116+ builtins = Collections .unmodifiableMap (builtinMap );
117+ builtinGlobalSymbols .put ("" , new HashSet <>(builtinMap .values ()));
118+ }
119+ } finally {
120+ resolutionLock .unlock ();
121+ }
111122 }
112123 return builtins ;
113124 }
114125
115- public static Map <String , Map <String , Symbol >> getLoadedTypeShedSymbols () {
116- return typeShedSymbols ;
117- }
118-
119126 public static ClassSymbol typeShedClass (String fullyQualifiedName ) {
120127 Symbol symbol = builtinSymbols ().get (fullyQualifiedName );
121128 if (symbol == null ) {
@@ -138,19 +145,34 @@ private static boolean searchedModuleMatchesCurrentProject(String searchedModule
138145 * Returns map of exported symbols by name for a given module
139146 */
140147 public static Map <String , Symbol > symbolsForModule (String moduleName ) {
141- return symbolsForModule (moduleName , new HashSet <>());
148+ Map <String , Symbol > symbols = typeShedSymbols .get (moduleName );
149+ if (symbols != null ) {
150+ return symbols ;
151+ }
152+
153+ resolutionLock .lock ();
154+ try {
155+ symbols = typeShedSymbols .get (moduleName );
156+ if (symbols != null ) {
157+ return symbols ;
158+ }
159+ return symbolsForModule (moduleName , new HashSet <>());
160+ } finally {
161+ resolutionLock .unlock ();
162+ }
142163 }
143164
144- private static Map <String , Symbol > symbolsForModule (String moduleName , Set <String > modulesInProgress ) {
165+ @ VisibleForTesting
166+ static Map <String , Symbol > symbolsForModule (String moduleName , Set <String > modulesInProgress ) {
145167 if (searchedModuleMatchesCurrentProject (moduleName )) {
146168 return Collections .emptyMap ();
147169 }
148- if (!TypeShed . typeShedSymbols .containsKey (moduleName )) {
170+ if (!typeShedSymbols .containsKey (moduleName )) {
149171 Map <String , Symbol > symbols = searchTypeShedForModule (moduleName , modulesInProgress );
150172 typeShedSymbols .put (moduleName , symbols );
151173 return symbols ;
152174 }
153- return TypeShed . typeShedSymbols .get (moduleName );
175+ return typeShedSymbols .get (moduleName );
154176 }
155177
156178 @ CheckForNull
0 commit comments