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) {
|
if (JetClassAnnotation.get(psiClass).kind() == JvmStdlibNames.FLAG_CLASS_KIND_OBJECT) {
|
||||||
processObjectClass(psiClass);
|
processObjectClass(psiClass);
|
||||||
}
|
}
|
||||||
if (!DescriptorResolverUtils.isKotlinClass(psiClass) && psiClass.isInterface()) {
|
if (!DescriptorResolverUtils.isKotlinClass(psiClass) && isFunctionalInterface(psiClass)) {
|
||||||
processFunctionalInterface(psiClass);
|
processFunctionalInterface(psiClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,6 +132,7 @@ public final class MembersCache {
|
|||||||
public void process() {
|
public void process() {
|
||||||
processFields();
|
processFields();
|
||||||
processMethods();
|
processMethods();
|
||||||
|
processNestedClasses();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean includeMember(PsiMemberWrapper member) {
|
private boolean includeMember(PsiMemberWrapper member) {
|
||||||
@@ -300,6 +301,18 @@ public final class MembersCache {
|
|||||||
private void createEmptyEntry(@NotNull Name identifier) {
|
private void createEmptyEntry(@NotNull Name identifier) {
|
||||||
getOrCreateEmpty(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) {
|
private static boolean isObjectMethodInInterface(@NotNull PsiMember member) {
|
||||||
@@ -313,8 +326,31 @@ public final class MembersCache {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return isObjectMethod((PsiMethod) member);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isObjectMethod(PsiMethod method) {
|
||||||
String formattedMethod = PsiFormatUtil.formatMethod(
|
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);
|
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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
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.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||||
import org.jetbrains.jet.lang.resolve.*;
|
import org.jetbrains.jet.lang.resolve.*;
|
||||||
import org.jetbrains.jet.lang.resolve.java.*;
|
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.sam.SingleAbstractMethodUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
|
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
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.*;
|
||||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
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) {
|
if (owner instanceof ClassDescriptor) {
|
||||||
ClassDescriptor classDescriptor = (ClassDescriptor) owner;
|
ClassDescriptor classDescriptor = (ClassDescriptor) owner;
|
||||||
|
|
||||||
@@ -313,6 +322,44 @@ public final class JavaFunctionResolver {
|
|||||||
return functions;
|
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
|
@Nullable
|
||||||
private SimpleFunctionDescriptor resolveSamConstructor(
|
private SimpleFunctionDescriptor resolveSamConstructor(
|
||||||
@NotNull NamespaceDescriptor ownerDescriptor,
|
@NotNull NamespaceDescriptor ownerDescriptor,
|
||||||
@@ -320,15 +367,11 @@ public final class JavaFunctionResolver {
|
|||||||
) {
|
) {
|
||||||
PsiClass functionalInterface = namedMembers.getFunctionalInterface();
|
PsiClass functionalInterface = namedMembers.getFunctionalInterface();
|
||||||
if (functionalInterface != null) {
|
if (functionalInterface != null) {
|
||||||
ClassifierDescriptor classifier = ownerDescriptor.getMemberScope().getClassifier(namedMembers.getName());
|
ClassDescriptor klass = findClassInNamespace(ownerDescriptor, namedMembers.getName());
|
||||||
if (classifier instanceof ClassDescriptor) {
|
if (klass != null && SingleAbstractMethodUtils.isFunctionalInterface(klass)) {
|
||||||
ClassDescriptor klass = (ClassDescriptor) classifier;
|
SimpleFunctionDescriptor constructorFunction = SingleAbstractMethodUtils.createConstructorFunction(ownerDescriptor, klass);
|
||||||
|
trace.record(BindingContext.SAM_CONSTRUCTOR_TO_TRAIT, constructorFunction, klass);
|
||||||
if (SingleAbstractMethodUtils.isFunctionalInterface(klass)) {
|
return constructorFunction;
|
||||||
SimpleFunctionDescriptor constructorFunction = SingleAbstractMethodUtils.createConstructorFunction(klass);
|
|
||||||
trace.record(BindingContext.SAM_CONSTRUCTOR_TO_TRAIT, constructorFunction, klass);
|
|
||||||
return constructorFunction;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
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.*;
|
||||||
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaNamespaceDescriptor;
|
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.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.JavaBaseScope;
|
||||||
import org.jetbrains.jet.lang.resolve.java.scope.JavaClassStaticMembersScope;
|
import org.jetbrains.jet.lang.resolve.java.scope.JavaClassStaticMembersScope;
|
||||||
import org.jetbrains.jet.lang.resolve.java.scope.JavaPackageScopeWithoutMembers;
|
import org.jetbrains.jet.lang.resolve.java.scope.JavaPackageScopeWithoutMembers;
|
||||||
@@ -220,6 +221,9 @@ public final class JavaNamespaceResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (PsiClass nestedClass : psiClass.getInnerClasses()) {
|
for (PsiClass nestedClass : psiClass.getInnerClasses()) {
|
||||||
|
if (MembersCache.isFunctionalInterface(nestedClass)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (nestedClass.hasModifierProperty(PsiModifier.STATIC) && hasStaticMembers(nestedClass)) {
|
if (nestedClass.hasModifierProperty(PsiModifier.STATIC) && hasStaticMembers(nestedClass)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -73,9 +73,9 @@ public class SingleAbstractMethodUtils {
|
|||||||
return KotlinBuiltIns.getInstance().getFunctionType(Collections.<AnnotationDescriptor>emptyList(), null, parameterTypes, returnType);
|
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(
|
SimpleFunctionDescriptorImpl result = new SimpleFunctionDescriptorImpl(
|
||||||
klass.getContainingDeclaration(),
|
owner,
|
||||||
klass.getAnnotations(),
|
klass.getAnnotations(),
|
||||||
klass.getName(),
|
klass.getName(),
|
||||||
CallableMemberDescriptor.Kind.SYNTHESIZED
|
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");
|
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")
|
@TestMetadata("Runnable.java")
|
||||||
public void testRunnable() throws Exception {
|
public void testRunnable() throws Exception {
|
||||||
doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/Runnable.java");
|
doTestCompiledJava("compiler/testData/loadJava/compiledJava/singleAbstractMethod/Runnable.java");
|
||||||
@@ -1177,7 +1182,7 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
|
|||||||
public void testDeeplyInnerClass() throws Exception {
|
public void testDeeplyInnerClass() throws Exception {
|
||||||
doTestCompiledJava("compiler/testData/loadJava/compiledJava/static/DeeplyInnerClass.java");
|
doTestCompiledJava("compiler/testData/loadJava/compiledJava/static/DeeplyInnerClass.java");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("DeeplyNestedStatic.java")
|
@TestMetadata("DeeplyNestedStatic.java")
|
||||||
public void testDeeplyNestedStatic() throws Exception {
|
public void testDeeplyNestedStatic() throws Exception {
|
||||||
doTestCompiledJava("compiler/testData/loadJava/compiledJava/static/DeeplyNestedStatic.java");
|
doTestCompiledJava("compiler/testData/loadJava/compiledJava/static/DeeplyNestedStatic.java");
|
||||||
|
|||||||
Reference in New Issue
Block a user