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:
Alexander Udalov
2014-04-02 22:08:24 +04:00
parent 4241eb9661
commit 9b2291d381
9 changed files with 114 additions and 41 deletions
@@ -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);