feat(KT-51123): save comments from js-function call inside arguments list.
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 689f293..f15ff5f 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
@@ -173,9 +173,11 @@
         }
     }
 
+    protected boolean insideComments = false;
     protected boolean needSemi = true;
     private boolean lineBreakAfterBlock = true;
 
+
     /**
      * "Global" blocks are either the global block of a fragment, or a block
      * nested directly within some other global block. This definition matters
@@ -198,6 +200,7 @@
 
     @Override
     public void visitArrayAccess(@NotNull JsArrayAccess x) {
+        printCommentsBeforeNode(x);
         pushSourceInfo(x.getSource());
 
         printPair(x, x.getArrayExpression());
@@ -205,17 +208,20 @@
         accept(x.getIndexExpression());
         rightSquare();
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitArray(@NotNull JsArrayLiteral x) {
+        printCommentsBeforeNode(x);
         pushSourceInfo(x.getSource());
 
         leftSquare();
         printExpressions(x.getExpressions());
         rightSquare();
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
@@ -233,6 +239,7 @@
 
     @Override
     public void visitBinaryExpression(@NotNull JsBinaryOperation binaryOperation) {
+        printCommentsBeforeNode(binaryOperation);
         pushSourceInfo(binaryOperation.getSource());
 
         JsBinaryOperator operator = binaryOperation.getOperator();
@@ -277,6 +284,7 @@
             rightParen();
         }
 
+        printCommentsAfterNode(binaryOperation);
         popSourceInfo();
     }
 
@@ -288,6 +296,7 @@
     @Override
     public void visitBoolean(@NotNull JsBooleanLiteral x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         if (x.getValue()) {
             p.print(CHARS_TRUE);
@@ -296,26 +305,31 @@
             p.print(CHARS_FALSE);
         }
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitBreak(@NotNull JsBreak x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(CHARS_BREAK);
         continueOrBreakLabel(x);
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitContinue(@NotNull JsContinue x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(CHARS_CONTINUE);
         continueOrBreakLabel(x);
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
@@ -330,12 +344,14 @@
     @Override
     public void visitCase(@NotNull JsCase x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(CHARS_CASE);
         space();
         accept(x.getCaseExpression());
         _colon();
 
+        printCommentsAfterNode(x);
         popSourceInfo();
 
         newlineOpt();
@@ -362,6 +378,7 @@
     @Override
     public void visitCatch(@NotNull JsCatch x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         spaceOpt();
         p.print(CHARS_CATCH);
@@ -382,6 +399,7 @@
         rightParen();
         spaceOpt();
 
+        printCommentsAfterNode(x);
         popSourceInfo();
 
         sourceLocationConsumer.pushSourceInfo(null);
@@ -392,6 +410,7 @@
     @Override
     public void visitConditional(@NotNull JsConditional x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         // Associativity: for the then and else branches, it is safe to insert
         // another
@@ -407,6 +426,7 @@
         spaceOpt();
         printPair(x, x.getElseExpression());
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
@@ -428,19 +448,23 @@
     @Override
     public void visitDebugger(@NotNull JsDebugger x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(CHARS_DEBUGGER);
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitDefault(@NotNull JsDefault x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(CHARS_DEFAULT);
         _colon();
 
+        printCommentsAfterNode(x);
         popSourceInfo();
         newlineOpt();
 
@@ -452,6 +476,7 @@
     @Override
     public void visitWhile(@NotNull JsWhile x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         _while();
         spaceOpt();
@@ -459,6 +484,7 @@
         accept(x.getCondition());
         rightParen();
 
+        printCommentsAfterNode(x);
         popSourceInfo();
 
         JsStatement body = materialize(x.getBody());
@@ -473,6 +499,7 @@
     @Override
     public void visitDoWhile(@NotNull JsDoWhile x) {
         sourceLocationConsumer.pushSourceInfo(null);
+        printCommentsBeforeNode(x);
 
         p.print(CHARS_DO);
 
@@ -499,6 +526,7 @@
         accept(x.getCondition());
         rightParen();
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
@@ -513,6 +541,7 @@
             source = x.getExpression().getSource();
         }
         pushSourceInfo(source);
+        printCommentsBeforeNode(x);
 
         boolean surroundWithParentheses = JsFirstExpressionVisitor.exec(x);
         if (surroundWithParentheses) {
@@ -523,12 +552,14 @@
             rightParen();
         }
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitFor(@NotNull JsFor x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         _for();
         spaceOpt();
@@ -563,6 +594,7 @@
 
         rightParen();
 
+        printCommentsAfterNode(x);
         popSourceInfo();
 
         JsStatement body = materialize(x.getBody());
@@ -579,6 +611,7 @@
     @Override
     public void visitForIn(@NotNull JsForIn x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         _for();
         spaceOpt();
@@ -609,6 +642,7 @@
 
         rightParen();
 
+        printCommentsAfterNode(x);
         popSourceInfo();
 
         JsStatement body = materialize(x.getBody());
@@ -622,12 +656,14 @@
     @Override
     public void visitFunction(@NotNull JsFunction x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(CHARS_FUNCTION);
         space();
 
         printFunction(x);
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
@@ -659,6 +695,7 @@
     @Override
     public void visitClass(@NotNull JsClass x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(CHARS_CLASS);
         space();
@@ -699,12 +736,14 @@
 
         needSemi = false;
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitIf(@NotNull JsIf x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         _if();
         spaceOpt();
@@ -712,6 +751,7 @@
         accept(x.getIfExpression());
         rightParen();
 
+        printCommentsAfterNode(x);
         popSourceInfo();
 
         JsStatement thenStmt = x.getThenStatement();
@@ -777,6 +817,7 @@
     @Override
     public void visitInvocation(@NotNull JsInvocation invocation) {
         pushSourceInfo(invocation.getSource());
+        printCommentsBeforeNode(invocation);
 
         printPair(invocation, invocation.getQualifier());
 
@@ -784,6 +825,7 @@
         printExpressions(invocation.getArguments());
         rightParen();
 
+        printCommentsAfterNode(invocation);
         popSourceInfo();
     }
 
@@ -800,10 +842,15 @@
 
     @Override
     public void visitNameRef(@NotNull JsNameRef nameRef) {
+        visitNameRef(nameRef, true);
+    }
+
+    public void visitNameRef(@NotNull JsNameRef nameRef, boolean withQualifier) {
         pushSourceInfo(nameRef.getSource());
+        printCommentsBeforeNode(nameRef);
 
         JsExpression qualifier = nameRef.getQualifier();
-        if (qualifier != null) {
+        if (qualifier != null && withQualifier) {
             boolean enclose;
             if (qualifier instanceof JsLiteral.JsValueLiteral) {
                 // "42.foo" is not allowed, but "(42).foo" is.
@@ -826,12 +873,14 @@
         p.maybeIndent();
         p.print(nameRef.getIdent());
 
+        printCommentsAfterNode(nameRef);
         popSourceInfo();
     }
 
     @Override
     public void visitNew(@NotNull JsNew x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(CHARS_NEW);
         space();
@@ -850,39 +899,47 @@
         printExpressions(x.getArguments());
         rightParen();
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitNull(@NotNull JsNullLiteral x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(CHARS_NULL);
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitInt(@NotNull JsIntLiteral x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(x.value);
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitDouble(@NotNull JsDoubleLiteral x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(x.value);
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitObjectLiteral(@NotNull JsObjectLiteral objectLiteral) {
         pushSourceInfo(objectLiteral.getSource());
+        printCommentsBeforeNode(objectLiteral);
 
         p.print('{');
 
@@ -908,26 +965,18 @@
             pushSourceInfo(item.getSource());
 
             JsExpression labelExpr = item.getLabelExpr();
-            // labels can be either string, integral, or decimal literals
-            if (labelExpr instanceof JsNameRef) {
-                p.print(((JsNameRef) labelExpr).getIdent());
-            }
-            else if (labelExpr instanceof JsStringLiteral) {
+
+            if (labelExpr instanceof JsStringLiteral) {
                 JsStringLiteral stringLiteral = (JsStringLiteral) labelExpr;
                 String value = stringLiteral.getValue();
-                boolean isValidIdentifier = IdentifierPolicyKt.isValidES5Identifier(value);
-
-                if (!isValidIdentifier)  {
-                    p.print('\'');
-                }
-
-                p.print(value);
-
-                if (!isValidIdentifier)  {
-                    p.print('\'');
+                if (IdentifierPolicyKt.isValidES5Identifier(value)) {
+                   labelExpr = new JsNameRef(value).withMetadataFrom(stringLiteral);
                 }
             }
-            else {
+            // labels can be either string, integral, or decimal literals
+            if (labelExpr instanceof JsNameRef) {
+                visitNameRef((JsNameRef) labelExpr, false);
+            } else {
                 accept(labelExpr);
             }
 
@@ -949,6 +998,8 @@
         }
 
         p.print('}');
+
+        printCommentsAfterNode(objectLiteral);
         popSourceInfo();
     }
 
@@ -960,6 +1011,7 @@
     @Override
     public void visitPostfixOperation(@NotNull JsPostfixOperation x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         JsUnaryOperator op = x.getOperator();
         JsExpression arg = x.getArg();
@@ -967,12 +1019,14 @@
         printPair(x, arg);
         p.print(op.getSymbol());
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitPrefixOperation(@NotNull JsPrefixOperation x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         JsUnaryOperator op = x.getOperator();
         p.print(op.getSymbol());
@@ -983,6 +1037,7 @@
         // unary operators always associate correctly (I think)
         printPair(x, arg);
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
@@ -994,6 +1049,7 @@
     @Override
     public void visitRegExp(@NotNull JsRegExp x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         slash();
         p.print(x.getPattern());
@@ -1003,12 +1059,14 @@
             p.print(flags);
         }
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitReturn(@NotNull JsReturn x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(CHARS_RETURN);
         JsExpression expr = x.getExpression();
@@ -1017,21 +1075,25 @@
             accept(expr);
         }
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitString(@NotNull JsStringLiteral x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(javaScriptString(x.getValue()));
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visit(@NotNull JsSwitch x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(CHARS_SWITCH);
         spaceOpt();
@@ -1039,6 +1101,7 @@
         accept(x.getExpression());
         rightParen();
 
+        printCommentsAfterNode(x);
         popSourceInfo();
 
 
@@ -1053,25 +1116,30 @@
     @Override
     public void visitThis(@NotNull JsThisRef x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(CHARS_THIS);
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitThrow(@NotNull JsThrow x) {
         pushSourceInfo(x.getSource());
+        printCommentsBeforeNode(x);
 
         p.print(CHARS_THROW);
         space();
         accept(x.getExpression());
 
+        printCommentsAfterNode(x);
         popSourceInfo();
     }
 
     @Override
     public void visitTry(@NotNull JsTry x) {
+        printCommentsBeforeNode(x);
         p.print(CHARS_TRY);
         spaceOpt();
         lineBreakAfterBlock = false;
@@ -1085,11 +1153,13 @@
             spaceOpt();
             accept(finallyBlock);
         }
+        printCommentsAfterNode(x);
     }
 
     @Override
     public void visit(@NotNull JsVar var) {
         pushSourceInfo(var.getSource());
+        printCommentsBeforeNode(var);
 
         nameOf(var);
         JsExpression initExpr = var.getInitExpression();
@@ -1104,12 +1174,14 @@
             }
         }
 
+        printCommentsAfterNode(var);
         popSourceInfo();
     }
 
     @Override
     public void visitVars(@NotNull JsVars vars) {
         pushSourceInfo(vars.getSource());
+        printCommentsBeforeNode(vars);
 
         var();
         space();
@@ -1129,15 +1201,20 @@
             accept(var);
         }
 
+        printCommentsAfterNode(vars);
         popSourceInfo();
     }
 
     @Override
     public void visitSingleLineComment(@NotNull JsSingleLineComment comment) {
+        if (needSemi && insideComments) {
+            semi();
+            space();
+        }
         p.print("//");
         p.print(comment.getText());
-        needSemi = false;
         newline();
+        needSemi = false;
     }
 
     @Override
@@ -1153,8 +1230,6 @@
         }
 
         p.print("*/");
