Add ability for DeclarationDescriptor validation

Not fully initialized DeclarationDescriptor could leak to bindingTrace.
It is hard to detect the outcome of that kind of leakage due to
possibility to have not fully initialized instances if PCE happens in
the middle of publication and instance full initialization.

#KT-56364
#KT-56388
#KT-54085
#KT-55150
This commit is contained in:
Vladimir Dolzhenko
2023-02-02 17:23:51 +01:00
committed by Space Team
parent a049fda75b
commit b04b3d389f
8 changed files with 57 additions and 10 deletions
@@ -17,9 +17,11 @@
package org.jetbrains.kotlin.resolve;
import com.google.common.collect.ImmutableMap;
import com.intellij.openapi.progress.ProgressManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.descriptors.ValidateableDescriptor;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.diagnostics.BindingContextSuppressCache;
@@ -33,6 +35,7 @@ import org.jetbrains.kotlin.util.slicedMap.*;
import java.util.Collection;
public class BindingTraceContext implements BindingTrace {
private static final boolean VALIDATION = Boolean.parseBoolean(System.getProperty("kotlin.bindingTrace.validation"));
// These flags are used for debugging of "Rewrite at slice..." exceptions
/* package */ final static boolean TRACK_REWRITES = false;
/* package */ final static boolean TRACK_WITH_STACK_TRACES = true;
@@ -40,6 +43,8 @@ public class BindingTraceContext implements BindingTrace {
private final MutableSlicedMap map;
private final MutableDiagnosticsWithSuppression mutableDiagnostics;
private final boolean isValidationEnabled;
private final BindingContext bindingContext = new CleanableBindingContext() {
@NotNull
@Override
@@ -91,20 +96,25 @@ public class BindingTraceContext implements BindingTrace {
}
public BindingTraceContext(BindingTraceFilter filter, boolean allowSliceRewrite) {
this(TRACK_REWRITES && !allowSliceRewrite ? new TrackingSlicedMap(TRACK_WITH_STACK_TRACES) : new SlicedMapImpl(allowSliceRewrite), filter);
this(filter, allowSliceRewrite, VALIDATION);
}
private BindingTraceContext(@NotNull MutableSlicedMap map, BindingTraceFilter filter) {
public BindingTraceContext(BindingTraceFilter filter, boolean allowSliceRewrite, boolean isValidationEnabled) {
this(TRACK_REWRITES && !allowSliceRewrite ? new TrackingSlicedMap(TRACK_WITH_STACK_TRACES) : new SlicedMapImpl(allowSliceRewrite), filter, isValidationEnabled);
}
private BindingTraceContext(@NotNull MutableSlicedMap map, BindingTraceFilter filter, boolean isValidationEnabled) {
this.map = map;
this.mutableDiagnostics =
filter.getIgnoreDiagnostics()
? null
: new MutableDiagnosticsWithSuppression(new BindingContextSuppressCache(bindingContext), Diagnostics.Companion.getEMPTY());
this.isValidationEnabled = isValidationEnabled;
}
@TestOnly
public static BindingTraceContext createTraceableBindingTrace() {
return new BindingTraceContext(new TrackingSlicedMap(TRACK_WITH_STACK_TRACES), BindingTraceFilter.Companion.getACCEPT_ALL());
return new BindingTraceContext(new TrackingSlicedMap(TRACK_WITH_STACK_TRACES), BindingTraceFilter.Companion.getACCEPT_ALL(), VALIDATION);
}
@Override
@@ -134,6 +144,9 @@ public class BindingTraceContext implements BindingTrace {
@Override
public <K, V> void record(WritableSlice<K, V> slice, K key, V value) {
if (isValidationEnabled && value instanceof ValidateableDescriptor && !ProgressManager.getInstance().isInNonCancelableSection()) {
((ValidateableDescriptor) value).validate();
}
map.put(slice, key, value);
}
@@ -76,7 +76,7 @@ class LazyAnnotations(
class LazyAnnotationDescriptor(
val c: LazyAnnotationsContext,
val annotationEntry: KtAnnotationEntry
) : AnnotationDescriptor, LazyEntity {
) : AnnotationDescriptor, LazyEntity, ValidateableDescriptor {
override val type by c.storageManager.createLazyValue(
computable = lazy@{
@@ -128,6 +128,11 @@ class LazyAnnotationDescriptor(
fun getSourceForArgument(name: Name): SourceElement =
valueArgumentsWithSourceInfo[name]?.second ?: SourceElement.NO_SOURCE
override fun validate() {
checkNotNull(scope) { "scope == null for $this" }
}
override fun forceResolveAllContents() {
ForceResolveUtil.forceResolveAllContents(type)
allValueArguments
@@ -702,6 +702,13 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
return false;
}
@Override
public void validate() {
if (parameters == null) {
throw new IllegalStateException("parameters == null for " + this);
}
}
@Override
public String toString() {
// not using DescriptorRenderer to preserve laziness