Loading SAM constructor functions for nested interfaces.
This commit is contained in:
+38
-2
@@ -94,7 +94,7 @@ public final class MembersCache {
|
||||
if (JetClassAnnotation.get(psiClass).kind() == JvmStdlibNames.FLAG_CLASS_KIND_OBJECT) {
|
||||
processObjectClass(psiClass);
|
||||
}
|
||||
if (!DescriptorResolverUtils.isKotlinClass(psiClass) && psiClass.isInterface()) {
|
||||
if (!DescriptorResolverUtils.isKotlinClass(psiClass) && isFunctionalInterface(psiClass)) {
|
||||
processFunctionalInterface(psiClass);
|
||||
}
|
||||
}
|
||||
@@ -132,6 +132,7 @@ public final class MembersCache {
|
||||
public void process() {
|
||||
processFields();
|
||||
processMethods();
|
||||
processNestedClasses();
|
||||
}
|
||||
|
||||
private boolean includeMember(PsiMemberWrapper member) {
|
||||
@@ -300,6 +301,18 @@ public final class MembersCache {
|
||||
private void createEmptyEntry(@NotNull Name identifier) {
|
||||
getOrCreateEmpty(identifier);
|
||||
}
|
||||
|
||||
private void processNestedClasses() {
|
||||
if (!staticMembers) {
|
||||
return;
|
||||
}
|
||||
for (PsiClass nested : psiClass.getPsiClass().getInnerClasses()) {
|
||||
if (isFunctionalInterface(nested)) {
|
||||
NamedMembers namedMembers = getOrCreateEmpty(Name.identifier(nested.getName()));
|
||||
namedMembers.setFunctionalInterface(nested);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isObjectMethodInInterface(@NotNull PsiMember member) {
|
||||
@@ -313,8 +326,31 @@ public final class MembersCache {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isObjectMethod((PsiMethod) member);
|
||||
}
|
||||
|
||||
private static boolean isObjectMethod(PsiMethod method) {
|
||||
String formattedMethod = PsiFormatUtil.formatMethod(
|
||||
(PsiMethod) member, PsiSubstitutor.EMPTY, SHOW_NAME | SHOW_PARAMETERS, SHOW_TYPE | SHOW_FQ_CLASS_NAMES);
|
||||
method, PsiSubstitutor.EMPTY, SHOW_NAME | SHOW_PARAMETERS, SHOW_TYPE | SHOW_FQ_CLASS_NAMES);
|
||||
return OBJECT_METHODS.contains(formattedMethod);
|
||||
}
|
||||
|
||||
public static boolean isFunctionalInterface(@NotNull PsiClass psiClass) {
|
||||
if (!psiClass.isInterface()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int foundAbstractMethods = 0;
|
||||
for (PsiMethod method : psiClass.getAllMethods()) {
|
||||
if (!isObjectMethod(method) && method.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
foundAbstractMethods++;
|
||||
|
||||
if (method.hasTypeParameters()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return foundAbstractMethods == 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+52
-9
@@ -27,6 +27,7 @@ import com.intellij.psi.util.PsiFormatUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorParent;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.java.*;
|
||||
@@ -40,6 +41,7 @@ import org.jetbrains.jet.lang.resolve.java.provider.PsiDeclarationProvider;
|
||||
import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||
|
||||
@@ -279,6 +281,13 @@ public final class JavaFunctionResolver {
|
||||
}
|
||||
}
|
||||
|
||||
if (owner instanceof NamespaceDescriptor) {
|
||||
SimpleFunctionDescriptor samConstructor = resolveSamConstructor((NamespaceDescriptor) owner, namedMembers);
|
||||
if (samConstructor != null) {
|
||||
functionsFromCurrent.add(samConstructor);
|
||||
}
|
||||
}
|
||||
|
||||
if (owner instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) owner;
|
||||
|
||||
@@ -313,6 +322,44 @@ public final class JavaFunctionResolver {
|
||||
return functions;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ClassDescriptor findClassInScope(@NotNull JetScope memberScope, @NotNull Name name) {
|
||||
ClassifierDescriptor classifier = memberScope.getClassifier(name);
|
||||
if (classifier instanceof ClassDescriptor) {
|
||||
return (ClassDescriptor) classifier;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// E.g. we have foo.Bar.Baz class declared in Java. It will produce the following descriptors structure:
|
||||
// namespace foo
|
||||
// +-- class Bar
|
||||
// | +-- class Baz
|
||||
// +-- namespace Bar
|
||||
// We need to find class 'Baz' in namespace 'foo.Bar'.
|
||||
@Nullable
|
||||
private static ClassDescriptor findClassInNamespace(@NotNull NamespaceDescriptor namespace, @NotNull Name name) {
|
||||
// First, try to find in namespace directly
|
||||
ClassDescriptor found = findClassInScope(namespace.getMemberScope(), name);
|
||||
if (found != null) {
|
||||
return found;
|
||||
}
|
||||
|
||||
// If unsuccessful, try to find class of the same name as current (class 'foo.Bar')
|
||||
NamespaceDescriptorParent parent = namespace.getContainingDeclaration();
|
||||
if (parent instanceof NamespaceDescriptor) {
|
||||
// Calling recursively, looking for 'Bar' in 'foo'
|
||||
ClassDescriptor classForCurrentNamespace = findClassInNamespace((NamespaceDescriptor) parent, namespace.getName());
|
||||
if (classForCurrentNamespace == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Try to find nested class 'Baz' in class 'foo.Bar'
|
||||
return findClassInScope(DescriptorUtils.getStaticNestedClassesScope(classForCurrentNamespace), name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private SimpleFunctionDescriptor resolveSamConstructor(
|
||||
@NotNull NamespaceDescriptor ownerDescriptor,
|
||||
@@ -320,15 +367,11 @@ public final class JavaFunctionResolver {
|
||||
) {
|
||||
PsiClass functionalInterface = namedMembers.getFunctionalInterface();
|
||||
if (functionalInterface != null) {
|
||||
ClassifierDescriptor classifier = ownerDescriptor.getMemberScope().getClassifier(namedMembers.getName());
|
||||
if (classifier instanceof ClassDescriptor) {
|
||||
ClassDescriptor klass = (ClassDescriptor) classifier;
|
||||
|
||||
if (SingleAbstractMethodUtils.isFunctionalInterface(klass)) {
|
||||
SimpleFunctionDescriptor constructorFunction = SingleAbstractMethodUtils.createConstructorFunction(klass);
|
||||
trace.record(BindingContext.SAM_CONSTRUCTOR_TO_TRAIT, constructorFunction, klass);
|
||||
return constructorFunction;
|
||||
}
|
||||
ClassDescriptor klass = findClassInNamespace(ownerDescriptor, namedMembers.getName());
|
||||
if (klass != null && SingleAbstractMethodUtils.isFunctionalInterface(klass)) {
|
||||
SimpleFunctionDescriptor constructorFunction = SingleAbstractMethodUtils.createConstructorFunction(ownerDescriptor, klass);
|
||||
trace.record(BindingContext.SAM_CONSTRUCTOR_TO_TRAIT, constructorFunction, klass);
|
||||
return constructorFunction;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
+4
@@ -35,6 +35,7 @@ import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.java.*;
|
||||
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaNamespaceDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.java.kt.JetPackageClassAnnotation;
|
||||
import org.jetbrains.jet.lang.resolve.java.provider.MembersCache;
|
||||
import org.jetbrains.jet.lang.resolve.java.scope.JavaBaseScope;
|
||||
import org.jetbrains.jet.lang.resolve.java.scope.JavaClassStaticMembersScope;
|
||||
import org.jetbrains.jet.lang.resolve.java.scope.JavaPackageScopeWithoutMembers;
|
||||
@@ -220,6 +221,9 @@ public final class JavaNamespaceResolver {
|
||||
}
|
||||
|
||||
for (PsiClass nestedClass : psiClass.getInnerClasses()) {
|
||||
if (MembersCache.isFunctionalInterface(nestedClass)) {
|
||||
return true;
|
||||
}
|
||||
if (nestedClass.hasModifierProperty(PsiModifier.STATIC) && hasStaticMembers(nestedClass)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+2
-2
@@ -73,9 +73,9 @@ public class SingleAbstractMethodUtils {
|
||||
return KotlinBuiltIns.getInstance().getFunctionType(Collections.<AnnotationDescriptor>emptyList(), null, parameterTypes, returnType);
|
||||
}
|
||||
|
||||
public static SimpleFunctionDescriptor createConstructorFunction(@NotNull ClassDescriptor klass) {
|
||||
public static SimpleFunctionDescriptor createConstructorFunction(@NotNull ClassOrNamespaceDescriptor owner, @NotNull ClassDescriptor klass) {
|
||||
SimpleFunctionDescriptorImpl result = new SimpleFunctionDescriptorImpl(
|
||||
klass.getContainingDeclaration(),
|
||||
owner,
|
||||
klass.getAnnotations(),
|
||||
klass.getName(),
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package test;
|
||||
|
||||
public interface Nested {
|
||||
|
||||
public interface Runnable {
|
||||
void run();
|
||||
}
|
||||
|
||||
public interface Deeper1 {
|
||||
public interface Runnable {
|
||||
void run();
|
||||
void run2();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Deeper2 {
|
||||
public interface Runnable {
|
||||
void run();
|
||||
String toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package test
|
||||
|
||||
public trait Nested : java.lang.Object {
|
||||
|
||||
public trait Deeper1 : java.lang.Object {
|
||||
|
||||
public trait Runnable : java.lang.Object {
|
||||
public abstract fun run() : jet.Unit
|
||||
public abstract fun run2() : jet.Unit
|
||||
}
|
||||
}
|
||||
|
||||
public trait Deeper2 : java.lang.Object {
|
||||
|
||||
public trait Runnable : java.lang.Object {
|
||||
public abstract fun run() : jet.Unit
|
||||
}
|
||||
}
|
||||
|
||||
public trait Runnable : java.lang.Object {
|
||||
public abstract fun run() : jet.Unit
|
||||
}
|
||||
}
|
||||
|
||||
package Nested {
|
||||
public /*synthesized*/ fun Runnable(/*0*/ function : () -> jet.Unit) : test.Nested.Runnable
|
||||
|
||||
package Deeper2 {
|
||||
public /*synthesized*/ fun Runnable(/*0*/ function : () -> jet.Unit) : test.Nested.Deeper2.Runnable
|
||||
}
|
||||
}
|
||||
@@ -1160,6 +1160,11 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
|
||||
doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/InterfaceWithObjectMethod.java");
|
||||
}
|
||||
|
||||
@TestMetadata("Nested.java")
|
||||
public void testNested() throws Exception {
|
||||
doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/Nested.java");
|
||||
}
|
||||
|
||||
@TestMetadata("Runnable.java")
|
||||
public void testRunnable() throws Exception {
|
||||
doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/Runnable.java");
|
||||
@@ -1177,7 +1182,7 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
|
||||
public void testDeeplyInnerClass() throws Exception {
|
||||
doTestCompiledJava("compiler/testData/loadJava/compiledJava/static/DeeplyInnerClass.java");
|
||||
}
|
||||
|
||||
|
||||
@TestMetadata("DeeplyNestedStatic.java")
|
||||
public void testDeeplyNestedStatic() throws Exception {
|
||||
doTestCompiledJava("compiler/testData/loadJava/compiledJava/static/DeeplyNestedStatic.java");
|
||||
|
||||
Reference in New Issue
Block a user