feat(KT-51123): save comments from js-function call inside arguments list.
This commit is contained in:
@@ -17,6 +17,7 @@ package com.google.gwt.dev.js;
|
||||
|
||||
import com.google.gwt.dev.js.parserExceptions.JsParserException;
|
||||
import com.google.gwt.dev.js.rhino.CodePosition;
|
||||
import com.google.gwt.dev.js.rhino.Comment;
|
||||
import com.google.gwt.dev.js.rhino.Node;
|
||||
import com.google.gwt.dev.js.rhino.TokenStream;
|
||||
import com.intellij.util.SmartList;
|
||||
@@ -25,6 +26,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class JsAstMapper {
|
||||
@@ -44,7 +46,18 @@ public class JsAstMapper {
|
||||
}
|
||||
|
||||
private JsNode map(Node node) throws JsParserException {
|
||||
return withLocation(mapWithoutLocation(node), node);
|
||||
return withLocation(mapWithComments(node), node);
|
||||
}
|
||||
|
||||
private JsNode mapWithComments(Node node) throws JsParserException {
|
||||
JsNode jsNode = mapWithoutLocation(node);
|
||||
|
||||
if (jsNode != null) {
|
||||
jsNode.setCommentsBeforeNode(mapComments(node.getCommentsBeforeNode()));
|
||||
jsNode.setCommentsAfterNode(mapComments(node.getCommentsAfterNode()));
|
||||
}
|
||||
|
||||
return jsNode;
|
||||
}
|
||||
|
||||
private JsNode mapWithoutLocation(Node node) throws JsParserException {
|
||||
@@ -216,12 +229,6 @@ public class JsAstMapper {
|
||||
case TokenStream.LABEL:
|
||||
return mapLabel(node);
|
||||
|
||||
case TokenStream.SINGLE_LINE_COMMENT:
|
||||
return mapSingleLineComment(node);
|
||||
|
||||
case TokenStream.MULTI_LINE_COMMENT:
|
||||
return mapMultiLineComment(node);
|
||||
|
||||
default:
|
||||
int tokenType = node.getType();
|
||||
throw createParserException("Unexpected top-level token type: "
|
||||
@@ -1139,4 +1146,19 @@ public class JsAstMapper {
|
||||
}
|
||||
return astNode;
|
||||
}
|
||||
|
||||
private List<JsComment> mapComments(Comment comment) {
|
||||
if (comment == null) return null;
|
||||
|
||||
List<JsComment> comments = new LinkedList<>();
|
||||
|
||||
while (comment != null) {
|
||||
String text = comment.getText();
|
||||
JsComment jsComment = comment.isMultiLine() ? new JsMultiLineComment(text) : new JsSingleLineComment(text);
|
||||
comments.add(jsComment);
|
||||
comment = comment.getNext();
|
||||
}
|
||||
|
||||
return comments;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package com.google.gwt.dev.js.rhino
|
||||
|
||||
class Comment(val text: String, val isMultiLine: Boolean) {
|
||||
var next: Comment? = null;
|
||||
}
|
||||
@@ -331,14 +331,6 @@ public class IRFactory {
|
||||
return new Node(nodeType, left, right, nodeOp, location);
|
||||
}
|
||||
|
||||
public Node createSingleLineComment(String string, CodePosition position) {
|
||||
return Node.newComment(TokenStream.SINGLE_LINE_COMMENT, string, position);
|
||||
}
|
||||
|
||||
public Node createMultiLineComment(String string, CodePosition position) {
|
||||
return Node.newComment(TokenStream.MULTI_LINE_COMMENT, string, position);
|
||||
}
|
||||
|
||||
public Node createAssignment(int nodeOp, Node left, Node right, CodePosition location) {
|
||||
int nodeType = left.getType();
|
||||
switch (nodeType) {
|
||||
|
||||
@@ -90,37 +90,6 @@ public class Node implements Cloneable {
|
||||
private String str;
|
||||
}
|
||||
|
||||
private static class CommentNode extends Node {
|
||||
CommentNode(int type, String str, CodePosition position) {
|
||||
super(type, position);
|
||||
if (null == str) {
|
||||
throw new IllegalArgumentException("CommentNode: str is null");
|
||||
}
|
||||
this.str = str;
|
||||
}
|
||||
|
||||
/** returns the string content.
|
||||
* @return non null.
|
||||
*/
|
||||
@Override
|
||||
public String getString() {
|
||||
return this.str;
|
||||
}
|
||||
|
||||
/** sets the string content.
|
||||
* @param str the new value. Non null.
|
||||
*/
|
||||
@Override
|
||||
public void setString(String str) {
|
||||
if (null == str) {
|
||||
throw new IllegalArgumentException("CommentNode: str is null");
|
||||
}
|
||||
this.str = str;
|
||||
}
|
||||
|
||||
private String str;
|
||||
}
|
||||
|
||||
public Node(int nodeType) {
|
||||
type = nodeType;
|
||||
}
|
||||
@@ -222,10 +191,6 @@ public class Node implements Cloneable {
|
||||
return new StringNode(type, str, position);
|
||||
}
|
||||
|
||||
public static Node newComment(int type, String str, CodePosition position) {
|
||||
return new CommentNode(type, str, position);
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
@@ -278,6 +243,24 @@ public class Node implements Cloneable {
|
||||
}
|
||||
}
|
||||
|
||||
public Comment getCommentsBeforeNode() {
|
||||
return commentBefore;
|
||||
}
|
||||
|
||||
public Comment getCommentsAfterNode() {
|
||||
return commentAfter;
|
||||
}
|
||||
|
||||
public void setCommentsBeforeNode(Comment comment) {
|
||||
if (comment == null) return;
|
||||
commentBefore = comment;
|
||||
}
|
||||
|
||||
public void setCommentsAfterNode(Comment comment) {
|
||||
if (comment == null) return;
|
||||
commentAfter = comment;
|
||||
}
|
||||
|
||||
public static final int
|
||||
TARGET_PROP = 1,
|
||||
BREAK_PROP = 2,
|
||||
@@ -441,5 +424,9 @@ public class Node implements Cloneable {
|
||||
private Node first; // first element of a linked list of children
|
||||
private Node last; // last element of a linked list of children
|
||||
private CodePosition position;
|
||||
|
||||
private Comment commentBefore;
|
||||
|
||||
private Comment commentAfter;
|
||||
private int operation;
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ public class Parser {
|
||||
|
||||
while (true) {
|
||||
ts.flags |= TokenStream.TSF_REGEXP;
|
||||
tt = ts.getTokenWithComment();
|
||||
tt = ts.getToken();
|
||||
ts.flags &= ~TokenStream.TSF_REGEXP;
|
||||
|
||||
if (tt <= TokenStream.EOF) {
|
||||
@@ -153,7 +153,7 @@ public class Parser {
|
||||
Node pn = nf.createBlock(ts.tokenPosition);
|
||||
try {
|
||||
int tt;
|
||||
while ((tt = ts.peekTokenWithComment()) > TokenStream.EOF && tt != TokenStream.RC) {
|
||||
while ((tt = ts.peekToken()) > TokenStream.EOF && tt != TokenStream.RC) {
|
||||
if (tt == TokenStream.FUNCTION) {
|
||||
ts.getToken();
|
||||
pn.addChildToBack(function(ts, false));
|
||||
@@ -334,7 +334,13 @@ public class Parser {
|
||||
private Node statement(TokenStream ts) throws IOException {
|
||||
CodePosition position = ts.lastPosition;
|
||||
try {
|
||||
return statementHelper(ts);
|
||||
Comment commentsBefore = getComments(ts);
|
||||
ts.collectCommentsAfter();
|
||||
Node result = statementHelper(ts);
|
||||
result.setCommentsBeforeNode(commentsBefore);
|
||||
ts.collectCommentsAfter();
|
||||
result.setCommentsAfterNode(getComments(ts));
|
||||
return result;
|
||||
}
|
||||
catch (JavaScriptException e) {
|
||||
// skip to end of statement
|
||||
@@ -360,7 +366,7 @@ public class Parser {
|
||||
|
||||
int lastExprType; // For wellTerminated
|
||||
|
||||
tt = ts.getTokenWithComment();
|
||||
tt = ts.getToken();
|
||||
CodePosition position = ts.tokenPosition;
|
||||
|
||||
switch (tt) {
|
||||
@@ -594,14 +600,6 @@ public class Parser {
|
||||
break;
|
||||
}
|
||||
|
||||
case TokenStream.SINGLE_LINE_COMMENT:
|
||||
pn = nf.createSingleLineComment(ts.getString(), ts.tokenPosition);
|
||||
break;
|
||||
|
||||
case TokenStream.MULTI_LINE_COMMENT:
|
||||
pn = nf.createMultiLineComment(ts.getString(), ts.tokenPosition);
|
||||
break;
|
||||
|
||||
case TokenStream.RETURN: {
|
||||
Node retExpr = null;
|
||||
int lineno;
|
||||
@@ -703,9 +701,7 @@ public class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
if (pn.type != TokenStream.SINGLE_LINE_COMMENT && pn.type != TokenStream.MULTI_LINE_COMMENT) {
|
||||
ts.matchToken(TokenStream.SEMI);
|
||||
}
|
||||
ts.matchToken(TokenStream.SEMI);
|
||||
|
||||
return pn;
|
||||
}
|
||||
@@ -740,22 +736,32 @@ public class Parser {
|
||||
|
||||
public Node expr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||
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 {
|
||||
Comment commentBeforeNode = getComments(ts);
|
||||
|
||||
Node pn = condExpr(ts, inForInit);
|
||||
|
||||
pn.setCommentsBeforeNode(commentBeforeNode);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ts.collectCommentsAfter();
|
||||
pn.setCommentsAfterNode(getComments(ts));
|
||||
|
||||
return pn;
|
||||
}
|
||||
|
||||
@@ -952,8 +958,7 @@ public class Parser {
|
||||
if (!matched) {
|
||||
do {
|
||||
listNode.addChildToBack(assignExpr(ts, false));
|
||||
}
|
||||
while (ts.matchToken(TokenStream.COMMA));
|
||||
} while (ts.matchToken(TokenStream.COMMA));
|
||||
|
||||
mustMatchToken(ts, TokenStream.GWT, "msg.no.paren.arg");
|
||||
}
|
||||
@@ -1012,7 +1017,7 @@ public class Parser {
|
||||
) throws IOException, JavaScriptException {
|
||||
lastExprEndLine = ts.getLineno();
|
||||
int tt;
|
||||
while ((tt = ts.getTokenWithComment()) > TokenStream.EOF) {
|
||||
while ((tt = ts.getToken()) > TokenStream.EOF) {
|
||||
CodePosition position = ts.tokenPosition;
|
||||
if (tt == TokenStream.DOT) {
|
||||
ts.treatKeywordAsIdentifier = true;
|
||||
@@ -1050,6 +1055,15 @@ public class Parser {
|
||||
}
|
||||
|
||||
public Node primaryExpr(TokenStream ts) throws IOException, JavaScriptException {
|
||||
Comment commentsBeforeNode = getComments(ts);
|
||||
Node node = primaryExprHelper(ts);
|
||||
node.setCommentsBeforeNode(commentsBeforeNode);
|
||||
ts.collectCommentsAfter();
|
||||
node.setCommentsAfterNode(getComments(ts));
|
||||
return node;
|
||||
}
|
||||
|
||||
private Node primaryExprHelper(TokenStream ts) throws IOException, JavaScriptException {
|
||||
int tt;
|
||||
|
||||
Node pn;
|
||||
@@ -1195,6 +1209,14 @@ public class Parser {
|
||||
return null; // should never reach here
|
||||
}
|
||||
|
||||
private Comment getComments(TokenStream ts) {
|
||||
Comment comment = ts.getHeadComment();
|
||||
if (comment != null) {
|
||||
ts.releaseComments();
|
||||
}
|
||||
return comment;
|
||||
}
|
||||
|
||||
private int lastExprEndLine; // Hack to handle function expr termination.
|
||||
private final IRFactory nf;
|
||||
private boolean ok; // Did the parse encounter an error?
|
||||
|
||||
@@ -253,8 +253,6 @@ public class TokenStream {
|
||||
|
||||
LAST_TOKEN = 147,
|
||||
NUMBER_INT = 148,
|
||||
SINGLE_LINE_COMMENT = 149,
|
||||
MULTI_LINE_COMMENT = 150,
|
||||
|
||||
// This value is only used as a return value for getTokenHelper,
|
||||
// which is only called from getToken and exists to avoid an excessive
|
||||
@@ -415,8 +413,6 @@ public class TokenStream {
|
||||
case NEWLOCAL: return "newlocal";
|
||||
case USELOCAL: return "uselocal";
|
||||
case SCRIPT: return "script";
|
||||
case SINGLE_LINE_COMMENT: return "singlelinecomment";
|
||||
case MULTI_LINE_COMMENT: return "multilinecomment";
|
||||
}
|
||||
return "<unknown="+token+">";
|
||||
}
|
||||
@@ -539,10 +535,6 @@ public class TokenStream {
|
||||
return peekTokenHelper(getToken());
|
||||
}
|
||||
|
||||
public int peekTokenWithComment() throws IOException {
|
||||
return peekTokenHelper(getTokenWithComment());
|
||||
}
|
||||
|
||||
private int peekTokenHelper(int token) throws IOException {
|
||||
this.pushbackToken = token;
|
||||
lastPosition = secondToLastPosition;
|
||||
@@ -596,15 +588,8 @@ public class TokenStream {
|
||||
in.unread();
|
||||
}
|
||||
|
||||
public int getTokenWithComment() throws IOException {
|
||||
lastTokenPosition = tokenPosition;
|
||||
int c;
|
||||
do {
|
||||
c = getTokenHelper();
|
||||
} while (c == RETRY_TOKEN);
|
||||
|
||||
updatePosition();
|
||||
return c;
|
||||
public void collectCommentsAfter() throws IOException {
|
||||
ungetToken(getToken());
|
||||
}
|
||||
|
||||
public int getToken() throws IOException {
|
||||
@@ -612,7 +597,7 @@ public class TokenStream {
|
||||
int c;
|
||||
do {
|
||||
c = getTokenHelper();
|
||||
} while (c == RETRY_TOKEN || c == SINGLE_LINE_COMMENT || c == MULTI_LINE_COMMENT);
|
||||
} while (c == RETRY_TOKEN);
|
||||
|
||||
updatePosition();
|
||||
return c;
|
||||
@@ -1084,8 +1069,8 @@ public class TokenStream {
|
||||
while ((c = in.read()) != -1 && c != '\n') {
|
||||
addToString(c);
|
||||
}
|
||||
this.string = getStringFromBuffer();
|
||||
return SINGLE_LINE_COMMENT;
|
||||
addCommentToQueue(new Comment(getStringFromBuffer(), false));
|
||||
return RETRY_TOKEN;
|
||||
}
|
||||
if (in.match('*')) {
|
||||
stringBufferTop = 0;
|
||||
@@ -1097,8 +1082,8 @@ public class TokenStream {
|
||||
reportTokenError("msg.unterminated.comment", null);
|
||||
return ERROR;
|
||||
}
|
||||
this.string = getStringFromBuffer();
|
||||
return MULTI_LINE_COMMENT; // `goto retry'
|
||||
addCommentToQueue(new Comment(getStringFromBuffer(), true));
|
||||
return RETRY_TOKEN; // `goto retry'
|
||||
}
|
||||
|
||||
// is it a regexp?
|
||||
@@ -1481,6 +1466,17 @@ public class TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
private void addCommentToQueue(Comment comment) {
|
||||
if (headComment == null) {
|
||||
headComment = comment;
|
||||
lastComment = comment;
|
||||
}
|
||||
else {
|
||||
lastComment.setNext(comment);
|
||||
lastComment = comment;
|
||||
}
|
||||
}
|
||||
|
||||
public String getSourceName() { return sourceName; }
|
||||
public int getLineno() { return in.getLineno(); }
|
||||
public int getOp() { return op; }
|
||||
@@ -1491,6 +1487,15 @@ public class TokenStream {
|
||||
public int getTokenno() { return tokenno; }
|
||||
public boolean eof() { return in.eof(); }
|
||||
|
||||
public Comment getHeadComment() {
|
||||
return headComment;
|
||||
}
|
||||
|
||||
public void releaseComments() {
|
||||
headComment = null;
|
||||
lastComment = null;
|
||||
}
|
||||
|
||||
// instance variables
|
||||
private LineBuffer in;
|
||||
|
||||
@@ -1511,6 +1516,9 @@ public class TokenStream {
|
||||
CodePosition tokenPosition;
|
||||
CodePosition lastTokenPosition;
|
||||
|
||||
private Comment headComment;
|
||||
private Comment lastComment;
|
||||
|
||||
private int op;
|
||||
public boolean treatKeywordAsIdentifier;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user