Move SAM utils from MembersCache to SAMUtils
This commit is contained in:
committed by
Pavel V. Talanov
parent
c5e37cc3de
commit
fb07a4c1ab
+23
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.lang.resolve.java;
|
package org.jetbrains.jet.lang.resolve.java;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.intellij.psi.*;
|
import com.intellij.psi.*;
|
||||||
import com.intellij.psi.impl.compiled.ClsClassImpl;
|
import com.intellij.psi.impl.compiled.ClsClassImpl;
|
||||||
import com.intellij.psi.util.PsiFormatUtil;
|
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;
|
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClassObject;
|
||||||
|
|
||||||
public final class DescriptorResolverUtils {
|
public final class DescriptorResolverUtils {
|
||||||
|
private static final ImmutableSet<String> OBJECT_METHODS = ImmutableSet.of("hashCode()", "equals(java.lang.Object)", "toString()");
|
||||||
|
|
||||||
private DescriptorResolverUtils() {
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -37,7 +37,6 @@ import org.jetbrains.jet.lang.resolve.BindingTrace;
|
|||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
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.mapping.JavaToKotlinClassMap;
|
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.java.wrapper.PsiMethodWrapper;
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
|
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
|
||||||
@@ -237,7 +236,7 @@ public class SignaturesPropagationData {
|
|||||||
: findSuperFunction(superclassToFunctions.get(classFqName), superMethod);
|
: findSuperFunction(superclassToFunctions.get(classFqName), superMethod);
|
||||||
if (superFun == null) {
|
if (superFun == null) {
|
||||||
// Super methods which are Object methods in interfaces are not loaded by JDR.
|
// Super methods which are Object methods in interfaces are not loaded by JDR.
|
||||||
if (!MembersCache.isObjectMethodInInterface(superMethod)) {
|
if (!DescriptorResolverUtils.isObjectMethodInInterface(superMethod)) {
|
||||||
reportCantFindSuperFunction(method);
|
reportCantFindSuperFunction(method);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
+5
-116
@@ -17,33 +17,25 @@
|
|||||||
package org.jetbrains.jet.lang.resolve.java.provider;
|
package org.jetbrains.jet.lang.resolve.java.provider;
|
||||||
|
|
||||||
import com.google.common.collect.HashMultimap;
|
import com.google.common.collect.HashMultimap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
import com.intellij.psi.*;
|
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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
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.JetJavaMirrorMarker;
|
||||||
import org.jetbrains.jet.lang.resolve.java.PsiClassFinder;
|
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.PsiFieldWrapper;
|
||||||
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMemberWrapper;
|
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMemberWrapper;
|
||||||
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.types.lang.KotlinBuiltIns;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static com.intellij.psi.util.MethodSignatureUtil.areSignaturesErasureEqual;
|
|
||||||
import static com.intellij.psi.util.PsiFormatUtilBase.*;
|
|
||||||
|
|
||||||
public final class MembersCache {
|
public final class MembersCache {
|
||||||
private static final ImmutableSet<String> OBJECT_METHODS = ImmutableSet.of("hashCode()", "equals(java.lang.Object)", "toString()");
|
|
||||||
|
|
||||||
private final Multimap<Name, Runnable> memberProcessingTasks = HashMultimap.create();
|
private final Multimap<Name, Runnable> memberProcessingTasks = HashMultimap.create();
|
||||||
private final Map<Name, NamedMembers> namedMembersMap = new HashMap<Name, NamedMembers>();
|
private final Map<Name, NamedMembers> namedMembersMap = new HashMap<Name, NamedMembers>();
|
||||||
|
|
||||||
@@ -128,7 +120,7 @@ public final class MembersCache {
|
|||||||
private void process() {
|
private void process() {
|
||||||
for (PsiClass psiClass : psiClasses) {
|
for (PsiClass psiClass : psiClasses) {
|
||||||
if (!(psiClass instanceof JetJavaMirrorMarker)) { // to filter out JetLightClasses
|
if (!(psiClass instanceof JetJavaMirrorMarker)) { // to filter out JetLightClasses
|
||||||
if (isSamInterface(psiClass)) {
|
if (SingleAbstractMethodUtils.isSamInterface(psiClass)) {
|
||||||
processSamInterface(psiClass);
|
processSamInterface(psiClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,7 +213,7 @@ public final class MembersCache {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isObjectMethodInInterface(member.getPsiMember())) {
|
if (DescriptorResolverUtils.isObjectMethodInInterface(member.getPsiMember())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,67 +245,13 @@ public final class MembersCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processNestedClass(PsiClass nested) {
|
private void processNestedClass(PsiClass nested) {
|
||||||
if (isSamInterface(nested)) {
|
if (SingleAbstractMethodUtils.isSamInterface(nested)) {
|
||||||
NamedMembers namedMembers = getOrCreateEmpty(Name.identifier(nested.getName()));
|
NamedMembers namedMembers = getOrCreateEmpty(Name.identifier(nested.getName()));
|
||||||
namedMembers.setSamInterface(nested);
|
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 static abstract class RunOnce implements Runnable {
|
||||||
private boolean hasRun = false;
|
private boolean hasRun = false;
|
||||||
|
|
||||||
@@ -326,53 +264,4 @@ public final class MembersCache {
|
|||||||
|
|
||||||
protected abstract void doRun();
|
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -34,7 +34,6 @@ import org.jetbrains.jet.lang.resolve.BindingTrace;
|
|||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
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.ClassDescriptorFromJvmBytecode;
|
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.sam.SingleAbstractMethodUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.java.scope.JavaClassNonStaticMembersScope;
|
import org.jetbrains.jet.lang.resolve.java.scope.JavaClassNonStaticMembersScope;
|
||||||
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
|
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
|
||||||
@@ -312,7 +311,7 @@ public final class JavaClassResolver {
|
|||||||
|
|
||||||
trace.record(BindingContext.CLASS, psiClass, classDescriptor);
|
trace.record(BindingContext.CLASS, psiClass, classDescriptor);
|
||||||
|
|
||||||
PsiMethod samInterfaceMethod = MembersCache.getSamInterfaceMethod(psiClass);
|
PsiMethod samInterfaceMethod = SingleAbstractMethodUtils.getSamInterfaceMethod(psiClass);
|
||||||
if (samInterfaceMethod != null) {
|
if (samInterfaceMethod != null) {
|
||||||
SimpleFunctionDescriptor abstractMethod = resolveFunctionOfSamInterface(samInterfaceMethod, classDescriptor);
|
SimpleFunctionDescriptor abstractMethod = resolveFunctionOfSamInterface(samInterfaceMethod, classDescriptor);
|
||||||
classDescriptor.setFunctionTypeForSamInterface(SingleAbstractMethodUtils.getFunctionTypeForAbstractMethod(abstractMethod));
|
classDescriptor.setFunctionTypeForSamInterface(SingleAbstractMethodUtils.getFunctionTypeForAbstractMethod(abstractMethod));
|
||||||
|
|||||||
+2
-2
@@ -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.*;
|
||||||
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.mapping.JavaToKotlinClassMap;
|
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.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.JavaPackageScope;
|
import org.jetbrains.jet.lang.resolve.java.scope.JavaPackageScope;
|
||||||
@@ -250,7 +250,7 @@ public final class JavaNamespaceResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (PsiClass nestedClass : psiClass.getInnerClasses()) {
|
for (PsiClass nestedClass : psiClass.getInnerClasses()) {
|
||||||
if (MembersCache.isSamInterface(nestedClass)) {
|
if (SingleAbstractMethodUtils.isSamInterface(nestedClass)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (nestedClass.hasModifierProperty(PsiModifier.STATIC) && hasStaticMembers(nestedClass)) {
|
if (nestedClass.hasModifierProperty(PsiModifier.STATIC) && hasStaticMembers(nestedClass)) {
|
||||||
|
|||||||
+88
-1
@@ -17,6 +17,9 @@
|
|||||||
package org.jetbrains.jet.lang.resolve.java.sam;
|
package org.jetbrains.jet.lang.resolve.java.sam;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
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.SimpleFunctionDescriptorImpl;
|
||||||
import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
|
import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
|
||||||
import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
|
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.descriptor.ClassDescriptorFromJvmBytecode;
|
||||||
import org.jetbrains.jet.lang.resolve.java.kotlinSignature.SignaturesUtil;
|
import org.jetbrains.jet.lang.resolve.java.kotlinSignature.SignaturesUtil;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
@@ -37,6 +40,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.intellij.psi.util.MethodSignatureUtil.areSignaturesErasureEqual;
|
||||||
import static org.jetbrains.jet.lang.types.Variance.INVARIANT;
|
import static org.jetbrains.jet.lang.types.Variance.INVARIANT;
|
||||||
|
|
||||||
public class SingleAbstractMethodUtils {
|
public class SingleAbstractMethodUtils {
|
||||||
@@ -311,6 +315,40 @@ public class SingleAbstractMethodUtils {
|
|||||||
private 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 {
|
private static class TypeParameters {
|
||||||
public final List<TypeParameterDescriptor> descriptors;
|
public final List<TypeParameterDescriptor> descriptors;
|
||||||
public final TypeSubstitutor substitutor;
|
public final TypeSubstitutor substitutor;
|
||||||
@@ -328,4 +366,53 @@ public class SingleAbstractMethodUtils {
|
|||||||
@Nullable JetType returnType
|
@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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user