-        needSemi = false;
-        newline();
     }
 
     @Override
@@ -1295,6 +1370,32 @@
         }
     }
 
+    private void printCommentsBeforeNode(JsNode x) {
+       printComments(x.getCommentsBeforeNode(), false);
+    }
+
+    private void printCommentsAfterNode(JsNode x) {
+        printComments(x.getCommentsAfterNode(), true);
+    }
+
+    private void printComments(List<JsComment> comments, boolean isAfterNode) {
+        if (comments == null) return;
+
+        boolean previousNeedSemi = needSemi;
+        needSemi = isAfterNode;
+        insideComments = true;
+
+        for (JsComment comment : comments) {
+            comment.accept(this);
+        }
+
+        insideComments = false;
+
+        if (!isAfterNode) {
+            needSemi = previousNeedSemi;
+        }
+    }
+
     private void popSourceInfo() {
         if (!sourceInfoStack.isEmpty() && sourceInfoStack.remove(sourceInfoStack.size() - 1) != null) {
             sourceLocationConsumer.popSourceInfo();
@@ -1308,6 +1409,7 @@
         }
 
         sourceLocationConsumer.pushSourceInfo(null);
+        printCommentsBeforeNode(x);
 
         boolean needBraces = !x.isTransparent();
 
@@ -1390,6 +1492,8 @@
         }
         needSemi = false;
 
+
+        printCommentsAfterNode(x);
         sourceLocationConsumer.popSourceInfo();
     }
 
diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/AbstractNode.java b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/AbstractNode.java
index 63838d1..fb99016 100644
--- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/AbstractNode.java
+++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/AbstractNode.java
@@ -20,7 +20,13 @@
 import org.jetbrains.kotlin.js.backend.ast.metadata.HasMetadata;
 import org.jetbrains.kotlin.js.util.TextOutputImpl;
 
+import java.util.LinkedList;
+import java.util.List;
+
 abstract class AbstractNode extends HasMetadata implements JsNode {
+    private List<JsComment> commentsBefore = null;
+    private List<JsComment> commentsAfter = null;
+
     @Override
     public String toString() {
         TextOutputImpl out = new TextOutputImpl();
@@ -29,12 +35,34 @@
     }
 
     @SuppressWarnings("unchecked")
-    protected <T extends HasMetadata & JsNode> T withMetadataFrom(T other) {
+    public <T extends HasMetadata & JsNode> T withMetadataFrom(T other) {
         this.copyMetadataFrom(other);
         Object otherSource = other.getSource();
         if (otherSource != null) {
             source(otherSource);
         }
+        setCommentsBeforeNode(other.getCommentsBeforeNode());
+        setCommentsAfterNode(other.getCommentsAfterNode());
         return (T) this;
     }
+
+    @Override
+    public List<JsComment> getCommentsBeforeNode() {
+        return commentsBefore;
+    }
+
+    @Override
+    public List<JsComment> getCommentsAfterNode() {
+        return commentsAfter;
+    }
+
+    @Override
+    public void setCommentsBeforeNode(List<JsComment> comments) {
+        commentsBefore = comments;
+    }
+
+    @Override
+    public void setCommentsAfterNode(List<JsComment> comments) {
+        commentsAfter = comments;
+    }
 }
diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsComment.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsComment.kt
new file mode 100644
index 0000000..751a821
--- /dev/null
+++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsComment.kt
@@ -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 org.jetbrains.kotlin.js.backend.ast
+
+interface JsComment : JsStatement {
+    val text: String
+}
\ No newline at end of file
diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsMultiLineComment.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsMultiLineComment.kt
index 12a7496..849a34d 100644
--- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsMultiLineComment.kt
+++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsMultiLineComment.kt
@@ -5,7 +5,7 @@
 
 package org.jetbrains.kotlin.js.backend.ast
 
-class JsMultiLineComment(val text: String) : SourceInfoAwareJsNode(), JsStatement {
+class JsMultiLineComment(override val text: String) : SourceInfoAwareJsNode(), JsComment {
     override fun accept(visitor: JsVisitor) {
         visitor.visitMultiLineComment(this)
     }
diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsNode.java b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsNode.java
index 1bc18a2..dd81329 100644
--- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsNode.java
+++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsNode.java
@@ -6,6 +6,9 @@
 
 import org.jetbrains.annotations.NotNull;
 
+import java.util.LinkedList;
+import java.util.List;
+
 public interface JsNode {
     /**
      * Causes this object to have the visitor visit itself and its children.
@@ -40,4 +43,12 @@
      * @param ctx the context of an existing traversal
      */
     void traverse(JsVisitorWithContext visitor, JsContext ctx);
+
+    List<JsComment> getCommentsBeforeNode();
+
+    List<JsComment> getCommentsAfterNode();
+
+    void setCommentsBeforeNode(List<JsComment> comment);
+
+    void setCommentsAfterNode(List<JsComment> comment);
 }
diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsSingleLineComment.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsSingleLineComment.kt
index b299b92..2129cd7 100644
--- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsSingleLineComment.kt
+++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsSingleLineComment.kt
@@ -5,7 +5,7 @@
 
 package org.jetbrains.kotlin.js.backend.ast
 
-class JsSingleLineComment(val text: String) : SourceInfoAwareJsNode(), JsStatement {
+class JsSingleLineComment(override val text: String) : SourceInfoAwareJsNode(), JsComment {
     override fun accept(visitor: JsVisitor) {
         visitor.visitSingleLineComment(this)
     }
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 85e51ab..24b13ff 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
@@ -17,6 +17,7 @@
 
 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.kotlin.js.backend.ast.*;
 
 import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
 
 public class JsAstMapper {
@@ -44,7 +46,18 @@
     }
 
     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 @@
             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 @@
         }
         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;
+    }
 }
diff --git a/js/js.parser/src/com/google/gwt/dev/js/rhino/Comment.kt b/js/js.parser/src/com/google/gwt/dev/js/rhino/Comment.kt
new file mode 100644
index 0000000..77da894
--- /dev/null
+++ b/js/js.parser/src/com/google/gwt/dev/js/rhino/Comment.kt
@@ -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;
+}
\ No newline at end of file
diff --git a/js/js.parser/src/com/google/gwt/dev/js/rhino/IRFactory.java b/js/js.parser/src/com/google/gwt/dev/js/rhino/IRFactory.java
index 31ff4c9..1ab1de0 100644
--- a/js/js.parser/src/com/google/gwt/dev/js/rhino/IRFactory.java
+++ b/js/js.parser/src/com/google/gwt/dev/js/rhino/IRFactory.java
@@ -331,14 +331,6 @@
         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) {
diff --git a/js/js.parser/src/com/google/gwt/dev/js/rhino/Node.java b/js/js.parser/src/com/google/gwt/dev/js/rhino/Node.java
index 587855d..1f9cd3f 100644
--- a/js/js.parser/src/com/google/gwt/dev/js/rhino/Node.java
+++ b/js/js.parser/src/com/google/gwt/dev/js/rhino/Node.java
@@ -90,37 +90,6 @@
         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 @@
         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 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 @@
     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;
 }
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 836b816..35f8421 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
@@ -110,7 +110,7 @@
 
         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 @@
         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 @@
     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 @@
 
         int lastExprType; // For wellTerminated
 
