1818
1919import java .util .List ;
2020import java .util .Optional ;
21+ import java .util .concurrent .locks .Lock ;
22+ import java .util .concurrent .locks .ReentrantLock ;
2123import java .util .stream .IntStream ;
2224import org .sonar .python .semantic .ProjectLevelSymbolTable ;
2325import org .sonar .python .types .v2 .LazyTypeWrapper ;
@@ -32,10 +34,13 @@ public class ProjectLevelTypeTable implements TypeTable {
3234 private final PythonType rootModule ;
3335 private final LazyTypesContext lazyTypesContext ;
3436
37+ private final Lock createOrResolveSubModuleLock ;
38+
3539 public ProjectLevelTypeTable (ProjectLevelSymbolTable projectLevelSymbolTable ) {
3640 this .lazyTypesContext = new LazyTypesContext (this );
3741 this .symbolsModuleTypeProvider = new SymbolsModuleTypeProvider (projectLevelSymbolTable , lazyTypesContext );
3842 this .rootModule = this .symbolsModuleTypeProvider .createBuiltinModule ();
43+ this .createOrResolveSubModuleLock = new ReentrantLock ();
3944 }
4045
4146 @ Override
@@ -76,16 +81,15 @@ public PythonType getType(List<String> typeFqnParts) {
7681
7782 // The member of the module is a LazyType, which means it's a re-exported type from a submodule
7883 // We try to resolve the submodule instead
79- Optional <PythonType > subModule = moduleType .resolveSubmodule (part );
80- parent = subModule .orElseGet (() -> symbolsModuleTypeProvider .convertModuleType (moduleFqnParts , moduleType ));
84+ parent = createOrResolveSubModule (moduleFqnParts , moduleType );
8185 continue ;
8286 }
8387 }
8488 resolvedMember = parent .resolveMember (part );
8589 if (resolvedMember .isPresent ()) {
8690 parent = resolvedMember .get ();
8791 } else if (parent instanceof ModuleType module ) {
88- parent = symbolsModuleTypeProvider . convertModuleType (moduleFqnParts , module );
92+ parent = createOrResolveSubModule (moduleFqnParts , module );
8993 } else {
9094 return PythonType .UNKNOWN ;
9195 }
@@ -106,19 +110,27 @@ private static boolean shouldResolveImmediately(LazyTypeWrapper lazyTypeWrapper,
106110 public PythonType getModuleType (List <String > typeFqnParts ) {
107111 var parent = rootModule ;
108112 for (int i = 0 ; i < typeFqnParts .size (); i ++) {
109- var part = typeFqnParts .get (i );
110113 var moduleFqnParts = IntStream .rangeClosed (0 , i )
111114 .mapToObj (typeFqnParts ::get )
112115 .toList ();
113116 if (!(parent instanceof ModuleType moduleType )) {
114117 return PythonType .UNKNOWN ;
115118 }
116- Optional <PythonType > resolvedSubmodule = moduleType .resolveSubmodule (part );
117- parent = resolvedSubmodule .orElseGet (() -> symbolsModuleTypeProvider .convertModuleType (moduleFqnParts , moduleType ));
119+ parent = createOrResolveSubModule (moduleFqnParts , moduleType );
118120 }
119121 return parent ;
120122 }
121123
124+ private PythonType createOrResolveSubModule (List <String > moduleFqn , ModuleType parent ) {
125+ try {
126+ createOrResolveSubModuleLock .lock ();
127+ String part = moduleFqn .get (moduleFqn .size () - 1 );
128+ return parent .resolveSubmodule (part ).orElseGet (() -> symbolsModuleTypeProvider .convertModuleType (moduleFqn , parent ));
129+ } finally {
130+ createOrResolveSubModuleLock .unlock ();
131+ }
132+ }
133+
122134 public LazyTypesContext lazyTypesContext () {
123135 return lazyTypesContext ;
124136 }
0 commit comments