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
|
||||
|
||||
Reference in New Issue
Block a user