Loading SAM constructor functions for nested interfaces.

This commit is contained in:
Evgeny Gerashchenko
2013-03-21 23:51:04 +04:00
parent 17cc055152
commit b891d6d87f
7 changed files with 155 additions and 14 deletions
@@ -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;
}
}
@@ -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;
@@ -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;
}
@@ -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