[polySymbols] WEB-74673 PolySymbols: non-indempotent computation in PolySymbolScopeWithCache

(cherry picked from commit 50b89102a59667a1e1ddbd51005a432b5fc17a88)

IJ-CR-174153

GitOrigin-RevId: dee12e01d16df2aa27e981700773674cb4cd1977
This commit is contained in:
Piotr Tomiak
2025-08-29 11:36:58 +02:00
committed by intellij-monorepo-bot
parent 42791ab7ff
commit 191db8a556
4 changed files with 46 additions and 5 deletions

View File

@@ -955,6 +955,11 @@
- getMatchingSymbols(com.intellij.polySymbols.PolySymbolQualifiedName,com.intellij.polySymbols.query.PolySymbolNameMatchQueryParams,com.intellij.polySymbols.query.PolySymbolQueryStack):java.util.List
- getSymbols(com.intellij.polySymbols.PolySymbolQualifiedKind,com.intellij.polySymbols.query.PolySymbolListSymbolsQueryParams,com.intellij.polySymbols.query.PolySymbolQueryStack):java.util.List
- isExclusiveFor(com.intellij.polySymbols.PolySymbolQualifiedKind):Z
*:com.intellij.polySymbols.query.PolySymbolThreadLocalCacheKeyProvider
- *sf:Companion:com.intellij.polySymbols.query.PolySymbolThreadLocalCacheKeyProvider$Companion
- sf:EP_NAME:com.intellij.openapi.extensions.ExtensionPointName
- a:getCacheKey(com.intellij.openapi.project.Project):java.lang.Object
*f:com.intellij.polySymbols.query.PolySymbolThreadLocalCacheKeyProvider$Companion
*:com.intellij.polySymbols.query.PolySymbolWithPattern
- com.intellij.polySymbols.PolySymbol
- a:getPattern():com.intellij.polySymbols.patterns.PolySymbolPattern

View File

@@ -60,6 +60,9 @@
<extensionPoint qualifiedName="com.intellij.polySymbols.matchCustomizerFactory"
interface="com.intellij.polySymbols.query.PolySymbolMatchCustomizerFactory"
dynamic="true"/>
<extensionPoint qualifiedName="com.intellij.polySymbols.threadLocalCacheKeyProvider"
interface="com.intellij.polySymbols.query.PolySymbolThreadLocalCacheKeyProvider"
dynamic="true"/>
</extensionPoints>
<extensions defaultExtensionNs="com.intellij">

View File

@@ -0,0 +1,33 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.polySymbols.query
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.project.Project
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.TestOnly
interface PolySymbolThreadLocalCacheKeyProvider {
fun getCacheKey(project: Project): Any?
@Suppress("TestOnlyProblems")
companion object {
@TestOnly
@JvmField
val EP_NAME: ExtensionPointName<PolySymbolThreadLocalCacheKeyProvider> =
ExtensionPointName.create<PolySymbolThreadLocalCacheKeyProvider>("com.intellij.polySymbols.threadLocalCacheKeyProvider")
@ApiStatus.Internal
fun getCacheKeys(initialCacheKey: Any?, project: Project): List<Any?> {
val extensions = EP_NAME.extensionList
val result = ArrayList<Any?>(extensions.size + 1)
result.add(initialCacheKey)
for (ext in extensions) {
result.add(ext.getCacheKey(project))
}
return result
}
}
}

View File

@@ -91,13 +91,13 @@ abstract class PolySymbolScopeWithCache<T : UserDataHolder, K>(
val manager = CachedValuesManager.getManager(project)
return if (key == Unit) {
manager.getCachedValue(dataHolder, manager.getKeyForClass(this::class.java), {
CachedValueProvider.Result(NamesProviderToMapCache(), PsiModificationTracker.NEVER_CHANGED)
CachedValueProvider.Result(NamesProviderToMapCache(project), PsiModificationTracker.NEVER_CHANGED)
}, false)
}
else {
manager.getCachedValue(dataHolder, manager.getKeyForClass(this::class.java), {
CachedValueProvider.Result(ConcurrentHashMap<K, NamesProviderToMapCache>(), ModificationTracker.NEVER_CHANGED)
}, false).getOrPut(key) { NamesProviderToMapCache() }
}, false).getOrPut(key) { NamesProviderToMapCache(project) }
}
}
@@ -158,8 +158,8 @@ abstract class PolySymbolScopeWithCache<T : UserDataHolder, K>(
private fun getMap(queryExecutor: PolySymbolQueryExecutor): PolySymbolSearchMap =
getNamesProviderToMapCache().getOrCreateMap(queryExecutor.namesProvider, this::createCachedSearchMap)
private class NamesProviderToMapCache {
private val cache: ConcurrentMap<PolySymbolNamesProvider, CachedValue<PolySymbolSearchMap>> = ContainerUtil.createConcurrentSoftKeySoftValueMap()
private class NamesProviderToMapCache(private val project: Project) {
private val cache: ConcurrentMap<List<Any?>, CachedValue<PolySymbolSearchMap>> = ContainerUtil.createConcurrentSoftKeySoftValueMap()
private var cacheMisses = 0
fun getOrCreateMap(
@@ -171,7 +171,7 @@ abstract class PolySymbolScopeWithCache<T : UserDataHolder, K>(
cacheMisses = 0
cache.clear()
}
return cache.getOrPut(namesProvider) {
return cache.getOrPut(PolySymbolThreadLocalCacheKeyProvider.getCacheKeys(namesProvider, project)) {
cacheMisses++
createCachedSearchMap(namesProvider)
}.value