JS: generate metadata for public inline functions
This commit is contained in:
+10
-11
@@ -45,6 +45,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
import static org.jetbrains.kotlin.resolve.InlineDescriptorUtils.allowsNonLocalReturns;
|
import static org.jetbrains.kotlin.resolve.InlineDescriptorUtils.allowsNonLocalReturns;
|
||||||
import static org.jetbrains.kotlin.resolve.InlineDescriptorUtils.checkNonLocalReturnUsage;
|
import static org.jetbrains.kotlin.resolve.InlineDescriptorUtils.checkNonLocalReturnUsage;
|
||||||
|
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getIsEffectivelyPublicApi;
|
||||||
|
|
||||||
class InlineChecker implements CallChecker {
|
class InlineChecker implements CallChecker {
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@ class InlineChecker implements CallChecker {
|
|||||||
public InlineChecker(@NotNull SimpleFunctionDescriptor descriptor) {
|
public InlineChecker(@NotNull SimpleFunctionDescriptor descriptor) {
|
||||||
assert descriptor.getInlineStrategy().isInline() : "This extension should be created only for inline functions but not " + descriptor;
|
assert descriptor.getInlineStrategy().isInline() : "This extension should be created only for inline functions but not " + descriptor;
|
||||||
this.descriptor = descriptor;
|
this.descriptor = descriptor;
|
||||||
this.isEffectivelyPublicApiFunction = isEffectivelyPublicApi(descriptor);
|
this.isEffectivelyPublicApiFunction = getIsEffectivelyPublicApi(descriptor);
|
||||||
|
|
||||||
for (ValueParameterDescriptor param : descriptor.getValueParameters()) {
|
for (ValueParameterDescriptor param : descriptor.getValueParameters()) {
|
||||||
if (isInlinableParameter(param)) {
|
if (isInlinableParameter(param)) {
|
||||||
@@ -242,24 +243,22 @@ class InlineChecker implements CallChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkVisibility(@NotNull CallableDescriptor declarationDescriptor, @NotNull JetElement expression, @NotNull BasicCallResolutionContext context){
|
private void checkVisibility(@NotNull CallableDescriptor declarationDescriptor, @NotNull JetElement expression, @NotNull BasicCallResolutionContext context){
|
||||||
if (isEffectivelyPublicApiFunction && !isEffectivelyPublicApi(declarationDescriptor) && declarationDescriptor.getVisibility() != Visibilities.LOCAL) {
|
boolean declarationDescriptorIsPublicApi = getIsEffectivelyPublicApi(declarationDescriptor) || isDefinedInInlineFunction(declarationDescriptor);
|
||||||
|
if (isEffectivelyPublicApiFunction && !declarationDescriptorIsPublicApi && declarationDescriptor.getVisibility() != Visibilities.LOCAL) {
|
||||||
context.trace.report(Errors.INVISIBLE_MEMBER_FROM_INLINE.on(expression, declarationDescriptor, descriptor));
|
context.trace.report(Errors.INVISIBLE_MEMBER_FROM_INLINE.on(expression, declarationDescriptor, descriptor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isEffectivelyPublicApi(@NotNull DeclarationDescriptorWithVisibility startDescriptor) {
|
private boolean isDefinedInInlineFunction(@NotNull DeclarationDescriptorWithVisibility startDescriptor) {
|
||||||
DeclarationDescriptorWithVisibility parent = startDescriptor;
|
DeclarationDescriptorWithVisibility parent = startDescriptor;
|
||||||
|
|
||||||
while (parent != null) {
|
while (parent != null) {
|
||||||
if (!parent.getVisibility().isPublicAPI()) {
|
if (parent.getContainingDeclaration() == descriptor) return true;
|
||||||
if (parent.getContainingDeclaration() == descriptor) {
|
|
||||||
//skip all defined in inline function
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
parent = DescriptorUtils.getParentOfType(parent, DeclarationDescriptorWithVisibility.class);
|
parent = DescriptorUtils.getParentOfType(parent, DeclarationDescriptorWithVisibility.class);
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkNonLocalReturn(
|
private void checkNonLocalReturn(
|
||||||
|
|||||||
@@ -68,4 +68,17 @@ public val ClassDescriptor.classObjectDescriptor: ClassDescriptor?
|
|||||||
}
|
}
|
||||||
else -> getDefaultObjectDescriptor()
|
else -> getDefaultObjectDescriptor()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public val DeclarationDescriptorWithVisibility.isEffectivelyPublicApi: Boolean
|
||||||
|
get() {
|
||||||
|
var parent: DeclarationDescriptorWithVisibility? = this
|
||||||
|
|
||||||
|
while (parent != null) {
|
||||||
|
if (!parent!!.getVisibility().isPublicAPI()) return false
|
||||||
|
|
||||||
|
parent = DescriptorUtils.getParentOfType(parent, javaClass<DeclarationDescriptorWithVisibility>())
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ public final class TopDownAnalyzerFacadeForJS {
|
|||||||
? new BindingTraceContext()
|
? new BindingTraceContext()
|
||||||
: new DelegatingBindingTrace(libraryContext, "trace with preanalyzed library");
|
: new DelegatingBindingTrace(libraryContext, "trace with preanalyzed library");
|
||||||
|
|
||||||
ModuleDescriptorImpl module = createJsModule("<module>");
|
ModuleDescriptorImpl module = createJsModule("<" + config.getModuleId() + ">");
|
||||||
module.addDependencyOnModule(module);
|
module.addDependencyOnModule(module);
|
||||||
module.addDependencyOnModule(KotlinBuiltIns.getInstance().getBuiltInsModule());
|
module.addDependencyOnModule(KotlinBuiltIns.getInstance().getBuiltInsModule());
|
||||||
ModuleDescriptor libraryModule = config.getLibraryModule();
|
ModuleDescriptor libraryModule = config.getLibraryModule();
|
||||||
|
|||||||
+12
-13
@@ -16,11 +16,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.inline.util.collectors
|
package org.jetbrains.kotlin.js.inline.util.collectors
|
||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.RecursiveJsVisitor
|
import com.google.dart.compiler.backend.js.ast.*
|
||||||
import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer
|
import org.jetbrains.kotlin.js.translate.expression.InlineMetadata
|
||||||
import com.google.dart.compiler.backend.js.ast.JsNameRef
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsFunction
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsName
|
|
||||||
|
|
||||||
import java.util.IdentityHashMap
|
import java.util.IdentityHashMap
|
||||||
|
|
||||||
@@ -30,16 +27,18 @@ class FunctionCollector : RecursiveJsVisitor() {
|
|||||||
override fun visitPropertyInitializer(x: JsPropertyInitializer?) {
|
override fun visitPropertyInitializer(x: JsPropertyInitializer?) {
|
||||||
super.visitPropertyInitializer(x)
|
super.visitPropertyInitializer(x)
|
||||||
|
|
||||||
val label = x?.getLabelExpr()
|
val label = x?.getLabelExpr() as? JsNameRef
|
||||||
|
val name = label?.getName()
|
||||||
|
if (name == null) return
|
||||||
|
|
||||||
val value = x?.getValueExpr()
|
val value = x?.getValueExpr()
|
||||||
|
val function = when (value) {
|
||||||
|
is JsFunction -> value
|
||||||
|
else -> InlineMetadata.decompose(value)?.function
|
||||||
|
}
|
||||||
|
|
||||||
if (label is JsNameRef && value is JsFunction) {
|
if (function is JsFunction) {
|
||||||
val name = label.getName()
|
functions[name] = function
|
||||||
val function = value as JsFunction
|
|
||||||
|
|
||||||
if (name != null) {
|
|
||||||
functions[name] = function
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,15 +17,22 @@
|
|||||||
package org.jetbrains.kotlin.js.translate.context;
|
package org.jetbrains.kotlin.js.translate.context;
|
||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.*;
|
import com.google.dart.compiler.backend.js.ast.*;
|
||||||
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||||
import org.jetbrains.kotlin.idea.JetLanguage;
|
import org.jetbrains.kotlin.idea.JetLanguage;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import static com.google.dart.compiler.backend.js.ast.AstPackage.JsObjectScope;
|
import static com.google.dart.compiler.backend.js.ast.AstPackage.JsObjectScope;
|
||||||
|
import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getModuleName;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getStableMangledNameForDescriptor;
|
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getStableMangledNameForDescriptor;
|
||||||
|
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName;
|
||||||
|
import static org.jetbrains.kotlin.resolve.DescriptorUtils.getFqNameSafe;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates different types of constants and naming conventions.
|
* Encapsulates different types of constants and naming conventions.
|
||||||
@@ -83,6 +90,10 @@ public final class Namer {
|
|||||||
private static final String PROTOTYPE_NAME = "prototype";
|
private static final String PROTOTYPE_NAME = "prototype";
|
||||||
public static final String CAPTURED_VAR_FIELD = "v";
|
public static final String CAPTURED_VAR_FIELD = "v";
|
||||||
|
|
||||||
|
public static final JsNameRef CREATE_INLINE_FUNCTION = new JsNameRef("defineInlineFunction", KOTLIN_OBJECT_REF);
|
||||||
|
private static final String INLINE_START_TAG = "inlineStartTag";
|
||||||
|
private static final String INLINE_END_TAG = "inlineEndTag";
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static final JsExpression UNDEFINED_EXPRESSION = new JsPrefixOperation(JsUnaryOperator.VOID, JsNumberLiteral.ZERO);
|
public static final JsExpression UNDEFINED_EXPRESSION = new JsPrefixOperation(JsUnaryOperator.VOID, JsNumberLiteral.ZERO);
|
||||||
|
|
||||||
@@ -96,6 +107,27 @@ public final class Namer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static String getInlineStartTag(@NotNull CallableDescriptor functionDescriptor) {
|
||||||
|
return formatInlineTag(functionDescriptor, INLINE_START_TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static String getInlineEndTag(@NotNull CallableDescriptor functionDescriptor) {
|
||||||
|
return formatInlineTag(functionDescriptor, INLINE_END_TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static String formatInlineTag(
|
||||||
|
@NotNull CallableDescriptor functionDescriptor,
|
||||||
|
@NotNull String tag
|
||||||
|
) {
|
||||||
|
FqName fqName = getFqNameSafe(functionDescriptor);
|
||||||
|
String mangledName = getSuggestedName(functionDescriptor);
|
||||||
|
String moduleName = getModuleName(functionDescriptor);
|
||||||
|
return StringUtil.join(Arrays.asList(tag, moduleName, fqName, mangledName), ".");
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static String getReceiverParameterName() {
|
public static String getReceiverParameterName() {
|
||||||
return RECEIVER_PARAMETER_NAME;
|
return RECEIVER_PARAMETER_NAME;
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.js.translate.context;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.dart.compiler.backend.js.ast.*;
|
import com.google.dart.compiler.backend.js.ast.*;
|
||||||
import com.intellij.openapi.util.Factory;
|
import com.intellij.openapi.util.Factory;
|
||||||
import com.intellij.psi.PsiElement;
|
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -40,12 +39,10 @@ import org.jetbrains.kotlin.types.reflect.ReflectionTypes;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.js.config.LibrarySourcesConfig.BUILTINS_JS_MODULE_NAME;
|
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.*;
|
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.*;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.*;
|
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.getMangledName;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName;
|
import static org.jetbrains.kotlin.js.translate.utils.ManglingUtils.getSuggestedName;
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isExtension;
|
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isExtension;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -486,22 +483,6 @@ public final class StaticContext {
|
|||||||
return JsAstUtils.replaceRootReference(
|
return JsAstUtils.replaceRootReference(
|
||||||
result, new JsArrayAccess(namer.kotlin("modules"), program.getStringLiteral(moduleName)));
|
result, new JsArrayAccess(namer.kotlin("modules"), program.getStringLiteral(moduleName)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getExternalModuleName(DeclarationDescriptor descriptor) {
|
|
||||||
if (isBuiltin(descriptor)) return BUILTINS_JS_MODULE_NAME;
|
|
||||||
|
|
||||||
PsiElement element = descriptorToDeclaration(descriptor);
|
|
||||||
if (element == null && descriptor instanceof PropertyAccessorDescriptor) {
|
|
||||||
element = descriptorToDeclaration(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element == null) {
|
|
||||||
ModuleDescriptor moduleDescriptor = DescriptorUtils.getContainingModule(descriptor);
|
|
||||||
String moduleName = moduleDescriptor.getName().asString();
|
|
||||||
return moduleName.substring(1, moduleName.length()-1);
|
|
||||||
}
|
|
||||||
return element.getContainingFile().getUserData(LibrarySourcesConfig.EXTERNAL_MODULE_NAME);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
Rule<JsExpression> constructorOrDefaultObjectHasTheSameQualifierAsTheClass = new Rule<JsExpression>() {
|
Rule<JsExpression> constructorOrDefaultObjectHasTheSameQualifierAsTheClass = new Rule<JsExpression>() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+10
-8
@@ -17,18 +17,12 @@
|
|||||||
package org.jetbrains.kotlin.js.translate.expression;
|
package org.jetbrains.kotlin.js.translate.expression;
|
||||||
|
|
||||||
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsFunction;
|
import com.google.dart.compiler.backend.js.ast.*;
|
||||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsParameter;
|
|
||||||
import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer;
|
|
||||||
import com.google.dart.compiler.backend.js.ast.metadata.MetadataPackage;
|
import com.google.dart.compiler.backend.js.ast.metadata.MetadataPackage;
|
||||||
import com.intellij.util.SmartList;
|
import com.intellij.util.SmartList;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality;
|
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
|
||||||
import org.jetbrains.kotlin.js.translate.context.AliasingContext;
|
import org.jetbrains.kotlin.js.translate.context.AliasingContext;
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer;
|
import org.jetbrains.kotlin.js.translate.context.Namer;
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||||
@@ -41,10 +35,12 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator.shouldBeInlined;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getFunctionDescriptor;
|
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getFunctionDescriptor;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.ErrorReportingUtils.message;
|
import static org.jetbrains.kotlin.js.translate.utils.ErrorReportingUtils.message;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.translateFunctionBody;
|
import static org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.translateFunctionBody;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.setParameters;
|
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.setParameters;
|
||||||
|
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getIsEffectivelyPublicApi;
|
||||||
|
|
||||||
public final class FunctionTranslator extends AbstractTranslator {
|
public final class FunctionTranslator extends AbstractTranslator {
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -101,6 +97,12 @@ public final class FunctionTranslator extends AbstractTranslator {
|
|||||||
public JsPropertyInitializer translateAsMethod() {
|
public JsPropertyInitializer translateAsMethod() {
|
||||||
JsName functionName = context().getNameForDescriptor(descriptor);
|
JsName functionName = context().getNameForDescriptor(descriptor);
|
||||||
generateFunctionObject();
|
generateFunctionObject();
|
||||||
|
|
||||||
|
if (shouldBeInlined(descriptor) && getIsEffectivelyPublicApi(descriptor)) {
|
||||||
|
InlineMetadata metadata = InlineMetadata.compose(functionObject, descriptor);
|
||||||
|
return new JsPropertyInitializer(functionName.makeRef(), metadata.getFunctionWithMetadata());
|
||||||
|
}
|
||||||
|
|
||||||
return new JsPropertyInitializer(functionName.makeRef(), functionObject);
|
return new JsPropertyInitializer(functionName.makeRef(), functionObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 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.translate.expression
|
||||||
|
|
||||||
|
import com.google.dart.compiler.backend.js.ast.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
|
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.*
|
||||||
|
|
||||||
|
import kotlin.platform.platformStatic
|
||||||
|
|
||||||
|
private val METADATA_PROPERTIES_COUNT = 3
|
||||||
|
|
||||||
|
public class InlineMetadata(
|
||||||
|
val startTag: JsStringLiteral,
|
||||||
|
val function: JsFunction,
|
||||||
|
val endTag: JsStringLiteral
|
||||||
|
) {
|
||||||
|
class object {
|
||||||
|
platformStatic
|
||||||
|
fun compose(function: JsFunction, descriptor: CallableDescriptor): InlineMetadata {
|
||||||
|
val program = function.getScope().getProgram()
|
||||||
|
val startTag = program.getStringLiteral(Namer.getInlineStartTag(descriptor))
|
||||||
|
val endTag = program.getStringLiteral(Namer.getInlineEndTag(descriptor))
|
||||||
|
return InlineMetadata(startTag, function, endTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads metadata from expression.
|
||||||
|
*
|
||||||
|
* To read metadata from source one needs to:
|
||||||
|
* 1. find index of startTag and endTag in source;
|
||||||
|
* 2. parse substring between startTagIndex - 1 (for opening quote)
|
||||||
|
* and endTagIndex + endTag.length() + 1 (for closing quote)
|
||||||
|
* 3. call InlineMetadata#decompose on resulting expression
|
||||||
|
*
|
||||||
|
* @see Namer#getInlineStartTag
|
||||||
|
* @see Namer#getInlineEndTag
|
||||||
|
* @see com.google.gwt.dev.js.JsParser
|
||||||
|
*/
|
||||||
|
platformStatic
|
||||||
|
fun decompose(expression: JsExpression?): InlineMetadata? =
|
||||||
|
when (expression) {
|
||||||
|
is JsBinaryOperation -> decomposeCommaExpression(expression)
|
||||||
|
is JsInvocation -> decomposeCreateFunctionCall(expression)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun decomposeCreateFunctionCall(call: JsInvocation): InlineMetadata? {
|
||||||
|
if (Namer.CREATE_INLINE_FUNCTION != call.getQualifier()) return null
|
||||||
|
|
||||||
|
return decomposePropertiesList(call.getArguments())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun decomposeCommaExpression(expression: JsExpression): InlineMetadata? {
|
||||||
|
val properties = arrayListOf<JsExpression>()
|
||||||
|
var decomposable: JsExpression? = expression
|
||||||
|
|
||||||
|
while (decomposable is JsExpression) {
|
||||||
|
val binOp = decomposable as? JsBinaryOperation
|
||||||
|
|
||||||
|
if (JsBinaryOperator.COMMA == binOp?.getOperator()) {
|
||||||
|
properties.add(binOp?.getArg2())
|
||||||
|
decomposable = binOp?.getArg1()
|
||||||
|
} else {
|
||||||
|
properties.add(decomposable)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return decomposePropertiesList(properties.reverse())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun decomposePropertiesList(properties: List<JsExpression>): InlineMetadata? {
|
||||||
|
if (properties.size() != METADATA_PROPERTIES_COUNT) return null
|
||||||
|
|
||||||
|
val startTag = properties[0] as? JsStringLiteral
|
||||||
|
val function = properties[1] as? JsFunction
|
||||||
|
val endTag = properties[2] as? JsStringLiteral
|
||||||
|
|
||||||
|
if (startTag == null || function == null || endTag == null) return null
|
||||||
|
|
||||||
|
return InlineMetadata(startTag, function, endTag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public val functionWithMetadata: JsExpression
|
||||||
|
get() {
|
||||||
|
val propertiesList = listOf(startTag, function, endTag)
|
||||||
|
return JsInvocation(Namer.CREATE_INLINE_FUNCTION, propertiesList)
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
@@ -89,6 +89,10 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl
|
|||||||
descriptor = resolvedCall.getCandidateDescriptor();
|
descriptor = resolvedCall.getCandidateDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return shouldBeInlined(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shouldBeInlined(@NotNull CallableDescriptor descriptor) {
|
||||||
if (descriptor instanceof SimpleFunctionDescriptor) {
|
if (descriptor instanceof SimpleFunctionDescriptor) {
|
||||||
return ((SimpleFunctionDescriptor) descriptor).getInlineStrategy().isInline();
|
return ((SimpleFunctionDescriptor) descriptor).getInlineStrategy().isInline();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,13 @@
|
|||||||
package org.jetbrains.kotlin.js.translate.utils;
|
package org.jetbrains.kotlin.js.translate.utils;
|
||||||
|
|
||||||
import com.intellij.openapi.util.Condition;
|
import com.intellij.openapi.util.Condition;
|
||||||
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
|
import org.jetbrains.kotlin.js.config.LibrarySourcesConfig;
|
||||||
import org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsPackage;
|
import org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsPackage;
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
|
||||||
import org.jetbrains.kotlin.name.Name;
|
import org.jetbrains.kotlin.name.Name;
|
||||||
@@ -37,7 +39,9 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.jetbrains.kotlin.js.config.LibrarySourcesConfig.BUILTINS_JS_MODULE_NAME;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject;
|
import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject;
|
||||||
|
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||||
|
|
||||||
public final class JsDescriptorUtils {
|
public final class JsDescriptorUtils {
|
||||||
@@ -161,4 +165,32 @@ public final class JsDescriptorUtils {
|
|||||||
JetType type = context.bindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
|
JetType type = context.bindingContext().get(BindingContext.EXPRESSION_TYPE, expression);
|
||||||
return type != null ? DescriptorUtilsPackage.getNameIfStandardType(type) : null;
|
return type != null ? DescriptorUtilsPackage.getNameIfStandardType(type) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static String getModuleName(@NotNull DeclarationDescriptor descriptor) {
|
||||||
|
String externalModuleName = getExternalModuleName(descriptor);
|
||||||
|
if (externalModuleName != null) return externalModuleName;
|
||||||
|
|
||||||
|
return getModuleNameFromDescriptorName(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static String getExternalModuleName(@NotNull DeclarationDescriptor descriptor) {
|
||||||
|
if (isBuiltin(descriptor)) return BUILTINS_JS_MODULE_NAME;
|
||||||
|
|
||||||
|
PsiElement element = descriptorToDeclaration(descriptor);
|
||||||
|
if (element == null && descriptor instanceof PropertyAccessorDescriptor) {
|
||||||
|
element = descriptorToDeclaration(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element == null) return getModuleNameFromDescriptorName(descriptor);
|
||||||
|
|
||||||
|
return element.getContainingFile().getUserData(LibrarySourcesConfig.EXTERNAL_MODULE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getModuleNameFromDescriptorName(DeclarationDescriptor descriptor) {
|
||||||
|
ModuleDescriptor moduleDescriptor = DescriptorUtils.getContainingModule(descriptor);
|
||||||
|
String moduleName = moduleDescriptor.getName().asString();
|
||||||
|
return moduleName.substring(1, moduleName.length() - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -475,4 +475,8 @@ var Kotlin = {};
|
|||||||
Object.defineProperty(Kotlin.modules, id, {value: declaration});
|
Object.defineProperty(Kotlin.modules, id, {value: declaration});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Kotlin.defineInlineFunction = function(startTag, fun, metadataArgs) {
|
||||||
|
return fun;
|
||||||
|
};
|
||||||
|
|
||||||
})(Kotlin);
|
})(Kotlin);
|
||||||
|
|||||||
Reference in New Issue
Block a user