feat(KT-51123): save comments from js-function call inside arguments list.

This commit is contained in:
Artem Kobzar
2022-06-13 12:58:18 +00:00
committed by Space
parent ec9d929532
commit e790607af5
19 changed files with 1858 additions and 172 deletions
@@ -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;