diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/JsToStringGenerationVisitor.java b/js/js.ast/src/org/jetbrains/kotlin/js/backend/JsToStringGenerationVisitor.java index dcaf3a71364..ac04c45c90d 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/JsToStringGenerationVisitor.java +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/JsToStringGenerationVisitor.java @@ -12,10 +12,7 @@ import org.jetbrains.kotlin.js.util.TextOutput; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * Produces text output from a JavaScript AST. @@ -47,6 +44,11 @@ public class JsToStringGenerationVisitor extends JsVisitor { private static final char[] CHARS_WHILE = "while".toCharArray(); private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + @NotNull + private final SourceLocationConsumer sourceLocationConsumer; + + @NotNull + private final List sourceInfoStack = new ArrayList<>(); public static CharSequence javaScriptString(String value) { return javaScriptString(value, false); @@ -60,7 +62,7 @@ public class JsToStringGenerationVisitor extends JsVisitor { */ @SuppressWarnings({"ConstantConditions", "UnnecessaryFullyQualifiedName", "JavadocReference"}) public static CharSequence javaScriptString(CharSequence chars, boolean forceDoubleQuote) { - final int n = chars.length(); + int n = chars.length(); int quoteCount = 0; int aposCount = 0; @@ -174,25 +176,40 @@ public class JsToStringGenerationVisitor extends JsVisitor { * those that appear directly within these global blocks. */ private Set globalBlocks = new THashSet(); + + @NotNull protected final TextOutput p; - public JsToStringGenerationVisitor(TextOutput out) { + public JsToStringGenerationVisitor(@NotNull TextOutput out, @NotNull SourceLocationConsumer sourceLocationConsumer) { p = out; + this.sourceLocationConsumer = sourceLocationConsumer; + } + + public JsToStringGenerationVisitor(@NotNull TextOutput out) { + this(out, NoOpSourceLocationConsumer.INSTANCE); } @Override public void visitArrayAccess(@NotNull JsArrayAccess x) { + pushSourceInfo(x.getSource()); + printPair(x, x.getArrayExpression()); leftSquare(); accept(x.getIndexExpression()); rightSquare(); + + popSourceInfo(); } @Override public void visitArray(@NotNull JsArrayLiteral x) { + pushSourceInfo(x.getSource()); + leftSquare(); printExpressions(x.getExpressions()); rightSquare(); + + popSourceInfo(); } private void printExpressions(List expressions) { @@ -209,6 +226,8 @@ public class JsToStringGenerationVisitor extends JsVisitor { @Override public void visitBinaryExpression(@NotNull JsBinaryOperation binaryOperation) { + pushSourceInfo(binaryOperation.getSource()); + JsBinaryOperator operator = binaryOperation.getOperator(); JsExpression arg1 = binaryOperation.getArg1(); boolean isExpressionEnclosed = parenPush(binaryOperation, arg1, !operator.isLeftAssociative()); @@ -250,6 +269,8 @@ public class JsToStringGenerationVisitor extends JsVisitor { if (isParenOpened) { rightParen(); } + + popSourceInfo(); } @Override @@ -259,29 +280,41 @@ public class JsToStringGenerationVisitor extends JsVisitor { @Override public void visitBoolean(@NotNull JsBooleanLiteral x) { + pushSourceInfo(x.getSource()); + if (x.getValue()) { p.print(CHARS_TRUE); } else { p.print(CHARS_FALSE); } + + popSourceInfo(); } @Override public void visitBreak(@NotNull JsBreak x) { + pushSourceInfo(x.getSource()); + p.print(CHARS_BREAK); continueOrBreakLabel(x); + + popSourceInfo(); } @Override public void visitContinue(@NotNull JsContinue x) { + pushSourceInfo(x.getSource()); + p.print(CHARS_CONTINUE); continueOrBreakLabel(x); + + popSourceInfo(); } private void continueOrBreakLabel(JsContinue x) { JsNameRef label = x.getLabel(); - if (label != null && label.getIdent() != null) { + if (label != null) { space(); p.print(label.getIdent()); } @@ -289,13 +322,20 @@ public class JsToStringGenerationVisitor extends JsVisitor { @Override public void visitCase(@NotNull JsCase x) { + pushSourceInfo(x.getSource()); + p.print(CHARS_CASE); space(); accept(x.getCaseExpression()); _colon(); + + popSourceInfo(); + newlineOpt(); + sourceLocationConsumer.pushSourceInfo(null); printSwitchMemberStatements(x); + sourceLocationConsumer.popSourceInfo(); } private void printSwitchMemberStatements(JsSwitchMember x) { @@ -314,6 +354,8 @@ public class JsToStringGenerationVisitor extends JsVisitor { @Override public void visitCatch(@NotNull JsCatch x) { + pushSourceInfo(x.getSource()); + spaceOpt(); p.print(CHARS_CATCH); spaceOpt(); @@ -332,11 +374,18 @@ public class JsToStringGenerationVisitor extends JsVisitor { rightParen(); spaceOpt(); + + popSourceInfo(); + + sourceLocationConsumer.pushSourceInfo(null); accept(x.getBody()); + sourceLocationConsumer.popSourceInfo(); } @Override public void visitConditional(@NotNull JsConditional x) { + pushSourceInfo(x.getSource()); + // Associativity: for the then and else branches, it is safe to insert // another // ternary expression, but if the test expression is a ternary, it should @@ -350,6 +399,8 @@ public class JsToStringGenerationVisitor extends JsVisitor { _colon(); spaceOpt(); printPair(x, x.getElseExpression()); + + popSourceInfo(); } private void printPair(JsExpression parent, JsExpression expression, boolean wrongAssoc) { @@ -369,35 +420,57 @@ public class JsToStringGenerationVisitor extends JsVisitor { @Override public void visitDebugger(@NotNull JsDebugger x) { + pushSourceInfo(x.getSource()); + p.print(CHARS_DEBUGGER); + + popSourceInfo(); } @Override public void visitDefault(@NotNull JsDefault x) { + pushSourceInfo(x.getSource()); + p.print(CHARS_DEFAULT); _colon(); + popSourceInfo(); + + sourceLocationConsumer.pushSourceInfo(null); printSwitchMemberStatements(x); + sourceLocationConsumer.popSourceInfo(); } @Override public void visitWhile(@NotNull JsWhile x) { + pushSourceInfo(x.getSource()); + _while(); spaceOpt(); leftParen(); accept(x.getCondition()); rightParen(); + + popSourceInfo(); + nestedPush(x.getBody()); + sourceLocationConsumer.pushSourceInfo(null); accept(x.getBody()); + sourceLocationConsumer.popSourceInfo(); nestedPop(x.getBody()); } @Override public void visitDoWhile(@NotNull JsDoWhile x) { + sourceLocationConsumer.pushSourceInfo(null); + p.print(CHARS_DO); nestedPush(x.getBody()); accept(x.getBody()); + sourceLocationConsumer.popSourceInfo(); nestedPop(x.getBody()); + + pushSourceInfo(x.getCondition().getSource()); if (needSemi) { semi(); newlineOpt(); @@ -406,11 +479,14 @@ public class JsToStringGenerationVisitor extends JsVisitor { spaceOpt(); needSemi = true; } + _while(); spaceOpt(); leftParen(); accept(x.getCondition()); rightParen(); + + popSourceInfo(); } @Override @@ -419,6 +495,12 @@ public class JsToStringGenerationVisitor extends JsVisitor { @Override public void visitExpressionStatement(@NotNull JsExpressionStatement x) { + Object source = x.getSource(); + if (source == null) { + source = x.getExpression().getSource(); + } + pushSourceInfo(source); + boolean surroundWithParentheses = JsFirstExpressionVisitor.exec(x); if (surroundWithParentheses) { leftParen(); @@ -427,10 +509,14 @@ public class JsToStringGenerationVisitor extends JsVisitor { if (surroundWithParentheses) { rightParen(); } + + popSourceInfo(); } @Override public void visitFor(@NotNull JsFor x) { + pushSourceInfo(x.getSource()); + _for(); spaceOpt(); leftParen(); @@ -463,15 +549,22 @@ public class JsToStringGenerationVisitor extends JsVisitor { } rightParen(); + + popSourceInfo(); + nestedPush(x.getBody()); if (x.getBody() != null) { + sourceLocationConsumer.pushSourceInfo(null); accept(x.getBody()); + sourceLocationConsumer.popSourceInfo(); } nestedPop(x.getBody()); } @Override public void visitForIn(@NotNull JsForIn x) { + pushSourceInfo(x.getSource()); + _for(); spaceOpt(); leftParen(); @@ -500,13 +593,20 @@ public class JsToStringGenerationVisitor extends JsVisitor { accept(x.getObjectExpression()); rightParen(); + + popSourceInfo(); + nestedPush(x.getBody()); + sourceLocationConsumer.pushSourceInfo(null); accept(x.getBody()); + sourceLocationConsumer.popSourceInfo(); nestedPop(x.getBody()); } @Override public void visitFunction(@NotNull JsFunction x) { + pushSourceInfo(x.getSource()); + p.print(CHARS_FUNCTION); space(); if (x.getName() != null) { @@ -524,24 +624,39 @@ public class JsToStringGenerationVisitor extends JsVisitor { space(); lineBreakAfterBlock = false; + + sourceLocationConsumer.pushSourceInfo(null); accept(x.getBody()); + sourceLocationConsumer.popSourceInfo(); + needSemi = true; + + popSourceInfo(); } @Override public void visitIf(@NotNull JsIf x) { + pushSourceInfo(x.getSource()); + _if(); spaceOpt(); leftParen(); accept(x.getIfExpression()); rightParen(); + + popSourceInfo(); + JsStatement thenStmt = x.getThenStatement(); JsStatement elseStatement = x.getElseStatement(); if (elseStatement != null && thenStmt instanceof JsIf && ((JsIf)thenStmt).getElseStatement() == null) { thenStmt = new JsBlock(thenStmt); } nestedPush(thenStmt); + + sourceLocationConsumer.pushSourceInfo(null); accept(thenStmt); + sourceLocationConsumer.popSourceInfo(); + nestedPop(thenStmt); if (elseStatement != null) { if (needSemi) { @@ -560,7 +675,9 @@ public class JsToStringGenerationVisitor extends JsVisitor { else { space(); } + sourceLocationConsumer.pushSourceInfo(null); accept(elseStatement); + sourceLocationConsumer.popSourceInfo(); if (!elseIf) { nestedPop(elseStatement); } @@ -569,11 +686,15 @@ public class JsToStringGenerationVisitor extends JsVisitor { @Override public void visitInvocation(@NotNull JsInvocation invocation) { + pushSourceInfo(invocation.getSource()); + printPair(invocation, invocation.getQualifier()); leftParen(); printExpressions(invocation.getArguments()); rightParen(); + + popSourceInfo(); } @Override @@ -581,14 +702,19 @@ public class JsToStringGenerationVisitor extends JsVisitor { nameOf(x); _colon(); spaceOpt(); + + sourceLocationConsumer.pushSourceInfo(null); accept(x.getStatement()); + sourceLocationConsumer.popSourceInfo(); } @Override public void visitNameRef(@NotNull JsNameRef nameRef) { + pushSourceInfo(nameRef.getSource()); + JsExpression qualifier = nameRef.getQualifier(); if (qualifier != null) { - final boolean enclose; + boolean enclose; if (qualifier instanceof JsLiteral.JsValueLiteral) { // "42.foo" is not allowed, but "(42).foo" is. enclose = qualifier instanceof JsNumberLiteral; @@ -609,10 +735,14 @@ public class JsToStringGenerationVisitor extends JsVisitor { p.maybeIndent(); p.print(nameRef.getIdent()); + + popSourceInfo(); } @Override public void visitNew(@NotNull JsNew x) { + pushSourceInfo(x.getSource()); + p.print(CHARS_NEW); space(); @@ -629,26 +759,43 @@ public class JsToStringGenerationVisitor extends JsVisitor { leftParen(); printExpressions(x.getArguments()); rightParen(); + + popSourceInfo(); } @Override public void visitNull(@NotNull JsNullLiteral x) { + pushSourceInfo(x.getSource()); + p.print(CHARS_NULL); + + popSourceInfo(); } @Override public void visitInt(@NotNull JsIntLiteral x) { + pushSourceInfo(x.getSource()); + p.print(x.value); + + popSourceInfo(); } @Override public void visitDouble(@NotNull JsDoubleLiteral x) { + pushSourceInfo(x.getSource()); + p.print(x.value); + + popSourceInfo(); } @Override public void visitObjectLiteral(@NotNull JsObjectLiteral objectLiteral) { + pushSourceInfo(objectLiteral.getSource()); + p.print('{'); + if (objectLiteral.isMultiline()) { p.indentIn(); } @@ -668,6 +815,8 @@ public class JsToStringGenerationVisitor extends JsVisitor { notFirst = true; + pushSourceInfo(item.getSource()); + JsExpression labelExpr = item.getLabelExpr(); // labels can be either string, integral, or decimal literals if (labelExpr instanceof JsNameRef) { @@ -688,6 +837,8 @@ public class JsToStringGenerationVisitor extends JsVisitor { if (wasEnclosed) { rightParen(); } + + popSourceInfo(); } if (objectLiteral.isMultiline()) { @@ -696,6 +847,7 @@ public class JsToStringGenerationVisitor extends JsVisitor { } p.print('}'); + popSourceInfo(); } @Override @@ -705,15 +857,21 @@ public class JsToStringGenerationVisitor extends JsVisitor { @Override public void visitPostfixOperation(@NotNull JsPostfixOperation x) { + pushSourceInfo(x.getSource()); + JsUnaryOperator op = x.getOperator(); JsExpression arg = x.getArg(); // unary operators always associate correctly (I think) printPair(x, arg); p.print(op.getSymbol()); + + popSourceInfo(); } @Override public void visitPrefixOperation(@NotNull JsPrefixOperation x) { + pushSourceInfo(x.getSource()); + JsUnaryOperator op = x.getOperator(); p.print(op.getSymbol()); JsExpression arg = x.getArg(); @@ -722,15 +880,19 @@ public class JsToStringGenerationVisitor extends JsVisitor { } // unary operators always associate correctly (I think) printPair(x, arg); + + popSourceInfo(); } @Override public void visitProgram(@NotNull JsProgram x) { - p.print(""); + x.acceptChildren(this); } @Override public void visitRegExp(@NotNull JsRegExp x) { + pushSourceInfo(x.getSource()); + slash(); p.print(x.getPattern()); slash(); @@ -738,46 +900,72 @@ public class JsToStringGenerationVisitor extends JsVisitor { if (flags != null) { p.print(flags); } + + popSourceInfo(); } @Override public void visitReturn(@NotNull JsReturn x) { + pushSourceInfo(x.getSource()); + p.print(CHARS_RETURN); JsExpression expr = x.getExpression(); if (expr != null) { space(); accept(expr); } + + popSourceInfo(); } @Override public void visitString(@NotNull JsStringLiteral x) { + pushSourceInfo(x.getSource()); + p.print(javaScriptString(x.getValue())); + + popSourceInfo(); } @Override public void visit(@NotNull JsSwitch x) { + pushSourceInfo(x.getSource()); + p.print(CHARS_SWITCH); spaceOpt(); leftParen(); accept(x.getExpression()); rightParen(); + + popSourceInfo(); + + + sourceLocationConsumer.pushSourceInfo(null); spaceOpt(); blockOpen(); acceptList(x.getCases()); blockClose(); + sourceLocationConsumer.popSourceInfo(); } @Override public void visitThis(@NotNull JsThisRef x) { + pushSourceInfo(x.getSource()); + p.print(CHARS_THIS); + + popSourceInfo(); } @Override public void visitThrow(@NotNull JsThrow x) { + pushSourceInfo(x.getSource()); + p.print(CHARS_THROW); space(); accept(x.getExpression()); + + popSourceInfo(); } @Override @@ -798,6 +986,8 @@ public class JsToStringGenerationVisitor extends JsVisitor { @Override public void visit(@NotNull JsVar var) { + pushSourceInfo(var.getSource()); + nameOf(var); JsExpression initExpr = var.getInitExpression(); if (initExpr != null) { @@ -810,10 +1000,14 @@ public class JsToStringGenerationVisitor extends JsVisitor { rightParen(); } } + + popSourceInfo(); } @Override public void visitVars(@NotNull JsVars vars) { + pushSourceInfo(vars.getSource()); + var(); space(); boolean sep = false; @@ -831,6 +1025,8 @@ public class JsToStringGenerationVisitor extends JsVisitor { accept(var); } + + popSourceInfo(); } @Override @@ -844,13 +1040,13 @@ public class JsToStringGenerationVisitor extends JsVisitor { space(); } else { - p.newline(); + newline(); } boolean notFirst = false; for (Map.Entry entry : comment.getTags().entrySet()) { if (notFirst) { - p.newline(); + newline(); p.print(' '); p.print('*'); } @@ -872,7 +1068,7 @@ public class JsToStringGenerationVisitor extends JsVisitor { } if (!asSingleLine) { - p.newline(); + newline(); } } @@ -890,18 +1086,39 @@ public class JsToStringGenerationVisitor extends JsVisitor { } } - protected final void newlineOpt() { + private void newlineOpt() { if (!p.isCompact()) { - p.newline(); + newline(); } } - protected void printJsBlock(JsBlock x, boolean finalNewline) { + private void newline() { + p.newline(); + sourceLocationConsumer.newLine(); + } + + private void pushSourceInfo(Object location) { + p.maybeIndent(); + sourceInfoStack.add(location); + if (location != null) { + sourceLocationConsumer.pushSourceInfo(location); + } + } + + private void popSourceInfo() { + if (!sourceInfoStack.isEmpty() && sourceInfoStack.remove(sourceInfoStack.size() - 1) != null) { + sourceLocationConsumer.popSourceInfo(); + } + } + + private void printJsBlock(JsBlock x, boolean finalNewline) { if (!lineBreakAfterBlock) { finalNewline = false; lineBreakAfterBlock = true; } + sourceLocationConsumer.pushSourceInfo(null); + boolean needBraces = !x.isGlobalBlock(); if (needBraces) { blockOpen(); @@ -949,7 +1166,7 @@ public class JsToStringGenerationVisitor extends JsVisitor { newlineOpt(); } else { - p.newline(); + newline(); } } else { @@ -973,6 +1190,8 @@ public class JsToStringGenerationVisitor extends JsVisitor { } } needSemi = false; + + sourceLocationConsumer.popSourceInfo(); } private void assignment() { diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/NoOpSourceLocationConsumer.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/NoOpSourceLocationConsumer.kt new file mode 100644 index 00000000000..ed5f8b90f69 --- /dev/null +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/NoOpSourceLocationConsumer.kt @@ -0,0 +1,25 @@ +/* + * 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.backend + +object NoOpSourceLocationConsumer : SourceLocationConsumer { + override fun newLine() {} + + override fun pushSourceInfo(info: Any?) {} + + override fun popSourceInfo() {} +} \ No newline at end of file diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/SourceLocationConsumer.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/SourceLocationConsumer.kt new file mode 100644 index 00000000000..d0de1e76743 --- /dev/null +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/SourceLocationConsumer.kt @@ -0,0 +1,25 @@ +/* + * 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.backend + +interface SourceLocationConsumer { + fun newLine() + + fun pushSourceInfo(info: Any?) + + fun popSourceInfo() +} diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/util/TextOutput.java b/js/js.ast/src/org/jetbrains/kotlin/js/util/TextOutput.java index 703304d73d9..b490683f15c 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/util/TextOutput.java +++ b/js/js.ast/src/org/jetbrains/kotlin/js/util/TextOutput.java @@ -32,21 +32,7 @@ public interface TextOutput { void printOpt(char c); - void printOpt(char[] s); - - void printOpt(String s); - boolean isCompact(); - boolean isJustNewlined(); - - void setOutListener(OutListener outListener); - void maybeIndent(); - - public interface OutListener { - void newLined(); - - void indentedAfterNewLine(); - } } diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/util/TextOutputImpl.java b/js/js.ast/src/org/jetbrains/kotlin/js/util/TextOutputImpl.java index 6768967de14..733b3ca1bcd 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/util/TextOutputImpl.java +++ b/js/js.ast/src/org/jetbrains/kotlin/js/util/TextOutputImpl.java @@ -17,8 +17,6 @@ public class TextOutputImpl implements TextOutput { private int line = 0; private int column = 0; - private OutListener outListener; - public TextOutputImpl() { this(false); } @@ -78,9 +76,6 @@ public class TextOutputImpl implements TextOutput { line++; column = 0; justNewlined = true; - if (outListener != null) { - outListener.newLined(); - } } @Override @@ -151,9 +146,6 @@ public class TextOutputImpl implements TextOutput { if (justNewlined && !compact) { printAndCount(indents[identLevel]); justNewlined = false; - if (outListener != null) { - outListener.indentedAfterNewLine(); - } } } @@ -173,9 +165,4 @@ public class TextOutputImpl implements TextOutput { public boolean isJustNewlined() { return justNewlined && !compact; } - - @Override - public void setOutListener(OutListener outListener) { - this.outListener = outListener; - } } diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt index 26b37d8fedc..60cabc14ef5 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt @@ -194,7 +194,7 @@ class FunctionReader( val sourceMap = info.sourceMap if (sourceMap != null) { - val remapper = SourceMapLocationRemapper(mapOf(info.filePath to sourceMap)) + val remapper = SourceMapLocationRemapper(sourceMap) remapper.remap(function) } diff --git a/js/js.parser/src/com/google/gwt/dev/js/JsAstMapper.java b/js/js.parser/src/com/google/gwt/dev/js/JsAstMapper.java index b2cb01e4ae0..a8185afe8b7 100644 --- a/js/js.parser/src/com/google/gwt/dev/js/JsAstMapper.java +++ b/js/js.parser/src/com/google/gwt/dev/js/JsAstMapper.java @@ -1115,7 +1115,10 @@ public class JsAstMapper { astNode.setSource(jsLocation); } else if (astNode instanceof JsExpressionStatement) { - ((JsExpressionStatement) astNode).getExpression().setSource(jsLocation); + JsExpression expression = ((JsExpressionStatement) astNode).getExpression(); + if (expression.getSource() == null) { + expression.setSource(jsLocation); + } } } return astNode; diff --git a/js/js.parser/src/com/google/gwt/dev/js/rhino/Parser.java b/js/js.parser/src/com/google/gwt/dev/js/rhino/Parser.java index cf38c55245e..5c3af8ddd85 100644 --- a/js/js.parser/src/com/google/gwt/dev/js/rhino/Parser.java +++ b/js/js.parser/src/com/google/gwt/dev/js/rhino/Parser.java @@ -180,7 +180,7 @@ public class Parser extends Observable { // by '(', assume starts memberExpr Node memberExprHead = nameNode; nameNode = null; - memberExprNode = memberExprTail(ts, false, memberExprHead, basePosition); + memberExprNode = memberExprTail(ts, false, memberExprHead); } mustMatchToken(ts, TokenStream.LP, "msg.no.paren.parms"); } @@ -708,20 +708,20 @@ public class Parser extends Observable { } private Node expr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException { - CodePosition position = getNextTokenPosition(ts); Node pn = assignExpr(ts, inForInit); while (ts.matchToken(TokenStream.COMMA)) { + CodePosition position = ts.tokenPosition; pn = nf.createBinary(TokenStream.COMMA, pn, assignExpr(ts, inForInit), position); } return pn; } private Node assignExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException { - CodePosition position = getNextTokenPosition(ts); Node pn = condExpr(ts, inForInit); if (ts.matchToken(TokenStream.ASSIGN)) { // omitted: "invalid assignment left-hand side" check. + CodePosition position = ts.tokenPosition; pn = nf.createBinary(TokenStream.ASSIGN, ts.getOp(), pn, assignExpr(ts, inForInit), position); } @@ -729,10 +729,10 @@ public class Parser extends Observable { } private Node condExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException { - CodePosition position = getNextTokenPosition(ts); Node pn = orExpr(ts, inForInit); if (ts.matchToken(TokenStream.HOOK)) { + CodePosition position = ts.tokenPosition; Node ifTrue = assignExpr(ts, false); mustMatchToken(ts, TokenStream.COLON, "msg.no.colon.cond"); Node ifFalse = assignExpr(ts, inForInit); @@ -743,9 +743,9 @@ public class Parser extends Observable { } private Node orExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException { - CodePosition position = getNextTokenPosition(ts); Node pn = andExpr(ts, inForInit); while (ts.matchToken(TokenStream.OR)) { + CodePosition position = ts.tokenPosition; pn = nf.createBinary(TokenStream.OR, pn, andExpr(ts, inForInit), position); } @@ -753,9 +753,9 @@ public class Parser extends Observable { } private Node andExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException { - CodePosition position = getNextTokenPosition(ts); Node pn = bitOrExpr(ts, inForInit); while (ts.matchToken(TokenStream.AND)) { + CodePosition position = ts.tokenPosition; pn = nf.createBinary(TokenStream.AND, pn, bitOrExpr(ts, inForInit), position); } @@ -763,44 +763,46 @@ public class Parser extends Observable { } private Node bitOrExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException { - CodePosition position = getNextTokenPosition(ts); Node pn = bitXorExpr(ts, inForInit); while (ts.matchToken(TokenStream.BITOR)) { + CodePosition position = ts.tokenPosition; pn = nf.createBinary(TokenStream.BITOR, pn, bitXorExpr(ts, inForInit), position); } return pn; } private Node bitXorExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException { - CodePosition position = getNextTokenPosition(ts); Node pn = bitAndExpr(ts, inForInit); while (ts.matchToken(TokenStream.BITXOR)) { + CodePosition position = ts.tokenPosition; pn = nf.createBinary(TokenStream.BITXOR, pn, bitAndExpr(ts, inForInit), position); } return pn; } private Node bitAndExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException { - CodePosition position = getNextTokenPosition(ts); Node pn = eqExpr(ts, inForInit); while (ts.matchToken(TokenStream.BITAND)) { + CodePosition position = ts.tokenPosition; pn = nf.createBinary(TokenStream.BITAND, pn, eqExpr(ts, inForInit), position); } return pn; } private Node eqExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException { - CodePosition position = getNextTokenPosition(ts); Node pn = relExpr(ts, inForInit); + while (ts.matchToken(TokenStream.EQOP)) { + CodePosition position = ts.tokenPosition; pn = nf.createBinary(TokenStream.EQOP, ts.getOp(), pn, relExpr(ts, inForInit), position); } return pn; } private Node relExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException { - CodePosition position = getNextTokenPosition(ts); Node pn = shiftExpr(ts); + CodePosition position = ts.tokenPosition; + while (ts.matchToken(TokenStream.RELOP)) { int op = ts.getOp(); if (inForInit && op == TokenStream.IN) { @@ -809,26 +811,26 @@ public class Parser extends Observable { } pn = nf.createBinary(TokenStream.RELOP, op, pn, shiftExpr(ts), position); + position = ts.tokenPosition; } return pn; } private Node shiftExpr(TokenStream ts) throws IOException, JavaScriptException { - CodePosition position = getNextTokenPosition(ts); Node pn = addExpr(ts); while (ts.matchToken(TokenStream.SHOP)) { + CodePosition position = ts.tokenPosition; pn = nf.createBinary(TokenStream.SHOP, ts.getOp(), pn, addExpr(ts), position); } return pn; } private Node addExpr(TokenStream ts) throws IOException, JavaScriptException { - CodePosition position = getNextTokenPosition(ts); int tt; Node pn = mulExpr(ts); while ((tt = ts.getToken()) == TokenStream.ADD || tt == TokenStream.SUB) { - // flushNewLines + CodePosition position = ts.tokenPosition; pn = nf.createBinary(tt, pn, mulExpr(ts), position); } ts.ungetToken(tt); @@ -837,13 +839,13 @@ public class Parser extends Observable { } private Node mulExpr(TokenStream ts) throws IOException, JavaScriptException { - CodePosition position = getNextTokenPosition(ts); int tt; Node pn = unaryExpr(ts); while ((tt = ts.peekToken()) == TokenStream.MUL || tt == TokenStream.DIV || tt == TokenStream.MOD) { tt = ts.getToken(); + CodePosition position = ts.tokenPosition; pn = nf.createBinary(tt, pn, unaryExpr(ts), position); } @@ -894,6 +896,7 @@ public class Parser extends Observable { if (((peeked = ts.peekToken()) == TokenStream.INC || peeked == TokenStream.DEC) && ts.getLineno() == lineno) { int pf = ts.getToken(); + position = ts.tokenPosition; return nf.createUnary(pf, TokenStream.POST, pn, position); } return pn; @@ -960,16 +963,17 @@ public class Parser extends Observable { pn = primaryExpr(ts); } - return memberExprTail(ts, allowCallSyntax, pn, position); + return memberExprTail(ts, allowCallSyntax, pn); } private Node memberExprTail( TokenStream ts, boolean allowCallSyntax, - Node pn, CodePosition position + Node pn ) throws IOException, JavaScriptException { lastExprEndLine = ts.getLineno(); int tt; while ((tt = ts.getToken()) > TokenStream.EOF) { + CodePosition position = ts.tokenPosition; if (tt == TokenStream.DOT) { ts.treatKeywordAsIdentifier = true; mustMatchToken(ts, TokenStream.NAME, "msg.no.name.after.dot"); @@ -1144,13 +1148,6 @@ public class Parser extends Observable { return null; // should never reach here } - private static CodePosition getNextTokenPosition(TokenStream ts) throws IOException, JavaScriptException { - int tt = ts.getToken(); - CodePosition result = ts.tokenPosition; - ts.ungetToken(tt); - return result; - } - private int lastExprEndLine; // Hack to handle function expr termination. private final IRFactory nf; private boolean ok; // Did the parse encounter an error? diff --git a/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMap.kt b/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMap.kt index dbd24ef2a91..83c3f697771 100644 --- a/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMap.kt +++ b/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMap.kt @@ -16,15 +16,26 @@ package org.jetbrains.kotlin.js.parser.sourcemaps +import java.io.PrintStream import java.io.Reader class SourceMap(val sourceContentResolver: (String) -> Reader?) { val groups = mutableListOf() + + fun debug(writer: PrintStream = System.out) { + for ((index, group) in groups.withIndex()) { + writer.print("${index + 1}:") + for (segment in group.segments) { + writer.print(" ${segment.generatedColumnNumber + 1}:${segment.sourceLineNumber + 1},${segment.sourceColumnNumber + 1}") + } + writer.println() + } + } } class SourceMapSegment( val generatedColumnNumber: Int, - val sourceFileName: String, + val sourceFileName: String?, val sourceLineNumber: Int, val sourceColumnNumber: Int ) diff --git a/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMapLocationRemapper.kt b/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMapLocationRemapper.kt index 467d2e279b7..7d7fa1f426b 100644 --- a/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMapLocationRemapper.kt +++ b/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMapLocationRemapper.kt @@ -18,51 +18,118 @@ package org.jetbrains.kotlin.js.parser.sourcemaps import org.jetbrains.kotlin.js.backend.ast.* -class SourceMapLocationRemapper(val sourceMaps: Map) { +class SourceMapLocationRemapper(private val sourceMap: SourceMap) { fun remap(node: JsNode) { - node.accept(visitor) + val listCollector = JsNodeFlatListCollector() + node.accept(listCollector) + applySourceMap(listCollector.nodeList) } - private val visitor = object : RecursiveJsVisitor() { - private var lastSourceMap: SourceMap? = null - private var lastGroup: SourceMapGroup? = null - private var lastSegmentIndex = 0 + private fun applySourceMap(nodes: List) { + var lastGroup: SourceMapGroup? = null + var lastGroupIndex = 0 + var lastSegment: SourceMapSegment? = null + var lastSegmentIndex = 0 - override fun visitElement(node: JsNode) { - if (node is SourceInfoAwareJsNode) { - if (!remapNode(node)) { - node.source = null + fun findCorrespondingSegment(node: SourceInfoAwareJsNode): SourceMapSegment? { + val source = node.source as? JsLocation ?: return null + val group = sourceMap.groups.getOrElse(source.startLine) { return null } + + if (lastGroup != group) { + if (lastGroup != null) { + val segmentsToSkip = lastGroup!!.segments.drop(lastSegmentIndex).toMutableList() + if (lastGroupIndex + 1 < source.startLine) { + segmentsToSkip += sourceMap.groups.subList((lastGroupIndex + 1), source.startLine).flatMap { it.segments } + } + + segmentsToSkip.lastOrNull()?.let { lastSegment = it } } + lastGroup = group + lastGroupIndex = source.startLine + lastSegmentIndex = 0 } - super.visitElement(node) + + while (lastSegmentIndex < group.segments.size) { + val segment = group.segments[lastSegmentIndex] + if (segment.generatedColumnNumber > source.startChar) break + + lastSegment = segment + lastSegmentIndex++ + } + + return lastSegment } - private fun remapNode(node: SourceInfoAwareJsNode): Boolean { - val source = node.source as? JsLocation ?: return false - val sourceMap = sourceMaps[source.file] ?: return false - val group = sourceMap.groups.getOrElse(source.startLine) { return false } - if (group.segments.isEmpty()) return false - - if (lastSourceMap != sourceMap || lastGroup != group) { - lastSegmentIndex = 0 + for (node in nodes.asSequence().filterIsInstance()) { + val segment = findCorrespondingSegment(node) + val sourceFileName = segment?.sourceFileName + node.source = if (sourceFileName != null) { + val location = JsLocation(segment.sourceFileName, segment.sourceLineNumber, segment.sourceColumnNumber) + JsLocationWithEmbeddedSource(location, sourceMap) { sourceMap.sourceContentResolver(segment.sourceFileName) } } - if (group.segments[lastSegmentIndex].generatedColumnNumber > source.startChar) { - if (lastSegmentIndex == 0) return false - lastSegmentIndex = 0 + else { + null } + } + } - while (lastSegmentIndex + 1 < group.segments.size) { - val nextIndex = lastSegmentIndex + 1 - if (group.segments[nextIndex].generatedColumnNumber > source.startChar) break - lastSegmentIndex = nextIndex + internal class JsNodeFlatListCollector : RecursiveJsVisitor() { + val nodeList = mutableListOf() + + override fun visitDoWhile(x: JsDoWhile) { + nodeList += x + accept(x.body) + accept(x.condition) + } + + override fun visitBinaryExpression(x: JsBinaryOperation) = handleNode(x, x.arg1, x.arg2) + + override fun visitConditional(x: JsConditional) = handleNode(x, x.testExpression, x.thenExpression, x.elseExpression) + + override fun visitArrayAccess(x: JsArrayAccess) = handleNode(x, x.arrayExpression, x.indexExpression) + + override fun visitArray(x: JsArrayLiteral) = handleNode(x, *x.expressions.toTypedArray()) + + override fun visitPrefixOperation(x: JsPrefixOperation) = handleNode(x, x.arg) + + override fun visitPostfixOperation(x: JsPostfixOperation) = handleNode(x, x.arg) + + override fun visitNameRef(nameRef: JsNameRef) = handleNode(nameRef, nameRef.qualifier) + + override fun visitInvocation(invocation: JsInvocation) = + handleNode(invocation, invocation.qualifier, *invocation.arguments.toTypedArray()) + + override fun visitElement(node: JsNode) { + nodeList += node + node.acceptChildren(this) + } + + private fun handleNode(node: JsNode, vararg children: JsNode?) { + val nonNullChildren = children.mapNotNull { it } + + if (nonNullChildren.isEmpty()) { + nodeList += node } + else { + val firstChild = nonNullChildren.first() + if (node.isNotBefore(firstChild)) { + accept(firstChild) + nodeList += node + nonNullChildren.drop(1).forEach { accept(it) } + } + else { + nodeList += node + nonNullChildren.forEach { accept(it) } + } + } + } - val segment = group.segments[lastSegmentIndex] - val location = JsLocation(segment.sourceFileName, segment.sourceLineNumber, segment.sourceColumnNumber) - node.source = JsLocationWithEmbeddedSource(location, sourceMap) { sourceMap.sourceContentResolver(segment.sourceFileName) } - - return true + private fun JsNode.isNotBefore(other: JsNode): Boolean { + val first = (source as? JsLocation ?: return false) + val second = (other.source as? JsLocation ?: return false) + if (first.file != second.file) return false + return first.startLine > second.startLine || (first.startLine == second.startLine && first.startChar >= second.startChar) } } } \ No newline at end of file diff --git a/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMapParser.kt b/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMapParser.kt index 422fb26bb11..e1d137928fe 100644 --- a/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMapParser.kt +++ b/js/js.parser/src/org/jetbrains/kotlin/js/parser/sourcemaps/SourceMapParser.kt @@ -14,22 +14,6 @@ * limitations under the License. */ -/* - * 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.parser.sourcemaps import org.json.JSONArray @@ -115,13 +99,15 @@ object SourceMapParser { if (stream.isEncodedInt) { stream.readInt() ?: return stream.createError("VLQ-encoded name index expected") } - } - if (sourceIndex !in sources.indices) { - return stream.createError("Source index $sourceIndex is out of bounds ${sources.indices}") + if (sourceIndex !in sources.indices) { + return stream.createError("Source index $sourceIndex is out of bounds ${sources.indices}") + } + currentGroup.segments += SourceMapSegment(jsColumn, sourceRoot + sources[sourceIndex], sourceLine, sourceColumn) + } + else { + currentGroup.segments += SourceMapSegment(jsColumn, null, -1, -1) } - - currentGroup.segments += SourceMapSegment(jsColumn, sourceRoot + sources[sourceIndex], sourceLine, sourceColumn) when { stream.isEof -> return stream.createError("Unexpected EOF, ',' or ';' expected") diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicBoxTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicBoxTest.kt index d117416ea77..397b3262cf5 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicBoxTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicBoxTest.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.js.JavaScript +import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.config.EcmaVersion import org.jetbrains.kotlin.js.config.JSConfigurationKeys @@ -42,7 +43,6 @@ import org.jetbrains.kotlin.js.dce.InputFile import org.jetbrains.kotlin.js.facade.* import org.jetbrains.kotlin.js.parser.parse import org.jetbrains.kotlin.js.parser.sourcemaps.* -import org.jetbrains.kotlin.js.sourceMap.JsSourceGenerationVisitor import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder import org.jetbrains.kotlin.js.test.utils.* @@ -430,8 +430,8 @@ abstract class BasicBoxTest( val output = TextOutputImpl() val pathResolver = SourceFilePathResolver(mutableListOf(File("."))) - val sourceMapBuilder = SourceMap3Builder(outputFile, output, "", SourceMapBuilderConsumer(pathResolver, false, false)) - generatedProgram.accept(JsSourceGenerationVisitor(output, sourceMapBuilder)) + val sourceMapBuilder = SourceMap3Builder(outputFile, output, "") + generatedProgram.accept(JsToStringGenerationVisitor(output, SourceMapBuilderConsumer(sourceMapBuilder, pathResolver, false, false))) val code = output.toString() val generatedSourceMap = sourceMapBuilder.build() @@ -446,7 +446,7 @@ abstract class BasicBoxTest( is SourceMapError -> error("Could not parse source map: ${sourceMapParseResult.message}") } - val remapper = SourceMapLocationRemapper(mapOf(outputFile.path to sourceMap)) + val remapper = SourceMapLocationRemapper(sourceMap) remapper.remap(parsedProgram) val codeWithRemappedLines = parsedProgram.toStringWithLineNumbers() diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/optimizer/BasicOptimizerTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/optimizer/BasicOptimizerTest.kt index b2b57b65d64..6f73a2cd7bb 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/optimizer/BasicOptimizerTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/optimizer/BasicOptimizerTest.kt @@ -16,15 +16,14 @@ package org.jetbrains.kotlin.js.test.optimizer - import com.google.gwt.dev.js.rhino.CodePosition import com.google.gwt.dev.js.rhino.ErrorReporter import com.intellij.openapi.util.io.FileUtil +import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.metadata.synthetic import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor import org.jetbrains.kotlin.js.parser.parse -import org.jetbrains.kotlin.js.sourceMap.JsSourceGenerationVisitor import org.jetbrains.kotlin.js.test.BasicBoxTest import org.jetbrains.kotlin.js.test.createScriptEngine import org.jetbrains.kotlin.js.translate.utils.JsAstUtils @@ -120,7 +119,7 @@ abstract class BasicOptimizerTest(private var basePath: String) { private fun astToString(ast: List): String { val output = TextOutputImpl() - val visitor = JsSourceGenerationVisitor(output, null) + val visitor = JsToStringGenerationVisitor(output) for (stmt in ast) { stmt.accept(visitor) } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/AmbiguousAstSourcePropagation.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/AmbiguousAstSourcePropagation.kt index 2769ed9c360..4c8ec193331 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/AmbiguousAstSourcePropagation.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/AmbiguousAstSourcePropagation.kt @@ -16,64 +16,20 @@ package org.jetbrains.kotlin.js.test.utils -import com.intellij.psi.PsiElement import org.jetbrains.kotlin.js.backend.ast.* class AmbiguousAstSourcePropagation : RecursiveJsVisitor() { - private var sourceDefined = false - - override fun visitConditional(x: JsConditional) = acceptAll(x, x.testExpression, x.thenExpression, x.elseExpression) - - override fun visitBinaryExpression(x: JsBinaryOperation) = acceptAll(x, x.arg1, x.arg2) - - override fun visitPostfixOperation(x: JsPostfixOperation) = acceptAll(x, x.arg) - - override fun visitArrayAccess(x: JsArrayAccess) = acceptAll(x, x.arrayExpression, x.indexExpression) - - override fun visitPropertyInitializer(x: JsPropertyInitializer) = acceptAll(x, x.labelExpr, x.valueExpr) - - override fun visitInvocation(invocation: JsInvocation) = acceptAll(invocation, invocation.qualifier, - *invocation.arguments.toTypedArray()) - - override fun visitNameRef(nameRef: JsNameRef) { - val qualifier = nameRef.qualifier - if (qualifier != null) { - acceptAll(nameRef, qualifier) - } - else { - super.visitNameRef(nameRef) - } - } + private var lastSource: Any? = null override fun visitElement(node: JsNode) { - val old = sourceDefined - propagate(node) + val source = node.source + if (source == null && node is JsExpression) { + node.source = lastSource + } - sourceDefined = false + val oldLastSource = lastSource + lastSource = node.source super.visitElement(node) - sourceDefined = old - } - - private fun acceptAll(node: JsNode, first: JsNode, vararg remaining: JsNode) { - val old = sourceDefined - propagate(node) - - accept(first) - - sourceDefined = false - remaining.forEach { accept(it) } - sourceDefined = old - } - - private fun propagate(node: JsNode) { - if (!sourceDefined) { - val source = node.source - if (source is JsLocationWithSource || source is PsiElement) { - sourceDefined = true - } - } - else if (node !is JsExpressionStatement) { - node.source = null - } + lastSource = oldLastSource } } \ No newline at end of file diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/LineCollector.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/LineCollector.kt index c70ca558636..dcb6b2d734a 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/LineCollector.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/LineCollector.kt @@ -87,10 +87,9 @@ class LineCollector : RecursiveJsVisitor() { override fun visitDoWhile(x: JsDoWhile) { withStatement(x) { - handleNodeLocation(x) + x.body.accept(this) x.condition.accept(this) } - x.body.accept(this) } override fun visitFor(x: JsFor) { @@ -130,8 +129,8 @@ class LineCollector : RecursiveJsVisitor() { override fun visit(x: JsSwitch) { withStatement(x) { x.expression.accept(this) + x.cases.forEach { accept(it) } } - x.cases.forEach { accept(it) } } override fun visitThrow(x: JsThrow) { @@ -140,6 +139,14 @@ class LineCollector : RecursiveJsVisitor() { } } + override fun visitTry(x: JsTry) { + withStatement(x) { + x.tryBlock.acceptChildren(this) + x.catches?.forEach { accept(it) } + x.finallyBlock?.acceptChildren(this) + } + } + private fun withStatement(statement: JsStatement, action: () -> Unit) { val oldStatement = currentStatement currentStatement = statement diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/LineOutputToStringVisitor.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/LineOutputToStringVisitor.kt index ac99b58f7ad..b6f381f7dc6 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/LineOutputToStringVisitor.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/utils/LineOutputToStringVisitor.kt @@ -73,6 +73,11 @@ class LineOutputToStringVisitor(output: TextOutput, val lineCollector: LineColle super.visitReturn(x) } + override fun visitTry(x: JsTry) { + printLineNumbers(x) + super.visitTry(x) + } + override fun visit(x: JsSwitch) { printLineNumbers(x) super.visit(x) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/facade/SourceMapBuilderConsumer.java b/js/js.translator/src/org/jetbrains/kotlin/js/facade/SourceMapBuilderConsumer.java index 2154bf93c84..4f3f1a1e458 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/facade/SourceMapBuilderConsumer.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/facade/SourceMapBuilderConsumer.java @@ -19,17 +19,24 @@ package org.jetbrains.kotlin.js.facade; import com.intellij.openapi.editor.Document; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.util.PairConsumer; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.js.backend.SourceLocationConsumer; +import org.jetbrains.kotlin.js.backend.ast.JsLocation; import org.jetbrains.kotlin.js.backend.ast.JsLocationWithSource; import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver; -import org.jetbrains.kotlin.js.sourceMap.SourceMapBuilder; +import org.jetbrains.kotlin.js.sourceMap.SourceMapMappingConsumer; import java.io.*; import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; import java.util.function.Supplier; -public class SourceMapBuilderConsumer implements PairConsumer { +public class SourceMapBuilderConsumer implements SourceLocationConsumer { + @NotNull + private final SourceMapMappingConsumer mappingConsumer; + @NotNull private final SourceFilePathResolver pathResolver; @@ -37,25 +44,50 @@ public class SourceMapBuilderConsumer implements PairConsumer sourceStack = new ArrayList<>(); + public SourceMapBuilderConsumer( + @NotNull SourceMapMappingConsumer mappingConsumer, @NotNull SourceFilePathResolver pathResolver, boolean provideCurrentModuleContent, boolean provideExternalModuleContent ) { + this.mappingConsumer = mappingConsumer; this.pathResolver = pathResolver; this.provideCurrentModuleContent = provideCurrentModuleContent; this.provideExternalModuleContent = provideExternalModuleContent; } @Override - public void consume(SourceMapBuilder builder, Object sourceInfo) { + public void newLine() { + mappingConsumer.newLine(); + } + + @Override + public void pushSourceInfo(@Nullable Object info) { + sourceStack.add(info); + addMapping(info); + } + + @Override + public void popSourceInfo() { + sourceStack.remove(sourceStack.size() - 1); + Object sourceInfo = !sourceStack.isEmpty() ? sourceStack.get(sourceStack.size() - 1) : null; + addMapping(sourceInfo); + } + + private void addMapping(@Nullable Object sourceInfo) { + if (sourceInfo == null) { + mappingConsumer.addEmptyMapping(); + } if (sourceInfo instanceof PsiElement) { PsiElement element = (PsiElement) sourceInfo; PsiFile psiFile = element.getContainingFile(); int offset = element.getNode().getStartOffset(); Document document = psiFile.getViewProvider().getDocument(); assert document != null; - int line = document.getLineNumber(offset); - int column = offset - document.getLineStartOffset(line); + int sourceLine = document.getLineNumber(offset); + int sourceColumn = offset - document.getLineStartOffset(sourceLine); File file = new File(psiFile.getViewProvider().getVirtualFile().getPath()); try { @@ -73,7 +105,8 @@ public class SourceMapBuilderConsumer implements PairConsumer null; } - builder.addMapping(pathResolver.getPathRelativeToSourceRoots(file), null, contentSupplier, line, column); + mappingConsumer.addMapping(pathResolver.getPathRelativeToSourceRoots(file), null, contentSupplier, + sourceLine, sourceColumn); } catch (IOException e) { throw new RuntimeException("IO error occurred generating source maps", e); @@ -82,7 +115,7 @@ public class SourceMapBuilderConsumer implements PairConsumer contentSupplier = provideExternalModuleContent ? location.getSourceProvider()::invoke : () -> null; - builder.addMapping(location.getFile(), location.getIdentityObject(), contentSupplier, + mappingConsumer.addMapping(location.getFile(), location.getIdentityObject(), contentSupplier, location.getStartLine(), location.getStartChar()); } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/facade/TranslationResult.kt b/js/js.translator/src/org/jetbrains/kotlin/js/facade/TranslationResult.kt index 5a995536292..87d382ccf3a 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/facade/TranslationResult.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/facade/TranslationResult.kt @@ -20,14 +20,15 @@ import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.vfs.VfsUtilCore import org.jetbrains.kotlin.backend.common.output.* import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor +import org.jetbrains.kotlin.js.backend.NoOpSourceLocationConsumer import org.jetbrains.kotlin.js.backend.ast.JsProgram import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.config.JsConfig import org.jetbrains.kotlin.js.config.SourceMapSourceEmbedding -import org.jetbrains.kotlin.js.sourceMap.JsSourceGenerationVisitor import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder -import org.jetbrains.kotlin.js.sourceMap.SourceMapBuilder +import org.jetbrains.kotlin.js.backend.SourceLocationConsumer import org.jetbrains.kotlin.js.translate.general.FileTranslationResult import org.jetbrains.kotlin.js.util.TextOutput import org.jetbrains.kotlin.js.util.TextOutputImpl @@ -55,26 +56,37 @@ abstract class TranslationResult protected constructor(val diagnostics: Diagnost val fileTranslationResults: Map ) : TranslationResult(diagnostics) { @Suppress("unused") // Used in kotlin-web-demo in WebDemoTranslatorFacade - fun getCode(): String = getCode(TextOutputImpl(), sourceMapBuilder = null) + fun getCode(): String { + val output = TextOutputImpl() + getCode(output, sourceLocationConsumer = null) + return output.toString() + } fun getOutputFiles(outputFile: File, outputPrefixFile: File?, outputPostfixFile: File?): OutputFileCollection { val output = TextOutputImpl() - val sourceMapBuilder = + + val sourceMapBuilder = SourceMap3Builder(outputFile, output, config.sourceMapPrefix) + val sourceMapBuilderConsumer = if (config.configuration.getBoolean(JSConfigurationKeys.SOURCE_MAP)) { val sourceRoots = config.sourceMapRoots.map { File(it) } val sourceMapContentEmbedding = config.sourceMapContentEmbedding val pathResolver = SourceFilePathResolver(sourceRoots) - val consumer = SourceMapBuilderConsumer( + SourceMapBuilderConsumer( + sourceMapBuilder, pathResolver, sourceMapContentEmbedding == SourceMapSourceEmbedding.ALWAYS, sourceMapContentEmbedding != SourceMapSourceEmbedding.NEVER) - SourceMap3Builder(outputFile, output, config.sourceMapPrefix, consumer) } else { null } - val code = getCode(output, sourceMapBuilder) + getCode(output, sourceMapBuilderConsumer) + if (sourceMapBuilderConsumer != null) { + sourceMapBuilder.addLink() + } + val code = output.toString() + val prefix = outputPrefixFile?.readText() ?: "" val postfix = outputPostfixFile?.readText() ?: "" val sourceFiles = files.map { @@ -108,18 +120,18 @@ abstract class TranslationResult protected constructor(val diagnostics: Diagnost } } - if (sourceMapBuilder != null) { + if (sourceMapBuilderConsumer != null) { sourceMapBuilder.skipLinesAtBeginning(StringUtil.getLineBreakCount(prefix)) val sourceMapFile = SimpleOutputFile(sourceFiles, sourceMapBuilder.outFile.name, sourceMapBuilder.build()) outputFiles.add(sourceMapFile) + sourceMapBuilder.addLink() } return SimpleOutputFileCollection(outputFiles) } - private fun getCode(output: TextOutput, sourceMapBuilder: SourceMapBuilder?): String { - program.accept(JsSourceGenerationVisitor(output, sourceMapBuilder)) - return output.toString() + private fun getCode(output: TextOutput, sourceLocationConsumer: SourceLocationConsumer?) { + program.accept(JsToStringGenerationVisitor(output, sourceLocationConsumer ?: NoOpSourceLocationConsumer)) } } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/sourceMap/JsSourceGenerationVisitor.java b/js/js.translator/src/org/jetbrains/kotlin/js/sourceMap/JsSourceGenerationVisitor.java deleted file mode 100644 index f626b8b725a..00000000000 --- a/js/js.translator/src/org/jetbrains/kotlin/js/sourceMap/JsSourceGenerationVisitor.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.sourceMap; - -import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor; -import org.jetbrains.kotlin.js.backend.ast.*; -import org.jetbrains.kotlin.js.util.TextOutput; -import com.intellij.util.SmartList; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; - -public class JsSourceGenerationVisitor extends JsToStringGenerationVisitor implements TextOutput.OutListener { - @Nullable - private final SourceMapBuilder sourceMapBuilder; - - private final List pendingSources = new SmartList<>(); - - public JsSourceGenerationVisitor(TextOutput out, @Nullable SourceMapBuilder sourceMapBuilder) { - super(out); - this.sourceMapBuilder = sourceMapBuilder; - out.setOutListener(this); - } - - @Override - public void newLined() { - if (sourceMapBuilder != null) { - sourceMapBuilder.newLine(); - } - } - - @Override - public void indentedAfterNewLine() { - if (pendingSources.isEmpty()) return; - - assert sourceMapBuilder != null; - for (Object source : pendingSources) { - sourceMapBuilder.processSourceInfo(source); - } - pendingSources.clear(); - } - - @Override - public void accept(JsNode node) { - mapSource(node); - super.accept(node); - } - - private void mapSource(JsNode node) { - if (sourceMapBuilder != null) { - Object sourceInfo = node.getSource(); - if (sourceInfo != null) { - if (p.isJustNewlined()) { - pendingSources.add(sourceInfo); - } - else { - sourceMapBuilder.processSourceInfo(sourceInfo); - } - } - } - } - - @Override - public void visitProgram(@NotNull JsProgram program) { - program.acceptChildren(this); - if (sourceMapBuilder != null) { - sourceMapBuilder.addLink(); - } - } -} diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/sourceMap/SourceMap3Builder.java b/js/js.translator/src/org/jetbrains/kotlin/js/sourceMap/SourceMap3Builder.java index 4d542078151..72408b57f7a 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/sourceMap/SourceMap3Builder.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/sourceMap/SourceMap3Builder.java @@ -17,11 +17,11 @@ package org.jetbrains.kotlin.js.sourceMap; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.PairConsumer; import gnu.trove.TObjectIntHashMap; import kotlin.io.TextStreamsKt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor; -import org.jetbrains.kotlin.js.common.SourceInfo; import org.jetbrains.kotlin.js.util.TextOutput; import java.io.File; @@ -35,7 +35,6 @@ public class SourceMap3Builder implements SourceMapBuilder { private final File generatedFile; private final TextOutput textOutput; private final String pathPrefix; - private final PairConsumer sourceInfoConsumer; private final TObjectIntHashMap sources = new TObjectIntHashMap() { @Override @@ -52,13 +51,16 @@ public class SourceMap3Builder implements SourceMapBuilder { private int previousSourceIndex; private int previousSourceLine; private int previousSourceColumn; + private int previousMappingOffset; + private int previousPreviousSourceIndex; + private int previousPreviousSourceLine; + private int previousPreviousSourceColumn; + private boolean currentMappingIsEmpty = true; - public SourceMap3Builder(File generatedFile, TextOutput textOutput, String pathPrefix, - PairConsumer sourceInfoConsumer) { + public SourceMap3Builder(File generatedFile, TextOutput textOutput, String pathPrefix) { this.generatedFile = generatedFile; this.textOutput = textOutput; this.pathPrefix = pathPrefix; - this.sourceInfoConsumer = sourceInfoConsumer; } @Override @@ -130,14 +132,6 @@ public class SourceMap3Builder implements SourceMapBuilder { out.insert(0, StringUtil.repeatSymbol(';', count)); } - @Override - public void processSourceInfo(Object sourceInfo) { - if (sourceInfo instanceof SourceInfo) { - throw new UnsupportedOperationException("SourceInfo is not yet supported"); - } - sourceInfoConsumer.consume(this, sourceInfo); - } - private int getSourceIndex(String source, Object identityObject, Supplier contentSupplier) { SourceKey key = new SourceKey(source, identityObject); int sourceIndex = sources.get(key); @@ -152,26 +146,20 @@ public class SourceMap3Builder implements SourceMapBuilder { } @Override - public void addMapping(String source, Object identityObject, Supplier sourceContent, int sourceLine, int sourceColumn) { + public void addMapping( + @NotNull String source, @Nullable Object identityObject, @NotNull Supplier sourceContent, + int sourceLine, int sourceColumn + ) { source = source.replace(File.separatorChar, '/'); - boolean newGroupStarted = previousGeneratedColumn == -1; - if (newGroupStarted) { - previousGeneratedColumn = 0; - } + int sourceIndex = getSourceIndex(source, identityObject, sourceContent); - int columnDiff = textOutput.getColumn() - previousGeneratedColumn; - if (!newGroupStarted && columnDiff == 0) { + if (!currentMappingIsEmpty && previousSourceIndex == sourceIndex && previousSourceLine == sourceLine && + previousSourceColumn == sourceColumn) { return; } - if (!newGroupStarted) { - out.append(','); - } - // TODO fix sections overlapping - // assert columnDiff != 0; - Base64VLQ.encode(out, columnDiff); - previousGeneratedColumn = textOutput.getColumn(); - int sourceIndex = getSourceIndex(source, identityObject, sourceContent); + startMapping(); + Base64VLQ.encode(out, sourceIndex - previousSourceIndex); previousSourceIndex = sourceIndex; @@ -180,6 +168,44 @@ public class SourceMap3Builder implements SourceMapBuilder { Base64VLQ.encode(out, sourceColumn - previousSourceColumn); previousSourceColumn = sourceColumn; + + currentMappingIsEmpty = false; + } + + @Override + public void addEmptyMapping() { + if (!currentMappingIsEmpty) { + startMapping(); + currentMappingIsEmpty = true; + } + } + + private void startMapping() { + boolean newGroupStarted = previousGeneratedColumn == -1; + if (newGroupStarted) { + previousGeneratedColumn = 0; + } + + int columnDiff = textOutput.getColumn() - previousGeneratedColumn; + if (!newGroupStarted) { + out.append(','); + } + + if (columnDiff > 0 || newGroupStarted) { + Base64VLQ.encode(out, columnDiff); + previousGeneratedColumn = textOutput.getColumn(); + + previousMappingOffset = out.length(); + previousPreviousSourceIndex = previousSourceIndex; + previousPreviousSourceLine = previousSourceLine; + previousPreviousSourceColumn = previousSourceColumn; + } + else { + out.setLength(previousMappingOffset); + previousSourceIndex = previousPreviousSourceIndex; + previousSourceLine = previousPreviousSourceLine; + previousSourceColumn = previousPreviousSourceColumn; + } } @Override diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/sourceMap/SourceMapBuilder.java b/js/js.translator/src/org/jetbrains/kotlin/js/sourceMap/SourceMapBuilder.java index 3b1b4fd2ecb..7838c224975 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/sourceMap/SourceMapBuilder.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/sourceMap/SourceMapBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * 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. @@ -17,18 +17,10 @@ package org.jetbrains.kotlin.js.sourceMap; import java.io.File; -import java.io.Reader; -import java.util.function.Supplier; - -public interface SourceMapBuilder { - void newLine(); +public interface SourceMapBuilder extends SourceMapMappingConsumer { void skipLinesAtBeginning(int count); - void addMapping(String source, Object identityObject, Supplier sourceContent, int sourceLine, int sourceColumn); - - void processSourceInfo(Object info); - void addLink(); File getOutFile(); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/sourceMap/SourceMapMappingConsumer.java b/js/js.translator/src/org/jetbrains/kotlin/js/sourceMap/SourceMapMappingConsumer.java new file mode 100644 index 00000000000..057b4c3f428 --- /dev/null +++ b/js/js.translator/src/org/jetbrains/kotlin/js/sourceMap/SourceMapMappingConsumer.java @@ -0,0 +1,35 @@ +/* + * 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.sourceMap; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.Reader; +import java.util.function.Supplier; + +public interface SourceMapMappingConsumer { + void newLine(); + + void addMapping( + @NotNull String source, @Nullable Object sourceIdentity, @NotNull Supplier sourceSupplier, + int sourceLine, int sourceColumn + ); + + void addEmptyMapping(); +} diff --git a/js/js.translator/testData/lineNumbers/andAndWithSideEffect.kt b/js/js.translator/testData/lineNumbers/andAndWithSideEffect.kt index 31b1c940ce1..c25419b19d5 100644 --- a/js/js.translator/testData/lineNumbers/andAndWithSideEffect.kt +++ b/js/js.translator/testData/lineNumbers/andAndWithSideEffect.kt @@ -6,4 +6,4 @@ fun box(x: Int, y: Int) { fun foo(x: Int) = x -// LINES: 3 3 3 4 4 4 4 2 3 7 \ No newline at end of file +// LINES: 3 3 * 3 4 4 * 4 4 2 3 7 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/doWhileWithComplexCondition.kt b/js/js.translator/testData/lineNumbers/doWhileWithComplexCondition.kt index 50d4ff5dfc4..ec097fc3f4a 100644 --- a/js/js.translator/testData/lineNumbers/doWhileWithComplexCondition.kt +++ b/js/js.translator/testData/lineNumbers/doWhileWithComplexCondition.kt @@ -13,4 +13,4 @@ fun box() { ) } -// LINES: 8 3 2 3 3 3 8 11 3 7 12 3 3 4 \ No newline at end of file +// LINES: 8 3 2 3 3 8 11 * 3 7 12 3 3 4 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/enumCompanionObject.kt b/js/js.translator/testData/lineNumbers/enumCompanionObject.kt index 3d0fd394dae..72e5646da2b 100644 --- a/js/js.translator/testData/lineNumbers/enumCompanionObject.kt +++ b/js/js.translator/testData/lineNumbers/enumCompanionObject.kt @@ -6,4 +6,4 @@ enum class Foo { } } -// LINES: 1 1 1 1 2 4 * 2 2 4 5 * 4 4 4 4 * 1 * 1 1 1 1 \ No newline at end of file +// LINES: 1 1 1 1 2 4 * 2 2 4 5 * 4 4 4 4 * 1 * 1 1 1 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/enumObject.kt b/js/js.translator/testData/lineNumbers/enumObject.kt index 3d7efeaf098..e6ab2eae337 100644 --- a/js/js.translator/testData/lineNumbers/enumObject.kt +++ b/js/js.translator/testData/lineNumbers/enumObject.kt @@ -10,4 +10,4 @@ enum class E { } } -// LINES: 1 1 1 1 2 4 8 * 2 2 4 4 5 * 4 4 8 8 9 * 8 8 * 1 * 1 1 1 1 1 1 \ No newline at end of file +// LINES: 1 1 1 1 2 4 8 * 2 2 4 4 5 * 4 4 8 8 9 * 8 8 * 1 * 1 1 1 1 1 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/inlineReturn.kt b/js/js.translator/testData/lineNumbers/inlineReturn.kt index 2f7979f87a6..ce34e36208e 100644 --- a/js/js.translator/testData/lineNumbers/inlineReturn.kt +++ b/js/js.translator/testData/lineNumbers/inlineReturn.kt @@ -21,4 +21,4 @@ fun bar(x: Int) { println("%") } -// LINES: 2 3 4 7 9 10 11 14 16 * 20 * 2 3 4 3 7 9 10 11 10 14 16 20 21 \ No newline at end of file +// LINES: 2 3 4 7 9 10 11 14 16 * 20 * 2 3 4 3 7 9 10 11 10 14 16 * 20 21 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/syntheticCodeInEnums.kt b/js/js.translator/testData/lineNumbers/syntheticCodeInEnums.kt index 3a16652e030..0d167f198cc 100644 --- a/js/js.translator/testData/lineNumbers/syntheticCodeInEnums.kt +++ b/js/js.translator/testData/lineNumbers/syntheticCodeInEnums.kt @@ -8,4 +8,4 @@ enum class E { } } -// LINES: 1 1 1 1 2 3 4 * 2 2 * 3 3 4 4 6 * 4 4 * 1 * 1 1 1 1 1 1 \ No newline at end of file +// LINES: 1 1 1 1 2 3 4 * 2 2 * 3 3 4 4 6 * 4 4 * 1 * 1 1 1 1 1 \ No newline at end of file diff --git a/js/js.translator/testData/lineNumbers/whileWithComplexCondition.kt b/js/js.translator/testData/lineNumbers/whileWithComplexCondition.kt index a926551781e..5babb223b2c 100644 --- a/js/js.translator/testData/lineNumbers/whileWithComplexCondition.kt +++ b/js/js.translator/testData/lineNumbers/whileWithComplexCondition.kt @@ -12,4 +12,4 @@ fun box() { } } -// LINES: 5 2 3 5 8 3 4 9 3 11 \ No newline at end of file +// LINES: 5 2 3 5 8 * 3 4 9 3 11 \ No newline at end of file diff --git a/js/js.translator/testData/test.html b/js/js.translator/testData/test.html index f3888d957fe..b87165d6617 100644 --- a/js/js.translator/testData/test.html +++ b/js/js.translator/testData/test.html @@ -3,10 +3,10 @@ - +