-        tt = ts.getTokenWithComment();
+        tt = ts.getToken();
         CodePosition position = ts.tokenPosition;
 
         switch (tt) {
@@ -594,14 +600,6 @@
                 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 @@
             }
         }
 
-        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 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 @@
         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 @@
     ) 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 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 @@
         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?
diff --git a/js/js.parser/src/com/google/gwt/dev/js/rhino/TokenStream.java b/js/js.parser/src/com/google/gwt/dev/js/rhino/TokenStream.java
index f22d76b..61f3e3d 100644
--- a/js/js.parser/src/com/google/gwt/dev/js/rhino/TokenStream.java
+++ b/js/js.parser/src/com/google/gwt/dev/js/rhino/TokenStream.java
@@ -253,8 +253,6 @@
 
         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 @@
                 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 @@
         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 @@
         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 @@
         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 @@
                 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 @@
                     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 @@
         }
     }
 
+    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 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 @@
     CodePosition tokenPosition;
     CodePosition lastTokenPosition;
 
+    private Comment headComment;
+    private Comment lastComment;
+
     private int op;
     public boolean treatKeywordAsIdentifier;
 
diff --git a/js/js.serializer/src/js-ast.proto b/js/js.serializer/src/js-ast.proto
index 1510c0c..a5e3c70 100644
--- a/js/js.serializer/src/js-ast.proto
+++ b/js/js.serializer/src/js-ast.proto
@@ -47,6 +47,8 @@
     optional bool synthetic = 3 [default = false];
     optional SideEffects side_effects = 4 [default = AFFECTS_STATE];
     optional JsImportedModule local_alias = 5;
+    repeated Comment before_comments = 6;
+    repeated Comment after_comments = 7;
 
     oneof expression {
         int32 simple_name_reference = 22;
@@ -128,6 +130,11 @@
     }
 }
 
