Skip to content

Commit

Permalink
[SLC] invalidate local class members cache on any file changes
Browse files Browse the repository at this point in the history
We should track the containing file modifications to avoid PIEAE by
changes in members

^KTIJ-26661 Fixed
  • Loading branch information
dimonchik0036 authored and qodana-bot committed Aug 16, 2023
1 parent 765a8bd commit e05cb49
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ open class KtLightClassForDecompiledDeclaration(
ClassInnerStuffCache(
/* aClass = */ this,
/* generateEnumMethods = */ true,
/* modificationTracker = */ project.createAllLibrariesModificationTracker(),
/* modificationTrackers = */ listOf(project.createAllLibrariesModificationTracker()),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,27 +50,27 @@ public final class ClassInnerStuffCache {
public static final String NOT_NULL_ANNOTATION_QUALIFIER = "@" + NotNull.class.getName();

private final @NotNull KtExtensibleLightClass myClass;
private final @NotNull ModificationTracker myModificationTracker;
private final @NotNull List<ModificationTracker> myModificationTrackers;
private final @NotNull Ref<Pair<Long, Interner<PsiMember>>> myInterner = Ref.create();
private final boolean myGenerateEnumMethods;

public ClassInnerStuffCache(
@NotNull KtExtensibleLightClass aClass,
boolean generateEnumMethods,
@NotNull ModificationTracker modificationTracker
@NotNull List<ModificationTracker> modificationTrackers
) {
myGenerateEnumMethods = generateEnumMethods;
myClass = aClass;
myModificationTracker = modificationTracker;
myModificationTrackers = modificationTrackers;
}

@NotNull
public PsiMethod[] getConstructors() {
return copy(CachedValuesManager.getCachedValue(
myClass,
() -> CachedValueProvider.Result.createSingleDependency(
() -> CachedValueProvider.Result.create(
PsiImplUtil.getConstructors(myClass),
myModificationTracker
myModificationTrackers
)
));
}
Expand All @@ -79,9 +79,9 @@ public PsiMethod[] getConstructors() {
public PsiField[] getFields() {
return copy(CachedValuesManager.getCachedValue(
myClass,
() -> CachedValueProvider.Result.createSingleDependency(
() -> CachedValueProvider.Result.create(
calcFields(),
myModificationTracker
myModificationTrackers
)
));
}
Expand All @@ -90,9 +90,9 @@ public PsiField[] getFields() {
public PsiMethod[] getMethods() {
return copy(CachedValuesManager.getCachedValue(
myClass,
() -> CachedValueProvider.Result.createSingleDependency(
() -> CachedValueProvider.Result.create(
calcMethods(),
myModificationTracker
myModificationTrackers
)
));
}
Expand All @@ -101,9 +101,9 @@ public PsiMethod[] getMethods() {
public PsiClass[] getInnerClasses() {
return copy(CachedValuesManager.getCachedValue(
myClass,
() -> CachedValueProvider.Result.createSingleDependency(
() -> CachedValueProvider.Result.create(
calcInnerClasses(),
myModificationTracker
myModificationTrackers
)
));
}
Expand All @@ -116,9 +116,9 @@ public PsiField findFieldByName(String name, boolean checkBases) {
else {
return CachedValuesManager.getCachedValue(
myClass,
() -> CachedValueProvider.Result.createSingleDependency(
() -> CachedValueProvider.Result.create(
getFieldsMap(),
myModificationTracker
myModificationTrackers
)
).get(name);
}
Expand All @@ -132,9 +132,9 @@ public PsiMethod[] findMethodsByName(String name, boolean checkBases) {
else {
return copy(notNull(CachedValuesManager.getCachedValue(
myClass,
() -> CachedValueProvider.Result.createSingleDependency(
() -> CachedValueProvider.Result.create(
getMethodsMap(),
myModificationTracker
myModificationTrackers
)
).get(name), PsiMethod.EMPTY_ARRAY));
}
Expand All @@ -148,9 +148,9 @@ public PsiClass findInnerClassByName(String name, boolean checkBases) {
else {
return CachedValuesManager.getCachedValue(
myClass,
() -> CachedValueProvider.Result.createSingleDependency(
() -> CachedValueProvider.Result.create(
getInnerClassesMap(),
myModificationTracker
myModificationTrackers
)
).get(name);
}
Expand All @@ -160,9 +160,9 @@ public PsiClass findInnerClassByName(String name, boolean checkBases) {
private PsiMethod getValuesMethod() {
return isEnum() ? internMember(CachedValuesManager.getCachedValue(
myClass,
() -> CachedValueProvider.Result.createSingleDependency(
() -> CachedValueProvider.Result.create(
makeValuesMethod(myClass),
myModificationTracker
myModificationTrackers
)
)) : null;
}
Expand All @@ -171,9 +171,9 @@ private PsiMethod getValuesMethod() {
private PsiMethod getValueOfMethod() {
return isEnum() ? internMember(CachedValuesManager.getCachedValue(
myClass,
() -> CachedValueProvider.Result.createSingleDependency(
() -> CachedValueProvider.Result.create(
makeValueOfMethod(myClass),
myModificationTracker
myModificationTrackers
)
)) : null;
}
Expand Down Expand Up @@ -201,7 +201,11 @@ private <T extends PsiMember> List<T> internMembers(List<T> members) {
@SuppressWarnings("unchecked")
private <T extends PsiMember> T internMember(T m) {
if (m == null) return null;
long modCount = myModificationTracker.getModificationCount();
long modCount = 0;
for (ModificationTracker tracker : myModificationTrackers) {
modCount += tracker.getModificationCount();
}

synchronized (myInterner) {
Pair<Long, Interner<PsiMember>> pair = myInterner.get();
if (pair == null || pair.first.longValue() != modCount) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.light.classes.symbol.classes

import com.intellij.navigation.ItemPresentation
import com.intellij.navigation.ItemPresentationProviders
import com.intellij.openapi.util.ModificationTracker
import com.intellij.openapi.util.Pair
import com.intellij.openapi.util.TextRange
import com.intellij.psi.*
Expand Down Expand Up @@ -37,10 +38,14 @@ abstract class SymbolLightClassBase protected constructor(val ktModule: KtModule
ClassInnerStuffCache(
/* aClass = */ this,
/* generateEnumMethods = */ false,
/* modificationTracker = */ project.createProjectWideOutOfBlockModificationTracker(),
/* modificationTrackers = */ modificationTrackerForClassInnerStuff(),
)
}

protected open fun modificationTrackerForClassInnerStuff(): List<ModificationTracker> {
return listOf(project.createProjectWideOutOfBlockModificationTracker())
}

override fun getFields(): Array<PsiField> = myInnersCache.fields

override fun getMethods(): Array<PsiMethod> = myInnersCache.methods
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package org.jetbrains.kotlin.light.classes.symbol.classes

import com.intellij.openapi.util.ModificationTracker
import com.intellij.psi.*
import com.intellij.psi.impl.InheritanceImplUtil
import com.intellij.psi.impl.PsiClassImplUtil
Expand Down Expand Up @@ -56,6 +57,10 @@ abstract class SymbolLightClassForClassLike<SType : KtClassOrObjectSymbol> prote
manager = manager,
)

override fun modificationTrackerForClassInnerStuff(): List<ModificationTracker> {
return classOrObjectDeclaration?.modificationTrackerForClassInnerStuff() ?: super.modificationTrackerForClassInnerStuff()
}

override val kotlinOrigin: KtClassOrObject? get() = classOrObjectDeclaration

internal inline fun <T> withClassOrObjectSymbol(crossinline action: KtAnalysisSession.(SType) -> T): T =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package org.jetbrains.kotlin.light.classes.symbol.classes

import com.intellij.openapi.util.ModificationTracker
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiManager
import com.intellij.psi.PsiModifier
Expand All @@ -22,6 +23,7 @@ import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.types.KtTypeMappingMode
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker
import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance
import org.jetbrains.kotlin.analysis.utils.printer.parentOfType
import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration
Expand Down Expand Up @@ -68,6 +70,16 @@ internal fun createLightClassNoCache(ktClassOrObject: KtClassOrObject, ktModule:
else -> SymbolLightClassForClassOrObject(ktClassOrObject, ktModule)
}

internal fun KtClassOrObject.modificationTrackerForClassInnerStuff(): List<ModificationTracker> {
val outOfBlockTracker = project.createProjectWideOutOfBlockModificationTracker()
return if (isLocal) {
val file = containingKtFile
listOf(outOfBlockTracker, ModificationTracker { file.modificationStamp })
} else {
listOf(outOfBlockTracker)
}
}

context(KtAnalysisSession)
internal fun createLightClassNoCache(
ktClassOrObjectSymbol: KtNamedClassOrObjectSymbol,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.light.classes.symbol.annotations.*
import org.jetbrains.kotlin.light.classes.symbol.classes.SymbolLightClassBase
import org.jetbrains.kotlin.light.classes.symbol.classes.SymbolLightClassForClassLike
import org.jetbrains.kotlin.light.classes.symbol.classes.SymbolLightClassForInterface
import org.jetbrains.kotlin.light.classes.symbol.classes.SymbolLightClassForInterfaceDefaultImpls
import org.jetbrains.kotlin.light.classes.symbol.classes.modificationTrackerForClassInnerStuff
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtTypeParameterListOwner
Expand Down Expand Up @@ -324,5 +326,11 @@ internal inline fun <reified T> Collection<T>.toArrayIfNotEmptyOrDefault(default
internal inline fun <R : PsiElement, T> R.cachedValue(
crossinline computer: () -> T,
): T = CachedValuesManager.getCachedValue(this) {
CachedValueProvider.Result.createSingleDependency(computer(), project.createProjectWideOutOfBlockModificationTracker())
val value = computer()
val specialClassTrackers = (this as? SymbolLightClassForClassLike<*>)?.classOrObjectDeclaration?.modificationTrackerForClassInnerStuff()
if (specialClassTrackers != null) {
CachedValueProvider.Result.create(value, specialClassTrackers)
} else {
CachedValueProvider.Result.createSingleDependency(value, project.createProjectWideOutOfBlockModificationTracker())
}
}

0 comments on commit e05cb49

Please sign in to comment.