diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java index 21bc8577a56..437c1c92a13 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/Namer.java @@ -25,7 +25,7 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.plugin.JetLanguage; import static com.google.dart.compiler.backend.js.ast.AstPackage.JsObjectScope; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.getStableMangledNameForDescriptor; +import static org.jetbrains.k2js.translate.utils.ManglingUtils.getStableMangledNameForDescriptor; /** * Encapuslates different types of constants and naming conventions. diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java index 3364ac89cec..71d05281c71 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java @@ -41,8 +41,8 @@ import java.util.Map; import static org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils.descriptorToDeclaration; import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.*; import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.*; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.getMangledName; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.getSuggestedName; +import static org.jetbrains.k2js.translate.utils.ManglingUtils.getMangledName; +import static org.jetbrains.k2js.translate.utils.ManglingUtils.getSuggestedName; /** * Aggregates all the static parts of the context. diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/UsageTracker.kt b/js/js.translator/src/org/jetbrains/k2js/translate/context/UsageTracker.kt index 00e88df04a4..1b6259deaf1 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/UsageTracker.kt +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/UsageTracker.kt @@ -19,7 +19,7 @@ package org.jetbrains.k2js.translate.context import org.jetbrains.jet.lang.descriptors.* import org.jetbrains.jet.lang.resolve.DescriptorUtils.isAncestor import com.google.dart.compiler.backend.js.ast.JsName -import org.jetbrains.k2js.translate.utils.TranslationUtils.getSuggestedName +import org.jetbrains.k2js.translate.utils.ManglingUtils.getSuggestedName import com.google.dart.compiler.backend.js.ast.JsFunctionScope private val CAPTURED_RECEIVER_NAME_PREFIX : String = "this$" diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DelegationTranslator.kt b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DelegationTranslator.kt index ce31cf47b8c..1783d7007dd 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DelegationTranslator.kt +++ b/js/js.translator/src/org/jetbrains/k2js/translate/declaration/DelegationTranslator.kt @@ -33,8 +33,8 @@ import org.jetbrains.k2js.translate.utils.TranslationUtils.* import org.jetbrains.jet.lang.resolve.DescriptorUtils import org.jetbrains.jet.backend.common.CodegenUtil import java.util.HashMap -import com.google.dart.compiler.backend.js.ast.JsLiteral import org.jetbrains.k2js.translate.declaration.propertyTranslator.addGetterAndSetter +import org.jetbrains.k2js.translate.utils.ManglingUtils.getMangledMemberNameForExplicitDelegation public class DelegationTranslator( private val classDeclaration: JetClassOrObject, diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/expression/LiteralFunctionTranslator.kt b/js/js.translator/src/org/jetbrains/k2js/translate/expression/LiteralFunctionTranslator.kt index 1c0239021e6..8117784470d 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/expression/LiteralFunctionTranslator.kt +++ b/js/js.translator/src/org/jetbrains/k2js/translate/expression/LiteralFunctionTranslator.kt @@ -26,7 +26,6 @@ import org.jetbrains.k2js.translate.context.* import org.jetbrains.k2js.translate.general.AbstractTranslator import org.jetbrains.k2js.translate.utils.BindingUtils.getFunctionDescriptor import org.jetbrains.k2js.translate.utils.FunctionBodyTranslator.translateFunctionBody -import org.jetbrains.k2js.translate.utils.TranslationUtils.getSuggestedName import org.jetbrains.k2js.translate.utils.TranslationUtils.simpleReturnFunction import org.jetbrains.jet.lang.descriptors.MemberDescriptor import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java index a9868d51d5e..f81d793b396 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/intrinsic/functions/factories/TopLevelFIF.java @@ -45,7 +45,7 @@ import java.util.List; import static org.jetbrains.k2js.translate.intrinsic.functions.basic.FunctionIntrinsic.CallParametersAwareFunctionIntrinsic; import static org.jetbrains.k2js.translate.intrinsic.functions.patterns.PatternBuilder.pattern; -import static org.jetbrains.k2js.translate.utils.TranslationUtils.getStableMangledNameForDescriptor; +import static org.jetbrains.k2js.translate.utils.ManglingUtils.getStableMangledNameForDescriptor; public final class TopLevelFIF extends CompositeFIF { public static final DescriptorPredicate EQUALS_IN_ANY = pattern("kotlin", "Any", "equals"); diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/ManglingUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/ManglingUtils.java new file mode 100644 index 00000000000..6de7aac9978 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/ManglingUtils.java @@ -0,0 +1,246 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.k2js.translate.utils; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.backend.common.CodegenUtil; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.resolve.OverrideResolver; +import org.jetbrains.jet.lang.resolve.name.FqName; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; + +import java.util.*; + +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFqName; + +public class ManglingUtils { + private ManglingUtils() {} + + public static final Comparator OVERLOADED_FUNCTION_COMPARATOR = new OverloadedFunctionComparator(); + + @NotNull + public static String getMangledName(@NotNull PropertyDescriptor descriptor, @NotNull String suggestedName) { + return getStableMangledName(suggestedName, getFqName(descriptor).asString()); + } + + @NotNull + public static String getSuggestedName(@NotNull DeclarationDescriptor descriptor) { + String suggestedName = descriptor.getName().asString(); + + if (descriptor instanceof FunctionDescriptor) { + suggestedName = getMangledName((FunctionDescriptor) descriptor); + } + + return suggestedName; + } + + @NotNull + private static String getMangledName(@NotNull FunctionDescriptor descriptor) { + if (needsStableMangling(descriptor)) { + return getStableMangledName(descriptor); + } + + return getSimpleMangledName(descriptor); + } + + //TODO extend logic for nested/inner declarations + private static boolean needsStableMangling(FunctionDescriptor descriptor) { + // Use stable mangling for overrides because we use stable mangling when any function inside a overridable declaration + // for avoid clashing names when inheritance. + if (JsDescriptorUtils.isOverride(descriptor)) { + return true; + } + + DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); + + if (containingDeclaration instanceof PackageFragmentDescriptor) { + return descriptor.getVisibility().isPublicAPI(); + } + else if (containingDeclaration instanceof ClassDescriptor) { + ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; + + // Use stable mangling when it's inside an overridable declaration to avoid clashing names on inheritance. + if (classDescriptor.getModality().isOverridable()) { + return true; + } + + // valueOf() is created in the library with a mangled name for every enum class + if (CodegenUtil.isEnumValueOfMethod(descriptor)) { + return true; + } + + // Don't use stable mangling when it inside a non-public API declaration. + if (!classDescriptor.getVisibility().isPublicAPI()) { + return false; + } + + // Ignore the `protected` visibility because it can be use outside a containing declaration + // only when the containing declaration is overridable. + if (descriptor.getVisibility() == Visibilities.PUBLIC) { + return true; + } + + return false; + } + + assert containingDeclaration instanceof CallableMemberDescriptor : + "containingDeclaration for descriptor have unsupported type for mangling, " + + "descriptor: " + descriptor + ", containingDeclaration: " + containingDeclaration; + + return false; + } + + @NotNull + public static String getMangledMemberNameForExplicitDelegation(@NotNull String suggestedName, FqName classFqName, FqName typeFqName) { + String forCalculateId = classFqName.asString() + ":" + typeFqName.asString(); + return getStableMangledName(suggestedName, forCalculateId); + } + + @NotNull + private static String getStableMangledName(@NotNull String suggestedName, String forCalculateId) { + int absHashCode = Math.abs(forCalculateId.hashCode()); + String suffix = absHashCode == 0 ? "" : ("_" + Integer.toString(absHashCode, Character.MAX_RADIX) + "$"); + return suggestedName + suffix; + } + + @NotNull + private static String getStableMangledName(@NotNull FunctionDescriptor descriptor) { + return getStableMangledName(descriptor.getName().asString(), getArgumentTypesAsString(descriptor)); + } + + @NotNull + private static String getSimpleMangledName(@NotNull final FunctionDescriptor descriptor) { + DeclarationDescriptor declaration = descriptor.getContainingDeclaration(); + + JetScope jetScope = null; + if (declaration instanceof PackageFragmentDescriptor) { + jetScope = ((PackageFragmentDescriptor) declaration).getMemberScope(); + } + else if (declaration instanceof ClassDescriptor) { + jetScope = ((ClassDescriptor) declaration).getDefaultType().getMemberScope(); + } + + int counter = 0; + + if (jetScope != null) { + Collection declarations = jetScope.getAllDescriptors(); + List + overloadedFunctions = ContainerUtil.mapNotNull(declarations, new Function() { + @Override + public FunctionDescriptor fun(DeclarationDescriptor declarationDescriptor) { + if (!(declarationDescriptor instanceof FunctionDescriptor)) return null; + + FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor; + + String name = AnnotationsUtils.getNameForAnnotatedObjectWithOverrides(functionDescriptor); + + // when name == null it's mean that it's not native. + if (name == null) { + // skip functions without arguments, because we don't use mangling for them + if (needsStableMangling(functionDescriptor) && !functionDescriptor.getValueParameters().isEmpty()) return null; + + name = declarationDescriptor.getName().asString(); + } + + return descriptor.getName().asString().equals(name) ? functionDescriptor : null; + } + }); + + if (overloadedFunctions.size() > 1) { + Collections.sort(overloadedFunctions, OVERLOADED_FUNCTION_COMPARATOR); + counter = ContainerUtil.indexOfIdentity(overloadedFunctions, descriptor); + assert counter >= 0; + } + } + + String name = descriptor.getName().asString(); + return counter == 0 ? name : name + '_' + counter; + } + + private static String getArgumentTypesAsString(FunctionDescriptor descriptor) { + StringBuilder argTypes = new StringBuilder(); + + ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter(); + if (receiverParameter != null) { + argTypes.append(TranslationUtils.getJetTypeFqName(receiverParameter.getType())).append("."); + } + + argTypes.append(StringUtil.join(descriptor.getValueParameters(), new Function() { + @Override + public String fun(ValueParameterDescriptor descriptor) { + return TranslationUtils.getJetTypeFqName(descriptor.getType()); + } + }, ",")); + + return argTypes.toString(); + } + + @NotNull + public static String getStableMangledNameForDescriptor(@NotNull ClassDescriptor descriptor, @NotNull String functionName) { + Collection functions = descriptor.getDefaultType().getMemberScope().getFunctions(Name.identifier(functionName)); + assert functions.size() == 1 : "Can't select a single function: " + functionName + " in " + descriptor; + return getSuggestedName(functions.iterator().next()); + } + + private static class OverloadedFunctionComparator implements Comparator { + @Override + public int compare(@NotNull FunctionDescriptor a, @NotNull FunctionDescriptor b) { + // native functions first + if (isNativeOrOverrideNative(a)) { + if (!isNativeOrOverrideNative(b)) return -1; + } + else if (isNativeOrOverrideNative(b)) { + return 1; + } + + // be visibility + // Actually "internal" > "private", but we want to have less number for "internal", so compare b with a instead of a with b. + Integer result = Visibilities.compare(b.getVisibility(), a.getVisibility()); + if (result != null && result != 0) return result; + + // by arity + int aArity = arity(a); + int bArity = arity(b); + if (aArity != bArity) return aArity - bArity; + + // by stringify argument types + String aArguments = getArgumentTypesAsString(a); + String bArguments = getArgumentTypesAsString(b); + assert aArguments != bArguments; + + return aArguments.compareTo(bArguments); + } + + private static int arity(FunctionDescriptor descriptor) { + return descriptor.getValueParameters().size() + (descriptor.getExtensionReceiverParameter() == null ? 0 : 1); + } + + private static boolean isNativeOrOverrideNative(FunctionDescriptor descriptor) { + if (AnnotationsUtils.isNativeObject(descriptor)) return true; + + Set declarations = OverrideResolver.getAllOverriddenDeclarations(descriptor); + for (FunctionDescriptor memberDescriptor : declarations) { + if (AnnotationsUtils.isNativeObject(memberDescriptor)) return true; + } + return false; + } + } +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java index ed96aa46b53..6de4be520a2 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/TranslationUtils.java @@ -17,26 +17,20 @@ package org.jetbrains.k2js.translate.utils; import com.google.dart.compiler.backend.js.ast.*; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.Function; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.backend.common.CodegenUtil; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor; import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.resolve.OverrideResolver; -import org.jetbrains.jet.lang.resolve.name.FqName; -import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.k2js.translate.context.TemporaryConstVariable; import org.jetbrains.k2js.translate.context.TranslationContext; import org.jetbrains.k2js.translate.general.Translation; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import static com.google.dart.compiler.backend.js.ast.JsBinaryOperator.*; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFqName; @@ -45,9 +39,9 @@ import static org.jetbrains.k2js.translate.context.Namer.getKotlinBackingFieldNa import static org.jetbrains.k2js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression; import static org.jetbrains.k2js.translate.utils.JsAstUtils.assignment; import static org.jetbrains.k2js.translate.utils.JsAstUtils.createDataDescriptor; +import static org.jetbrains.k2js.translate.utils.ManglingUtils.getMangledName; public final class TranslationUtils { - public static final Comparator OVERLOADED_FUNCTION_COMPARATOR = new OverloadedFunctionComparator(); private TranslationUtils() { } @@ -139,162 +133,6 @@ public final class TranslationUtils { return new JsConditional(testExpression, thenExpression, elseExpression); } - @NotNull - public static String getMangledName(@NotNull PropertyDescriptor descriptor, @NotNull String suggestedName) { - return getStableMangledName(suggestedName, getFqName(descriptor).asString()); - } - - @NotNull - public static String getSuggestedName(@NotNull DeclarationDescriptor descriptor) { - String suggestedName = descriptor.getName().asString(); - - if (descriptor instanceof FunctionDescriptor) { - suggestedName = getMangledName((FunctionDescriptor) descriptor); - } - - return suggestedName; - } - - @NotNull - private static String getMangledName(@NotNull FunctionDescriptor descriptor) { - if (needsStableMangling(descriptor)) { - return getStableMangledName(descriptor); - } - - return getSimpleMangledName(descriptor); - } - - //TODO extend logic for nested/inner declarations - private static boolean needsStableMangling(FunctionDescriptor descriptor) { - // Use stable mangling for overrides because we use stable mangling when any function inside a overridable declaration - // for avoid clashing names when inheritance. - if (JsDescriptorUtils.isOverride(descriptor)) { - return true; - } - - DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); - - if (containingDeclaration instanceof PackageFragmentDescriptor) { - return descriptor.getVisibility().isPublicAPI(); - } - else if (containingDeclaration instanceof ClassDescriptor) { - ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; - - // Use stable mangling when it's inside an overridable declaration to avoid clashing names on inheritance. - if (classDescriptor.getModality().isOverridable()) { - return true; - } - - // valueOf() is created in the library with a mangled name for every enum class - if (CodegenUtil.isEnumValueOfMethod(descriptor)) { - return true; - } - - // Don't use stable mangling when it inside a non-public API declaration. - if (!classDescriptor.getVisibility().isPublicAPI()) { - return false; - } - - // Ignore the `protected` visibility because it can be use outside a containing declaration - // only when the containing declaration is overridable. - if (descriptor.getVisibility() == Visibilities.PUBLIC) { - return true; - } - - return false; - } - - assert containingDeclaration instanceof CallableMemberDescriptor : - "containingDeclaration for descriptor have unsupported type for mangling, " + - "descriptor: " + descriptor + ", containingDeclaration: " + containingDeclaration; - - return false; - } - - @NotNull - public static String getMangledMemberNameForExplicitDelegation(@NotNull String suggestedName, FqName classFqName, FqName typeFqName) { - String forCalculateId = classFqName.asString() + ":" + typeFqName.asString(); - return getStableMangledName(suggestedName, forCalculateId); - } - - @NotNull - private static String getStableMangledName(@NotNull String suggestedName, String forCalculateId) { - int absHashCode = Math.abs(forCalculateId.hashCode()); - String suffix = absHashCode == 0 ? "" : ("_" + Integer.toString(absHashCode, Character.MAX_RADIX) + "$"); - return suggestedName + suffix; - } - - @NotNull - private static String getStableMangledName(@NotNull FunctionDescriptor descriptor) { - return getStableMangledName(descriptor.getName().asString(), getArgumentTypesAsString(descriptor)); - } - - @NotNull - private static String getSimpleMangledName(@NotNull final FunctionDescriptor descriptor) { - DeclarationDescriptor declaration = descriptor.getContainingDeclaration(); - - JetScope jetScope = null; - if (declaration instanceof PackageFragmentDescriptor) { - jetScope = ((PackageFragmentDescriptor) declaration).getMemberScope(); - } - else if (declaration instanceof ClassDescriptor) { - jetScope = ((ClassDescriptor) declaration).getDefaultType().getMemberScope(); - } - - int counter = 0; - - if (jetScope != null) { - Collection declarations = jetScope.getAllDescriptors(); - List overloadedFunctions = ContainerUtil.mapNotNull(declarations, new Function() { - @Override - public FunctionDescriptor fun(DeclarationDescriptor declarationDescriptor) { - if (!(declarationDescriptor instanceof FunctionDescriptor)) return null; - - FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor; - - String name = AnnotationsUtils.getNameForAnnotatedObjectWithOverrides(functionDescriptor); - - // when name == null it's mean that it's not native. - if (name == null) { - // skip functions without arguments, because we don't use mangling for them - if (needsStableMangling(functionDescriptor) && !functionDescriptor.getValueParameters().isEmpty()) return null; - - name = declarationDescriptor.getName().asString(); - } - - return descriptor.getName().asString().equals(name) ? functionDescriptor : null; - } - }); - - if (overloadedFunctions.size() > 1) { - Collections.sort(overloadedFunctions, OVERLOADED_FUNCTION_COMPARATOR); - counter = ContainerUtil.indexOfIdentity(overloadedFunctions, descriptor); - assert counter >= 0; - } - } - - String name = descriptor.getName().asString(); - return counter == 0 ? name : name + '_' + counter; - } - - private static String getArgumentTypesAsString(FunctionDescriptor descriptor) { - StringBuilder argTypes = new StringBuilder(); - - ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter(); - if (receiverParameter != null) { - argTypes.append(getJetTypeFqName(receiverParameter.getType())).append("."); - } - - argTypes.append(StringUtil.join(descriptor.getValueParameters(), new Function() { - @Override - public String fun(ValueParameterDescriptor descriptor) { - return getJetTypeFqName(descriptor.getType()); - } - }, ",")); - - return argTypes.toString(); - } - @NotNull public static String getJetTypeFqName(@NotNull JetType jetType) { ClassifierDescriptor declaration = jetType.getConstructor().getDeclarationDescriptor(); @@ -430,13 +268,6 @@ public final class TranslationUtils { return ensureNotNull; } - @NotNull - public static String getStableMangledNameForDescriptor(@NotNull ClassDescriptor descriptor, @NotNull String functionName) { - Collection functions = descriptor.getDefaultType().getMemberScope().getFunctions(Name.identifier(functionName)); - assert functions.size() == 1 : "Can't select a single function: " + functionName + " in " + descriptor; - return getSuggestedName(functions.iterator().next()); - } - @NotNull public static String getSuggestedNameForInnerDeclaration(TranslationContext context, DeclarationDescriptor descriptor) { String suggestedName = ""; @@ -461,48 +292,4 @@ public final class TranslationUtils { } return suggestedName; } - - private static class OverloadedFunctionComparator implements Comparator { - @Override - public int compare(@NotNull FunctionDescriptor a, @NotNull FunctionDescriptor b) { - // native functions first - if (isNativeOrOverrideNative(a)) { - if (!isNativeOrOverrideNative(b)) return -1; - } - else if (isNativeOrOverrideNative(b)) { - return 1; - } - - // be visibility - // Actually "internal" > "private", but we want to have less number for "internal", so compare b with a instead of a with b. - Integer result = Visibilities.compare(b.getVisibility(), a.getVisibility()); - if (result != null && result != 0) return result; - - // by arity - int aArity = arity(a); - int bArity = arity(b); - if (aArity != bArity) return aArity - bArity; - - // by stringify argument types - String aArguments = getArgumentTypesAsString(a); - String bArguments = getArgumentTypesAsString(b); - assert aArguments != bArguments; - - return aArguments.compareTo(bArguments); - } - - private static int arity(FunctionDescriptor descriptor) { - return descriptor.getValueParameters().size() + (descriptor.getExtensionReceiverParameter() == null ? 0 : 1); - } - - private static boolean isNativeOrOverrideNative(FunctionDescriptor descriptor) { - if (AnnotationsUtils.isNativeObject(descriptor)) return true; - - Set declarations = OverrideResolver.getAllOverriddenDeclarations(descriptor); - for (FunctionDescriptor memberDescriptor : declarations) { - if (AnnotationsUtils.isNativeObject(memberDescriptor)) return true; - } - return false; - } - } }