Skip to content

Commit 4cc30e2

Browse files
Seppli11sonartech
authored andcommitted
SONARPY-3132 Fix synchronization on SymbolsModuleTypeProvider#convertModuleType(...) (#342)
GitOrigin-RevId: 05ee1e281e92613e75b9a6f15d03ebb849dc2d99
1 parent c9371a9 commit 4cc30e2

3 files changed

Lines changed: 22 additions & 12 deletions

File tree

python-frontend/src/main/java/org/sonar/plugins/python/api/types/v2/ModuleType.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.HashMap;
2020
import java.util.Map;
2121
import java.util.Optional;
22+
import java.util.concurrent.ConcurrentHashMap;
2223
import javax.annotation.CheckForNull;
2324
import javax.annotation.Nullable;
2425
import org.sonar.api.Beta;
@@ -39,18 +40,15 @@ public ModuleType(@Nullable String name,
3940
this.fullyQualifiedName = fullyQualifiedName;
4041
this.parent = parent;
4142
this.members = members;
42-
this.subModules = new HashMap<>();
43+
this.subModules = new ConcurrentHashMap<>();
4344
registerAsSubmoduleOfParent(parent);
4445
}
4546

4647
private void registerAsSubmoduleOfParent(@Nullable ModuleType parent) {
4748
if (parent == null) {
4849
return;
4950
}
50-
TypeWrapper subModule = parent.subModules.get(this.name);
51-
if (subModule == null) {
52-
parent.subModules.put(this.name, TypeWrapper.of(this));
53-
}
51+
parent.subModules.putIfAbsent(this.name, TypeWrapper.of(this));
5452
}
5553

5654
public ModuleType(@Nullable String name) {

python-frontend/src/main/java/org/sonar/python/semantic/v2/ProjectLevelTypeTable.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.util.List;
2020
import java.util.Optional;
21+
import java.util.concurrent.locks.Lock;
22+
import java.util.concurrent.locks.ReentrantLock;
2123
import java.util.stream.IntStream;
2224
import org.sonar.python.semantic.ProjectLevelSymbolTable;
2325
import 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
}

python-frontend/src/main/java/org/sonar/python/semantic/v2/SymbolsModuleTypeProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public ModuleType createBuiltinModule() {
6060
return rootModule;
6161
}
6262

63-
public synchronized PythonType convertModuleType(List<String> moduleFqn, ModuleType parent) {
63+
public PythonType convertModuleType(List<String> moduleFqn, ModuleType parent) {
6464
var moduleName = moduleFqn.get(moduleFqn.size() - 1);
6565
var moduleFqnString = getModuleFqnString(moduleFqn);
6666
Optional<ModuleType> result = createModuleTypeFromProjectLevelSymbolTable(moduleName, moduleFqnString, parent)

0 commit comments

Comments
 (0)