Avoid duplication of imports introduced during JS inlining
This commit is contained in:
+91
-13
@@ -47071,6 +47071,15 @@ public final class DebugJsAstProtoBuf {
|
|||||||
* <code>optional int32 local_name_id = 3;</code>
|
* <code>optional int32 local_name_id = 3;</code>
|
||||||
*/
|
*/
|
||||||
int getLocalNameId();
|
int getLocalNameId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
boolean hasImported();
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
boolean getImported();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Protobuf type {@code org.jetbrains.kotlin.serialization.js.ast.Name}
|
* Protobuf type {@code org.jetbrains.kotlin.serialization.js.ast.Name}
|
||||||
@@ -47139,6 +47148,11 @@ public final class DebugJsAstProtoBuf {
|
|||||||
localNameId_ = input.readInt32();
|
localNameId_ = input.readInt32();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 32: {
|
||||||
|
bitField0_ |= 0x00000008;
|
||||||
|
imported_ = input.readBool();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
|
} catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
|
||||||
@@ -47224,10 +47238,26 @@ public final class DebugJsAstProtoBuf {
|
|||||||
return localNameId_;
|
return localNameId_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final int IMPORTED_FIELD_NUMBER = 4;
|
||||||
|
private boolean imported_;
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
public boolean hasImported() {
|
||||||
|
return ((bitField0_ & 0x00000008) == 0x00000008);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
public boolean getImported() {
|
||||||
|
return imported_;
|
||||||
|
}
|
||||||
|
|
||||||
private void initFields() {
|
private void initFields() {
|
||||||
temporary_ = false;
|
temporary_ = false;
|
||||||
identifier_ = 0;
|
identifier_ = 0;
|
||||||
localNameId_ = 0;
|
localNameId_ = 0;
|
||||||
|
imported_ = false;
|
||||||
}
|
}
|
||||||
private byte memoizedIsInitialized = -1;
|
private byte memoizedIsInitialized = -1;
|
||||||
public final boolean isInitialized() {
|
public final boolean isInitialized() {
|
||||||
@@ -47255,6 +47285,9 @@ public final class DebugJsAstProtoBuf {
|
|||||||
if (((bitField0_ & 0x00000004) == 0x00000004)) {
|
if (((bitField0_ & 0x00000004) == 0x00000004)) {
|
||||||
output.writeInt32(3, localNameId_);
|
output.writeInt32(3, localNameId_);
|
||||||
}
|
}
|
||||||
|
if (((bitField0_ & 0x00000008) == 0x00000008)) {
|
||||||
|
output.writeBool(4, imported_);
|
||||||
|
}
|
||||||
getUnknownFields().writeTo(output);
|
getUnknownFields().writeTo(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47276,6 +47309,10 @@ public final class DebugJsAstProtoBuf {
|
|||||||
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
|
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
|
||||||
.computeInt32Size(3, localNameId_);
|
.computeInt32Size(3, localNameId_);
|
||||||
}
|
}
|
||||||
|
if (((bitField0_ & 0x00000008) == 0x00000008)) {
|
||||||
|
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
|
||||||
|
.computeBoolSize(4, imported_);
|
||||||
|
}
|
||||||
size += getUnknownFields().getSerializedSize();
|
size += getUnknownFields().getSerializedSize();
|
||||||
memoizedSerializedSize = size;
|
memoizedSerializedSize = size;
|
||||||
return size;
|
return size;
|
||||||
@@ -47399,6 +47436,8 @@ public final class DebugJsAstProtoBuf {
|
|||||||
bitField0_ = (bitField0_ & ~0x00000002);
|
bitField0_ = (bitField0_ & ~0x00000002);
|
||||||
localNameId_ = 0;
|
localNameId_ = 0;
|
||||||
bitField0_ = (bitField0_ & ~0x00000004);
|
bitField0_ = (bitField0_ & ~0x00000004);
|
||||||
|
imported_ = false;
|
||||||
|
bitField0_ = (bitField0_ & ~0x00000008);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47439,6 +47478,10 @@ public final class DebugJsAstProtoBuf {
|
|||||||
to_bitField0_ |= 0x00000004;
|
to_bitField0_ |= 0x00000004;
|
||||||
}
|
}
|
||||||
result.localNameId_ = localNameId_;
|
result.localNameId_ = localNameId_;
|
||||||
|
if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
|
||||||
|
to_bitField0_ |= 0x00000008;
|
||||||
|
}
|
||||||
|
result.imported_ = imported_;
|
||||||
result.bitField0_ = to_bitField0_;
|
result.bitField0_ = to_bitField0_;
|
||||||
onBuilt();
|
onBuilt();
|
||||||
return result;
|
return result;
|
||||||
@@ -47464,6 +47507,9 @@ public final class DebugJsAstProtoBuf {
|
|||||||
if (other.hasLocalNameId()) {
|
if (other.hasLocalNameId()) {
|
||||||
setLocalNameId(other.getLocalNameId());
|
setLocalNameId(other.getLocalNameId());
|
||||||
}
|
}
|
||||||
|
if (other.hasImported()) {
|
||||||
|
setImported(other.getImported());
|
||||||
|
}
|
||||||
this.mergeUnknownFields(other.getUnknownFields());
|
this.mergeUnknownFields(other.getUnknownFields());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -47591,6 +47637,38 @@ public final class DebugJsAstProtoBuf {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean imported_ ;
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
public boolean hasImported() {
|
||||||
|
return ((bitField0_ & 0x00000008) == 0x00000008);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
public boolean getImported() {
|
||||||
|
return imported_;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
public Builder setImported(boolean value) {
|
||||||
|
bitField0_ |= 0x00000008;
|
||||||
|
imported_ = value;
|
||||||
|
onChanged();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
public Builder clearImported() {
|
||||||
|
bitField0_ = (bitField0_ & ~0x00000008);
|
||||||
|
imported_ = false;
|
||||||
|
onChanged();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.serialization.js.ast.Name)
|
// @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.serialization.js.ast.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49082,19 +49160,19 @@ public final class DebugJsAstProtoBuf {
|
|||||||
"ule\022\024\n\014signature_id\030\001 \002(\005\022\025\n\rexpression_" +
|
"ule\022\024\n\014signature_id\030\001 \002(\005\022\025\n\rexpression_" +
|
||||||
"id\030\002 \002(\005\"\034\n\013StringTable\022\r\n\005entry\030\001 \003(\t\"K" +
|
"id\030\002 \002(\005\"\034\n\013StringTable\022\r\n\005entry\030\001 \003(\t\"K" +
|
||||||
"\n\tNameTable\022>\n\005entry\030\001 \003(\0132/.org.jetbrai",
|
"\n\tNameTable\022>\n\005entry\030\001 \003(\0132/.org.jetbrai",
|
||||||
"ns.kotlin.serialization.js.ast.Name\"D\n\004N" +
|
"ns.kotlin.serialization.js.ast.Name\"V\n\004N" +
|
||||||
"ame\022\021\n\ttemporary\030\001 \002(\010\022\022\n\nidentifier\030\002 \001" +
|
"ame\022\021\n\ttemporary\030\001 \002(\010\022\022\n\nidentifier\030\002 \001" +
|
||||||
"(\005\022\025\n\rlocal_name_id\030\003 \001(\005\"\346\001\n\005Chunk\022L\n\014s" +
|
"(\005\022\025\n\rlocal_name_id\030\003 \001(\005\022\020\n\010imported\030\004 " +
|
||||||
"tring_table\030\001 \002(\01326.org.jetbrains.kotlin" +
|
"\001(\010\"\346\001\n\005Chunk\022L\n\014string_table\030\001 \002(\01326.or" +
|
||||||
".serialization.js.ast.StringTable\022H\n\nnam" +
|
"g.jetbrains.kotlin.serialization.js.ast." +
|
||||||
"e_table\030\002 \002(\01324.org.jetbrains.kotlin.ser" +
|
"StringTable\022H\n\nname_table\030\002 \002(\01324.org.je" +
|
||||||
"ialization.js.ast.NameTable\022E\n\010fragment\030" +
|
"tbrains.kotlin.serialization.js.ast.Name" +
|
||||||
"\003 \002(\01323.org.jetbrains.kotlin.serializati" +
|
"Table\022E\n\010fragment\030\003 \002(\01323.org.jetbrains." +
|
||||||
"on.js.ast.Fragment*@\n\013SideEffects\022\021\n\rAFF" +
|
"kotlin.serialization.js.ast.Fragment*@\n\013" +
|
||||||
"ECTS_STATE\020\001\022\024\n\020DEPENDS_ON_STATE\020\002\022\010\n\004PU",
|
"SideEffects\022\021\n\rAFFECTS_STATE\020\001\022\024\n\020DEPEND",
|
||||||
"RE\020\003*?\n\016InlineStrategy\022\017\n\013AS_FUNCTION\020\000\022" +
|
"S_ON_STATE\020\002\022\010\n\004PURE\020\003*?\n\016InlineStrategy" +
|
||||||
"\014\n\010IN_PLACE\020\001\022\016\n\nNOT_INLINE\020\002B\024B\022DebugJs" +
|
"\022\017\n\013AS_FUNCTION\020\000\022\014\n\010IN_PLACE\020\001\022\016\n\nNOT_I" +
|
||||||
"AstProtoBuf"
|
"NLINE\020\002B\024B\022DebugJsAstProtoBuf"
|
||||||
};
|
};
|
||||||
org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||||
new org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
|
new org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
|
||||||
@@ -49431,7 +49509,7 @@ public final class DebugJsAstProtoBuf {
|
|||||||
internal_static_org_jetbrains_kotlin_serialization_js_ast_Name_fieldAccessorTable = new
|
internal_static_org_jetbrains_kotlin_serialization_js_ast_Name_fieldAccessorTable = new
|
||||||
org.jetbrains.kotlin.protobuf.GeneratedMessage.FieldAccessorTable(
|
org.jetbrains.kotlin.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||||
internal_static_org_jetbrains_kotlin_serialization_js_ast_Name_descriptor,
|
internal_static_org_jetbrains_kotlin_serialization_js_ast_Name_descriptor,
|
||||||
new java.lang.String[] { "Temporary", "Identifier", "LocalNameId", });
|
new java.lang.String[] { "Temporary", "Identifier", "LocalNameId", "Imported", });
|
||||||
internal_static_org_jetbrains_kotlin_serialization_js_ast_Chunk_descriptor =
|
internal_static_org_jetbrains_kotlin_serialization_js_ast_Chunk_descriptor =
|
||||||
getDescriptor().getMessageTypes().get(54);
|
getDescriptor().getMessageTypes().get(54);
|
||||||
internal_static_org_jetbrains_kotlin_serialization_js_ast_Chunk_fieldAccessorTable = new
|
internal_static_org_jetbrains_kotlin_serialization_js_ast_Chunk_fieldAccessorTable = new
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.builtins.isFunctionTypeOrSubtype
|
|||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind
|
import org.jetbrains.kotlin.js.backend.ast.metadata.SideEffectKind
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.metadata.imported
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.inlineStrategy
|
import org.jetbrains.kotlin.js.backend.ast.metadata.inlineStrategy
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects
|
import org.jetbrains.kotlin.js.backend.ast.metadata.sideEffects
|
||||||
import org.jetbrains.kotlin.js.config.JsConfig
|
import org.jetbrains.kotlin.js.config.JsConfig
|
||||||
@@ -237,6 +238,12 @@ class FunctionReader(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
wrapperStatements?.forEach {
|
||||||
|
if (it is JsVars && it.vars.size == 1 && it.vars[0].initExpression?.let { extractImportTag(it) } != null) {
|
||||||
|
it.vars[0].name.imported = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return FunctionWithWrapper(function, wrapper)
|
return FunctionWithWrapper(function, wrapper)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
|||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink;
|
import org.jetbrains.kotlin.diagnostics.DiagnosticSink;
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||||
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor;
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
|
||||||
import org.jetbrains.kotlin.js.config.JsConfig;
|
import org.jetbrains.kotlin.js.config.JsConfig;
|
||||||
@@ -42,6 +41,7 @@ import java.util.*;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.jetbrains.kotlin.js.inline.util.CollectUtilsKt.getImportTag;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.flattenStatement;
|
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.flattenStatement;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
|
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
|
||||||
|
|
||||||
@@ -92,6 +92,8 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (JsProgramFragment fragment : fragmentsToProcess) {
|
for (JsProgramFragment fragment : fragmentsToProcess) {
|
||||||
|
inliner.existingImports.clear();
|
||||||
|
|
||||||
inliner.inliningContexts.push(inliner.new JsInliningContext(inliner.new ListContext<JsStatement>()));
|
inliner.inliningContexts.push(inliner.new JsInliningContext(inliner.new ListContext<JsStatement>()));
|
||||||
inliner.acceptStatement(fragment.getDeclarationBlock());
|
inliner.acceptStatement(fragment.getDeclarationBlock());
|
||||||
|
|
||||||
@@ -146,18 +148,6 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static String getImportTag(JsVars jsVars) {
|
|
||||||
if (jsVars.getVars().size() == 1) {
|
|
||||||
JsVars.JsVar jsVar = jsVars.getVars().get(0);
|
|
||||||
if (jsVar.getInitExpression() != null) {
|
|
||||||
return extractImportTag(jsVar.getInitExpression());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean visit(@NotNull JsFunction function, @NotNull JsContext context) {
|
public boolean visit(@NotNull JsFunction function, @NotNull JsContext context) {
|
||||||
FunctionWithWrapper functionWithWrapper = functionsByFunctionNodes.get(function);
|
FunctionWithWrapper functionWithWrapper = functionsByFunctionNodes.get(function);
|
||||||
@@ -499,42 +489,6 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
return namedFunctionsStack.peek();
|
return namedFunctionsStack.peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static String extractImportTag(@NotNull JsExpression expression) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
return extractImportTagImpl(expression, sb) ? sb.toString() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean extractImportTagImpl(@NotNull JsExpression expression, @NotNull StringBuilder sb) {
|
|
||||||
if (expression instanceof JsNameRef) {
|
|
||||||
JsNameRef nameRef = (JsNameRef) expression;
|
|
||||||
if (nameRef.getQualifier() != null) {
|
|
||||||
if (!extractImportTagImpl(nameRef.getQualifier(), sb)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sb.append('.');
|
|
||||||
}
|
|
||||||
sb.append(JsToStringGenerationVisitor.javaScriptString(nameRef.getIdent()));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (expression instanceof JsArrayAccess) {
|
|
||||||
JsArrayAccess arrayAccess = (JsArrayAccess) expression;
|
|
||||||
if (!extractImportTagImpl(arrayAccess.getArrayExpression(), sb)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sb.append(".");
|
|
||||||
if (!(arrayAccess.getIndexExpression() instanceof JsStringLiteral)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
JsStringLiteral stringLiteral = (JsStringLiteral) arrayAccess.getIndexExpression();
|
|
||||||
sb.append(JsToStringGenerationVisitor.javaScriptString(stringLiteral.getValue()));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reportInlineCycle(@NotNull JsInvocation call, @NotNull JsFunction calledFunction) {
|
private void reportInlineCycle(@NotNull JsInvocation call, @NotNull JsFunction calledFunction) {
|
||||||
MetadataProperties.setInlineStrategy(call, InlineStrategy.NOT_INLINE);
|
MetadataProperties.setInlineStrategy(call, InlineStrategy.NOT_INLINE);
|
||||||
Iterator<JsCallInfo> it = inlineCallInfos.descendingIterator();
|
Iterator<JsCallInfo> it = inlineCallInfos.descendingIterator();
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 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.inline.clean
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
import org.jetbrains.kotlin.js.inline.util.getImportTag
|
||||||
|
import org.jetbrains.kotlin.js.inline.util.replaceNames
|
||||||
|
|
||||||
|
fun removeDuplicateImports(node: JsNode) {
|
||||||
|
node.accept(object : RecursiveJsVisitor() {
|
||||||
|
override fun visitBlock(x: JsBlock) {
|
||||||
|
super.visitBlock(x)
|
||||||
|
removeDuplicateImports(x.statements)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeDuplicateImports(statements: MutableList<JsStatement>) {
|
||||||
|
val existingImports = mutableMapOf<String, JsName>()
|
||||||
|
val replacements = mutableMapOf<JsName, JsExpression>()
|
||||||
|
removeDuplicateImports(statements, existingImports, replacements)
|
||||||
|
|
||||||
|
for (statement in statements) {
|
||||||
|
replaceNames(statement, replacements)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeDuplicateImports(
|
||||||
|
statements: MutableList<JsStatement>,
|
||||||
|
existingImports: MutableMap<String, JsName>,
|
||||||
|
replacements: MutableMap<JsName, JsExpression>
|
||||||
|
) {
|
||||||
|
var index = 0
|
||||||
|
while (index < statements.size) {
|
||||||
|
val statement = statements[index]
|
||||||
|
if (statement is JsVars) {
|
||||||
|
val importTag = getImportTag(statement)
|
||||||
|
if (importTag != null) {
|
||||||
|
val name = statement.vars[0].name
|
||||||
|
val existingName = existingImports[importTag]
|
||||||
|
if (existingName != null) {
|
||||||
|
replacements[name] = existingName.makeRef()
|
||||||
|
statements.removeAt(index)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
existingImports[importTag] = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (statement is JsBlock) {
|
||||||
|
removeDuplicateImports(statement.statements, existingImports, replacements)
|
||||||
|
}
|
||||||
|
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.inline.util
|
package org.jetbrains.kotlin.js.inline.util
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.metadata.imported
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.staticRef
|
import org.jetbrains.kotlin.js.backend.ast.metadata.staticRef
|
||||||
import org.jetbrains.kotlin.js.inline.util.collectors.InstanceCollector
|
import org.jetbrains.kotlin.js.inline.util.collectors.InstanceCollector
|
||||||
import org.jetbrains.kotlin.js.translate.expression.InlineMetadata
|
import org.jetbrains.kotlin.js.translate.expression.InlineMetadata
|
||||||
@@ -344,3 +346,42 @@ fun JsNode.collectBreakContinueTargets(): Map<JsContinue, JsStatement> {
|
|||||||
|
|
||||||
return targets
|
return targets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getImportTag(jsVars: JsVars): String? {
|
||||||
|
if (jsVars.vars.size == 1) {
|
||||||
|
val jsVar = jsVars.vars[0]
|
||||||
|
if (jsVar.initExpression != null && jsVar.name.imported) {
|
||||||
|
return extractImportTag(jsVar.initExpression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun extractImportTag(expression: JsExpression): String? {
|
||||||
|
val sb = StringBuilder()
|
||||||
|
return if (extractImportTagImpl(expression, sb)) sb.toString() else null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractImportTagImpl(expression: JsExpression, sb: StringBuilder): Boolean {
|
||||||
|
when (expression) {
|
||||||
|
is JsNameRef -> {
|
||||||
|
val nameRef = expression
|
||||||
|
if (nameRef.qualifier != null) {
|
||||||
|
if (!extractImportTagImpl(nameRef.qualifier!!, sb)) return false
|
||||||
|
sb.append('.')
|
||||||
|
}
|
||||||
|
sb.append(JsToStringGenerationVisitor.javaScriptString(nameRef.ident))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
is JsArrayAccess -> {
|
||||||
|
val arrayAccess = expression
|
||||||
|
if (!extractImportTagImpl(arrayAccess.arrayExpression, sb)) return false
|
||||||
|
sb.append(".")
|
||||||
|
val stringLiteral = arrayAccess.indexExpression as? JsStringLiteral ?: return false
|
||||||
|
sb.append(JsToStringGenerationVisitor.javaScriptString(stringLiteral.value))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
-4
@@ -23,11 +23,16 @@ class NameReplacingVisitor(private val replaceMap: Map<JsName, JsExpression>) :
|
|||||||
override fun endVisit(x: JsNameRef, ctx: JsContext<JsNode>) {
|
override fun endVisit(x: JsNameRef, ctx: JsContext<JsNode>) {
|
||||||
if (x.qualifier != null) return
|
if (x.qualifier != null) return
|
||||||
val replacement = replaceMap[x.name] ?: return
|
val replacement = replaceMap[x.name] ?: return
|
||||||
val replacementCopy = replacement.deepCopy()
|
if (replacement is JsNameRef) {
|
||||||
if (x.source != null) {
|
applyToNamedNode(x)
|
||||||
replacementCopy.source = x.source
|
}
|
||||||
|
else {
|
||||||
|
val replacementCopy = replacement.deepCopy()
|
||||||
|
if (x.source != null) {
|
||||||
|
replacementCopy.source = x.source
|
||||||
|
}
|
||||||
|
ctx.replaceMe(accept(replacementCopy))
|
||||||
}
|
}
|
||||||
ctx.replaceMe(accept(replacementCopy))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun endVisit(x: JsVars.JsVar, ctx: JsContext<*>) = applyToNamedNode(x)
|
override fun endVisit(x: JsVars.JsVar, ctx: JsContext<*>) = applyToNamedNode(x)
|
||||||
|
|||||||
+2
-2
@@ -61,12 +61,12 @@ class SourceMapLocationRemapper(private val sourceMap: SourceMap) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (node in nodes.asSequence().filterIsInstance<SourceInfoAwareJsNode>()) {
|
for (node in nodes.asSequence().filterIsInstance<SourceInfoAwareJsNode>()) {
|
||||||
val segment = findCorrespondingSegment(node)
|
val segment = findCorrespondingSegment(node)
|
||||||
val sourceFileName = segment?.sourceFileName
|
val sourceFileName = segment?.sourceFileName
|
||||||
node.source = if (sourceFileName != null) {
|
node.source = if (sourceFileName != null) {
|
||||||
val location = JsLocation(segment.sourceFileName, segment.sourceLineNumber, segment.sourceColumnNumber)
|
val location = JsLocation(segment.sourceFileName, segment.sourceLineNumber, segment.sourceColumnNumber)
|
||||||
JsLocationWithEmbeddedSource(location, sourceMap) { sourceMap.sourceContentResolver(segment.sourceFileName) }
|
JsLocationWithEmbeddedSource(location, null) { sourceMap.sourceContentResolver(segment.sourceFileName) }
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
null
|
null
|
||||||
|
|||||||
@@ -426,6 +426,7 @@ message Name {
|
|||||||
required bool temporary = 1;
|
required bool temporary = 1;
|
||||||
optional int32 identifier = 2;
|
optional int32 identifier = 2;
|
||||||
optional int32 local_name_id = 3;
|
optional int32 local_name_id = 3;
|
||||||
|
optional bool imported = 4 [default = false];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,9 @@ class JsAstDeserializer(program: JsProgram, private val sourceRoots: Iterable<Fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (nameBinding in fragment.nameBindings) {
|
for (nameBinding in fragment.nameBindings) {
|
||||||
nameBinding.name.imported = nameBinding.key in fragment.imports
|
if (nameBinding.key in fragment.imports) {
|
||||||
|
nameBinding.name.imported = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fragment
|
return fragment
|
||||||
@@ -438,6 +440,9 @@ class JsAstDeserializer(program: JsProgram, private val sourceRoots: Iterable<Fi
|
|||||||
if (nameProto.hasLocalNameId()) {
|
if (nameProto.hasLocalNameId()) {
|
||||||
name.localAlias = deserializeName(nameProto.localNameId)
|
name.localAlias = deserializeName(nameProto.localNameId)
|
||||||
}
|
}
|
||||||
|
if (nameProto.hasImported()) {
|
||||||
|
name.imported = nameProto.imported
|
||||||
|
}
|
||||||
nameCache[id] = name
|
nameCache[id] = name
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34763,6 +34763,15 @@ public final class JsAstProtoBuf {
|
|||||||
* <code>optional int32 local_name_id = 3;</code>
|
* <code>optional int32 local_name_id = 3;</code>
|
||||||
*/
|
*/
|
||||||
int getLocalNameId();
|
int getLocalNameId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
boolean hasImported();
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
boolean getImported();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Protobuf type {@code org.jetbrains.kotlin.serialization.js.ast.Name}
|
* Protobuf type {@code org.jetbrains.kotlin.serialization.js.ast.Name}
|
||||||
@@ -34829,6 +34838,11 @@ public final class JsAstProtoBuf {
|
|||||||
localNameId_ = input.readInt32();
|
localNameId_ = input.readInt32();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 32: {
|
||||||
|
bitField0_ |= 0x00000008;
|
||||||
|
imported_ = input.readBool();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
|
} catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
|
||||||
@@ -34908,10 +34922,26 @@ public final class JsAstProtoBuf {
|
|||||||
return localNameId_;
|
return localNameId_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final int IMPORTED_FIELD_NUMBER = 4;
|
||||||
|
private boolean imported_;
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
public boolean hasImported() {
|
||||||
|
return ((bitField0_ & 0x00000008) == 0x00000008);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
public boolean getImported() {
|
||||||
|
return imported_;
|
||||||
|
}
|
||||||
|
|
||||||
private void initFields() {
|
private void initFields() {
|
||||||
temporary_ = false;
|
temporary_ = false;
|
||||||
identifier_ = 0;
|
identifier_ = 0;
|
||||||
localNameId_ = 0;
|
localNameId_ = 0;
|
||||||
|
imported_ = false;
|
||||||
}
|
}
|
||||||
private byte memoizedIsInitialized = -1;
|
private byte memoizedIsInitialized = -1;
|
||||||
public final boolean isInitialized() {
|
public final boolean isInitialized() {
|
||||||
@@ -34939,6 +34969,9 @@ public final class JsAstProtoBuf {
|
|||||||
if (((bitField0_ & 0x00000004) == 0x00000004)) {
|
if (((bitField0_ & 0x00000004) == 0x00000004)) {
|
||||||
output.writeInt32(3, localNameId_);
|
output.writeInt32(3, localNameId_);
|
||||||
}
|
}
|
||||||
|
if (((bitField0_ & 0x00000008) == 0x00000008)) {
|
||||||
|
output.writeBool(4, imported_);
|
||||||
|
}
|
||||||
output.writeRawBytes(unknownFields);
|
output.writeRawBytes(unknownFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34960,6 +34993,10 @@ public final class JsAstProtoBuf {
|
|||||||
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
|
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
|
||||||
.computeInt32Size(3, localNameId_);
|
.computeInt32Size(3, localNameId_);
|
||||||
}
|
}
|
||||||
|
if (((bitField0_ & 0x00000008) == 0x00000008)) {
|
||||||
|
size += org.jetbrains.kotlin.protobuf.CodedOutputStream
|
||||||
|
.computeBoolSize(4, imported_);
|
||||||
|
}
|
||||||
size += unknownFields.size();
|
size += unknownFields.size();
|
||||||
memoizedSerializedSize = size;
|
memoizedSerializedSize = size;
|
||||||
return size;
|
return size;
|
||||||
@@ -35060,6 +35097,8 @@ public final class JsAstProtoBuf {
|
|||||||
bitField0_ = (bitField0_ & ~0x00000002);
|
bitField0_ = (bitField0_ & ~0x00000002);
|
||||||
localNameId_ = 0;
|
localNameId_ = 0;
|
||||||
bitField0_ = (bitField0_ & ~0x00000004);
|
bitField0_ = (bitField0_ & ~0x00000004);
|
||||||
|
imported_ = false;
|
||||||
|
bitField0_ = (bitField0_ & ~0x00000008);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35095,6 +35134,10 @@ public final class JsAstProtoBuf {
|
|||||||
to_bitField0_ |= 0x00000004;
|
to_bitField0_ |= 0x00000004;
|
||||||
}
|
}
|
||||||
result.localNameId_ = localNameId_;
|
result.localNameId_ = localNameId_;
|
||||||
|
if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
|
||||||
|
to_bitField0_ |= 0x00000008;
|
||||||
|
}
|
||||||
|
result.imported_ = imported_;
|
||||||
result.bitField0_ = to_bitField0_;
|
result.bitField0_ = to_bitField0_;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -35110,6 +35153,9 @@ public final class JsAstProtoBuf {
|
|||||||
if (other.hasLocalNameId()) {
|
if (other.hasLocalNameId()) {
|
||||||
setLocalNameId(other.getLocalNameId());
|
setLocalNameId(other.getLocalNameId());
|
||||||
}
|
}
|
||||||
|
if (other.hasImported()) {
|
||||||
|
setImported(other.getImported());
|
||||||
|
}
|
||||||
setUnknownFields(
|
setUnknownFields(
|
||||||
getUnknownFields().concat(other.unknownFields));
|
getUnknownFields().concat(other.unknownFields));
|
||||||
return this;
|
return this;
|
||||||
@@ -35238,6 +35284,38 @@ public final class JsAstProtoBuf {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean imported_ ;
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
public boolean hasImported() {
|
||||||
|
return ((bitField0_ & 0x00000008) == 0x00000008);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
public boolean getImported() {
|
||||||
|
return imported_;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
public Builder setImported(boolean value) {
|
||||||
|
bitField0_ |= 0x00000008;
|
||||||
|
imported_ = value;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* <code>optional bool imported = 4;</code>
|
||||||
|
*/
|
||||||
|
public Builder clearImported() {
|
||||||
|
bitField0_ = (bitField0_ & ~0x00000008);
|
||||||
|
imported_ = false;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.serialization.js.ast.Name)
|
// @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.serialization.js.ast.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,12 @@ class JsAstSerializer(private val pathResolver: (File) -> String) {
|
|||||||
private val nameMap = mutableMapOf<JsName, Int>()
|
private val nameMap = mutableMapOf<JsName, Int>()
|
||||||
private val stringMap = mutableMapOf<String, Int>()
|
private val stringMap = mutableMapOf<String, Int>()
|
||||||
private val fileStack: Deque<String> = ArrayDeque()
|
private val fileStack: Deque<String> = ArrayDeque()
|
||||||
|
private val importedNames = mutableSetOf<JsName>()
|
||||||
|
|
||||||
fun serialize(fragment: JsProgramFragment, output: OutputStream) {
|
fun serialize(fragment: JsProgramFragment, output: OutputStream) {
|
||||||
|
val namesBySignature = fragment.nameBindings.associate { it.key to it.name }
|
||||||
|
importedNames.clear()
|
||||||
|
importedNames += fragment.imports.map { namesBySignature[it.key]!! }
|
||||||
serialize(fragment).writeTo(output)
|
serialize(fragment).writeTo(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,6 +560,10 @@ class JsAstSerializer(private val pathResolver: (File) -> String) {
|
|||||||
builder.localNameId = serialize(it)
|
builder.localNameId = serialize(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name.imported && name !in importedNames) {
|
||||||
|
builder.imported = true
|
||||||
|
}
|
||||||
|
|
||||||
val result = nameTableBuilder.entryCount
|
val result = nameTableBuilder.entryCount
|
||||||
nameTableBuilder.addEntry(builder)
|
nameTableBuilder.addEntry(builder)
|
||||||
result
|
result
|
||||||
|
|||||||
@@ -4838,6 +4838,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("repeatedImport.kt")
|
||||||
|
public void testRepeatedImport() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/repeatedImport.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/simple.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/simple.kt");
|
||||||
|
|||||||
@@ -83,6 +83,13 @@ public class DirectiveTestUtils {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static final DirectiveHandler PROPERTY_READ_COUNT = new DirectiveHandler("PROPERTY_READ_COUNT") {
|
||||||
|
@Override
|
||||||
|
void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
|
||||||
|
checkPropertyReadCount(ast, arguments.getNamedArgument("name"), Integer.parseInt(arguments.getNamedArgument("count")));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private static final DirectiveHandler FUNCTION_CALLED_IN_SCOPE = new DirectiveHandler("CHECK_CALLED_IN_SCOPE") {
|
private static final DirectiveHandler FUNCTION_CALLED_IN_SCOPE = new DirectiveHandler("CHECK_CALLED_IN_SCOPE") {
|
||||||
@Override
|
@Override
|
||||||
void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
|
void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
|
||||||
@@ -299,6 +306,7 @@ public class DirectiveTestUtils {
|
|||||||
PROPERTY_NOT_USED,
|
PROPERTY_NOT_USED,
|
||||||
PROPERTY_NOT_READ_FROM,
|
PROPERTY_NOT_READ_FROM,
|
||||||
PROPERTY_NOT_WRITTEN_TO,
|
PROPERTY_NOT_WRITTEN_TO,
|
||||||
|
PROPERTY_READ_COUNT,
|
||||||
PROPERTY_WRITE_COUNT,
|
PROPERTY_WRITE_COUNT,
|
||||||
FUNCTION_CALLED_IN_SCOPE,
|
FUNCTION_CALLED_IN_SCOPE,
|
||||||
FUNCTION_NOT_CALLED_IN_SCOPE,
|
FUNCTION_NOT_CALLED_IN_SCOPE,
|
||||||
@@ -340,12 +348,16 @@ public class DirectiveTestUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void checkPropertyReadCount(JsNode node, String propertyName, int expectedCount) throws Exception {
|
||||||
|
PropertyReferenceCollector counter = PropertyReferenceCollector.Companion.collect(node);
|
||||||
|
assertEquals("Property read count: " + propertyName, expectedCount, counter.unqualifiedReadCount(propertyName));
|
||||||
|
}
|
||||||
|
|
||||||
private static void checkPropertyWriteCount(JsNode node, String propertyName, int expectedCount) throws Exception {
|
private static void checkPropertyWriteCount(JsNode node, String propertyName, int expectedCount) throws Exception {
|
||||||
PropertyReferenceCollector counter = PropertyReferenceCollector.Companion.collect(node);
|
PropertyReferenceCollector counter = PropertyReferenceCollector.Companion.collect(node);
|
||||||
assertEquals("Property write count: " + propertyName, expectedCount, counter.unqualifiedWriteCount(propertyName));
|
assertEquals("Property write count: " + propertyName, expectedCount, counter.unqualifiedWriteCount(propertyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void checkFunctionNotCalled(@NotNull JsNode node, @NotNull String functionName, @Nullable String exceptFunction)
|
public static void checkFunctionNotCalled(@NotNull JsNode node, @NotNull String functionName, @Nullable String exceptFunction)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Set<String> excludedScopes = exceptFunction != null ? Collections.singleton(exceptFunction) : Collections.emptySet();
|
Set<String> excludedScopes = exceptFunction != null ? Collections.singleton(exceptFunction) : Collections.emptySet();
|
||||||
|
|||||||
@@ -24,17 +24,19 @@ import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
|||||||
|
|
||||||
class PropertyReferenceCollector : RecursiveJsVisitor() {
|
class PropertyReferenceCollector : RecursiveJsVisitor() {
|
||||||
|
|
||||||
private val identReadSet = hashSetOf<String>()
|
private val identReadMap = hashMapOf<String, Int>()
|
||||||
private val identWriteMap = hashMapOf<String, Int>()
|
private val identWriteMap = hashMapOf<String, Int>()
|
||||||
|
|
||||||
fun hasUnqualifiedReads(expectedIdent: String) = expectedIdent in identReadSet
|
fun hasUnqualifiedReads(expectedIdent: String) = expectedIdent in identReadMap
|
||||||
fun hasUnqualifiedWrites(expectedIdent: String) = expectedIdent in identWriteMap
|
fun hasUnqualifiedWrites(expectedIdent: String) = expectedIdent in identWriteMap
|
||||||
|
|
||||||
fun unqualifiedWriteCount(expectedIdent: String): Int = identWriteMap[expectedIdent] ?: 0
|
fun unqualifiedWriteCount(expectedIdent: String): Int = identWriteMap[expectedIdent] ?: 0
|
||||||
|
|
||||||
|
fun unqualifiedReadCount(expectedIdent: String): Int = identReadMap[expectedIdent] ?: 0
|
||||||
|
|
||||||
override fun visitNameRef(nameRef: JsNameRef) {
|
override fun visitNameRef(nameRef: JsNameRef) {
|
||||||
super.visitNameRef(nameRef)
|
super.visitNameRef(nameRef)
|
||||||
identReadSet.add(nameRef.ident)
|
identReadMap[nameRef.ident] = 1 + unqualifiedReadCount(nameRef.ident)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBinaryExpression(x: JsBinaryOperation) {
|
override fun visitBinaryExpression(x: JsBinaryOperation) {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.js.facade.exceptions.TranslationException;
|
|||||||
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer;
|
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer;
|
||||||
import org.jetbrains.kotlin.js.inline.JsInliner;
|
import org.jetbrains.kotlin.js.inline.JsInliner;
|
||||||
import org.jetbrains.kotlin.js.inline.clean.LabeledBlockToDoWhileTransformation;
|
import org.jetbrains.kotlin.js.inline.clean.LabeledBlockToDoWhileTransformation;
|
||||||
|
import org.jetbrains.kotlin.js.inline.clean.RemoveDuplicateImportsKt;
|
||||||
import org.jetbrains.kotlin.js.inline.clean.RemoveUnusedImportsKt;
|
import org.jetbrains.kotlin.js.inline.clean.RemoveUnusedImportsKt;
|
||||||
import org.jetbrains.kotlin.js.inline.clean.ResolveTemporaryNamesKt;
|
import org.jetbrains.kotlin.js.inline.clean.ResolveTemporaryNamesKt;
|
||||||
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver;
|
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver;
|
||||||
@@ -185,6 +186,7 @@ public final class K2JSTranslator {
|
|||||||
incrementalResults.processHeader(serializationUtil.serializeHeader(null).toByteArray());
|
incrementalResults.processHeader(serializationUtil.serializeHeader(null).toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RemoveDuplicateImportsKt.removeDuplicateImports(translationResult.getProgram());
|
||||||
ResolveTemporaryNamesKt.resolveTemporaryNames(translationResult.getProgram());
|
ResolveTemporaryNamesKt.resolveTemporaryNames(translationResult.getProgram());
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
|
||||||
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
if (hasError(diagnostics)) return new TranslationResult.Fail(diagnostics);
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// MODULE: lib
|
||||||
|
// FILE: lib.kt
|
||||||
|
fun foo(x: String) = "foo($x)"
|
||||||
|
|
||||||
|
inline fun bar(x: String) = "bar(${foo(x)})"
|
||||||
|
|
||||||
|
inline fun baz(x: String) = "baz(${foo(x)})"
|
||||||
|
|
||||||
|
// MODULE: main(lib)
|
||||||
|
// FILE: a.kt
|
||||||
|
// PROPERTY_READ_COUNT: name=foo_61zpoe$ count=1
|
||||||
|
fun test1() = bar("q")
|
||||||
|
|
||||||
|
// FILE: b.kt
|
||||||
|
// RECOMPILE
|
||||||
|
fun test2() = baz("w")
|
||||||
|
|
||||||
|
// FILE: main.kt
|
||||||
|
// RECOMPILE
|
||||||
|
fun box(): String {
|
||||||
|
val a = test1()
|
||||||
|
if (a != "bar(foo(q))") return "fail1: $a"
|
||||||
|
|
||||||
|
val b = test2()
|
||||||
|
if (b != "baz(foo(w))") return "fail2: $b"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+1
-1
@@ -17,4 +17,4 @@ fun bar(a: String, b: Char, x: Int) {
|
|||||||
a.foo(b)
|
a.foo(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LINES: 6 4 4 5 5 8 8 8 8 8 11 9 9 10 10 18 14 14 14 14 14 15 17 17 9 9 14 10 17 10 14 14 * 1 * 1
|
// LINES: 6 4 4 5 5 8 8 8 8 8 8 8 11 9 9 10 10 8 8 8 8 18 14 14 14 14 14 15 17 17 9 9 14 10 17 10 14 14 * 1 * 1
|
||||||
@@ -9,4 +9,4 @@ fun bar() {
|
|||||||
foo(42)
|
foo(42)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LINES: 1 1 1 1 1 6 2 2 3 3 4 4 10 2 2 9 2 3 3 4 4
|
// LINES: 1 1 1 1 1 6 2 2 3 3 4 4 1 1 10 2 2 9 2 3 3 4 4
|
||||||
+1
-1
@@ -21,4 +21,4 @@ fun bar(x: Int) {
|
|||||||
println("%")
|
println("%")
|
||||||
}
|
}
|
||||||
|
|
||||||
// LINES: 1 1 1 1 1 1 1 17 2 2 3 3 4 7 7 9 9 10 10 11 14 14 16 16 22 20 20 20 20 2 2 3 3 4 3 7 7 9 9 10 10 11 10 14 14 16 16 * 20 21 21
|
// LINES: 1 1 1 1 1 1 1 17 2 2 3 3 4 7 7 9 9 10 10 11 14 14 16 16 1 1 22 20 20 20 20 2 2 3 3 4 3 7 7 9 9 10 10 11 10 14 14 16 16 * 20 21 21
|
||||||
Reference in New Issue
Block a user