From fb07a4c1ab791f4840afa228364cbfcb876413ef Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 25 Jul 2013 17:28:26 +0400 Subject: [PATCH] Move SAM utils from MembersCache to SAMUtils --- .../resolve/java/DescriptorResolverUtils.java | 23 ++++ .../SignaturesPropagationData.java | 3 +- .../resolve/java/provider/MembersCache.java | 121 +----------------- .../java/resolver/JavaClassResolver.java | 3 +- .../java/resolver/JavaNamespaceResolver.java | 4 +- .../java/sam/SingleAbstractMethodUtils.java | 89 ++++++++++++- 6 files changed, 120 insertions(+), 123 deletions(-) diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java index 6c52398cb78..a002e43979c 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java @@ -16,6 +16,7 @@ package org.jetbrains.jet.lang.resolve.java; +import com.google.common.collect.ImmutableSet; import com.intellij.psi.*; import com.intellij.psi.impl.compiled.ClsClassImpl; import com.intellij.psi.util.PsiFormatUtil; @@ -36,6 +37,8 @@ import static com.intellij.psi.util.PsiFormatUtilBase.*; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClassObject; public final class DescriptorResolverUtils { + private static final ImmutableSet OBJECT_METHODS = ImmutableSet.of("hashCode()", "equals(java.lang.Object)", "toString()"); + private DescriptorResolverUtils() { } @@ -144,4 +147,24 @@ public final class DescriptorResolverUtils { } }; } + + public static boolean isObjectMethodInInterface(@NotNull PsiMember member) { + if (!(member instanceof PsiMethod)) { + return false; + } + PsiClass containingClass = member.getContainingClass(); + assert containingClass != null : "containing class is null for " + member; + + if (!containingClass.isInterface()) { + return false; + } + + return isObjectMethod((PsiMethod) member); + } + + public static boolean isObjectMethod(@NotNull PsiMethod method) { + String formattedMethod = PsiFormatUtil.formatMethod( + method, PsiSubstitutor.EMPTY, SHOW_NAME | SHOW_PARAMETERS, SHOW_TYPE | SHOW_FQ_CLASS_NAMES); + return OBJECT_METHODS.contains(formattedMethod); + } } 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 f8835758a67..465deeb844d 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 @@ -37,7 +37,6 @@ import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.java.*; import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap; -import org.jetbrains.jet.lang.resolve.java.provider.MembersCache; 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; @@ -237,7 +236,7 @@ public class SignaturesPropagationData { : findSuperFunction(superclassToFunctions.get(classFqName), superMethod); if (superFun == null) { // Super methods which are Object methods in interfaces are not loaded by JDR. - if (!MembersCache.isObjectMethodInInterface(superMethod)) { + if (!DescriptorResolverUtils.isObjectMethodInInterface(superMethod)) { reportCantFindSuperFunction(method); } continue; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/provider/MembersCache.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/provider/MembersCache.java index c94407ae521..18dc5b6c122 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/provider/MembersCache.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/provider/MembersCache.java @@ -17,33 +17,25 @@ package org.jetbrains.jet.lang.resolve.java.provider; import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multimap; import com.intellij.psi.*; -import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; -import com.intellij.psi.util.PsiFormatUtil; -import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils; import org.jetbrains.jet.lang.resolve.java.JetJavaMirrorMarker; import org.jetbrains.jet.lang.resolve.java.PsiClassFinder; +import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils; import org.jetbrains.jet.lang.resolve.java.wrapper.PsiFieldWrapper; import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMemberWrapper; import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper; import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import static com.intellij.psi.util.MethodSignatureUtil.areSignaturesErasureEqual; -import static com.intellij.psi.util.PsiFormatUtilBase.*; - public final class MembersCache { - private static final ImmutableSet OBJECT_METHODS = ImmutableSet.of("hashCode()", "equals(java.lang.Object)", "toString()"); - private final Multimap memberProcessingTasks = HashMultimap.create(); private final Map namedMembersMap = new HashMap(); @@ -128,7 +120,7 @@ public final class MembersCache { private void process() { for (PsiClass psiClass : psiClasses) { if (!(psiClass instanceof JetJavaMirrorMarker)) { // to filter out JetLightClasses - if (isSamInterface(psiClass)) { + if (SingleAbstractMethodUtils.isSamInterface(psiClass)) { processSamInterface(psiClass); } } @@ -221,7 +213,7 @@ public final class MembersCache { return false; } - if (isObjectMethodInInterface(member.getPsiMember())) { + if (DescriptorResolverUtils.isObjectMethodInInterface(member.getPsiMember())) { return false; } @@ -253,67 +245,13 @@ public final class MembersCache { } private void processNestedClass(PsiClass nested) { - if (isSamInterface(nested)) { + if (SingleAbstractMethodUtils.isSamInterface(nested)) { NamedMembers namedMembers = getOrCreateEmpty(Name.identifier(nested.getName())); namedMembers.setSamInterface(nested); } } } - public static boolean isObjectMethodInInterface(@NotNull PsiMember member) { - if (!(member instanceof PsiMethod)) { - return false; - } - PsiClass containingClass = member.getContainingClass(); - assert containingClass != null : "containing class is null for " + member; - - if (!containingClass.isInterface()) { - return false; - } - - return isObjectMethod((PsiMethod) member); - } - - private static boolean isObjectMethod(PsiMethod method) { - String formattedMethod = PsiFormatUtil.formatMethod( - method, PsiSubstitutor.EMPTY, SHOW_NAME | SHOW_PARAMETERS, SHOW_TYPE | SHOW_FQ_CLASS_NAMES); - return OBJECT_METHODS.contains(formattedMethod); - } - - public static boolean isSamInterface(@NotNull PsiClass psiClass) { - return getSamInterfaceMethod(psiClass) != null; - } - - // Returns null if not SAM interface - @Nullable - public static PsiMethod getSamInterfaceMethod(@NotNull PsiClass psiClass) { - String qualifiedName = psiClass.getQualifiedName(); - if (qualifiedName == null || qualifiedName.startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME.asString() + ".")) { - return null; - } - if (!psiClass.isInterface() || psiClass.isAnnotationType()) { - return null; - } - - return findOnlyAbstractMethod(psiClass); - } - - @Nullable - private static PsiMethod findOnlyAbstractMethod(@NotNull PsiClass psiClass) { - PsiClassType classType = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass); - - OnlyAbstractMethodFinder finder = new OnlyAbstractMethodFinder(); - if (finder.find(classType)) { - return finder.getFoundMethod(); - } - return null; - } - - private static boolean isVarargMethod(@NotNull PsiMethod method) { - PsiParameter lastParameter = ArrayUtil.getLastElement(method.getParameterList().getParameters()); - return lastParameter != null && lastParameter.getType() instanceof PsiEllipsisType; - } - private static abstract class RunOnce implements Runnable { private boolean hasRun = false; @@ -326,53 +264,4 @@ public final class MembersCache { protected abstract void doRun(); } - - private static class OnlyAbstractMethodFinder { - private MethodSignatureBackedByPsiMethod found; - - private boolean find(@NotNull PsiClassType classType) { - PsiClassType.ClassResolveResult classResolveResult = classType.resolveGenerics(); - PsiSubstitutor classSubstitutor = classResolveResult.getSubstitutor(); - PsiClass psiClass = classResolveResult.getElement(); - if (psiClass == null) { - return false; // can't resolve class -> not a SAM interface - } - if (CommonClassNames.JAVA_LANG_OBJECT.equals(psiClass.getQualifiedName())) { - return true; - } - for (PsiMethod method : psiClass.getMethods()) { - if (isObjectMethod(method)) { // e.g., ignore toString() declared in interface - continue; - } - if (method.hasTypeParameters()) { - return false; // if interface has generic methods, it is not a SAM interface - } - - if (found == null) { - found = (MethodSignatureBackedByPsiMethod) method.getSignature(classSubstitutor); - continue; - } - if (!found.getName().equals(method.getName())) { - return false; // optimizing heuristic - } - MethodSignatureBackedByPsiMethod current = (MethodSignatureBackedByPsiMethod) method.getSignature(classSubstitutor); - if (!areSignaturesErasureEqual(current, found) || isVarargMethod(method) != isVarargMethod(found.getMethod())) { - return false; // different signatures - } - } - - for (PsiType t : classType.getSuperTypes()) { - if (!find((PsiClassType) t)) { - return false; - } - } - - return true; - } - - @Nullable - PsiMethod getFoundMethod() { - return found == null ? null : found.getMethod(); - } - } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java index a48adf5a8ac..ab567a96a45 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaClassResolver.java @@ -34,7 +34,6 @@ import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.java.*; import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode; -import org.jetbrains.jet.lang.resolve.java.provider.MembersCache; import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils; import org.jetbrains.jet.lang.resolve.java.scope.JavaClassNonStaticMembersScope; import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper; @@ -312,7 +311,7 @@ public final class JavaClassResolver { trace.record(BindingContext.CLASS, psiClass, classDescriptor); - PsiMethod samInterfaceMethod = MembersCache.getSamInterfaceMethod(psiClass); + PsiMethod samInterfaceMethod = SingleAbstractMethodUtils.getSamInterfaceMethod(psiClass); if (samInterfaceMethod != null) { SimpleFunctionDescriptor abstractMethod = resolveFunctionOfSamInterface(samInterfaceMethod, classDescriptor); classDescriptor.setFunctionTypeForSamInterface(SingleAbstractMethodUtils.getFunctionTypeForAbstractMethod(abstractMethod)); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java index 24d60eb3bad..2c78433490e 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/JavaNamespaceResolver.java @@ -37,7 +37,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.mapping.JavaToKotlinClassMap; -import org.jetbrains.jet.lang.resolve.java.provider.MembersCache; +import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils; 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.JavaPackageScope; @@ -250,7 +250,7 @@ public final class JavaNamespaceResolver { } for (PsiClass nestedClass : psiClass.getInnerClasses()) { - if (MembersCache.isSamInterface(nestedClass)) { + if (SingleAbstractMethodUtils.isSamInterface(nestedClass)) { return true; } if (nestedClass.hasModifierProperty(PsiModifier.STATIC) && hasStaticMembers(nestedClass)) { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java index 281fa655c5e..62e89729531 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java @@ -17,6 +17,9 @@ package org.jetbrains.jet.lang.resolve.java.sam; import com.google.common.collect.Lists; +import com.intellij.psi.*; +import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; +import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -25,7 +28,7 @@ import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl; import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl; import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl; import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl; -import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil; +import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils; import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode; import org.jetbrains.jet.lang.resolve.java.kotlinSignature.SignaturesUtil; import org.jetbrains.jet.lang.resolve.name.Name; @@ -37,6 +40,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import static com.intellij.psi.util.MethodSignatureUtil.areSignaturesErasureEqual; import static org.jetbrains.jet.lang.types.Variance.INVARIANT; public class SingleAbstractMethodUtils { @@ -311,6 +315,40 @@ public class SingleAbstractMethodUtils { private SingleAbstractMethodUtils() { } + public static boolean isSamInterface(@NotNull PsiClass psiClass) { + return getSamInterfaceMethod(psiClass) != null; + } + + // Returns null if not SAM interface + @Nullable + public static PsiMethod getSamInterfaceMethod(@NotNull PsiClass psiClass) { + String qualifiedName = psiClass.getQualifiedName(); + if (qualifiedName == null || qualifiedName.startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME.asString() + ".")) { + return null; + } + if (!psiClass.isInterface() || psiClass.isAnnotationType()) { + return null; + } + + return findOnlyAbstractMethod(psiClass); + } + + @Nullable + private static PsiMethod findOnlyAbstractMethod(@NotNull PsiClass psiClass) { + PsiClassType classType = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass); + + OnlyAbstractMethodFinder finder = new OnlyAbstractMethodFinder(); + if (finder.find(classType)) { + return finder.getFoundMethod(); + } + return null; + } + + private static boolean isVarargMethod(@NotNull PsiMethod method) { + PsiParameter lastParameter = ArrayUtil.getLastElement(method.getParameterList().getParameters()); + return lastParameter != null && lastParameter.getType() instanceof PsiEllipsisType; + } + private static class TypeParameters { public final List descriptors; public final TypeSubstitutor substitutor; @@ -328,4 +366,53 @@ public class SingleAbstractMethodUtils { @Nullable JetType returnType ); } + + private static class OnlyAbstractMethodFinder { + private MethodSignatureBackedByPsiMethod found; + + private boolean find(@NotNull PsiClassType classType) { + PsiClassType.ClassResolveResult classResolveResult = classType.resolveGenerics(); + PsiSubstitutor classSubstitutor = classResolveResult.getSubstitutor(); + PsiClass psiClass = classResolveResult.getElement(); + if (psiClass == null) { + return false; // can't resolve class -> not a SAM interface + } + if (CommonClassNames.JAVA_LANG_OBJECT.equals(psiClass.getQualifiedName())) { + return true; + } + for (PsiMethod method : psiClass.getMethods()) { + if (DescriptorResolverUtils.isObjectMethod(method)) { // e.g., ignore toString() declared in interface + continue; + } + if (method.hasTypeParameters()) { + return false; // if interface has generic methods, it is not a SAM interface + } + + if (found == null) { + found = (MethodSignatureBackedByPsiMethod) method.getSignature(classSubstitutor); + continue; + } + if (!found.getName().equals(method.getName())) { + return false; // optimizing heuristic + } + MethodSignatureBackedByPsiMethod current = (MethodSignatureBackedByPsiMethod) method.getSignature(classSubstitutor); + if (!areSignaturesErasureEqual(current, found) || isVarargMethod(method) != isVarargMethod(found.getMethod())) { + return false; // different signatures + } + } + + for (PsiType t : classType.getSuperTypes()) { + if (!find((PsiClassType) t)) { + return false; + } + } + + return true; + } + + @Nullable + PsiMethod getFoundMethod() { + return found == null ? null : found.getMethod(); + } + } }