Fix StackOverflowError on cyclic hierarchy Java<->Kotlin
Report errors not only when superclasses are MutableClassDescriptorLite, but any classes #KT-2115 Fixed
This commit is contained in:
@@ -29,7 +29,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptorLite;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
|
||||
@@ -77,13 +76,13 @@ public class OverrideResolver {
|
||||
Set<ClassDescriptorWithResolutionScopes> ourClasses = new HashSet<ClassDescriptorWithResolutionScopes>(c.getAllClasses());
|
||||
Set<ClassifierDescriptor> processed = new HashSet<ClassifierDescriptor>();
|
||||
|
||||
for (MutableClassDescriptorLite klass : ContainerUtil.reverse(c.getClassesTopologicalOrder())) {
|
||||
if (klass instanceof MutableClassDescriptor && ourClasses.contains(klass)) {
|
||||
generateOverridesAndDelegationInAClass((MutableClassDescriptor) klass, processed, ourClasses);
|
||||
for (MutableClassDescriptor klass : ContainerUtil.reverse(c.getClassesTopologicalOrder())) {
|
||||
if (ourClasses.contains(klass)) {
|
||||
generateOverridesAndDelegationInAClass(klass, processed, ourClasses);
|
||||
|
||||
MutableClassDescriptorLite classObject = klass.getClassObjectDescriptor();
|
||||
if (classObject instanceof MutableClassDescriptor) {
|
||||
generateOverridesAndDelegationInAClass((MutableClassDescriptor) classObject, processed, ourClasses);
|
||||
MutableClassDescriptor classObject = klass.getClassObjectDescriptor();
|
||||
if (classObject != null) {
|
||||
generateOverridesAndDelegationInAClass(classObject, processed, ourClasses);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import kotlin.Function1;
|
||||
import kotlin.KotlinPackage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptorLite;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.MutablePackageFragmentDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||
@@ -44,7 +44,7 @@ public class TopDownAnalysisContext implements BodiesResolveContext {
|
||||
private final Map<JetClassOrObject, ClassDescriptorWithResolutionScopes> classes = Maps.newLinkedHashMap();
|
||||
protected final Map<JetFile, MutablePackageFragmentDescriptor> packageFragments = Maps.newHashMap();
|
||||
protected final Set<JetFile> files = new LinkedHashSet<JetFile>();
|
||||
private List<MutableClassDescriptorLite> classesTopologicalOrder = null;
|
||||
private List<MutableClassDescriptor> classesTopologicalOrder = null;
|
||||
|
||||
private final Map<JetDeclaration, JetScope> declaringScopes = Maps.newHashMap();
|
||||
private final Map<JetNamedFunction, SimpleFunctionDescriptor> functions = Maps.newLinkedHashMap();
|
||||
@@ -183,11 +183,11 @@ public class TopDownAnalysisContext implements BodiesResolveContext {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<MutableClassDescriptorLite> getClassesTopologicalOrder() {
|
||||
public List<MutableClassDescriptor> getClassesTopologicalOrder() {
|
||||
return classesTopologicalOrder;
|
||||
}
|
||||
|
||||
public void setClassesTopologicalOrder(@NotNull List<MutableClassDescriptorLite> classesTopologicalOrder) {
|
||||
public void setClassesTopologicalOrder(@NotNull List<MutableClassDescriptor> classesTopologicalOrder) {
|
||||
this.classesTopologicalOrder = classesTopologicalOrder;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||
import kotlin.KotlinPackage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
@@ -218,38 +219,38 @@ public class TypeHierarchyResolver {
|
||||
}
|
||||
}
|
||||
|
||||
private static List<MutableClassDescriptorLite> topologicallySortClassesAndObjects(@NotNull TopDownAnalysisContext c) {
|
||||
@NotNull
|
||||
private static List<MutableClassDescriptor> topologicallySortClassesAndObjects(@NotNull TopDownAnalysisContext c) {
|
||||
// A topsort is needed only for better diagnostics:
|
||||
// edges that get removed to disconnect loops are more reasonable in this case
|
||||
//noinspection unchecked
|
||||
return DFS.topologicalOrder(
|
||||
List<ClassDescriptor> orderedClasses = DFS.topologicalOrder(
|
||||
(Iterable) c.getAllClasses(),
|
||||
new DFS.Neighbors<MutableClassDescriptorLite>() {
|
||||
new DFS.Neighbors<ClassDescriptor>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterable<MutableClassDescriptorLite> getNeighbors(MutableClassDescriptorLite current) {
|
||||
List<MutableClassDescriptorLite> result = Lists.newArrayList();
|
||||
for (JetType supertype : current.getSupertypes()) {
|
||||
DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor();
|
||||
if (declarationDescriptor instanceof MutableClassDescriptorLite) {
|
||||
MutableClassDescriptorLite classDescriptor = (MutableClassDescriptorLite) declarationDescriptor;
|
||||
result.add(classDescriptor);
|
||||
public Iterable<ClassDescriptor> getNeighbors(ClassDescriptor current) {
|
||||
List<ClassDescriptor> result = Lists.newArrayList();
|
||||
for (JetType supertype : current.getDefaultType().getConstructor().getSupertypes()) {
|
||||
DeclarationDescriptor descriptor = supertype.getConstructor().getDeclarationDescriptor();
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
result.add((ClassDescriptor) descriptor);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
return KotlinPackage.filterIsInstance(orderedClasses, MutableClassDescriptor.class);
|
||||
}
|
||||
|
||||
private void detectAndDisconnectLoops(@NotNull TopDownAnalysisContext c) {
|
||||
// Loop detection and disconnection
|
||||
List<Runnable> tasks = new ArrayList<Runnable>();
|
||||
for (final MutableClassDescriptorLite klass : c.getClassesTopologicalOrder()) {
|
||||
for (final MutableClassDescriptor klass : c.getClassesTopologicalOrder()) {
|
||||
for (final JetType supertype : klass.getSupertypes()) {
|
||||
ClassifierDescriptor supertypeDescriptor = supertype.getConstructor().getDeclarationDescriptor();
|
||||
if (supertypeDescriptor instanceof MutableClassDescriptorLite) {
|
||||
MutableClassDescriptorLite superclass = (MutableClassDescriptorLite) supertypeDescriptor;
|
||||
if (supertypeDescriptor instanceof ClassDescriptor) {
|
||||
ClassDescriptor superclass = (ClassDescriptor) supertypeDescriptor;
|
||||
if (isReachable(superclass, klass, new HashSet<ClassDescriptor>())) {
|
||||
tasks.add(new Runnable() {
|
||||
@Override
|
||||
@@ -269,15 +270,19 @@ public class TypeHierarchyResolver {
|
||||
}
|
||||
|
||||
// Temporary. Duplicates logic from LazyClassTypeConstructor.isReachable
|
||||
private static boolean isReachable(MutableClassDescriptorLite from, MutableClassDescriptorLite to, Set<ClassDescriptor> visited) {
|
||||
private static boolean isReachable(
|
||||
@NotNull ClassDescriptor from,
|
||||
@NotNull MutableClassDescriptor to,
|
||||
@NotNull Set<ClassDescriptor> visited
|
||||
) {
|
||||
if (!visited.add(from)) return false;
|
||||
for (JetType supertype : from.getSupertypes()) {
|
||||
for (JetType supertype : from.getDefaultType().getConstructor().getSupertypes()) {
|
||||
TypeConstructor supertypeConstructor = supertype.getConstructor();
|
||||
if (supertypeConstructor.getDeclarationDescriptor() == to) {
|
||||
return true;
|
||||
}
|
||||
ClassifierDescriptor superclass = supertypeConstructor.getDeclarationDescriptor();
|
||||
if (superclass instanceof MutableClassDescriptorLite && isReachable((MutableClassDescriptorLite) superclass, to, visited)) {
|
||||
if (superclass instanceof ClassDescriptor && isReachable((ClassDescriptor) superclass, to, visited)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// FILE: A.java
|
||||
|
||||
interface A extends C {
|
||||
void foo();
|
||||
}
|
||||
|
||||
// FILE: B.kt
|
||||
|
||||
trait B : <!CYCLIC_INHERITANCE_HIERARCHY!>A<!> {
|
||||
fun bar()
|
||||
}
|
||||
|
||||
// FILE: C.java
|
||||
|
||||
interface C extends B {
|
||||
void baz();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// FILE: J.java
|
||||
|
||||
class J extends K {
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
// FILE: K.kt
|
||||
|
||||
class K : <!CYCLIC_INHERITANCE_HIERARCHY!>J<!>() {
|
||||
fun bar() {}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// FILE: I.kt
|
||||
|
||||
open class I : <!CYCLIC_INHERITANCE_HIERARCHY!>K<!>() {
|
||||
fun foo() {}
|
||||
}
|
||||
|
||||
// FILE: J.java
|
||||
|
||||
class J extends I {
|
||||
void bar() {}
|
||||
}
|
||||
|
||||
// FILE: K.kt
|
||||
|
||||
open class K : <!CYCLIC_INHERITANCE_HIERARCHY!>J<!>() {
|
||||
fun baz() {}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ import org.jetbrains.jet.checkers.AbstractJetDiagnosticsTest;
|
||||
@InnerTestClasses({JetDiagnosticsTestGenerated.Tests.class, JetDiagnosticsTestGenerated.Script.class, JetDiagnosticsTestGenerated.TailRecursion.class})
|
||||
public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
@TestMetadata("compiler/testData/diagnostics/tests")
|
||||
@InnerTestClasses({Tests.Annotations.class, Tests.BackingField.class, Tests.CallableReference.class, Tests.Cast.class, Tests.CheckArguments.class, Tests.ClassObjects.class, Tests.ControlFlowAnalysis.class, Tests.ControlStructures.class, Tests.DataClasses.class, Tests.DataFlow.class, Tests.DataFlowInfoTraversal.class, Tests.DeclarationChecks.class, Tests.DelegatedProperty.class, Tests.Deparenthesize.class, Tests.Enum.class, Tests.Evaluate.class, Tests.Extensions.class, Tests.FunctionLiterals.class, Tests.Generics.class, Tests.Imports.class, Tests.IncompleteCode.class, Tests.Inference.class, Tests.Infos.class, Tests.Inline.class, Tests.Inner.class, Tests.J_k.class, Tests.Jdk_annotations.class, Tests.Library.class, Tests.NamedArguments.class, Tests.NullabilityAndAutoCasts.class, Tests.NullableTypes.class, Tests.Numbers.class, Tests.Objects.class, Tests.OperatorsOverloading.class, Tests.Overload.class, Tests.Override.class, Tests.Recovery.class, Tests.Redeclarations.class, Tests.Regressions.class, Tests.Resolve.class, Tests.Scopes.class, Tests.SenselessComparison.class, Tests.Shadowing.class, Tests.SmartCasts.class, Tests.Substitutions.class, Tests.Subtyping.class, Tests.Suppress.class, Tests.ThisAndSuper.class, Tests.Unit.class, Tests.Varargs.class, Tests.When.class})
|
||||
@InnerTestClasses({Tests.Annotations.class, Tests.BackingField.class, Tests.CallableReference.class, Tests.Cast.class, Tests.CheckArguments.class, Tests.ClassObjects.class, Tests.ControlFlowAnalysis.class, Tests.ControlStructures.class, Tests.CyclicHierarchy.class, Tests.DataClasses.class, Tests.DataFlow.class, Tests.DataFlowInfoTraversal.class, Tests.DeclarationChecks.class, Tests.DelegatedProperty.class, Tests.Deparenthesize.class, Tests.Enum.class, Tests.Evaluate.class, Tests.Extensions.class, Tests.FunctionLiterals.class, Tests.Generics.class, Tests.Imports.class, Tests.IncompleteCode.class, Tests.Inference.class, Tests.Infos.class, Tests.Inline.class, Tests.Inner.class, Tests.J_k.class, Tests.Jdk_annotations.class, Tests.Library.class, Tests.NamedArguments.class, Tests.NullabilityAndAutoCasts.class, Tests.NullableTypes.class, Tests.Numbers.class, Tests.Objects.class, Tests.OperatorsOverloading.class, Tests.Overload.class, Tests.Override.class, Tests.Recovery.class, Tests.Redeclarations.class, Tests.Regressions.class, Tests.Resolve.class, Tests.Scopes.class, Tests.SenselessComparison.class, Tests.Shadowing.class, Tests.SmartCasts.class, Tests.Substitutions.class, Tests.Subtyping.class, Tests.Suppress.class, Tests.ThisAndSuper.class, Tests.Unit.class, Tests.Varargs.class, Tests.When.class})
|
||||
public static class Tests extends AbstractJetDiagnosticsTest {
|
||||
@TestMetadata("Abstract.kt")
|
||||
public void testAbstract() throws Exception {
|
||||
@@ -149,11 +149,6 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest("compiler/testData/diagnostics/tests/CovariantOverrideType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("CyclicHierarchy.kt")
|
||||
public void testCyclicHierarchy() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/CyclicHierarchy.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("DefaultValuesTypechecking.kt")
|
||||
public void testDefaultValuesTypechecking() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/DefaultValuesTypechecking.kt");
|
||||
@@ -1822,6 +1817,39 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/cyclicHierarchy")
|
||||
public static class CyclicHierarchy extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInCyclicHierarchy() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/diagnostics/tests/cyclicHierarchy"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("cyclicHierarchy.kt")
|
||||
public void testCyclicHierarchy() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/cyclicHierarchy/cyclicHierarchy.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("javaKotlinJavaCycle.kt")
|
||||
public void testJavaKotlinJavaCycle() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/cyclicHierarchy/javaKotlinJavaCycle.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinJavaCycle.kt")
|
||||
public void testKotlinJavaCycle() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaCycle.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinJavaKotlinCycle.kt")
|
||||
public void testKotlinJavaKotlinCycle() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaKotlinCycle.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt303.kt")
|
||||
public void testKt303() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/cyclicHierarchy/kt303.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/dataClasses")
|
||||
public static class DataClasses extends AbstractJetDiagnosticsTest {
|
||||
public void testAllFilesPresentInDataClasses() throws Exception {
|
||||
@@ -5739,11 +5767,6 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest("compiler/testData/diagnostics/tests/regressions/kt302.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt303.kt")
|
||||
public void testKt303() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/regressions/kt303.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt306.kt")
|
||||
public void testKt306() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/regressions/kt306.kt");
|
||||
@@ -7104,6 +7127,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
suite.addTestSuite(ClassObjects.class);
|
||||
suite.addTest(ControlFlowAnalysis.innerSuite());
|
||||
suite.addTestSuite(ControlStructures.class);
|
||||
suite.addTestSuite(CyclicHierarchy.class);
|
||||
suite.addTestSuite(DataClasses.class);
|
||||
suite.addTest(DataFlow.innerSuite());
|
||||
suite.addTestSuite(DataFlowInfoTraversal.class);
|
||||
|
||||
Reference in New Issue
Block a user