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:
committed by
Space Team
parent
a049fda75b
commit
b04b3d389f
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -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
|
||||
|
||||
+7
@@ -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
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated;
|
||||
|
||||
public interface DeclarationDescriptor extends Annotated, Named {
|
||||
public interface DeclarationDescriptor extends Annotated, Named, ValidateableDescriptor {
|
||||
/**
|
||||
* @return The descriptor that corresponds to the original declaration of this element.
|
||||
* A descriptor can be obtained from its original by substituting type arguments (of the declaring class
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.descriptors;
|
||||
|
||||
public interface ValidateableDescriptor {
|
||||
default void validate() {}
|
||||
}
|
||||
+6
-4
@@ -17,10 +17,7 @@
|
||||
package org.jetbrains.kotlin.descriptors.impl;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorNonRoot;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource;
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
|
||||
@@ -64,4 +61,9 @@ public abstract class DeclarationDescriptorNonRootImpl
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() {
|
||||
containingDeclaration.validate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -306,6 +306,11 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() {
|
||||
getTypeParameters();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<ValueParameterDescriptor> getValueParameters() {
|
||||
|
||||
+6
-1
@@ -180,11 +180,16 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp
|
||||
List<TypeParameterDescriptor> parameters = typeParameters;
|
||||
// Diagnostics for EA-212070
|
||||
if (parameters == null) {
|
||||
throw new IllegalStateException("typeParameters == null for " + this.toString());
|
||||
throw new IllegalStateException("typeParameters == null for " + this);
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() {
|
||||
getTypeParameters();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public List<ReceiverParameterDescriptor> getContextReceiverParameters() {
|
||||
|
||||
Reference in New Issue
Block a user