From 6c6abab0337d9d58f48688e9818c59b5b1f8bb35 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Thu, 6 Dec 2012 19:48:07 +0400 Subject: [PATCH] Supported propagation for Java subclass of Kotlin class. --- .../jet/lang/resolve/java/JetClsMethod.java | 25 +++++++++ .../SignaturesPropagationData.java | 16 +++--- .../jet/asJava/wrappers/JetClsMethodImpl.java | 9 ++- .../subclassingKotlinInJava/expected.txt | 10 ++++ .../java/test/JavaSubclass.java | 7 +++ .../kotlin/KotlinClass.kt | 5 ++ .../jet/jvm/compiler/LoadJavaCustomTest.java | 56 +++++++++++++++++++ 7 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetClsMethod.java create mode 100644 compiler/testData/loadJavaCustom/subclassingKotlinInJava/expected.txt create mode 100644 compiler/testData/loadJavaCustom/subclassingKotlinInJava/java/test/JavaSubclass.java create mode 100644 compiler/testData/loadJavaCustom/subclassingKotlinInJava/kotlin/KotlinClass.kt diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetClsMethod.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetClsMethod.java new file mode 100644 index 00000000000..e0326984867 --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JetClsMethod.java @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.java; + +import com.intellij.psi.PsiMethod; +import org.jetbrains.jet.lang.psi.JetDeclaration; + +/** ClsMethod created for Kotlin declaration for it to be resolved from Java */ +public interface JetClsMethod extends PsiMethod { + JetDeclaration getOrigin(); +} diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java index 52923591392..bf95ae98a79 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java @@ -23,16 +23,15 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.HierarchicalMethodSignature; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTrace; -import org.jetbrains.jet.lang.resolve.java.CollectionClassMapping; -import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; -import org.jetbrains.jet.lang.resolve.java.JavaToKotlinClassMap; -import org.jetbrains.jet.lang.resolve.java.JavaToKotlinMethodMap; +import org.jetbrains.jet.lang.resolve.java.*; import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; @@ -200,12 +199,14 @@ public class SignaturesPropagationData { ) { List superFunctions = Lists.newArrayList(); for (HierarchicalMethodSignature superSignature : method.getPsiMethod().getHierarchicalMethodSignature().getSuperSignatures()) { - DeclarationDescriptor superFun = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, superSignature.getMethod()); + PsiMethod superMethod = superSignature.getMethod(); + PsiElement superDeclaration = superMethod instanceof JetClsMethod ? ((JetClsMethod) superMethod).getOrigin() : superMethod; + DeclarationDescriptor superFun = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, superDeclaration); if (superFun instanceof FunctionDescriptor) { superFunctions.add(((FunctionDescriptor) superFun)); } else { - PsiClass psiClass = superSignature.getMethod().getContainingClass(); + PsiClass psiClass = superMethod.getContainingClass(); assert psiClass != null; String fqName = psiClass.getQualifiedName(); assert fqName != null; @@ -222,8 +223,7 @@ public class SignaturesPropagationData { } } else { - List funsFromMap = - JavaToKotlinMethodMap.INSTANCE.getFunctions(superSignature.getMethod(), containingClass); + List funsFromMap = JavaToKotlinMethodMap.INSTANCE.getFunctions(superMethod, containingClass); superFunctions.addAll(funsFromMap); } } diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/wrappers/JetClsMethodImpl.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/wrappers/JetClsMethodImpl.java index 274470bd981..a9f15d276e3 100644 --- a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/wrappers/JetClsMethodImpl.java +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/wrappers/JetClsMethodImpl.java @@ -20,8 +20,10 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.impl.compiled.ClsMethodImpl; import com.intellij.psi.impl.java.stubs.PsiMethodStub; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetDeclaration; +import org.jetbrains.jet.lang.resolve.java.JetClsMethod; -public class JetClsMethodImpl extends ClsMethodImpl { +public class JetClsMethodImpl extends ClsMethodImpl implements JetClsMethod { @NotNull private final PsiElement origin; @@ -40,4 +42,9 @@ public class JetClsMethodImpl extends ClsMethodImpl { public PsiElement getNavigationElement() { return origin; } + + @Override + public JetDeclaration getOrigin() { + return (JetDeclaration) origin; + } } diff --git a/compiler/testData/loadJavaCustom/subclassingKotlinInJava/expected.txt b/compiler/testData/loadJavaCustom/subclassingKotlinInJava/expected.txt new file mode 100644 index 00000000000..01a53201180 --- /dev/null +++ b/compiler/testData/loadJavaCustom/subclassingKotlinInJava/expected.txt @@ -0,0 +1,10 @@ +namespace test + +public open class test.JavaSubclass : test.KotlinClass { + public final /*constructor*/ fun (): test.JavaSubclass + public open override /*1*/ fun foo(): jet.String +} +public open class test.KotlinClass : jet.Any { + public final /*constructor*/ fun (): test.KotlinClass + public open fun foo(): jet.String +} diff --git a/compiler/testData/loadJavaCustom/subclassingKotlinInJava/java/test/JavaSubclass.java b/compiler/testData/loadJavaCustom/subclassingKotlinInJava/java/test/JavaSubclass.java new file mode 100644 index 00000000000..6f4480eb350 --- /dev/null +++ b/compiler/testData/loadJavaCustom/subclassingKotlinInJava/java/test/JavaSubclass.java @@ -0,0 +1,7 @@ +package test; + +public class JavaSubclass extends KotlinClass { + public String foo() { + return ""; + } +} diff --git a/compiler/testData/loadJavaCustom/subclassingKotlinInJava/kotlin/KotlinClass.kt b/compiler/testData/loadJavaCustom/subclassingKotlinInJava/kotlin/KotlinClass.kt new file mode 100644 index 00000000000..70cf8e3e42b --- /dev/null +++ b/compiler/testData/loadJavaCustom/subclassingKotlinInJava/kotlin/KotlinClass.kt @@ -0,0 +1,5 @@ +package test + +public open class KotlinClass { + public open fun foo(): String = "" +} diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaCustomTest.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaCustomTest.java index 7a31a7d9540..bf3ee22ffc7 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaCustomTest.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadJavaCustomTest.java @@ -16,20 +16,37 @@ package org.jetbrains.jet.jvm.compiler; +import com.google.common.base.Predicates; import com.intellij.openapi.util.Pair; +import com.intellij.psi.PsiFile; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.CompileCompilerDependenciesTest; import org.jetbrains.jet.ConfigurationKind; import org.jetbrains.jet.JetTestUtils; +import org.jetbrains.jet.TestJdkKind; import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; +import org.jetbrains.jet.config.CommonConfigurationKeys; +import org.jetbrains.jet.config.CompilerConfiguration; +import org.jetbrains.jet.di.InjectorForJavaSemanticServices; +import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJvm; +import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor; +import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; +import org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule; +import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.lang.resolve.lazy.KotlinTestWithEnvironment; +import org.jetbrains.jet.lang.resolve.lazy.LazyResolveTestUtil; +import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.test.util.NamespaceComparator; import java.io.File; import java.util.Arrays; +import java.util.Collections; import java.util.List; import static org.jetbrains.jet.jvm.compiler.LoadDescriptorUtil.compileJavaAndLoadTestNamespaceAndBindingContextFromBinary; @@ -117,4 +134,43 @@ public final class LoadJavaCustomTest extends KotlinTestWithEnvironment { doTest(dir + "RawSuperType.txt", dir + "RawSuperType.java"); } + + public static class SubclassingKotlinInJavaTest extends KotlinTestWithEnvironment { + @Override + protected JetCoreEnvironment createEnvironment() { + File dir = new File(PATH + "/subclassingKotlinInJava"); + + CompilerConfiguration configuration = CompileCompilerDependenciesTest.compilerConfigurationForTests( + ConfigurationKind.JDK_ONLY, TestJdkKind.MOCK_JDK, new File(dir, "java")); + configuration.put(CommonConfigurationKeys.SOURCE_ROOTS_KEY, Arrays.asList(new File(dir, "kotlin").getAbsolutePath())); + return new JetCoreEnvironment(getTestRootDisposable(), configuration); + } + + public void testSubclassingKotlinInJava() throws Exception { + File dir = new File(PATH + "/subclassingKotlinInJava"); + + InjectorForJavaSemanticServices injectorForJava = new InjectorForJavaSemanticServices(getProject()); + + // we need the same binding trace for resolve from Java and Kotlin + BindingTrace bindingTrace = injectorForJava.getBindingTrace(); + + InjectorForTopDownAnalyzerForJvm injectorForAnalyzer = new InjectorForTopDownAnalyzerForJvm( + getProject(), + new TopDownAnalysisParameters(Predicates.alwaysFalse(), false, false, Collections.emptyList()), + bindingTrace, + new ModuleDescriptor(Name.special(""))); + + injectorForAnalyzer.getTopDownAnalyzer().analyzeFiles(getEnvironment().getSourceFiles(), Collections.emptyList()); + + JavaDescriptorResolver javaDescriptorResolver = injectorForJava.getJavaDescriptorResolver(); + NamespaceDescriptor namespaceDescriptor = javaDescriptorResolver.resolveNamespace( + LoadDescriptorUtil.TEST_PACKAGE_FQNAME, DescriptorSearchRule.INCLUDE_KOTLIN); + assert namespaceDescriptor != null; + + NamespaceComparator.compareNamespaces(namespaceDescriptor, namespaceDescriptor, + NamespaceComparator.DONT_INCLUDE_METHODS_OF_OBJECT, new File(dir, "expected.txt")); + + ExpectedLoadErrorsUtil.checkForLoadErrors(namespaceDescriptor, bindingTrace.getBindingContext()); + } + } }