+message Comment {
+    required string text = 1;
+    required bool multiline = 2;
+}
+
 message BinaryOperation {
     required Expression left = 1;
     required Expression right = 2;
@@ -233,6 +240,8 @@
     optional int32 fileId = 1;
     optional Location location = 2;
     optional bool synthetic = 3 [default = false];
+    repeated Comment before_comments = 4;
+    repeated Comment after_comments = 5;
 
     oneof statement {
         Return return_statement = 21;
diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstDeserializerBase.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstDeserializerBase.kt
index e8a0aff..f3df930 100644
--- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstDeserializerBase.kt
+++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstDeserializerBase.kt
@@ -28,7 +28,19 @@
         return statement
     }
 
-    protected fun deserializeNoMetadata(proto: JsAstProtoBuf.Statement): JsStatement = when (proto.statementCase) {
+    protected fun deserializeNoMetadata(proto: JsAstProtoBuf.Statement): JsStatement {
+        return deserializeNoMetadataHelper(proto).apply {
+            if (proto.beforeCommentsCount != 0) {
+                commentsBeforeNode = proto.beforeCommentsList.map(::deserializeComment)
+            }
+
+            if (proto.afterCommentsCount != 0) {
+                commentsAfterNode = proto.afterCommentsList.map(::deserializeComment)
+            }
+        }
+    }
+
+    protected fun deserializeNoMetadataHelper(proto: JsAstProtoBuf.Statement): JsStatement = when (proto.statementCase) {
         JsAstProtoBuf.Statement.StatementCase.RETURN_STATEMENT -> {
             val returnProto = proto.returnStatement
             JsReturn(if (returnProto.hasValue()) deserialize(returnProto.value) else null)
@@ -192,7 +204,19 @@
         )
     }
 
-    protected fun deserializeNoMetadata(proto: JsAstProtoBuf.Expression): JsExpression = when (proto.expressionCase) {
+    protected fun deserializeNoMetadata(proto: JsAstProtoBuf.Expression): JsExpression {
+        return deserializeNoMetadataHelper(proto).apply {
+            if (proto.beforeCommentsCount != 0) {
+                commentsBeforeNode = proto.beforeCommentsList.map(::deserializeComment)
+            }
+
+            if (proto.afterCommentsCount != 0) {
+                commentsAfterNode = proto.afterCommentsList.map(::deserializeComment)
+            }
+        }
+    }
+
+    protected fun deserializeNoMetadataHelper(proto: JsAstProtoBuf.Expression): JsExpression = when (proto.expressionCase) {
         JsAstProtoBuf.Expression.ExpressionCase.THIS_LITERAL -> JsThisRef()
         JsAstProtoBuf.Expression.ExpressionCase.NULL_LITERAL -> JsNullLiteral()
         JsAstProtoBuf.Expression.ExpressionCase.TRUE_LITERAL -> JsBooleanLiteral(true)
@@ -480,5 +504,13 @@
         return node
     }
 
+    protected fun deserializeComment(comment: JsAstProtoBuf.Comment): JsComment {
+        return if (comment.multiline) {
+            JsMultiLineComment(comment.text)
+        } else {
+            JsSingleLineComment(comment.text)
+        }
+    }
+
     protected abstract fun embedSources(deserializedLocation: JsLocation, file: String): JsLocationWithSource?
 }
\ No newline at end of file
diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java
index 99e31bf..3833511 100644
--- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java
+++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java
@@ -1343,6 +1343,34 @@
     org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.JsImportedModule getLocalAlias();
 
     /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+     */
+    java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> 
+        getBeforeCommentsList();
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+     */
+    org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment getBeforeComments(int index);
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+     */
+    int getBeforeCommentsCount();
+
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+     */
+    java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> 
+        getAfterCommentsList();
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+     */
+    org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment getAfterComments(int index);
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+     */
+    int getAfterCommentsCount();
+
+    /**
      * <code>optional int32 simple_name_reference = 22;</code>
      */
     boolean hasSimpleNameReference();
@@ -1629,6 +1657,22 @@
               bitField0_ |= 0x00000010;
               break;
             }
+            case 50: {
+              if (!((mutable_bitField0_ & 0x00000020) == 0x00000020)) {
+                beforeComments_ = new java.util.ArrayList<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment>();
+                mutable_bitField0_ |= 0x00000020;
+              }
+              beforeComments_.add(input.readMessage(org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.PARSER, extensionRegistry));
+              break;
+            }
+            case 58: {
+              if (!((mutable_bitField0_ & 0x00000040) == 0x00000040)) {
+                afterComments_ = new java.util.ArrayList<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment>();
+                mutable_bitField0_ |= 0x00000040;
+              }
+              afterComments_.add(input.readMessage(org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.PARSER, extensionRegistry));
+              break;
+            }
             case 176: {
               expressionCase_ = 22;
               expression_ = input.readInt32();
@@ -1878,6 +1922,12 @@
         throw new org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException(
             e.getMessage()).setUnfinishedMessage(this);
       } finally {
+        if (((mutable_bitField0_ & 0x00000020) == 0x00000020)) {
+          beforeComments_ = java.util.Collections.unmodifiableList(beforeComments_);
+        }
+        if (((mutable_bitField0_ & 0x00000040) == 0x00000040)) {
+          afterComments_ = java.util.Collections.unmodifiableList(afterComments_);
+        }
         try {
           unknownFieldsCodedOutput.flush();
         } catch (java.io.IOException e) {
@@ -2048,6 +2098,76 @@
       return localAlias_;
     }
 
+    public static final int BEFORE_COMMENTS_FIELD_NUMBER = 6;
+    private java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> beforeComments_;
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+     */
+    public java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> getBeforeCommentsList() {
+      return beforeComments_;
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+     */
+    public java.util.List<? extends org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.CommentOrBuilder> 
+        getBeforeCommentsOrBuilderList() {
+      return beforeComments_;
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+     */
+    public int getBeforeCommentsCount() {
+      return beforeComments_.size();
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+     */
+    public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment getBeforeComments(int index) {
+      return beforeComments_.get(index);
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+     */
+    public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.CommentOrBuilder getBeforeCommentsOrBuilder(
+        int index) {
+      return beforeComments_.get(index);
+    }
+
+    public static final int AFTER_COMMENTS_FIELD_NUMBER = 7;
+    private java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> afterComments_;
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+     */
+    public java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> getAfterCommentsList() {
+      return afterComments_;
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+     */
+    public java.util.List<? extends org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.CommentOrBuilder> 
+        getAfterCommentsOrBuilderList() {
+      return afterComments_;
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+     */
+    public int getAfterCommentsCount() {
+      return afterComments_.size();
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+     */
+    public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment getAfterComments(int index) {
+      return afterComments_.get(index);
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+     */
+    public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.CommentOrBuilder getAfterCommentsOrBuilder(
+        int index) {
+      return afterComments_.get(index);
+    }
+
     public static final int SIMPLE_NAME_REFERENCE_FIELD_NUMBER = 22;
     /**
      * <code>optional int32 simple_name_reference = 22;</code>
@@ -2411,6 +2531,8 @@
       synthetic_ = false;
       sideEffects_ = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.SideEffects.AFFECTS_STATE;
       localAlias_ = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.JsImportedModule.getDefaultInstance();
+      beforeComments_ = java.util.Collections.emptyList();
+      afterComments_ = java.util.Collections.emptyList();
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -2430,6 +2552,18 @@
           return false;
         }
       }
+      for (int i = 0; i < getBeforeCommentsCount(); i++) {
+        if (!getBeforeComments(i).isInitialized()) {
+          memoizedIsInitialized = 0;
+          return false;
+        }
+      }
+      for (int i = 0; i < getAfterCommentsCount(); i++) {
+        if (!getAfterComments(i).isInitialized()) {
+          memoizedIsInitialized = 0;
+          return false;
+        }
+      }
       if (hasRegExpLiteral()) {
         if (!getRegExpLiteral().isInitialized()) {
           memoizedIsInitialized = 0;
@@ -2530,6 +2664,12 @@
       if (((bitField0_ & 0x00000010) == 0x00000010)) {
         output.writeMessage(5, localAlias_);
       }
+      for (int i = 0; i < beforeComments_.size(); i++) {
+        output.writeMessage(6, beforeComments_.get(i));
+      }
+      for (int i = 0; i < afterComments_.size(); i++) {
+        output.writeMessage(7, afterComments_.get(i));
+      }
       if (expressionCase_ == 22) {
         output.writeInt32(
             22, (int)((java.lang.Integer) expression_));
@@ -2626,6 +2766,14 @@
         size += org.jetbrains.kotlin.protobuf.CodedOutputStream
           .computeMessageSize(5, localAlias_);
       }
+      for (int i = 0; i < beforeComments_.size(); i++) {
+        size += org.jetbrains.kotlin.protobuf.CodedOutputStream
+          .computeMessageSize(6, beforeComments_.get(i));
+      }
+      for (int i = 0; i < afterComments_.size(); i++) {
+        size += org.jetbrains.kotlin.protobuf.CodedOutputStream
+          .computeMessageSize(7, afterComments_.get(i));
+      }
       if (expressionCase_ == 22) {
         size += org.jetbrains.kotlin.protobuf.CodedOutputStream
           .computeInt32Size(
@@ -2818,6 +2966,10 @@
         bitField0_ = (bitField0_ & ~0x00000008);
         localAlias_ = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.JsImportedModule.getDefaultInstance();
         bitField0_ = (bitField0_ & ~0x00000010);
+        beforeComments_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000020);
+        afterComments_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000040);
         expressionCase_ = 0;
         expression_ = null;
         return this;
@@ -2863,6 +3015,16 @@
           to_bitField0_ |= 0x00000010;
         }
         result.localAlias_ = localAlias_;
+        if (((bitField0_ & 0x00000020) == 0x00000020)) {
+          beforeComments_ = java.util.Collections.unmodifiableList(beforeComments_);
+          bitField0_ = (bitField0_ & ~0x00000020);
+        }
+        result.beforeComments_ = beforeComments_;
+        if (((bitField0_ & 0x00000040) == 0x00000040)) {
+          afterComments_ = java.util.Collections.unmodifiableList(afterComments_);
+          bitField0_ = (bitField0_ & ~0x00000040);
+        }
+        result.afterComments_ = afterComments_;
         if (expressionCase_ == 22) {
           result.expression_ = expression_;
         }
@@ -2948,6 +3110,26 @@
         if (other.hasLocalAlias()) {
           mergeLocalAlias(other.getLocalAlias());
         }
+        if (!other.beforeComments_.isEmpty()) {
+          if (beforeComments_.isEmpty()) {
+            beforeComments_ = other.beforeComments_;
+            bitField0_ = (bitField0_ & ~0x00000020);
+          } else {
+            ensureBeforeCommentsIsMutable();
+            beforeComments_.addAll(other.beforeComments_);
+          }
+          
+        }
+        if (!other.afterComments_.isEmpty()) {
+          if (afterComments_.isEmpty()) {
+            afterComments_ = other.afterComments_;
+            bitField0_ = (bitField0_ & ~0x00000040);
+          } else {
+            ensureAfterCommentsIsMutable();
+            afterComments_.addAll(other.afterComments_);
+          }
+          
+        }
         switch (other.getExpressionCase()) {
           case SIMPLE_NAME_REFERENCE: {
             setSimpleNameReference(other.getSimpleNameReference());
@@ -3055,6 +3237,18 @@
             return false;
           }
         }
+        for (int i = 0; i < getBeforeCommentsCount(); i++) {
+          if (!getBeforeComments(i).isInitialized()) {
+            
+            return false;
+          }
+        }
+        for (int i = 0; i < getAfterCommentsCount(); i++) {
+          if (!getAfterComments(i).isInitialized()) {
+            
+            return false;
+          }
+        }
         if (hasRegExpLiteral()) {
           if (!getRegExpLiteral().isInitialized()) {
             
@@ -3388,6 +3582,256 @@
         return this;
       }
 
+      private java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> beforeComments_ =
+        java.util.Collections.emptyList();
+      private void ensureBeforeCommentsIsMutable() {
+        if (!((bitField0_ & 0x00000020) == 0x00000020)) {
+          beforeComments_ = new java.util.ArrayList<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment>(beforeComments_);
+          bitField0_ |= 0x00000020;
+         }
+      }
+
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+       */
+      public java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> getBeforeCommentsList() {
+        return java.util.Collections.unmodifiableList(beforeComments_);
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+       */
+      public int getBeforeCommentsCount() {
+        return beforeComments_.size();
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+       */
+      public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment getBeforeComments(int index) {
+        return beforeComments_.get(index);
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+       */
+      public Builder setBeforeComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureBeforeCommentsIsMutable();
+        beforeComments_.set(index, value);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+       */
+      public Builder setBeforeComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.Builder builderForValue) {
+        ensureBeforeCommentsIsMutable();
+        beforeComments_.set(index, builderForValue.build());
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+       */
+      public Builder addBeforeComments(org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureBeforeCommentsIsMutable();
+        beforeComments_.add(value);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+       */
+      public Builder addBeforeComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureBeforeCommentsIsMutable();
+        beforeComments_.add(index, value);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+       */
+      public Builder addBeforeComments(
+          org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.Builder builderForValue) {
+        ensureBeforeCommentsIsMutable();
+        beforeComments_.add(builderForValue.build());
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+       */
+      public Builder addBeforeComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.Builder builderForValue) {
+        ensureBeforeCommentsIsMutable();
+        beforeComments_.add(index, builderForValue.build());
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+       */
+      public Builder addAllBeforeComments(
+          java.lang.Iterable<? extends org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> values) {
+        ensureBeforeCommentsIsMutable();
+        org.jetbrains.kotlin.protobuf.AbstractMessageLite.Builder.addAll(
+            values, beforeComments_);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+       */
+      public Builder clearBeforeComments() {
+        beforeComments_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000020);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 6;</code>
+       */
+      public Builder removeBeforeComments(int index) {
+        ensureBeforeCommentsIsMutable();
+        beforeComments_.remove(index);
+
+        return this;
+      }
+
+      private java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> afterComments_ =
+        java.util.Collections.emptyList();
+      private void ensureAfterCommentsIsMutable() {
+        if (!((bitField0_ & 0x00000040) == 0x00000040)) {
+          afterComments_ = new java.util.ArrayList<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment>(afterComments_);
+          bitField0_ |= 0x00000040;
+         }
+      }
+
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+       */
+      public java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> getAfterCommentsList() {
+        return java.util.Collections.unmodifiableList(afterComments_);
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+       */
+      public int getAfterCommentsCount() {
+        return afterComments_.size();
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+       */
+      public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment getAfterComments(int index) {
+        return afterComments_.get(index);
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+       */
+      public Builder setAfterComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureAfterCommentsIsMutable();
+        afterComments_.set(index, value);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+       */
+      public Builder setAfterComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.Builder builderForValue) {
+        ensureAfterCommentsIsMutable();
+        afterComments_.set(index, builderForValue.build());
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+       */
+      public Builder addAfterComments(org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureAfterCommentsIsMutable();
+        afterComments_.add(value);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+       */
+      public Builder addAfterComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureAfterCommentsIsMutable();
+        afterComments_.add(index, value);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+       */
+      public Builder addAfterComments(
+          org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.Builder builderForValue) {
+        ensureAfterCommentsIsMutable();
+        afterComments_.add(builderForValue.build());
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+       */
+      public Builder addAfterComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.Builder builderForValue) {
+        ensureAfterCommentsIsMutable();
+        afterComments_.add(index, builderForValue.build());
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+       */
+      public Builder addAllAfterComments(
+          java.lang.Iterable<? extends org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> values) {
+        ensureAfterCommentsIsMutable();
+        org.jetbrains.kotlin.protobuf.AbstractMessageLite.Builder.addAll(
+            values, afterComments_);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+       */
+      public Builder clearAfterComments() {
+        afterComments_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000040);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 7;</code>
+       */
+      public Builder removeAfterComments(int index) {
+        ensureAfterCommentsIsMutable();
+        afterComments_.remove(index);
+
+        return this;
+      }
+
       /**
        * <code>optional int32 simple_name_reference = 22;</code>
        */
@@ -10080,6 +10524,531 @@
     // @@protoc_insertion_point(class_scope:org.jetbrains.kotlin.serialization.js.ast.DocCommentTag)
   }
 
+  public interface CommentOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:org.jetbrains.kotlin.serialization.js.ast.Comment)
+      org.jetbrains.kotlin.protobuf.MessageLiteOrBuilder {
+
+    /**
+     * <code>required string text = 1;</code>
+     */
+    boolean hasText();
+    /**
+     * <code>required string text = 1;</code>
+     */
+    java.lang.String getText();
+    /**
+     * <code>required string text = 1;</code>
+     */
+    org.jetbrains.kotlin.protobuf.ByteString
+        getTextBytes();
+
+    /**
+     * <code>required bool multiline = 2;</code>
+     */
+    boolean hasMultiline();
+    /**
+     * <code>required bool multiline = 2;</code>
+     */
+    boolean getMultiline();
+  }
+  /**
+   * Protobuf type {@code org.jetbrains.kotlin.serialization.js.ast.Comment}
+   */
+  public static final class Comment extends
+      org.jetbrains.kotlin.protobuf.GeneratedMessageLite implements
+      // @@protoc_insertion_point(message_implements:org.jetbrains.kotlin.serialization.js.ast.Comment)
+      CommentOrBuilder {
+    // Use Comment.newBuilder() to construct.
+    private Comment(org.jetbrains.kotlin.protobuf.GeneratedMessageLite.Builder builder) {
+      super(builder);
+      this.unknownFields = builder.getUnknownFields();
+    }
+    private Comment(boolean noInit) { this.unknownFields = org.jetbrains.kotlin.protobuf.ByteString.EMPTY;}
+
+    private static final Comment defaultInstance;
+    public static Comment getDefaultInstance() {
+      return defaultInstance;
+    }
+
+    public Comment getDefaultInstanceForType() {
+      return defaultInstance;
+    }
+
+    private final org.jetbrains.kotlin.protobuf.ByteString unknownFields;
+    private Comment(
+        org.jetbrains.kotlin.protobuf.CodedInputStream input,
+        org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException {
+      initFields();
+      int mutable_bitField0_ = 0;
+      org.jetbrains.kotlin.protobuf.ByteString.Output unknownFieldsOutput =
+          org.jetbrains.kotlin.protobuf.ByteString.newOutput();
+      org.jetbrains.kotlin.protobuf.CodedOutputStream unknownFieldsCodedOutput =
+          org.jetbrains.kotlin.protobuf.CodedOutputStream.newInstance(
+              unknownFieldsOutput, 1);
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            default: {
+              if (!parseUnknownField(input, unknownFieldsCodedOutput,
+                                     extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+            case 10: {
+              org.jetbrains.kotlin.protobuf.ByteString bs = input.readBytes();
+              bitField0_ |= 0x00000001;
+              text_ = bs;
+              break;
+            }
+            case 16: {
+              bitField0_ |= 0x00000002;
+              multiline_ = input.readBool();
+              break;
+            }
+          }
+        }
+      } catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException(
+            e.getMessage()).setUnfinishedMessage(this);
+      } finally {
+        try {
+          unknownFieldsCodedOutput.flush();
+        } catch (java.io.IOException e) {
+        // Should not happen
+        } finally {
+          unknownFields = unknownFieldsOutput.toByteString();
+        }
+        makeExtensionsImmutable();
+      }
+    }
+    public static org.jetbrains.kotlin.protobuf.Parser<Comment> PARSER =
+        new org.jetbrains.kotlin.protobuf.AbstractParser<Comment>() {
+      public Comment parsePartialFrom(
+          org.jetbrains.kotlin.protobuf.CodedInputStream input,
+          org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException {
+        return new Comment(input, extensionRegistry);
+      }
+    };
+
+    @java.lang.Override
+    public org.jetbrains.kotlin.protobuf.Parser<Comment> getParserForType() {
+      return PARSER;
+    }
+
+    private int bitField0_;
+    public static final int TEXT_FIELD_NUMBER = 1;
+    private java.lang.Object text_;
+    /**
+     * <code>required string text = 1;</code>
+     */
+    public boolean hasText() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>required string text = 1;</code>
+     */
+    public java.lang.String getText() {
+      java.lang.Object ref = text_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        org.jetbrains.kotlin.protobuf.ByteString bs = 
+            (org.jetbrains.kotlin.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          text_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>required string text = 1;</code>
+     */
+    public org.jetbrains.kotlin.protobuf.ByteString
+        getTextBytes() {
+      java.lang.Object ref = text_;
+      if (ref instanceof java.lang.String) {
+        org.jetbrains.kotlin.protobuf.ByteString b = 
+            org.jetbrains.kotlin.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        text_ = b;
+        return b;
+      } else {
+        return (org.jetbrains.kotlin.protobuf.ByteString) ref;
+      }
+    }
+
+    public static final int MULTILINE_FIELD_NUMBER = 2;
+    private boolean multiline_;
+    /**
+     * <code>required bool multiline = 2;</code>
+     */
+    public boolean hasMultiline() {
+      return ((bitField0_ & 0x00000002) == 0x00000002);
+    }
+    /**
+     * <code>required bool multiline = 2;</code>
+     */
+    public boolean getMultiline() {
+      return multiline_;
+    }
+
+    private void initFields() {
+      text_ = "";
+      multiline_ = false;
+    }
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      if (!hasText()) {
+        memoizedIsInitialized = 0;
+        return false;
+      }
+      if (!hasMultiline()) {
+        memoizedIsInitialized = 0;
+        return false;
+      }
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    public void writeTo(org.jetbrains.kotlin.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      getSerializedSize();
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeBytes(1, getTextBytes());
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        output.writeBool(2, multiline_);
+      }
+      output.writeRawBytes(unknownFields);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public int getSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += org.jetbrains.kotlin.protobuf.CodedOutputStream
+          .computeBytesSize(1, getTextBytes());
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        size += org.jetbrains.kotlin.protobuf.CodedOutputStream
+          .computeBoolSize(2, multiline_);
+      }
+      size += unknownFields.size();
+      memoizedSerializedSize = size;
+      return size;
+    }
+
+    private static final long serialVersionUID = 0L;
+    @java.lang.Override
+    protected java.lang.Object writeReplace()
+        throws java.io.ObjectStreamException {
+      return super.writeReplace();
+    }
+
+    public static org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment parseFrom(
+        org.jetbrains.kotlin.protobuf.ByteString data)
+        throws org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment parseFrom(
+        org.jetbrains.kotlin.protobuf.ByteString data,
+        org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment parseFrom(byte[] data)
+        throws org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment parseFrom(
+        byte[] data,
+        org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment parseFrom(
+        java.io.InputStream input,
+        org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+    public static org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
+    }
+    public static org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment parseDelimitedFrom(
+        java.io.InputStream input,
+        org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
+    }
+    public static org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment parseFrom(
+        org.jetbrains.kotlin.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment parseFrom(
+        org.jetbrains.kotlin.protobuf.CodedInputStream input,
+        org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+
+    public static Builder newBuilder() { return Builder.create(); }
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder(org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment prototype) {
+      return newBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() { return newBuilder(this); }
+
+    /**
+     * Protobuf type {@code org.jetbrains.kotlin.serialization.js.ast.Comment}
+     */
+    public static final class Builder extends
+        org.jetbrains.kotlin.protobuf.GeneratedMessageLite.Builder<
+          org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment, Builder>
+        implements
+        // @@protoc_insertion_point(builder_implements:org.jetbrains.kotlin.serialization.js.ast.Comment)
+        org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.CommentOrBuilder {
+      // Construct using org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private void maybeForceBuilderInitialization() {
+      }
+      private static Builder create() {
+        return new Builder();
+      }
+
+      public Builder clear() {
+        super.clear();
+        text_ = "";
+        bitField0_ = (bitField0_ & ~0x00000001);
+        multiline_ = false;
+        bitField0_ = (bitField0_ & ~0x00000002);
+        return this;
+      }
+
+      public Builder clone() {
+        return create().mergeFrom(buildPartial());
+      }
+
+      public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment getDefaultInstanceForType() {
+        return org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.getDefaultInstance();
+      }
+
+      public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment build() {
+        org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment buildPartial() {
+        org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment result = new org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        result.text_ = text_;
+        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+          to_bitField0_ |= 0x00000002;
+        }
+        result.multiline_ = multiline_;
+        result.bitField0_ = to_bitField0_;
+        return result;
+      }
+
+      public Builder mergeFrom(org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment other) {
+        if (other == org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.getDefaultInstance()) return this;
+        if (other.hasText()) {
+          bitField0_ |= 0x00000001;
+          text_ = other.text_;
+          
+        }
+        if (other.hasMultiline()) {
+          setMultiline(other.getMultiline());
+        }
+        setUnknownFields(
+            getUnknownFields().concat(other.unknownFields));
+        return this;
+      }
+
+      public final boolean isInitialized() {
+        if (!hasText()) {
+          
+          return false;
+        }
+        if (!hasMultiline()) {
+          
+          return false;
+        }
+        return true;
+      }
+
+      public Builder mergeFrom(
+          org.jetbrains.kotlin.protobuf.CodedInputStream input,
+          org.jetbrains.kotlin.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int bitField0_;
+
+      private java.lang.Object text_ = "";
+      /**
+       * <code>required string text = 1;</code>
+       */
+      public boolean hasText() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
+      }
+      /**
+       * <code>required string text = 1;</code>
+       */
+      public java.lang.String getText() {
+        java.lang.Object ref = text_;
+        if (!(ref instanceof java.lang.String)) {
+          org.jetbrains.kotlin.protobuf.ByteString bs =
+              (org.jetbrains.kotlin.protobuf.ByteString) ref;
+          java.lang.String s = bs.toStringUtf8();
+          if (bs.isValidUtf8()) {
+            text_ = s;
+          }
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>required string text = 1;</code>
+       */
+      public org.jetbrains.kotlin.protobuf.ByteString
+          getTextBytes() {
+        java.lang.Object ref = text_;
+        if (ref instanceof String) {
+          org.jetbrains.kotlin.protobuf.ByteString b = 
+              org.jetbrains.kotlin.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          text_ = b;
+          return b;
+        } else {
+          return (org.jetbrains.kotlin.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>required string text = 1;</code>
+       */
+      public Builder setText(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        text_ = value;
+        
+        return this;
+      }
+      /**
+       * <code>required string text = 1;</code>
+       */
+      public Builder clearText() {
+        bitField0_ = (bitField0_ & ~0x00000001);
+        text_ = getDefaultInstance().getText();
+        
+        return this;
+      }
+      /**
+       * <code>required string text = 1;</code>
+       */
+      public Builder setTextBytes(
+          org.jetbrains.kotlin.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000001;
+        text_ = value;
+        
+        return this;
+      }
+
+      private boolean multiline_ ;
+      /**
+       * <code>required bool multiline = 2;</code>
+       */
+      public boolean hasMultiline() {
+        return ((bitField0_ & 0x00000002) == 0x00000002);
+      }
+      /**
+       * <code>required bool multiline = 2;</code>
+       */
+      public boolean getMultiline() {
+        return multiline_;
+      }
+      /**
+       * <code>required bool multiline = 2;</code>
+       */
+      public Builder setMultiline(boolean value) {
+        bitField0_ |= 0x00000002;
+        multiline_ = value;
+        
+        return this;
+      }
+      /**
+       * <code>required bool multiline = 2;</code>
+       */
+      public Builder clearMultiline() {
+        bitField0_ = (bitField0_ & ~0x00000002);
+        multiline_ = false;
+        
+        return this;
+      }
+
+      // @@protoc_insertion_point(builder_scope:org.jetbrains.kotlin.serialization.js.ast.Comment)
+    }
+
+    static {
+      defaultInstance = new Comment(true);
+      defaultInstance.initFields();
+    }
+
+    // @@protoc_insertion_point(class_scope:org.jetbrains.kotlin.serialization.js.ast.Comment)
+  }
+
   public interface BinaryOperationOrBuilder extends
       // @@protoc_insertion_point(interface_extends:org.jetbrains.kotlin.serialization.js.ast.BinaryOperation)
       org.jetbrains.kotlin.protobuf.MessageLiteOrBuilder {
@@ -15495,6 +16464,34 @@
     boolean getSynthetic();
 
     /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+     */
+    java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> 
+        getBeforeCommentsList();
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+     */
+    org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment getBeforeComments(int index);
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+     */
+    int getBeforeCommentsCount();
+
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+     */
+    java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> 
+        getAfterCommentsList();
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+     */
+    org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment getAfterComments(int index);
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+     */
+    int getAfterCommentsCount();
+
+    /**
      * <code>optional .org.jetbrains.kotlin.serialization.js.ast.Return return_statement = 21;</code>
      */
     boolean hasReturnStatement();
@@ -15747,6 +16744,22 @@
               synthetic_ = input.readBool();
               break;
             }
+            case 34: {
+              if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) {
+                beforeComments_ = new java.util.ArrayList<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment>();
+                mutable_bitField0_ |= 0x00000008;
+              }
+              beforeComments_.add(input.readMessage(org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.PARSER, extensionRegistry));
+              break;
+            }
+            case 42: {
+              if (!((mutable_bitField0_ & 0x00000010) == 0x00000010)) {
+                afterComments_ = new java.util.ArrayList<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment>();
+                mutable_bitField0_ |= 0x00000010;
+              }
+              afterComments_.add(input.readMessage(org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.PARSER, extensionRegistry));
+              break;
+            }
             case 170: {
               org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Return.Builder subBuilder = null;
               if (statementCase_ == 21) {
@@ -16015,6 +17028,12 @@
         throw new org.jetbrains.kotlin.protobuf.InvalidProtocolBufferException(
             e.getMessage()).setUnfinishedMessage(this);
       } finally {
+        if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) {
+          beforeComments_ = java.util.Collections.unmodifiableList(beforeComments_);
+        }
+        if (((mutable_bitField0_ & 0x00000010) == 0x00000010)) {
+          afterComments_ = java.util.Collections.unmodifiableList(afterComments_);
+        }
         try {
           unknownFieldsCodedOutput.flush();
         } catch (java.io.IOException e) {
@@ -16153,6 +17172,76 @@
       return synthetic_;
     }
 
+    public static final int BEFORE_COMMENTS_FIELD_NUMBER = 4;
+    private java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> beforeComments_;
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+     */
+    public java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> getBeforeCommentsList() {
+      return beforeComments_;
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+     */
+    public java.util.List<? extends org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.CommentOrBuilder> 
+        getBeforeCommentsOrBuilderList() {
+      return beforeComments_;
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+     */
+    public int getBeforeCommentsCount() {
+      return beforeComments_.size();
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+     */
+    public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment getBeforeComments(int index) {
+      return beforeComments_.get(index);
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+     */
+    public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.CommentOrBuilder getBeforeCommentsOrBuilder(
+        int index) {
+      return beforeComments_.get(index);
+    }
+
+    public static final int AFTER_COMMENTS_FIELD_NUMBER = 5;
+    private java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> afterComments_;
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+     */
+    public java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> getAfterCommentsList() {
+      return afterComments_;
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+     */
+    public java.util.List<? extends org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.CommentOrBuilder> 
+        getAfterCommentsOrBuilderList() {
+      return afterComments_;
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+     */
+    public int getAfterCommentsCount() {
+      return afterComments_.size();
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+     */
+    public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment getAfterComments(int index) {
+      return afterComments_.get(index);
+    }
+    /**
+     * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+     */
+    public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.CommentOrBuilder getAfterCommentsOrBuilder(
+        int index) {
+      return afterComments_.get(index);
+    }
+
     public static final int RETURN_STATEMENT_FIELD_NUMBER = 21;
     /**
      * <code>optional .org.jetbrains.kotlin.serialization.js.ast.Return return_statement = 21;</code>
@@ -16497,6 +17586,8 @@
       fileId_ = 0;
       location_ = org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Location.getDefaultInstance();
       synthetic_ = false;
+      beforeComments_ = java.util.Collections.emptyList();
+      afterComments_ = java.util.Collections.emptyList();
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -16510,6 +17601,18 @@
           return false;
         }
       }
+      for (int i = 0; i < getBeforeCommentsCount(); i++) {
+        if (!getBeforeComments(i).isInitialized()) {
+          memoizedIsInitialized = 0;
+          return false;
+        }
+      }
+      for (int i = 0; i < getAfterCommentsCount(); i++) {
+        if (!getAfterComments(i).isInitialized()) {
+          memoizedIsInitialized = 0;
+          return false;
+        }
+      }
       if (hasReturnStatement()) {
         if (!getReturnStatement().isInitialized()) {
           memoizedIsInitialized = 0;
@@ -16622,6 +17725,12 @@
       if (((bitField0_ & 0x00000004) == 0x00000004)) {
         output.writeBool(3, synthetic_);
       }
+      for (int i = 0; i < beforeComments_.size(); i++) {
+        output.writeMessage(4, beforeComments_.get(i));
+      }
+      for (int i = 0; i < afterComments_.size(); i++) {
+        output.writeMessage(5, afterComments_.get(i));
+      }
       if (statementCase_ == 21) {
         output.writeMessage(21, (org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Return) statement_);
       }
@@ -16703,6 +17812,14 @@
         size += org.jetbrains.kotlin.protobuf.CodedOutputStream
           .computeBoolSize(3, synthetic_);
       }
+      for (int i = 0; i < beforeComments_.size(); i++) {
+        size += org.jetbrains.kotlin.protobuf.CodedOutputStream
+          .computeMessageSize(4, beforeComments_.get(i));
+      }
+      for (int i = 0; i < afterComments_.size(); i++) {
+        size += org.jetbrains.kotlin.protobuf.CodedOutputStream
+          .computeMessageSize(5, afterComments_.get(i));
+      }
       if (statementCase_ == 21) {
         size += org.jetbrains.kotlin.protobuf.CodedOutputStream
           .computeMessageSize(21, (org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Return) statement_);
@@ -16883,6 +18000,10 @@
         bitField0_ = (bitField0_ & ~0x00000002);
         synthetic_ = false;
         bitField0_ = (bitField0_ & ~0x00000004);
+        beforeComments_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000008);
+        afterComments_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000010);
         statementCase_ = 0;
         statement_ = null;
         return this;
@@ -16920,6 +18041,16 @@
           to_bitField0_ |= 0x00000004;
         }
         result.synthetic_ = synthetic_;
+        if (((bitField0_ & 0x00000008) == 0x00000008)) {
+          beforeComments_ = java.util.Collections.unmodifiableList(beforeComments_);
+          bitField0_ = (bitField0_ & ~0x00000008);
+        }
+        result.beforeComments_ = beforeComments_;
+        if (((bitField0_ & 0x00000010) == 0x00000010)) {
+          afterComments_ = java.util.Collections.unmodifiableList(afterComments_);
+          bitField0_ = (bitField0_ & ~0x00000010);
+        }
+        result.afterComments_ = afterComments_;
         if (statementCase_ == 21) {
           result.statement_ = statement_;
         }
@@ -16996,6 +18127,26 @@
         if (other.hasSynthetic()) {
           setSynthetic(other.getSynthetic());
         }
+        if (!other.beforeComments_.isEmpty()) {
+          if (beforeComments_.isEmpty()) {
+            beforeComments_ = other.beforeComments_;
+            bitField0_ = (bitField0_ & ~0x00000008);
+          } else {
+            ensureBeforeCommentsIsMutable();
+            beforeComments_.addAll(other.beforeComments_);
+          }
+          
+        }
+        if (!other.afterComments_.isEmpty()) {
+          if (afterComments_.isEmpty()) {
+            afterComments_ = other.afterComments_;
+            bitField0_ = (bitField0_ & ~0x00000010);
+          } else {
+            ensureAfterCommentsIsMutable();
+            afterComments_.addAll(other.afterComments_);
+          }
+          
+        }
         switch (other.getStatementCase()) {
           case RETURN_STATEMENT: {
             mergeReturnStatement(other.getReturnStatement());
@@ -17093,6 +18244,18 @@
             return false;
           }
         }
+        for (int i = 0; i < getBeforeCommentsCount(); i++) {
+          if (!getBeforeComments(i).isInitialized()) {
+            
+            return false;
+          }
+        }
+        for (int i = 0; i < getAfterCommentsCount(); i++) {
+          if (!getAfterComments(i).isInitialized()) {
+            
+            return false;
+          }
+        }
         if (hasReturnStatement()) {
           if (!getReturnStatement().isInitialized()) {
             
@@ -17349,6 +18512,256 @@
         return this;
       }
 
+      private java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> beforeComments_ =
+        java.util.Collections.emptyList();
+      private void ensureBeforeCommentsIsMutable() {
+        if (!((bitField0_ & 0x00000008) == 0x00000008)) {
+          beforeComments_ = new java.util.ArrayList<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment>(beforeComments_);
+          bitField0_ |= 0x00000008;
+         }
+      }
+
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+       */
+      public java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> getBeforeCommentsList() {
+        return java.util.Collections.unmodifiableList(beforeComments_);
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+       */
+      public int getBeforeCommentsCount() {
+        return beforeComments_.size();
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+       */
+      public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment getBeforeComments(int index) {
+        return beforeComments_.get(index);
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+       */
+      public Builder setBeforeComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureBeforeCommentsIsMutable();
+        beforeComments_.set(index, value);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+       */
+      public Builder setBeforeComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.Builder builderForValue) {
+        ensureBeforeCommentsIsMutable();
+        beforeComments_.set(index, builderForValue.build());
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+       */
+      public Builder addBeforeComments(org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureBeforeCommentsIsMutable();
+        beforeComments_.add(value);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+       */
+      public Builder addBeforeComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureBeforeCommentsIsMutable();
+        beforeComments_.add(index, value);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+       */
+      public Builder addBeforeComments(
+          org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.Builder builderForValue) {
+        ensureBeforeCommentsIsMutable();
+        beforeComments_.add(builderForValue.build());
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+       */
+      public Builder addBeforeComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.Builder builderForValue) {
+        ensureBeforeCommentsIsMutable();
+        beforeComments_.add(index, builderForValue.build());
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+       */
+      public Builder addAllBeforeComments(
+          java.lang.Iterable<? extends org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> values) {
+        ensureBeforeCommentsIsMutable();
+        org.jetbrains.kotlin.protobuf.AbstractMessageLite.Builder.addAll(
+            values, beforeComments_);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+       */
+      public Builder clearBeforeComments() {
+        beforeComments_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000008);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment before_comments = 4;</code>
+       */
+      public Builder removeBeforeComments(int index) {
+        ensureBeforeCommentsIsMutable();
+        beforeComments_.remove(index);
+
+        return this;
+      }
+
+      private java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> afterComments_ =
+        java.util.Collections.emptyList();
+      private void ensureAfterCommentsIsMutable() {
+        if (!((bitField0_ & 0x00000010) == 0x00000010)) {
+          afterComments_ = new java.util.ArrayList<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment>(afterComments_);
+          bitField0_ |= 0x00000010;
+         }
+      }
+
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+       */
+      public java.util.List<org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> getAfterCommentsList() {
+        return java.util.Collections.unmodifiableList(afterComments_);
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+       */
+      public int getAfterCommentsCount() {
+        return afterComments_.size();
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+       */
+      public org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment getAfterComments(int index) {
+        return afterComments_.get(index);
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+       */
+      public Builder setAfterComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureAfterCommentsIsMutable();
+        afterComments_.set(index, value);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+       */
+      public Builder setAfterComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.Builder builderForValue) {
+        ensureAfterCommentsIsMutable();
+        afterComments_.set(index, builderForValue.build());
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+       */
+      public Builder addAfterComments(org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureAfterCommentsIsMutable();
+        afterComments_.add(value);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+       */
+      public Builder addAfterComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureAfterCommentsIsMutable();
+        afterComments_.add(index, value);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+       */
+      public Builder addAfterComments(
+          org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.Builder builderForValue) {
+        ensureAfterCommentsIsMutable();
+        afterComments_.add(builderForValue.build());
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+       */
+      public Builder addAfterComments(
+          int index, org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment.Builder builderForValue) {
+        ensureAfterCommentsIsMutable();
+        afterComments_.add(index, builderForValue.build());
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+       */
+      public Builder addAllAfterComments(
+          java.lang.Iterable<? extends org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.Comment> values) {
+        ensureAfterCommentsIsMutable();
+        org.jetbrains.kotlin.protobuf.AbstractMessageLite.Builder.addAll(
+            values, afterComments_);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+       */
+      public Builder clearAfterComments() {
+        afterComments_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000010);
+
+        return this;
+      }
+      /**
+       * <code>repeated .org.jetbrains.kotlin.serialization.js.ast.Comment after_comments = 5;</code>
+       */
+      public Builder removeAfterComments(int index) {
+        ensureAfterCommentsIsMutable();
+        afterComments_.remove(index);
+
+        return this;
+      }
+
       /**
        * <code>optional .org.jetbrains.kotlin.serialization.js.ast.Return return_statement = 21;</code>
        */
diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstSerializerBase.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstSerializerBase.kt
index a569e86..b16eed6 100644
--- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstSerializerBase.kt
+++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstSerializerBase.kt
@@ -174,8 +174,10 @@
             }
         }
 
-        withLocation(statement, { visitor.builder.fileId = it }, { visitor.builder.location = it }) {
-            statement.accept(visitor)
+        withComments(statement, { visitor.builder.addBeforeComments(it) }, { visitor.builder.addAfterComments(it) }) {
+            withLocation(statement, { visitor.builder.fileId = it }, { visitor.builder.location = it }) {
+                statement.accept(visitor)
+            }
         }
 
         if (statement is HasMetadata && statement.synthetic) {
@@ -348,8 +350,10 @@
             }
         }
 
-        withLocation(expression, { visitor.builder.fileId = it }, { visitor.builder.location = it }) {
-            expression.accept(visitor)
+        withComments(expression, { visitor.builder.addBeforeComments(it) }, { visitor.builder.addAfterComments(it) }) {
+            withLocation(expression, { visitor.builder.fileId = it }, { visitor.builder.location = it }) {
+                expression.accept(visitor)
+            }
         }
 
         with(visitor.builder) {
@@ -522,6 +526,18 @@
         result
     }
 
+    protected fun serialize(comment: JsComment): JsAstProtoBuf.Comment {
+        val builder = JsAstProtoBuf.Comment.newBuilder().apply {
+            text = comment.text
+            multiline = when (comment) {
+                is JsSingleLineComment -> false
+                is JsMultiLineComment -> true
+                else -> error("Unknown type of comment ${comment.javaClass.name}")
+            }
+        }
+        return builder.build()
+    }
+
     private inline fun withLocation(node: JsNode, fileConsumer: (Int) -> Unit, locationConsumer: (JsAstProtoBuf.Location) -> Unit, inner: () -> Unit) {
         val location = extractLocation(node)
         var fileChanged = false
@@ -546,5 +562,16 @@
         }
     }
 
+    private inline fun withComments(
+        node: JsNode,
+        beforeCommentsConsumer: (JsAstProtoBuf.Comment) -> Unit,
+        afterCommentsConsumer: (JsAstProtoBuf.Comment) -> Unit,
+        inner: () -> Unit
+    ) {
+        node.commentsBeforeNode?.forEach { beforeCommentsConsumer(serialize(it))}
+        node.commentsAfterNode?.forEach { afterCommentsConsumer(serialize(it))}
+        inner()
+    }
+
     abstract fun extractLocation(node: JsNode): JsLocation?
 }
\ No newline at end of file
diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/testOld/utils/DirectiveTestUtils.java b/js/js.tests/test/org/jetbrains/kotlin/js/testOld/utils/DirectiveTestUtils.java
index 0df4d78..73f8755 100644
--- a/js/js.tests/test/org/jetbrains/kotlin/js/testOld/utils/DirectiveTestUtils.java
+++ b/js/js.tests/test/org/jetbrains/kotlin/js/testOld/utils/DirectiveTestUtils.java
@@ -184,6 +184,10 @@
             this.isElementExists = isElementExists;
         }
 
+        protected boolean isElementExists() {
+            return isElementExists;
+        }
+
         @Override
         void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
             loadArguments(arguments);
@@ -306,26 +310,41 @@
 
         @Override
         protected JsVisitor getJsVisitorForElement() {
-            return isMultiLine ? new RecursiveJsVisitor() {
+            return new RecursiveJsVisitor() {
                 @Override
-                public void visitMultiLineComment(@NotNull JsMultiLineComment comment) {
-                    if (isTheSameText(comment.getText(), text)) {
-                        setElementExists(true);
+                protected void visitElement(@NotNull JsNode node) {
+                    checkCommentExistsIn(node.getCommentsBeforeNode());
+                    checkCommentExistsIn(node.getCommentsAfterNode());
+                    super.visitElement(node);
+                }
+
+                @Override
+                public void visitSingleLineComment(JsSingleLineComment comment) {
+                    checkCommentExistsIn(Arrays.asList(comment));
+                }
+
+                @Override
+                public void visitMultiLineComment(JsMultiLineComment comment) {
+                    checkCommentExistsIn(Arrays.asList(comment));
+                }
+                private void checkCommentExistsIn(List<JsComment> comments) {
+                    if (comments == null) return;
+                    for (JsComment comment : comments) {
+                        if (isNeededCommentType(comment) && isTheSameText(comment.getText(), text)) {
+                            setElementExists(true);
+                        }
                     }
                 }
-            } : new RecursiveJsVisitor() {
-                @Override
-                public void visitSingleLineComment(@NotNull JsSingleLineComment comment) {
-                    if (isTheSameText(comment.getText(), text)) {
-                        setElementExists(true);
-                    }
+
+                private boolean isNeededCommentType(JsComment comment) {
+                    return isMultiLine ? comment instanceof JsMultiLineComment : comment instanceof  JsSingleLineComment;
                 }
             };
         }
 
         @Override
         protected void loadArguments(@NotNull ArgumentsHelper arguments) {
-            this.text = arguments.findNamedArgument("text").replace("\\n", System.lineSeparator());
+            this.text = arguments.findNamedArgument("text").replace("\\n", System.lineSeparator());;
             this.isMultiLine = Boolean.parseBoolean(arguments.findNamedArgument("multiline"));
         }
 
@@ -338,44 +357,10 @@
             for (int i = 0; i < lines1.size(); i++) {
                 if (!lines1.get(i).trim().equals(lines2.get(i).trim())) return false;
             }
-            
+
             return true;
         }
-    };
 
-    private static final DirectiveHandler CHECK_COMMENT_DOESNT_EXIST = new NodeExistenceDirective("CHECK_COMMENT_DOESNT_EXIST", false) {
-        private String text;
-        private boolean isMultiLine;
-
-        @Override
-        protected String getTextForError() {
-            return (isMultiLine ? "Multi line" : "Single line") + " comment with text '" + text + "' exists, but it should not";
-        }
-
-        @Override
-        protected JsVisitor getJsVisitorForElement() {
-            return isMultiLine ? new RecursiveJsVisitor() {
-                @Override
-                public void visitMultiLineComment(@NotNull JsMultiLineComment comment) {
-                    if (comment.getText().trim() == text) {
-                        setElementExists(true);
-                    }
-                }
-            } : new RecursiveJsVisitor() {
-                @Override
-                public void visitSingleLineComment(@NotNull JsSingleLineComment comment) {
-                    if (comment.getText().trim() == text) {
-                        setElementExists(true);
-                    }
-                }
-            };
-        }
-
-        @Override
-        protected void loadArguments(@NotNull ArgumentsHelper arguments) {
-            this.text = arguments.findNamedArgument("text");
-            this.isMultiLine = Boolean.parseBoolean(arguments.findNamedArgument("multiline"));
-        }
     };
 
     private static final DirectiveHandler ONLY_THIS_QUALIFIED_REFERENCES = new DirectiveHandler("ONLY_THIS_QUALIFIED_REFERENCES") {
@@ -496,7 +481,6 @@
             FUNCTIONS_HAVE_SAME_LINES,
             ONLY_THIS_QUALIFIED_REFERENCES,
             CHECK_COMMENT_EXISTS,
-            CHECK_COMMENT_DOESNT_EXIST,
             COUNT_LABELS,
             COUNT_VARS,
             COUNT_BREAKS,
diff --git a/js/js.translator/testData/box/jsCode/comments.kt b/js/js.translator/testData/box/jsCode/comments.kt
index ee58bb1..3a9b846 100644
--- a/js/js.translator/testData/box/jsCode/comments.kt
+++ b/js/js.translator/testData/box/jsCode/comments.kt
@@ -9,13 +9,28 @@
 // CHECK_COMMENT_EXISTS: text="After call single line comment" multiline=false
 // CHECK_COMMENT_EXISTS: text="After call multi line comment" multiline=true
 // CHECK_COMMENT_EXISTS: text="The header multiline\ncomment" multiline=true
-// CHECK_COMMENT_DOESNT_EXIST: text="random position comment 1" multiline=true
-// CHECK_COMMENT_DOESNT_EXIST: text="random position comment 2" multiline=true
-// CHECK_COMMENT_DOESNT_EXIST: text="random position comment 3" multiline=true
 // CHECK_COMMENT_EXISTS: text="1Multi line comment\n" multiline=true
 // CHECK_COMMENT_EXISTS: text="2Multi line comment\n\n\n" multiline=true
 // CHECK_COMMENT_EXISTS: text="3Multi line\n\n\n\n\ncomment\n" multiline=true
 // CHECK_COMMENT_EXISTS: text="" multiline=true
+// CHECK_COMMENT_EXISTS: text="Multi line comment inside function" multiline=true
+// CHECK_COMMENT_EXISTS: text="After call single line comment" multiline=false
+// CHECK_COMMENT_EXISTS: text="After call multi line comment" multiline=true
+// CHECK_COMMENT_EXISTS: text="Before argument 1" multiline=true
+// CHECK_COMMENT_EXISTS: text="Before argument 2" multiline=true
+// CHECK_COMMENT_EXISTS: text="After argument 1" multiline=true
+// CHECK_COMMENT_EXISTS: text="After argument 2" multiline=true
+// CHECK_COMMENT_EXISTS: text="object:" multiline=true
+// CHECK_COMMENT_EXISTS: text="property:" multiline=true
+// CHECK_COMMENT_EXISTS: text="descriptor:" multiline=true
+// CHECK_COMMENT_EXISTS: text="Descriptor end" multiline=true
+
+/*
+* java.lang.AssertionError(Multi line comment with text 'The header multiline\ncomment' doesn't exist)
+  java.lang.AssertionError(Multi line comment with text '1Multi line comment\n' doesn't exist)
+  java.lang.AssertionError(Multi line comment with text '2Multi line comment\n\n\n' doesn't exist)
+  java.lang.AssertionError(Multi line comment with text '3Multi line\n\n\n\n\ncomment\n' doesn't exist)
+* */
 
 package foo
 
@@ -42,8 +57,6 @@
         
         foo(); /* After call multi line comment */
         
-        var /*random position comment 1*/ c /*random position comment 2*/ = /*random position comment 3*/ "Random position";
-        
         /* 1Multi line comment 
         */
         foo();
@@ -63,6 +76,21 @@
         
         /**/
         foo();
+        
+        foo(
+            /* Before argument 1 */
+            /* Before argument 2 */
+            4
+            /* After argument 1 */
+            /* After argument 2 */
+        );
+        
+        var test = {
+             test: Object.defineProperty(/* object: */{}, /* property: */'some_property', /* descriptor: */ {
+              value: 42,
+              writable: false
+            } /* Descriptor end */)
+        }
     """)
     return "OK"
 }
\ No newline at end of file
diff --git a/js/js.translator/testData/js-optimizer/if-reduction/returnStatement.optimized.js b/js/js.translator/testData/js-optimizer/if-reduction/returnStatement.optimized.js
index 0384243..f8a7530b 100644
--- a/js/js.translator/testData/js-optimizer/if-reduction/returnStatement.optimized.js
+++ b/js/js.translator/testData/js-optimizer/if-reduction/returnStatement.optimized.js
@@ -1,5 +1,4 @@
 function test(n) {
-    /*synthetic*/
     return n >= 0 ? n : -n;
 }