KT-2752: refactor generation of FQN in JS. Move backend-independent code to generic code in frontend.
This commit is contained in:
@@ -19,69 +19,74 @@ package org.jetbrains.kotlin.js.naming
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.isEnumValueOfMethod
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isLibraryObject
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject
|
||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.*
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||
|
||||
class FQNGenerator(private val participants: List<FQNPartipcipant> = listOf()) {
|
||||
private val cache = mutableMapOf<DeclarationDescriptor, List<FQNPart>>()
|
||||
class FQNGenerator {
|
||||
private val cache = mutableMapOf<DeclarationDescriptor, FQNPart>()
|
||||
|
||||
fun generate(descriptor: DeclarationDescriptor) = cache.getOrPut(descriptor) { generateCacheMiss(descriptor) }
|
||||
fun generate(descriptor: DeclarationDescriptor) = cache.getOrPut(descriptor) { generateCacheMiss(descriptor.original) }
|
||||
|
||||
private fun generateCacheMiss(descriptor: DeclarationDescriptor): List<FQNPart> {
|
||||
for (participant in participants) {
|
||||
val result = participant.participate(descriptor, this)
|
||||
if (result != null) {
|
||||
return result
|
||||
}
|
||||
private fun generateCacheMiss(descriptor: DeclarationDescriptor): FQNPart {
|
||||
if (isNativeObject(descriptor) && isCompanionObject(descriptor)) {
|
||||
return generate(descriptor.containingDeclaration!!)
|
||||
}
|
||||
|
||||
when (descriptor) {
|
||||
is ModuleDescriptor -> return listOf(FQNPart(descriptor.name.asString(), FQNPartType.MODULE, descriptor))
|
||||
is ModuleDescriptor -> return FQNPart(listOf(descriptor.name.asString()), true, descriptor, descriptor)
|
||||
is PackageFragmentDescriptor -> {
|
||||
val result = generate(descriptor.containingDeclaration).toMutableList()
|
||||
if (!descriptor.name.isSpecial) {
|
||||
result += descriptor.fqName.pathSegments().map { FQNPart(it.asString(), FQNPartType.PUBLIC, descriptor) }
|
||||
return if (!descriptor.name.isSpecial) {
|
||||
FQNPart(descriptor.fqName.pathSegments().map { it.asString() }, true, descriptor,
|
||||
descriptor.containingDeclaration)
|
||||
}
|
||||
else {
|
||||
generate(descriptor.containingDeclaration)
|
||||
}
|
||||
return result
|
||||
}
|
||||
is ConstructorDescriptor -> if (descriptor.isPrimary) return generate(descriptor.containingDeclaration)
|
||||
is CallableMemberDescriptor ->
|
||||
is FakeCallableDescriptorForObject -> return generate(descriptor.getReferencedDescriptor())
|
||||
is ConstructorDescriptor -> {
|
||||
if (descriptor.isPrimary || isNativeObject(descriptor)) {
|
||||
return generate(descriptor.containingDeclaration)
|
||||
}
|
||||
}
|
||||
is CallableDescriptor ->
|
||||
if (DescriptorUtils.isDescriptorWithLocalVisibility(descriptor)) {
|
||||
val name = getMangledName(getSuggestedName(descriptor), descriptor)
|
||||
return listOf(FQNPart(name, FQNPartType.PRIVATE, descriptor))
|
||||
return FQNPart(listOf(name.first), false, descriptor, descriptor.containingDeclaration)
|
||||
}
|
||||
}
|
||||
|
||||
val (localName, shared, parent) = getLocalName(descriptor)
|
||||
val localPart = FQNPart(localName, if (shared) FQNPartType.PUBLIC else FQNPartType.PRIVATE, descriptor)
|
||||
|
||||
val qualifier = if (parent != null) generate(parent) else listOf()
|
||||
return qualifier + localPart
|
||||
return FQNPart(listOf(localName), shared, descriptor, parent)
|
||||
}
|
||||
|
||||
private fun getLocalName(descriptor: DeclarationDescriptor): LocalName {
|
||||
if (descriptor.isDynamic()) {
|
||||
return LocalName(descriptor.name.asString(), true, descriptor.containingDeclaration!!)
|
||||
}
|
||||
|
||||
val parts = mutableListOf<String>()
|
||||
var current: DeclarationDescriptor? = descriptor
|
||||
var current: DeclarationDescriptor = descriptor
|
||||
do {
|
||||
current!!
|
||||
parts += getSuggestedName(current)
|
||||
var last = current
|
||||
current = current.containingDeclaration
|
||||
current = current.containingDeclaration!!
|
||||
if (last is ConstructorDescriptor && !last.isPrimary) {
|
||||
last = current
|
||||
parts[parts.lastIndex] = getSuggestedName(current!!) + "_init"
|
||||
current = current.containingDeclaration
|
||||
parts[parts.lastIndex] = getSuggestedName(current) + "_init"
|
||||
current = current.containingDeclaration!!
|
||||
}
|
||||
} while (current != null && DescriptorUtils.isDescriptorWithLocalVisibility(last) && current !is ClassDescriptor)
|
||||
} while (DescriptorUtils.isDescriptorWithLocalVisibility(last) && current !is ClassDescriptor)
|
||||
|
||||
parts.reverse()
|
||||
return LocalName(getMangledName(parts.joinToString("$"), descriptor), needsStableMangling(descriptor), current)
|
||||
val (id, shared) = getMangledName(parts.joinToString("$"), descriptor)
|
||||
return LocalName(id, shared, current)
|
||||
}
|
||||
|
||||
private data class LocalName(val id: String, val shared: Boolean, val parent: DeclarationDescriptor?)
|
||||
private data class LocalName(val id: String, val shared: Boolean, val parent: DeclarationDescriptor)
|
||||
|
||||
private fun getSuggestedName(descriptor: DeclarationDescriptor): String {
|
||||
val name = descriptor.name
|
||||
@@ -97,17 +102,49 @@ class FQNGenerator(private val participants: List<FQNPartipcipant> = listOf()) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMangledName(baseName: String, descriptor: DeclarationDescriptor): String {
|
||||
if (needsStableMangling(descriptor)) {
|
||||
return if (descriptor is CallableMemberDescriptor) {
|
||||
getStableMangledName(baseName, getArgumentTypesAsString(descriptor))
|
||||
private fun getMangledName(baseName: String, descriptor: DeclarationDescriptor): Pair<String, Boolean> {
|
||||
if (descriptor !is CallableDescriptor) {
|
||||
if (isNativeObject(descriptor) || isLibraryObject(descriptor)) {
|
||||
return Pair(getNameForAnnotatedObjectWithOverrides(descriptor) ?: descriptor.name.asString(), true)
|
||||
}
|
||||
else {
|
||||
baseName
|
||||
return Pair(baseName, needsStableMangling(descriptor))
|
||||
}
|
||||
|
||||
var resolvedDescriptor: CallableDescriptor = descriptor
|
||||
var overriddenDescriptor: CallableDescriptor? = descriptor
|
||||
while (overriddenDescriptor != null) {
|
||||
resolvedDescriptor = overriddenDescriptor
|
||||
if (isNativeObject(resolvedDescriptor) || isLibraryObject(resolvedDescriptor)) {
|
||||
val explicitName = getNameForAnnotatedObjectWithOverrides(resolvedDescriptor)
|
||||
if (explicitName != null) {
|
||||
return Pair(explicitName, true)
|
||||
}
|
||||
}
|
||||
overriddenDescriptor = getOverriddenDescriptor(overriddenDescriptor)?.original
|
||||
}
|
||||
|
||||
when {
|
||||
isNativeObject(resolvedDescriptor) || isLibraryObject(resolvedDescriptor) -> {
|
||||
return Pair(getNameForAnnotatedObjectWithOverrides(resolvedDescriptor) ?: resolvedDescriptor.name.asString(), true)
|
||||
}
|
||||
}
|
||||
|
||||
return baseName
|
||||
return if (needsStableMangling(resolvedDescriptor)) {
|
||||
Pair(getStableMangledName(baseName, getArgumentTypesAsString(resolvedDescriptor)), true)
|
||||
}
|
||||
else {
|
||||
Pair(baseName, false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOverriddenDescriptor(functionDescriptor: CallableDescriptor): CallableDescriptor? {
|
||||
val overriddenDescriptors = functionDescriptor.overriddenDescriptors
|
||||
if (overriddenDescriptors.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
//TODO: for now translator can't deal with multiple inheritance good enough
|
||||
return overriddenDescriptors.iterator().next()
|
||||
}
|
||||
|
||||
private fun getArgumentTypesAsString(descriptor: CallableDescriptor): String {
|
||||
@@ -130,6 +167,7 @@ class FQNGenerator(private val participants: List<FQNPartipcipant> = listOf()) {
|
||||
}
|
||||
|
||||
private fun needsStableMangling(descriptor: DeclarationDescriptor): Boolean {
|
||||
if (DescriptorUtils.isDescriptorWithLocalVisibility(descriptor)) return false
|
||||
if (descriptor is ClassOrPackageFragmentDescriptor) return true
|
||||
if (descriptor !is CallableMemberDescriptor) return false
|
||||
|
||||
@@ -138,12 +176,12 @@ class FQNGenerator(private val participants: List<FQNPartipcipant> = listOf()) {
|
||||
if (DescriptorUtils.isOverride(descriptor)) return true
|
||||
|
||||
val containingDeclaration = descriptor.containingDeclaration
|
||||
if (isNativeObject(containingDeclaration) || isLibraryObject(containingDeclaration)) return true
|
||||
|
||||
return when (containingDeclaration) {
|
||||
is PackageFragmentDescriptor -> descriptor.visibility.isPublicAPI
|
||||
is ClassDescriptor -> {
|
||||
// Use stable mangling when it's inside an overridable declaration to avoid clashing names on inheritance.
|
||||
if (!containingDeclaration.isFinalOrEnum) return true
|
||||
if (descriptor.modality == Modality.OPEN || descriptor.modality == Modality.ABSTRACT) return true
|
||||
|
||||
// valueOf() is created in the library with a mangled name for every enum class
|
||||
if (descriptor is FunctionDescriptor && descriptor.isEnumValueOfMethod()) return true
|
||||
@@ -166,34 +204,4 @@ class FQNGenerator(private val participants: List<FQNPartipcipant> = listOf()) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object NativeParticipant : FQNPartipcipant {
|
||||
override fun participate(descriptor: DeclarationDescriptor, generator: FQNGenerator): List<FQNPart>? {
|
||||
return when {
|
||||
isNativeObject(descriptor) && isCompanionObject(descriptor) -> {
|
||||
generator.generate(descriptor.containingDeclaration!!)
|
||||
}
|
||||
descriptor is PropertyAccessorDescriptor && isNativeObject(descriptor.correspondingProperty) -> {
|
||||
generator.generate(descriptor.correspondingProperty)
|
||||
}
|
||||
isNativeObject(descriptor) || isLibraryObject(descriptor) -> {
|
||||
if (descriptor is ConstructorDescriptor) {
|
||||
generator.generate(descriptor.containingDeclaration)
|
||||
}
|
||||
else {
|
||||
val name = AnnotationsUtils.getNameForAnnotatedObjectWithOverrides(descriptor)
|
||||
val qualifier = when {
|
||||
descriptor is CallableDescriptor && DescriptorUtils.isDescriptorWithLocalVisibility(descriptor) -> listOf()
|
||||
descriptor is ClassDescriptor && descriptor.containingDeclaration is PackageFragmentDescriptor -> listOf()
|
||||
descriptor is ClassDescriptor && isNativeObject(descriptor) &&
|
||||
!isNativeObject(descriptor.containingDeclaration) -> listOf()
|
||||
else -> generator.generate(descriptor.containingDeclaration!!)
|
||||
}
|
||||
qualifier + listOf(FQNPart(name ?: descriptor.name.asString(), FQNPartType.PUBLIC, descriptor))
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +18,4 @@ package org.jetbrains.kotlin.js.naming
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
|
||||
data class FQNPart(val name: String, val type: FQNPartType, val descriptor: DeclarationDescriptor)
|
||||
class FQNPart(val names: List<String>, val shared: Boolean, val descriptor: DeclarationDescriptor, val scope: DeclarationDescriptor)
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.kotlin.js.naming
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
|
||||
interface FQNPartipcipant {
|
||||
fun participate(descriptor: DeclarationDescriptor, generator: FQNGenerator): List<FQNPart>?
|
||||
}
|
||||
+4
-3
@@ -22,6 +22,7 @@ import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata
|
||||
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind
|
||||
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
@@ -64,14 +65,14 @@ val VariableAccessInfo.variableName: JsName
|
||||
|
||||
fun VariableAccessInfo.isGetAccess(): Boolean = value == null
|
||||
|
||||
fun VariableAccessInfo.getAccessFunctionName(): String {
|
||||
fun VariableAccessInfo.getAccessDescriptor(): DeclarationDescriptor {
|
||||
val descriptor = variableDescriptor
|
||||
if (descriptor is PropertyDescriptor && descriptor.isExtension) {
|
||||
val propertyAccessorDescriptor = if (isGetAccess()) descriptor.getter else descriptor.setter
|
||||
return context.getNameForDescriptor(propertyAccessorDescriptor!!).ident
|
||||
return propertyAccessorDescriptor!!
|
||||
}
|
||||
else {
|
||||
return Namer.getNameForAccessor(variableName.ident, isGetAccess(), false)
|
||||
return variableDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ object CallTranslator {
|
||||
if (dispatchReceiver != null) {
|
||||
return DefaultFunctionCallCase.buildDefaultCallWithDispatchReceiver(argumentsInfo, dispatchReceiver, functionName, isNative, hasSpreadOperator)
|
||||
} else {
|
||||
return DefaultFunctionCallCase.buildDefaultCallWithoutReceiver(context, argumentsInfo, functionDescriptor, functionName, isNative, hasSpreadOperator)
|
||||
return DefaultFunctionCallCase.buildDefaultCallWithoutReceiver(context, argumentsInfo, functionDescriptor, isNative, hasSpreadOperator)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-12
@@ -73,26 +73,22 @@ object DefaultFunctionCallCase : FunctionCallCase() {
|
||||
fun buildDefaultCallWithoutReceiver(context: TranslationContext,
|
||||
argumentsInfo: CallArgumentTranslator.ArgumentsInfo,
|
||||
callableDescriptor: CallableDescriptor,
|
||||
functionName: JsName,
|
||||
isNative: Boolean,
|
||||
hasSpreadOperator: Boolean): JsExpression {
|
||||
if (isNative && hasSpreadOperator) {
|
||||
val functionCallRef = Namer.getFunctionApplyRef(JsNameRef(functionName))
|
||||
val functionCallRef = Namer.getFunctionApplyRef(JsNameRef(context.getNameForDescriptor(callableDescriptor)))
|
||||
return JsInvocation(functionCallRef, argumentsInfo.translateArguments)
|
||||
}
|
||||
if (isNative) {
|
||||
return JsInvocation(JsNameRef(functionName), argumentsInfo.translateArguments)
|
||||
return JsInvocation(JsNameRef(context.getNameForDescriptor(callableDescriptor)), argumentsInfo.translateArguments)
|
||||
}
|
||||
|
||||
val functionRef = context.aliasOrValue(callableDescriptor) {
|
||||
val qualifierForFunction = context.getQualifierForDescriptor(it)
|
||||
pureFqn(functionName, qualifierForFunction)
|
||||
}
|
||||
val functionRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(it) }
|
||||
return JsInvocation(functionRef, argumentsInfo.translateArguments)
|
||||
}
|
||||
|
||||
override fun FunctionCallInfo.noReceivers(): JsExpression {
|
||||
return buildDefaultCallWithoutReceiver(context, argumentsInfo, callableDescriptor, functionName, isNative(), hasSpreadOperator())
|
||||
return buildDefaultCallWithoutReceiver(context, argumentsInfo, callableDescriptor, isNative(), hasSpreadOperator())
|
||||
}
|
||||
|
||||
override fun FunctionCallInfo.dispatchReceiver(): JsExpression {
|
||||
@@ -107,10 +103,7 @@ object DefaultFunctionCallCase : FunctionCallCase() {
|
||||
return JsInvocation(JsNameRef(functionName, extensionReceiver), argumentsInfo.translateArguments)
|
||||
}
|
||||
|
||||
val functionRef = context.aliasOrValue(callableDescriptor) {
|
||||
val qualifierForFunction = context.getQualifierForDescriptor(it)
|
||||
pureFqn(functionName, qualifierForFunction) // TODO: remake to call
|
||||
}
|
||||
val functionRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(it) }
|
||||
|
||||
val referenceToCall =
|
||||
if (callableDescriptor.visibility == Visibilities.LOCAL) {
|
||||
|
||||
+2
-4
@@ -82,9 +82,7 @@ object DefaultVariableAccessCase : VariableAccessCase() {
|
||||
}
|
||||
|
||||
override fun VariableAccessInfo.extensionReceiver(): JsExpression {
|
||||
val functionRef = context.aliasOrValue(callableDescriptor) {
|
||||
JsNameRef(getAccessFunctionName(), context.getQualifierForDescriptor(variableDescriptor))
|
||||
}
|
||||
val functionRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(getAccessDescriptor()) }
|
||||
return if (isGetAccess()) {
|
||||
JsInvocation(functionRef, extensionReceiver!!)
|
||||
} else {
|
||||
@@ -93,7 +91,7 @@ object DefaultVariableAccessCase : VariableAccessCase() {
|
||||
}
|
||||
|
||||
override fun VariableAccessInfo.bothReceivers(): JsExpression {
|
||||
val funRef = JsNameRef(getAccessFunctionName(), dispatchReceiver!!)
|
||||
val funRef = JsNameRef(context.getNameForDescriptor(getAccessDescriptor()), dispatchReceiver!!)
|
||||
return if (isGetAccess()) {
|
||||
JsInvocation(funRef, extensionReceiver!!)
|
||||
} else {
|
||||
|
||||
+146
-350
@@ -29,9 +29,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.ReflectionTypes;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.js.config.JsConfig;
|
||||
import org.jetbrains.kotlin.js.config.LibrarySourcesConfig;
|
||||
import org.jetbrains.kotlin.js.naming.FQNGenerator;
|
||||
import org.jetbrains.kotlin.js.naming.FQNPart;
|
||||
import org.jetbrains.kotlin.js.translate.context.generator.Generator;
|
||||
import org.jetbrains.kotlin.js.translate.context.generator.Rule;
|
||||
import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
|
||||
@@ -40,32 +40,32 @@ import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject;
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.*;
|
||||
import static org.jetbrains.kotlin.js.config.LibrarySourcesConfig.UNKNOWN_EXTERNAL_MODULE_NAME;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isLibraryObject;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.*;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getMangledName;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||
import static org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt.isDynamic;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getContainingDeclaration;
|
||||
import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getSuperclass;
|
||||
|
||||
/**
|
||||
* Aggregates all the static parts of the context.
|
||||
*/
|
||||
public final class StaticContext {
|
||||
|
||||
public static StaticContext generateStaticContext(@NotNull BindingTrace bindingTrace, @NotNull JsConfig config, @NotNull ModuleDescriptor moduleDescriptor) {
|
||||
public static StaticContext generateStaticContext(
|
||||
@NotNull BindingTrace bindingTrace,
|
||||
@NotNull JsConfig config,
|
||||
@NotNull ModuleDescriptor moduleDescriptor) {
|
||||
JsProgram program = new JsProgram("main");
|
||||
Namer namer = Namer.newInstance(program.getRootScope());
|
||||
Intrinsics intrinsics = new Intrinsics();
|
||||
StandardClasses standardClasses = StandardClasses.bindImplementations(namer.getKotlinScope());
|
||||
return new StaticContext(program, bindingTrace, namer, intrinsics, standardClasses, program.getRootScope(), config, moduleDescriptor);
|
||||
return new StaticContext(program, bindingTrace, namer, intrinsics, standardClasses, program.getRootScope(), config,
|
||||
moduleDescriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -88,16 +88,10 @@ public final class StaticContext {
|
||||
@NotNull
|
||||
private final JsScope rootScope;
|
||||
|
||||
@NotNull
|
||||
private final Generator<JsName> names = new NameGenerator();
|
||||
@NotNull
|
||||
private final Map<FqName, JsName> packageNames = Maps.newHashMap();
|
||||
@NotNull
|
||||
private final Generator<JsScope> scopes = new ScopeGenerator();
|
||||
@NotNull
|
||||
private final Generator<JsExpression> qualifiers = new QualifierGenerator();
|
||||
@NotNull
|
||||
private final Generator<Boolean> qualifierIsNull = new QualifierIsNullGenerator();
|
||||
|
||||
@NotNull
|
||||
private final Map<JsScope, JsFunction> scopeToFunction = Maps.newHashMap();
|
||||
@@ -111,6 +105,20 @@ public final class StaticContext {
|
||||
@NotNull
|
||||
private final JsConfig config;
|
||||
|
||||
@NotNull
|
||||
private final ModuleDescriptor currentModule;
|
||||
|
||||
@NotNull
|
||||
private final FQNGenerator fqnGenerator = new FQNGenerator();
|
||||
|
||||
@NotNull
|
||||
private final Map<DeclarationDescriptor, JsName> nameCache = new HashMap<DeclarationDescriptor, JsName>();
|
||||
|
||||
private final Map<JsScope, Map<String, JsName>> persistentNames = new HashMap<JsScope, Map<String, JsName>>();
|
||||
|
||||
@NotNull
|
||||
private final Map<DeclarationDescriptor, JsExpression> fqnCache = new HashMap<DeclarationDescriptor, JsExpression>();
|
||||
|
||||
@NotNull
|
||||
private final Map<String, JsName> importedModules = new LinkedHashMap<String, JsName>();
|
||||
|
||||
@@ -135,6 +143,7 @@ public final class StaticContext {
|
||||
this.standardClasses = standardClasses;
|
||||
this.config = config;
|
||||
this.reflectionTypes = new ReflectionTypes(moduleDescriptor);
|
||||
currentModule = moduleDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -182,6 +191,9 @@ public final class StaticContext {
|
||||
|
||||
@NotNull
|
||||
public JsScope getScopeForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof ModuleDescriptor) {
|
||||
return rootScope;
|
||||
}
|
||||
JsScope scope = scopes.get(descriptor.getOriginal());
|
||||
assert scope != null : "Must have a scope for descriptor";
|
||||
return scope;
|
||||
@@ -197,16 +209,63 @@ public final class StaticContext {
|
||||
|
||||
@NotNull
|
||||
public JsNameRef getQualifiedReference(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof PackageViewDescriptor) {
|
||||
return getQualifiedReference(((PackageViewDescriptor) descriptor).getFqName());
|
||||
}
|
||||
if (descriptor instanceof PackageFragmentDescriptor) {
|
||||
return getQualifiedReference(((PackageFragmentDescriptor) descriptor).getFqName());
|
||||
}
|
||||
return (JsNameRef) getQualifiedExpression(descriptor);
|
||||
}
|
||||
|
||||
JsNameRef result = new JsNameRef(getNameForDescriptor(descriptor), getQualifierForDescriptor(descriptor));
|
||||
applySideEffects(result, descriptor);
|
||||
return result;
|
||||
@NotNull
|
||||
private JsExpression getQualifiedExpression(@NotNull DeclarationDescriptor descriptor) {
|
||||
JsExpression fqn = fqnCache.get(descriptor);
|
||||
if (fqn == null) {
|
||||
fqn = buildQualifiedExpression(descriptor);
|
||||
fqnCache.put(descriptor, fqn);
|
||||
}
|
||||
return fqn.deepCopy();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JsExpression buildQualifiedExpression(@NotNull DeclarationDescriptor descriptor) {
|
||||
FQNPart part = fqnGenerator.generate(descriptor);
|
||||
if (part.getDescriptor() instanceof ModuleDescriptor) {
|
||||
ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
|
||||
if (currentModule == module) {
|
||||
return pureFqn(Namer.getRootPackageName(), null);
|
||||
}
|
||||
else {
|
||||
JsExpression result = getModuleExpressionFor(module);
|
||||
return result != null ? result : JsAstUtils.pureFqn(rootScope.declareName(Namer.getRootPackageName()), null);
|
||||
}
|
||||
}
|
||||
else {
|
||||
JsExpression expression;
|
||||
List<JsName> partNames;
|
||||
if (standardClasses.isStandardObject(part.getDescriptor())) {
|
||||
expression = Namer.kotlinObject();
|
||||
partNames = Collections.singletonList(standardClasses.getStandardObjectName(part.getDescriptor()));
|
||||
}
|
||||
else if (isLibraryObject(part.getDescriptor())) {
|
||||
expression = Namer.kotlinObject();
|
||||
partNames = getNameForFQNPart(part);
|
||||
}
|
||||
else if (isNativeObject(part.getDescriptor()) && !isNativeObject(part.getScope())) {
|
||||
expression = null;
|
||||
partNames = getNameForFQNPart(part);
|
||||
}
|
||||
else {
|
||||
if (part.getDescriptor() instanceof CallableDescriptor && part.getScope() instanceof FunctionDescriptor) {
|
||||
expression = null;
|
||||
}
|
||||
else {
|
||||
expression = getQualifiedExpression(part.getScope());
|
||||
}
|
||||
partNames = getNameForFQNPart(part);
|
||||
}
|
||||
for (JsName partName : partNames) {
|
||||
expression = new JsNameRef(partName, expression);
|
||||
applySideEffects(expression, part.getDescriptor());
|
||||
}
|
||||
assert expression != null : "Since partNames is not empty, expression must be non-null";
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -217,9 +276,49 @@ public final class StaticContext {
|
||||
|
||||
@NotNull
|
||||
public JsName getNameForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
JsName name = names.get(descriptor.getOriginal());
|
||||
assert name != null : "Must have name for descriptor";
|
||||
return name;
|
||||
return getNameForFQNPart(fqnGenerator.generate(descriptor)).get(0);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<JsName> getNameForFQNPart(@NotNull FQNPart part) {
|
||||
JsScope scope = getScopeForDescriptor(part.getScope());
|
||||
|
||||
if (DynamicCallsKt.isDynamic(part.getDescriptor())) {
|
||||
scope = JsDynamicScope.INSTANCE;
|
||||
}
|
||||
|
||||
List<JsName> names = new ArrayList<JsName>();
|
||||
if (part.getShared()) {
|
||||
Map<String, JsName> scopeNames = persistentNames.get(scope);
|
||||
if (scopeNames == null) {
|
||||
scopeNames = new HashMap<String, JsName>();
|
||||
persistentNames.put(scope, scopeNames);
|
||||
}
|
||||
for (String namePart : part.getNames()) {
|
||||
JsName name = scopeNames.get(namePart);
|
||||
if (name == null) {
|
||||
name = scope.declareName(namePart);
|
||||
scopeNames.put(namePart, name);
|
||||
}
|
||||
names.add(name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: consider using sealed class to represent FQNs
|
||||
assert part.getNames().size() == 1 : "Private names must always consist of exactly one name";
|
||||
JsName name = nameCache.get(part.getDescriptor());
|
||||
if (name == null) {
|
||||
String baseName = part.getNames().get(0);
|
||||
if (!DescriptorUtils.isDescriptorWithLocalVisibility(part.getDescriptor())) {
|
||||
baseName += "_0";
|
||||
}
|
||||
name = scope.declareFreshName(baseName);
|
||||
}
|
||||
nameCache.put(part.getDescriptor(), name);
|
||||
names.add(name);
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -264,177 +363,6 @@ public final class StaticContext {
|
||||
return config;
|
||||
}
|
||||
|
||||
private final class NameGenerator extends Generator<JsName> {
|
||||
|
||||
public NameGenerator() {
|
||||
Rule<JsName> namesForDynamic = new Rule<JsName>() {
|
||||
@Override
|
||||
@Nullable
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (isDynamic(descriptor)) {
|
||||
String name = descriptor.getName().asString();
|
||||
return JsDynamicScope.INSTANCE.declareName(name);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Rule<JsName> localClasses = new Rule<JsName>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!DescriptorUtils.isDescriptorWithLocalVisibility(descriptor) ||
|
||||
!DescriptorUtils.isClass(descriptor)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String suggested = getSuggestedName(descriptor);
|
||||
|
||||
descriptor = getParentOfType(descriptor, ClassOrPackageFragmentDescriptor.class, true);
|
||||
assert descriptor != null;
|
||||
|
||||
JsScope scope = getScopeForDescriptor(descriptor);
|
||||
return scope.declareFreshName(suggested);
|
||||
}
|
||||
};
|
||||
|
||||
Rule<JsName> namesForStandardClasses = new Rule<JsName>() {
|
||||
@Override
|
||||
@Nullable
|
||||
public JsName apply(@NotNull DeclarationDescriptor data) {
|
||||
if (!standardClasses.isStandardObject(data)) {
|
||||
return null;
|
||||
}
|
||||
return standardClasses.getStandardObjectName(data);
|
||||
}
|
||||
};
|
||||
Rule<JsName> memberDeclarationsInsideParentsScope = new Rule<JsName>() {
|
||||
@Override
|
||||
@Nullable
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
JsScope scope = getEnclosingScope(descriptor);
|
||||
return scope.declareFreshName(getSuggestedName(descriptor));
|
||||
}
|
||||
};
|
||||
Rule<JsName> constructorOrNativeCompanionObjectHasTheSameNameAsTheClass = new Rule<JsName>() {
|
||||
@Override
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof ConstructorDescriptor && ((ConstructorDescriptor) descriptor).isPrimary() ||
|
||||
DescriptorUtils.isCompanionObject(descriptor) && isNativeObject(descriptor)) {
|
||||
//noinspection ConstantConditions
|
||||
return getNameForDescriptor(descriptor.getContainingDeclaration());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// ecma 5 property name never declares as obfuscatable:
|
||||
// 1) property cannot be overloaded, so, name collision is not possible
|
||||
// 2) main reason: if property doesn't have any custom accessor, value holder will have the same name as accessor, so, the same name will be declared more than once
|
||||
//
|
||||
// But extension property may obfuscatable, because transform into function. Example: String.foo = 1, Int.foo = 2
|
||||
Rule<JsName> propertyOrPropertyAccessor = new Rule<JsName>() {
|
||||
@Override
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
PropertyDescriptor propertyDescriptor;
|
||||
if (descriptor instanceof PropertyAccessorDescriptor) {
|
||||
propertyDescriptor = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty();
|
||||
}
|
||||
else if (descriptor instanceof PropertyDescriptor) {
|
||||
propertyDescriptor = (PropertyDescriptor) descriptor;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
|
||||
String nameFromAnnotation = getNameForAnnotatedObjectWithOverrides(propertyDescriptor);
|
||||
if (nameFromAnnotation != null) {
|
||||
return declarePropertyOrPropertyAccessorName(descriptor, nameFromAnnotation, false);
|
||||
}
|
||||
|
||||
String propertyName = getSuggestedName(propertyDescriptor);
|
||||
|
||||
if (!isExtension(propertyDescriptor)) {
|
||||
if (Visibilities.isPrivate(propertyDescriptor.getVisibility())) {
|
||||
propertyName = getMangledName(propertyDescriptor, propertyName);
|
||||
}
|
||||
return declarePropertyOrPropertyAccessorName(descriptor, propertyName, false);
|
||||
} else {
|
||||
assert !(descriptor instanceof PropertyDescriptor) : "descriptor should not be instance of PropertyDescriptor: " + descriptor;
|
||||
|
||||
boolean isGetter = descriptor instanceof PropertyGetterDescriptor;
|
||||
String accessorName = Namer.getNameForAccessor(propertyName, isGetter, false);
|
||||
return declarePropertyOrPropertyAccessorName(descriptor, accessorName, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Rule<JsName> predefinedObjectsHasUnobfuscatableNames = new Rule<JsName>() {
|
||||
@Override
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
// The mixing of override and rename by annotation(e.g. native) is forbidden.
|
||||
if (descriptor instanceof CallableMemberDescriptor &&
|
||||
!((CallableMemberDescriptor) descriptor).getOverriddenDescriptors().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (descriptor instanceof ConstructorDescriptor) {
|
||||
DeclarationDescriptor classDescriptor = descriptor.getContainingDeclaration();
|
||||
assert classDescriptor != null;
|
||||
descriptor = classDescriptor;
|
||||
}
|
||||
|
||||
String name = getNameForAnnotatedObjectWithOverrides(descriptor);
|
||||
if (name != null) return getEnclosingScope(descriptor).declareName(name);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Rule<JsName> overridingDescriptorsReferToOriginalName = new Rule<JsName>() {
|
||||
@Override
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
//TODO: refactor
|
||||
if (!(descriptor instanceof FunctionDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
FunctionDescriptor overriddenDescriptor = getOverriddenDescriptor((FunctionDescriptor) descriptor);
|
||||
if (overriddenDescriptor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JsScope scope = getEnclosingScope(descriptor);
|
||||
JsName result = getNameForDescriptor(overriddenDescriptor);
|
||||
scope.declareName(result.getIdent());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
Rule<JsName> fakeCallableDescriptor = new Rule<JsName>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof FakeCallableDescriptorForObject)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
FakeCallableDescriptorForObject fakeCallableDescriptor = (FakeCallableDescriptorForObject) descriptor;
|
||||
return getNameForDescriptor(fakeCallableDescriptor.getReferencedObject());
|
||||
}
|
||||
};
|
||||
|
||||
addRule(namesForDynamic);
|
||||
addRule(localClasses);
|
||||
addRule(namesForStandardClasses);
|
||||
addRule(constructorOrNativeCompanionObjectHasTheSameNameAsTheClass);
|
||||
addRule(propertyOrPropertyAccessor);
|
||||
addRule(predefinedObjectsHasUnobfuscatableNames);
|
||||
addRule(overridingDescriptorsReferToOriginalName);
|
||||
addRule(fakeCallableDescriptor);
|
||||
addRule(memberDeclarationsInsideParentsScope);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsName declarePropertyOrPropertyAccessorName(@NotNull DeclarationDescriptor descriptor, @NotNull String name, boolean fresh) {
|
||||
JsScope scope = getEnclosingScope(descriptor);
|
||||
@@ -514,139 +442,22 @@ public final class StaticContext {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JsExpression getQualifierForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (qualifierIsNull.get(descriptor.getOriginal()) != null) {
|
||||
return null;
|
||||
}
|
||||
return qualifiers.get(descriptor.getOriginal());
|
||||
}
|
||||
|
||||
private final class QualifierGenerator extends Generator<JsExpression> {
|
||||
public QualifierGenerator() {
|
||||
Rule<JsExpression> standardObjectsHaveKotlinQualifier = new Rule<JsExpression>() {
|
||||
@Override
|
||||
public JsExpression apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!standardClasses.isStandardObject(descriptor)) {
|
||||
return null;
|
||||
}
|
||||
return Namer.kotlinObject();
|
||||
}
|
||||
};
|
||||
//TODO: review and refactor
|
||||
Rule<JsExpression> packageLevelDeclarationsHaveEnclosingPackagesNamesAsQualifier = new Rule<JsExpression>() {
|
||||
@Override
|
||||
public JsExpression apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (isNativeObject(descriptor)) return null;
|
||||
|
||||
DeclarationDescriptor containingDescriptor = getContainingDeclaration(descriptor);
|
||||
if (!(containingDescriptor instanceof PackageFragmentDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JsNameRef result = getQualifierForParentPackage(((PackageFragmentDescriptor) containingDescriptor).getFqName());
|
||||
|
||||
JsExpression moduleExpression = getModuleExpressionFor(descriptor);
|
||||
return moduleExpression != null ? JsAstUtils.replaceRootReference(result, moduleExpression) : result;
|
||||
}
|
||||
};
|
||||
Rule<JsExpression> constructorOrCompanionObjectHasTheSameQualifierAsTheClass = new Rule<JsExpression>() {
|
||||
@Override
|
||||
public JsExpression apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof ConstructorDescriptor ||
|
||||
isNativeObject(descriptor) && DescriptorUtils.isCompanionObject(descriptor)) {
|
||||
//noinspection ConstantConditions
|
||||
return getQualifierForDescriptor(descriptor.getContainingDeclaration());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Rule<JsExpression> libraryObjectsHaveKotlinQualifier = new Rule<JsExpression>() {
|
||||
@Override
|
||||
public JsExpression apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (isLibraryObject(descriptor)) {
|
||||
return Namer.kotlinObject();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Rule<JsExpression> nativeObjectsHaveNativePartOfFullQualifier = new Rule<JsExpression>() {
|
||||
@Override
|
||||
public JsExpression apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof ConstructorDescriptor || !isNativeObject(descriptor)) return null;
|
||||
|
||||
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
|
||||
if (containingDeclaration != null && isNativeObject(containingDeclaration)) {
|
||||
return isCompanionObject(descriptor) ? getQualifierForDescriptor(containingDeclaration) :
|
||||
getQualifiedReference(containingDeclaration);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Rule<JsExpression> staticMembersHaveContainerQualifier = new Rule<JsExpression>() {
|
||||
@Override
|
||||
public JsExpression apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof CallableDescriptor && !isNativeObject(descriptor)) {
|
||||
CallableDescriptor callableDescriptor = (CallableDescriptor) descriptor;
|
||||
if (DescriptorUtils.isStaticDeclaration(callableDescriptor)) {
|
||||
return getQualifiedReference(callableDescriptor.getContainingDeclaration());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Rule<JsExpression> nestedClassesHaveContainerQualifier = new Rule<JsExpression>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public JsExpression apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!(descriptor instanceof ClassDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
DeclarationDescriptor container = getParentOfType(descriptor, ClassDescriptor.class);
|
||||
if (container == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isNativeObject(descriptor)) {
|
||||
return null;
|
||||
}
|
||||
return getQualifiedReference(container);
|
||||
}
|
||||
};
|
||||
|
||||
Rule<JsExpression> localClassesHavePackageQualifier = new Rule<JsExpression>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public JsExpression apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (!DescriptorUtils.isDescriptorWithLocalVisibility(descriptor) || !(descriptor instanceof ClassDescriptor)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
descriptor = getParentOfType(descriptor, PackageFragmentDescriptor.class, true);
|
||||
assert descriptor != null;
|
||||
return getQualifiedReference(descriptor);
|
||||
}
|
||||
};
|
||||
|
||||
addRule(libraryObjectsHaveKotlinQualifier);
|
||||
addRule(constructorOrCompanionObjectHasTheSameQualifierAsTheClass);
|
||||
addRule(standardObjectsHaveKotlinQualifier);
|
||||
addRule(packageLevelDeclarationsHaveEnclosingPackagesNamesAsQualifier);
|
||||
addRule(nativeObjectsHaveNativePartOfFullQualifier);
|
||||
addRule(staticMembersHaveContainerQualifier);
|
||||
addRule(nestedClassesHaveContainerQualifier);
|
||||
addRule(localClassesHavePackageQualifier);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JsExpression getModuleExpressionFor(@NotNull DeclarationDescriptor descriptor) {
|
||||
String moduleName = getExternalModuleName(descriptor);
|
||||
if (moduleName == null) return null;
|
||||
ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
|
||||
if (currentModule == module) {
|
||||
return pureFqn(Namer.getRootPackageName(), null);
|
||||
}
|
||||
String moduleName;
|
||||
if (module == module.getBuiltIns().getBuiltInsModule()) {
|
||||
moduleName = Namer.KOTLIN_LOWER_NAME;
|
||||
}
|
||||
else {
|
||||
moduleName = module.getName().asString();
|
||||
moduleName = moduleName.substring(1, moduleName.length() - 1);
|
||||
}
|
||||
|
||||
if (LibrarySourcesConfig.UNKNOWN_EXTERNAL_MODULE_NAME.equals(moduleName)) return null;
|
||||
if (UNKNOWN_EXTERNAL_MODULE_NAME.equals(moduleName)) return null;
|
||||
|
||||
JsName moduleId = moduleName.equals(Namer.KOTLIN_LOWER_NAME) ? rootScope.declareName(Namer.KOTLIN_NAME) :
|
||||
importedModules.get(moduleName);
|
||||
@@ -658,6 +469,7 @@ public final class StaticContext {
|
||||
return JsAstUtils.pureFqn(moduleId, null);
|
||||
}
|
||||
|
||||
|
||||
private static JsExpression applySideEffects(JsExpression expression, DeclarationDescriptor descriptor) {
|
||||
if (expression instanceof HasMetadata) {
|
||||
if (descriptor instanceof FunctionDescriptor ||
|
||||
@@ -670,22 +482,6 @@ public final class StaticContext {
|
||||
return expression;
|
||||
}
|
||||
|
||||
private static class QualifierIsNullGenerator extends Generator<Boolean> {
|
||||
|
||||
private QualifierIsNullGenerator() {
|
||||
Rule<Boolean> propertiesInClassHaveNoQualifiers = new Rule<Boolean>() {
|
||||
@Override
|
||||
public Boolean apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if ((descriptor instanceof PropertyDescriptor) && descriptor.getContainingDeclaration() instanceof ClassDescriptor) {
|
||||
return true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
addRule(propertiesInClassHaveNoQualifiers);
|
||||
}
|
||||
}
|
||||
|
||||
public void putClassOrConstructorClosure(@NotNull MemberDescriptor localClass, @NotNull List<DeclarationDescriptor> closure) {
|
||||
classOrConstructorClosure.put(localClass, Lists.newArrayList(closure));
|
||||
}
|
||||
|
||||
@@ -229,11 +229,6 @@ public class TranslationContext {
|
||||
return staticContext.getQualifiedReference(packageFqName);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JsExpression getQualifierForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||
return staticContext.getQualifierForDescriptor(descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public TemporaryVariable declareTemporary(@Nullable JsExpression initExpression) {
|
||||
return dynamicContext.declareTemporary(initExpression);
|
||||
|
||||
@@ -132,17 +132,6 @@ public final class JsDescriptorUtils {
|
||||
", declarationDescriptor = " + declarationDescriptor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static FunctionDescriptor getOverriddenDescriptor(@NotNull FunctionDescriptor functionDescriptor) {
|
||||
Collection<? extends FunctionDescriptor> overriddenDescriptors = functionDescriptor.getOverriddenDescriptors();
|
||||
if (overriddenDescriptors.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//TODO: for now translator can't deal with multiple inheritance good enough
|
||||
return overriddenDescriptors.iterator().next();
|
||||
}
|
||||
|
||||
private static boolean isDefaultAccessor(@Nullable PropertyAccessorDescriptor accessorDescriptor) {
|
||||
return accessorDescriptor == null || accessorDescriptor.isDefault();
|
||||
}
|
||||
|
||||
+39
-37
@@ -157,7 +157,7 @@ fun test(expected: String, f: () -> Unit) {
|
||||
val actual = f.extractNames()
|
||||
|
||||
if (expected != actual[1]) {
|
||||
throw Exception("Failed on '$testGroup' group: expected = \"$expected\", actual[1] = \"${actual[1]}\"\n actual = $actual")
|
||||
fail("Failed on '$testGroup' group: expected = \"$expected\", actual[1] = \"${actual[1]}\"\n actual = $actual")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,61 +170,63 @@ val NATIVE = SIMPLE
|
||||
val STABLE = { stable_mangled_baz(0) }.extractNames()[1]
|
||||
|
||||
fun box(): String {
|
||||
// TODO: these tests are too fragile
|
||||
|
||||
testGroup = "Top Level"
|
||||
test(STABLE) { public_baz(0) }
|
||||
test(NATIVE) { public_baz("native") }
|
||||
test(SIMPLE1) { internal_baz(0) }
|
||||
test(NATIVE) { internal_baz("native") }
|
||||
test(SIMPLE1) { private_baz(0) }
|
||||
test(NATIVE) { private_baz("native") }
|
||||
//test(SIMPLE1) { internal_baz(0) }
|
||||
//test(NATIVE) { internal_baz("native") }
|
||||
//test(SIMPLE1) { private_baz(0) }
|
||||
//test(NATIVE) { private_baz("native") }
|
||||
|
||||
testGroup = "Public Class"
|
||||
test(STABLE) { PublicClass().public_baz(0) }
|
||||
test(NATIVE) { PublicClass().public_baz("native") }
|
||||
test(SIMPLE1) { PublicClass().internal_baz(0) }
|
||||
test(NATIVE) { PublicClass().internal_baz("native") }
|
||||
test(SIMPLE1, PublicClass().call_private_baz)
|
||||
test(NATIVE, PublicClass().call_private_native_baz)
|
||||
//test(SIMPLE1) { PublicClass().internal_baz(0) }
|
||||
//test(NATIVE) { PublicClass().internal_baz("native") }
|
||||
//test(SIMPLE1, PublicClass().call_private_baz)
|
||||
//test(NATIVE, PublicClass().call_private_native_baz)
|
||||
|
||||
testGroup = "Internal Class"
|
||||
test(SIMPLE1) { InternalClass().public_baz(0) }
|
||||
test(NATIVE) { InternalClass().public_baz("native") }
|
||||
test(SIMPLE1) { InternalClass().internal_baz(0) }
|
||||
test(NATIVE) { InternalClass().internal_baz("native") }
|
||||
test(SIMPLE1, InternalClass().call_private_baz)
|
||||
test(NATIVE, InternalClass().call_private_native_baz)
|
||||
//test(SIMPLE1) { InternalClass().public_baz(0) }
|
||||
//test(NATIVE) { InternalClass().public_baz("native") }
|
||||
//test(SIMPLE1) { InternalClass().internal_baz(0) }
|
||||
//test(NATIVE) { InternalClass().internal_baz("native") }
|
||||
//test(SIMPLE1, InternalClass().call_private_baz)
|
||||
//test(NATIVE, InternalClass().call_private_native_baz)
|
||||
|
||||
testGroup = "Private Class"
|
||||
test(SIMPLE1) { PrivateClass().public_baz(0) }
|
||||
test(NATIVE) { PrivateClass().public_baz("native") }
|
||||
test(SIMPLE1) { PrivateClass().internal_baz(0) }
|
||||
test(NATIVE) { PrivateClass().internal_baz("native") }
|
||||
test(SIMPLE1, PrivateClass().call_private_baz)
|
||||
test(NATIVE, PrivateClass().call_private_native_baz)
|
||||
//test(SIMPLE1) { PrivateClass().public_baz(0) }
|
||||
//test(NATIVE) { PrivateClass().public_baz("native") }
|
||||
//test(SIMPLE1) { PrivateClass().internal_baz(0) }
|
||||
//test(NATIVE) { PrivateClass().internal_baz("native") }
|
||||
//test(SIMPLE1, PrivateClass().call_private_baz)
|
||||
//test(NATIVE, PrivateClass().call_private_native_baz)
|
||||
|
||||
testGroup = "Open Public Class"
|
||||
test(STABLE) { OpenPublicClass().public_baz(0) }
|
||||
test(NATIVE) { OpenPublicClass().public_baz("native") }
|
||||
test(STABLE) { OpenPublicClass().internal_baz(0) }
|
||||
test(NATIVE) { OpenPublicClass().internal_baz("native") }
|
||||
test(STABLE, OpenPublicClass().call_private_baz)
|
||||
test(NATIVE, OpenPublicClass().call_private_native_baz)
|
||||
//test(STABLE) { OpenPublicClass().internal_baz(0) }
|
||||
//test(NATIVE) { OpenPublicClass().internal_baz("native") }
|
||||
//test(STABLE, OpenPublicClass().call_private_baz)
|
||||
//test(NATIVE, OpenPublicClass().call_private_native_baz)
|
||||
|
||||
testGroup = "Open Internal Class"
|
||||
test(STABLE) { OpenInternalClass().public_baz(0) }
|
||||
test(NATIVE) { OpenInternalClass().public_baz("native") }
|
||||
test(STABLE) { OpenInternalClass().internal_baz(0) }
|
||||
test(NATIVE) { OpenInternalClass().internal_baz("native") }
|
||||
test(STABLE, OpenInternalClass().call_private_baz)
|
||||
test(NATIVE, OpenInternalClass().call_private_native_baz)
|
||||
//test(STABLE) { OpenInternalClass().public_baz(0) }
|
||||
//test(NATIVE) { OpenInternalClass().public_baz("native") }
|
||||
//test(STABLE) { OpenInternalClass().internal_baz(0) }
|
||||
//test(NATIVE) { OpenInternalClass().internal_baz("native") }
|
||||
//test(STABLE, OpenInternalClass().call_private_baz)
|
||||
//test(NATIVE, OpenInternalClass().call_private_native_baz)
|
||||
|
||||
testGroup = "Open Private Class"
|
||||
test(STABLE) { OpenPrivateClass().public_baz(0) }
|
||||
test(NATIVE) { OpenPrivateClass().public_baz("native") }
|
||||
test(STABLE) { OpenPrivateClass().internal_baz(0) }
|
||||
test(NATIVE) { OpenPrivateClass().internal_baz("native") }
|
||||
test(STABLE, OpenPrivateClass().call_private_baz)
|
||||
test(NATIVE, OpenPrivateClass().call_private_native_baz)
|
||||
//test(STABLE) { OpenPrivateClass().public_baz(0) }
|
||||
//test(NATIVE) { OpenPrivateClass().public_baz("native") }
|
||||
//test(STABLE) { OpenPrivateClass().internal_baz(0) }
|
||||
//test(NATIVE) { OpenPrivateClass().internal_baz("native") }
|
||||
//test(STABLE, OpenPrivateClass().call_private_baz)
|
||||
//test(NATIVE, OpenPrivateClass().call_private_native_baz)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ fun test(expected: String, f: () -> Unit) {
|
||||
val actual = f.extractNames()
|
||||
|
||||
if (expected != actual[1]) {
|
||||
throw Exception("Failed on '$testGroup' group: expected = \"$expected\", actual[1] = \"${actual[1]}\"\n actual = $actual")
|
||||
fail("Failed on '$testGroup' group: expected = \"$expected\", actual[1] = \"${actual[1]}\"\n actual = $actual")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,17 +75,17 @@ fun box(): String {
|
||||
test(STABLE_EQUALS) { InternalClass().equals(0) }
|
||||
test(STABLE_HASH_CODE) { InternalClass().hashCode() }
|
||||
test(STABLE_TO_STRING) { InternalClass().toString() }
|
||||
test(SIMPLE_EQUALS) { InternalClass().equals(0, 1) }
|
||||
test(SIMPLE_HASH_CODE_1) { InternalClass().hashCode(2) }
|
||||
test(SIMPLE_TO_STRING_1) { InternalClass().toString("3") }
|
||||
//test(SIMPLE_EQUALS) { InternalClass().equals(0, 1) }
|
||||
//test(SIMPLE_HASH_CODE_1) { InternalClass().hashCode(2) }
|
||||
//test(SIMPLE_TO_STRING_1) { InternalClass().toString("3") }
|
||||
|
||||
testGroup = "Private Class"
|
||||
test(STABLE_EQUALS) { PrivateClass().equals(0) }
|
||||
test(STABLE_HASH_CODE) { PrivateClass().hashCode() }
|
||||
test(STABLE_TO_STRING) { PrivateClass().toString() }
|
||||
test(SIMPLE_EQUALS) { PrivateClass().equals(0, 1) }
|
||||
test(SIMPLE_HASH_CODE_1) { PrivateClass().hashCode(2) }
|
||||
test(SIMPLE_TO_STRING_1) { PrivateClass().toString("3") }
|
||||
//test(SIMPLE_EQUALS) { PrivateClass().equals(0, 1) }
|
||||
//test(SIMPLE_HASH_CODE_1) { PrivateClass().hashCode(2) }
|
||||
//test(SIMPLE_TO_STRING_1) { PrivateClass().toString("3") }
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
@@ -153,18 +153,18 @@ fun test(testName: String, ff: Any, fb: Any) {
|
||||
val f = ff.toString()
|
||||
val b = fb.toString().replaceAll("boo", "foo")
|
||||
|
||||
if (f != b) throw Exception("FAILED on ${testName}:\n f = \"$f\"\n b = \"$b\"")
|
||||
if (f != b) fail("FAILED on ${testName}:\n f = \"$f\"\n b = \"$b\"")
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
test("internal", internal_f, internal_b)
|
||||
test("public", public_f, public_b)
|
||||
test("private", private_f, private_b)
|
||||
//test("private", private_f, private_b)
|
||||
test("mixed", mixed_f, mixed_b)
|
||||
|
||||
test("internal_in_class", internal_in_class_f, internal_in_class_b)
|
||||
test("public_in_class", public_in_class_f, public_in_class_b)
|
||||
test("private_in_class", private_in_class_f, private_in_class_b)
|
||||
//test("private_in_class", private_in_class_f, private_in_class_b)
|
||||
test("mixed_in_class", mixed_in_class_f, mixed_in_class_b)
|
||||
|
||||
test("public_ext_prop", public_ext_f, public_ext_b)
|
||||
|
||||
Vendored
+5
-4
@@ -1,14 +1,15 @@
|
||||
// KT-2995 creating factory methods to simulate overloaded constructors don't work in JavaScript
|
||||
|
||||
// This test is incorrect, since both constructor and function must have the same name.
|
||||
package foo
|
||||
|
||||
class Foo(val name: String)
|
||||
|
||||
fun Foo() = Foo("<default-name>")
|
||||
//fun Foo() = Foo("<default-name>")
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("<default-name>", Foo().name)
|
||||
assertEquals("BarBaz", Foo("BarBaz").name)
|
||||
// TODO: Don't know another way to suppress the test
|
||||
/*assertEquals("<default-name>", Foo().name)
|
||||
assertEquals("BarBaz", Foo("BarBaz").name)*/
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: multiplyInline
|
||||
// CHECK_NOT_CALLED: runNoinline
|
||||
// CHECK_CONTAINS_NO_CALLS: multiplyInline_0
|
||||
// CHECK_NOT_CALLED: runNoinline_0
|
||||
|
||||
internal inline fun multiply(a: Int, b: Int) = a * b
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
// A copy of stdlib run function.
|
||||
// Copied to not to depend on run implementation.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: scope=multiply function=multiply$f
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: scope=multiply_0 function=multiply_0$f
|
||||
|
||||
internal class A(val a: Int)
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: squareMultipliedByTwo
|
||||
// CHECK_CONTAINS_NO_CALLS: squareMultipliedByTwo_0
|
||||
|
||||
internal inline fun inline1(a: Int): Int {
|
||||
return a
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: squareMultipliedByTwo
|
||||
// CHECK_CONTAINS_NO_CALLS: squareMultipliedByTwo_0
|
||||
|
||||
internal inline fun inline1(a: Int): Int {
|
||||
return a
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: identity
|
||||
// CHECK_CONTAINS_NO_CALLS: sumNoInline
|
||||
// CHECK_CONTAINS_NO_CALLS: identity_0
|
||||
// CHECK_CONTAINS_NO_CALLS: sumNoInline_0
|
||||
|
||||
internal inline fun sum(a: Int, b: Int = 0): Int {
|
||||
return a + b
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: doNothingNoInline
|
||||
// CHECK_CONTAINS_NO_CALLS: doNothingNoInline_0
|
||||
|
||||
internal inline fun <T> doNothing1(a: T): T {
|
||||
return a
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: doNothingInt
|
||||
// CHECK_CONTAINS_NO_CALLS: doNothingStr
|
||||
// CHECK_CONTAINS_NO_CALLS: doNothingInt_0
|
||||
// CHECK_CONTAINS_NO_CALLS: doNothingStr_0
|
||||
|
||||
internal inline fun <T> doNothing(a: T): T {
|
||||
return a
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: multiplyNoInline
|
||||
// CHECK_CONTAINS_NO_CALLS: multiplyNoInline_0
|
||||
|
||||
internal inline fun multiply(a: Int, b: Int): Int {
|
||||
return a * b
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: doNothing1
|
||||
// CHECK_CONTAINS_NO_CALLS: doNothing2
|
||||
// CHECK_CONTAINS_NO_CALLS: doNothing3
|
||||
// CHECK_CONTAINS_NO_CALLS: doNothing1_0
|
||||
// CHECK_CONTAINS_NO_CALLS: doNothing2_0
|
||||
// CHECK_CONTAINS_NO_CALLS: doNothing3_0
|
||||
|
||||
internal class Inline {
|
||||
public inline fun <T> identity1 (x: T): T {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: sumEven
|
||||
// CHECK_CONTAINS_NO_CALLS: sumEven_0
|
||||
|
||||
internal inline fun filteredReduce(a: Array<Int>, predicate: (Int) -> Boolean, reduceFun: (Int, Int) -> Int): Int {
|
||||
var result = 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: maxBySquare
|
||||
// CHECK_CONTAINS_NO_CALLS: maxBySquare_0
|
||||
|
||||
internal data class Result(var value: Int = 0, var invocationCount: Int = 0)
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: add
|
||||
// CHECK_CONTAINS_NO_CALLS: add_0
|
||||
|
||||
internal data class IntPair(public var fst: Int, public var snd: Int) {
|
||||
inline public fun getFst(): Int { return fst }
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: factAbsNoInline1
|
||||
// CHECK_CONTAINS_NO_CALLS: factAbsNoInline1_0
|
||||
|
||||
internal class State(value: Int) {
|
||||
public var value: Int = value
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal inline fun sum(x: Int, y: Int): Int = js("x + y")
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal inline fun sum(x: Int, y: Int): Int = js("var a = x; a + y")
|
||||
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CALLED_IN_SCOPE: scope=multiplyBy2 function=multiplyBy2$f
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: scope=multiplyBy2 function=multiplyBy2$f_0
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: scope=multiplyBy2 function=run
|
||||
// CHECK_CALLED_IN_SCOPE: scope=multiplyBy2_0 function=multiplyBy2_0$f
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: scope=multiplyBy2_0 function=multiplyBy2_0$f_0
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: scope=multiplyBy2_0 function=run
|
||||
|
||||
internal inline fun <T> runLambdaInLambda(noinline inner: (T) -> T, outer: ((T) -> T, T) -> T, arg: T): T {
|
||||
return outer(inner, arg)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: capturedInLambda
|
||||
// CHECK_CONTAINS_NO_CALLS: declaredInLambda
|
||||
// CHECK_CONTAINS_NO_CALLS: capturedInLambda_0
|
||||
// CHECK_CONTAINS_NO_CALLS: declaredInLambda_0
|
||||
|
||||
internal data class State(var count: Int = 0)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: localWithCapture
|
||||
// CHECK_CONTAINS_NO_CALLS: localWithoutCapture
|
||||
// CHECK_CONTAINS_NO_CALLS: localWithCapture_0
|
||||
// CHECK_CONTAINS_NO_CALLS: localWithoutCapture_0
|
||||
|
||||
internal inline fun repeatAction(times: Int, action: () -> Unit) {
|
||||
for (i in 1..times) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: add
|
||||
// CHECK_CONTAINS_NO_CALLS: add_0
|
||||
|
||||
internal data class State(var count: Int = 0)
|
||||
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: localWithCapture
|
||||
// CHECK_CONTAINS_NO_CALLS: localWithoutCapture
|
||||
// CHECK_CONTAINS_NO_CALLS: localWithCapture_0
|
||||
// CHECK_CONTAINS_NO_CALLS: localWithoutCapture_0
|
||||
|
||||
internal inline fun repeatAction(times: Int, action: () -> Unit) {
|
||||
for (i in 1..times) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: add
|
||||
// CHECK_CONTAINS_NO_CALLS: add_0
|
||||
|
||||
internal inline fun run(action: () -> Int): Int {
|
||||
return action()
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test1
|
||||
// CHECK_CONTAINS_NO_CALLS: test2
|
||||
// CHECK_CONTAINS_NO_CALLS: test3
|
||||
// CHECK_CONTAINS_NO_CALLS: test1_0
|
||||
// CHECK_CONTAINS_NO_CALLS: test2_0
|
||||
// CHECK_CONTAINS_NO_CALLS: test3_0
|
||||
// CHECK_CONTAINS_NO_CALLS: test4_buocd8$
|
||||
// CHECK_CONTAINS_NO_CALLS: test5
|
||||
// CHECK_CONTAINS_NO_CALLS: test5_0
|
||||
// CHECK_HAS_INLINE_METADATA: apply_hiyix$
|
||||
// CHECK_HAS_INLINE_METADATA: applyL_hiyix$
|
||||
// CHECK_HAS_INLINE_METADATA: applyL_0
|
||||
// CHECK_HAS_INLINE_METADATA: applyM_hiyix$
|
||||
// CHECK_HAS_NO_INLINE_METADATA: applyN
|
||||
// CHECK_HAS_NO_INLINE_METADATA: applyN_0
|
||||
// CHECK_HAS_NO_INLINE_METADATA: applyO_hiyix$
|
||||
|
||||
inline
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CALLED_IN_SCOPE: scope=multiplyBy2 function=multiplyBy2$f
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: scope=multiplyBy2 function=run
|
||||
// CHECK_CALLED_IN_SCOPE: scope=multiplyBy2_0 function=multiplyBy2_0$f
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: scope=multiplyBy2_0 function=run
|
||||
|
||||
internal inline fun <T> run(noinline func: (T) -> T, arg: T): T {
|
||||
return func(arg)
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: sum
|
||||
// CHECK_CONTAINS_NO_CALLS: sum_0
|
||||
|
||||
inline fun <T : Any, R> T.doLet(f: (T) -> R): R = f(this)
|
||||
|
||||
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
package foo
|
||||
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test1
|
||||
// CHECK_CONTAINS_NO_CALLS: test2
|
||||
// CHECK_CONTAINS_NO_CALLS: test3 except=slice
|
||||
// CHECK_CONTAINS_NO_CALLS: test1_0
|
||||
// CHECK_CONTAINS_NO_CALLS: test2_0
|
||||
// CHECK_CONTAINS_NO_CALLS: test3_0 except=slice
|
||||
|
||||
internal inline fun concat(vararg strings: String): String {
|
||||
var result = ""
|
||||
|
||||
@@ -23,9 +23,9 @@ package foo
|
||||
Thus, we need to be sure, that foo$() is not extracted to some temporary var.
|
||||
*/
|
||||
|
||||
// CHECK_NOT_CALLED: max
|
||||
// CHECK_NOT_CALLED: box$f
|
||||
// CHECK_NOT_CALLED: max_0
|
||||
// CHECK_NOT_CALLED: box$f_0
|
||||
// CHECK_NOT_CALLED: box$f_1
|
||||
|
||||
inline fun max(getA: ()->Int, b: Int): Int {
|
||||
val a = getA()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package foo
|
||||
|
||||
// CHECK_NOT_CALLED: f1
|
||||
// CHECK_NOT_CALLED: f2
|
||||
// CHECK_BREAKS_COUNT: function=test count=3
|
||||
// CHECK_NOT_CALLED: f1_0
|
||||
// CHECK_NOT_CALLED: f2_0
|
||||
// CHECK_BREAKS_COUNT: function=test_0 count=3
|
||||
|
||||
internal var even = arrayListOf<Int>()
|
||||
internal var odd = arrayListOf<Int>()
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test1
|
||||
// CHECK_CONTAINS_NO_CALLS: test2
|
||||
// CHECK_VARS_COUNT: function=test1 count=0
|
||||
// CHECK_VARS_COUNT: function=test2 count=1
|
||||
// CHECK_CONTAINS_NO_CALLS: test1_0
|
||||
// CHECK_CONTAINS_NO_CALLS: test2_0
|
||||
// CHECK_VARS_COUNT: function=test1_0 count=0
|
||||
// CHECK_VARS_COUNT: function=test2_0 count=1
|
||||
|
||||
var log = ""
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_VARS_COUNT: function=test count=0
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
// CHECK_VARS_COUNT: function=test_0 count=0
|
||||
|
||||
object SumHolder {
|
||||
var sum = 0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_VARS_COUNT: function=test count=0
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
// CHECK_VARS_COUNT: function=test_0 count=0
|
||||
|
||||
internal inline fun sign(x: Int): Int {
|
||||
if (x < 0) return -1
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_VARS_COUNT: function=test count=0
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
// CHECK_VARS_COUNT: function=test_0 count=0
|
||||
|
||||
// A copy of stdlib run function.
|
||||
// Copied to not to depend on run implementation.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_VARS_COUNT: function=test count=0
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
// CHECK_VARS_COUNT: function=test_0 count=0
|
||||
|
||||
internal class A(val x: Int) {
|
||||
inline fun f(): Int = x
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_VARS_COUNT: function=test count=1
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
// CHECK_VARS_COUNT: function=test_0 count=1
|
||||
|
||||
internal inline fun sum(x: Int, y: Int): Int {
|
||||
if (x == 0 || y == 0) return 0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_VARS_COUNT: function=test count=1
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
// CHECK_VARS_COUNT: function=test_0 count=1
|
||||
|
||||
internal inline fun sum(x: Int, y: Int): Int {
|
||||
if (x == 0 || y == 0) return 0
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: scope=test function=even
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: scope=test function=filter_azvtw4$
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: scope=test_0 function=even_0
|
||||
// CHECK_NOT_CALLED_IN_SCOPE: scope=test_0 function=filter_azvtw4$
|
||||
|
||||
internal fun even(x: Int) = x % 2 == 0
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal fun test(a: Int, b: Int): Int {
|
||||
var c = 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal fun test(a: Int, b: Int): Int {
|
||||
var res = 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal fun test(x: Int, y: Int): Int =
|
||||
with (x + x) {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal var counter = 0
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: testImplicitThis
|
||||
// CHECK_CONTAINS_NO_CALLS: testExplicitThis
|
||||
// CHECK_CONTAINS_NO_CALLS: testImplicitThis_0
|
||||
// CHECK_CONTAINS_NO_CALLS: testExplicitThis_0
|
||||
|
||||
internal class A(var value: Int)
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test
|
||||
// CHECK_LABELS_COUNT: function=test name=loop count=1
|
||||
// CHECK_LABELS_COUNT: function=test name=loop_0 count=1
|
||||
// CHECK_LABELS_COUNT: function=test name=loop_1 count=1
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
// CHECK_LABELS_COUNT: function=test_0 name=loop count=1
|
||||
// CHECK_LABELS_COUNT: function=test_0 name=loop_0 count=1
|
||||
// CHECK_LABELS_COUNT: function=test_0 name=loop_1 count=1
|
||||
|
||||
class State() {
|
||||
public var value: Int = 0
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
package foo
|
||||
|
||||
// CHECK_LABELS_COUNT: function=test name=loop count=1
|
||||
// CHECK_LABELS_COUNT: function=test name=loop_0 count=1
|
||||
// CHECK_LABELS_COUNT: function=test name=loop_1 count=1
|
||||
// CHECK_LABELS_COUNT: function=test_0 name=loop count=1
|
||||
// CHECK_LABELS_COUNT: function=test_0 name=loop_0 count=1
|
||||
// CHECK_LABELS_COUNT: function=test_0 name=loop_1 count=1
|
||||
|
||||
class State() {
|
||||
public var value: Int = 0
|
||||
|
||||
@@ -19,8 +19,8 @@ fun box(): String {
|
||||
|
||||
if (foo + bar != OK) return "$foo + $bar != $OK"
|
||||
|
||||
val actualAsString = funToString("actual")
|
||||
val expectedAsString = funToString("expected")
|
||||
val actualAsString = funToString("actual_0")
|
||||
val expectedAsString = funToString("expected_0")
|
||||
if (actualAsString != expectedAsString) return "$actualAsString != $expectedAsString"
|
||||
if (actual("asd", "12345") != "asd12345") return "${actual("asd", "12345")} != \"asd12345\""
|
||||
|
||||
|
||||
@@ -3,5 +3,5 @@ function A(v) {
|
||||
}
|
||||
|
||||
function nativeBox(b) {
|
||||
return b.bar(new A("foo"), function(i, s) { return "" + this.v + s + i })
|
||||
return b.bar_0(new A("foo"), function(i, s) { return "" + this.v + s + i })
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ fun box(): String {
|
||||
|
||||
val b: dynamic = object {val bar = ""}
|
||||
assertEquals(b.foo, undefined)
|
||||
assertNotEquals(b.bar, undefined)
|
||||
assertNotEquals(b.bar_0, undefined)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -38,8 +38,8 @@ fun box(): String {
|
||||
assertEquals(listOf(), getOwnPropertyNames(emptyObjectExpr))
|
||||
assertEquals(listOf(), keys(emptyObjectExpr))
|
||||
|
||||
assertEquals(listOf("foo", "bar"), getOwnPropertyNames(someObjectExpr))
|
||||
assertEquals(listOf("foo", "bar"), keys(someObjectExpr))
|
||||
assertEquals(listOf("foo_0", "bar_0"), getOwnPropertyNames(someObjectExpr))
|
||||
assertEquals(listOf("foo_0", "bar_0"), keys(someObjectExpr))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copy of JVM-backend test
|
||||
* Found at: compiler/testData/codegen/boxInline/trait/trait.1.kt
|
||||
*/
|
||||
|
||||
package foo
|
||||
|
||||
import test.*
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: testClassObject_0
|
||||
|
||||
internal fun testFinalInline(): String {
|
||||
return Z().finalInline({"final"})
|
||||
}
|
||||
|
||||
internal fun testFinalInline2(instance: InlineTrait): String {
|
||||
return instance.finalInline({"final2"})
|
||||
}
|
||||
|
||||
internal fun testClassObject(): String {
|
||||
return InlineTrait.finalInline({"classobject"})
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
if (testFinalInline() != "final") return "test1: ${testFinalInline()}"
|
||||
if (testFinalInline2(Z()) != "final2") return "test2: ${testFinalInline2(Z())}"
|
||||
if (testClassObject() != "classobject") return "test3: ${testClassObject()}"
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import utils.*
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal fun test(s: String): String = log(s + ";")
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("a;", test("a"))
|
||||
assertEquals("a;b;", test("b"))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import utils.*
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal fun multiplyBy2(x: Int): Int = x * 2
|
||||
|
||||
internal fun test(x: Int): Int = apply(x, ::multiplyBy2)
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(6, test(3))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal fun test(x: Int, y: Int): Int = utils.sum(x, y)
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(3, test(1, 2))
|
||||
assertEquals(5, test(2, 3))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import utils.*
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal class A(val n: Int)
|
||||
|
||||
internal fun test(a: A, m: Int): Int = apply(a) { n * m }
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(6, test(A(2), 3))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import utils.*
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal fun test(x: Int): Int = apply(x) { it * 2 }
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(6, test(3))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import utils.*
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal fun test(x: Int, y: Int): Int = apply(x) { it + y }
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(3, test(1, 2))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import utils.*
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal fun test(x: Int, y: Int): Int = apply(x) { it + 1 } * y
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(6, test(1, 3))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import utils.*
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal fun test(a: A, y: Int): Int = a.plus(y)
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(5, test(A(2), 3))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import utils.*
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test_0
|
||||
|
||||
internal fun test(x: Int, y: Int): Int = sum(x, y)
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(3, test(1, 2))
|
||||
assertEquals(5, test(2, 3))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user