Repository: eslint/eslint (JavaScript)

Issue:
space-before-function-paren removes comments when fixing
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).

    This template is for bug reports. If you are here for another reason, please see below:

    1. To propose a new rule: https://eslint.org/docs/developer-guide/contributing/new-rules
    2. To request a rule change: https://eslint.org/docs/developer-guide/contributing/rule-changes
    3. To request a change that is not a bug fix, rule change, or new rule: https://eslint.org/docs/developer-guide/contributing/changes
    4. If you have any questions, please stop by our chatroom: https://gitter.im/eslint/eslint

    Note that leaving sections blank will make it difficult for us to troubleshoot and we may have to close the issue.
-->

**Tell us about your environment**

* **ESLint Version:** v6.3.0
* **Node Version:** NA (using https://eslint.org/demo)
* **npm Version:** NA (using https://eslint.org/demo)

**What parser (default, Babel-ESLint, etc.) are you using?**
default

**Please show your full configuration:**

<details>
<summary>Configuration</summary>

<!-- Paste your configuration below: -->
```js
{
    "parserOptions": {
        "ecmaVersion": 10,
        "sourceType": "module",
        "ecmaFeatures": {}
    },
    "rules": {
        "space-before-function-paren": ["error", "never"]
    },
    "env": {}
}
```

</details>

**What did you do? Please include the actual source code causing the issue, as well as the command that you used to run ESLint.**

Tried to fix the following code

<!-- Paste the source code below: -->
```js
function delay /*:: <T>*/() {}
```

https://eslint.org/demo#eyJ0ZXh0IjoiLyplc2xpbnQgc3BhY2UtYmVmb3JlLWZ1bmN0aW9uLXBhcmVuOiBbJ2Vycm9yJywgJ25ldmVyJ10qL1xuZnVuY3Rpb24gZGVsYXkgLyo6OiA8VD4qLygpIHt9Iiwib3B0aW9ucyI6eyJwYXJzZXJPcHRpb25zIjp7ImVjbWFWZXJzaW9uIjoxMSwic291cmNlVHlwZSI6Im1vZHVsZSIsImVjbWFGZWF0dXJlcyI6e319LCJydWxlcyI6e30sImVudiI6e319fQ==

**What did you expect to happen?**
The space after `delay` to be removed while preserving the comment.

**What actually happened? Please include the actual, raw output from ESLint.**
The space and the comment after `delay` got removed.

**Are you willing to submit a pull request to fix this bug?**
No

**Cause**
https://github.com/eslint/eslint/blob/460c5ad176eaf39ff579cd96b3bcbe0539093f8f/lib/rules/space-before-function-paren.js#L127
The fixing is done by removing everything between the identifier and the opening parenthesis (without taking comments into consideration)


Discussion:
Hi @zaygraveyard, thanks for the report! I can reproduce this bug.
Perhaps we could implement here the logic from `template-tag-spacing`?

[Demo](https://eslint.org/demo#eyJ0ZXh0IjoiLyplc2xpbnQgdGVtcGxhdGUtdGFnLXNwYWNpbmc6IFtcImVycm9yXCIsIFwibmV2ZXJcIl0qL1xuXG5mb28gLyogYmxvY2sgY29tbWVudCAqL2BgO1xuXG5mb28gLypjb21tZW50IDEqL1xuLypjb21tZW50IDIqL2BgO1xuXG5mb28gLy8gbGluZSBjb21tZW50IFxuYGA7XG5cblxuIiwib3B0aW9ucyI6eyJwYXJzZXJPcHRpb25zIjp7ImVjbWFWZXJzaW9uIjoxMSwic291cmNlVHlwZSI6Im1vZHVsZSIsImVjbWFGZWF0dXJlcyI6e319LCJydWxlcyI6e30sImVudiI6e319fQ==)

It concatenates all block comments. If there is a line comment, just reports without the autofix.
@mdjermanovic yes, this would indeed fix this issue since it would preserve the comments
I'm working on this



Patch:
diff --git a/lib/rules/space-before-function-paren.js b/lib/rules/space-before-function-paren.js
index ca20dbc4abf9..3a6d430f3620 100644
--- a/lib/rules/space-before-function-paren.js
+++ b/lib/rules/space-before-function-paren.js
@@ -124,7 +124,18 @@ module.exports = {
                     node,
                     loc: leftToken.loc.end,
                     message: "Unexpected space before function parentheses.",
-                    fix: fixer => fixer.removeRange([leftToken.range[1], rightToken.range[0]])
+                    fix(fixer) {
+                        const comments = sourceCode.getCommentsBefore(rightToken);
+
+                        // Don't fix anything if there's a single line comment between the left and the right token
+                        if (comments.some(comment => comment.type === "Line")) {
+                            return null;
+                        }
+                        return fixer.replaceTextRange(
+                            [leftToken.range[1], rightToken.range[0]],
+                            comments.reduce((text, comment) => text + sourceCode.getText(comment), "")
+                        );
+                    }
                 });
             } else if (!hasSpacing && functionConfig === "always") {
                 context.report({


Test patch:
diff --git a/tests/lib/rules/space-before-function-paren.js b/tests/lib/rules/space-before-function-paren.js
index 5bcfd7be16c6..961d6895adc5 100644
--- a/tests/lib/rules/space-before-function-paren.js
+++ b/tests/lib/rules/space-before-function-paren.js
@@ -24,6 +24,11 @@ ruleTester.run("space-before-function-paren", rule, {
         "function foo () {}",
         "var foo = function () {}",
         "var bar = function foo () {}",
+        "var bar = function foo/**/ () {}",
+        "var bar = function foo /**/() {}",
+        "var bar = function foo/**/\n() {}",
+        "var bar = function foo\n/**/() {}",
+        "var bar = function foo//\n() {}",
         "var obj = { get foo () {}, set foo (val) {} };",
         {
             code: "var obj = { foo () {} };",
@@ -34,6 +39,9 @@ ruleTester.run("space-before-function-paren", rule, {
 
         { code: "function foo() {}", options: ["never"] },
         { code: "var foo = function() {}", options: ["never"] },
+        { code: "var foo = function/**/() {}", options: ["never"] },
+        { code: "var foo = function/* */() {}", options: ["never"] },
+        { code: "var foo = function/* *//*  */() {}", options: ["never"] },
         { code: "var bar = function foo() {}", options: ["never"] },
         { code: "var obj = { get foo() {}, set foo(val) {} };", options: ["never"] },
         {
@@ -226,6 +234,84 @@ ruleTester.run("space-before-function-paren", rule, {
                 }
             ]
         },
+        {
+            code: "function foo /* */ () {}",
+            output: "function foo/* */() {}",
+            options: ["never"],
+            errors: [
+                {
+                    type: "FunctionDeclaration",
+                    message: "Unexpected space before function parentheses.",
+                    line: 1,
+                    column: 13
+                }
+            ]
+        },
+        {
+            code: "function foo/* block comment */ () {}",
+            output: "function foo/* block comment */() {}",
+            options: ["never"],
+            errors: [
+                {
+                    type: "FunctionDeclaration",
+                    message: "Unexpected space before function parentheses.",
+                    line: 1,
+                    column: 13
+                }
+            ]
+        },
+        {
+            code: "function foo/* 1 */ /* 2 */ \n /* 3 */\n/* 4 */ () {}",
+            output: "function foo/* 1 *//* 2 *//* 3 *//* 4 */() {}",
+            options: ["never"],
+            errors: [
+                {
+                    type: "FunctionDeclaration",
+                    message: "Unexpected space before function parentheses.",
+                    line: 1,
+                    column: 13
+                }
+            ]
+        },
+        {
+            code: "function foo//\n() {}",
+            output: null,
+            options: ["never"],
+            errors: [
+                {
+                    type: "FunctionDeclaration",
+                    message: "Unexpected space before function parentheses.",
+                    line: 1,
+                    column: 13
+                }
+            ]
+        },
+        {
+            code: "function foo // line comment \n () {}",
+            output: null,
+            options: ["never"],
+            errors: [
+                {
+                    type: "FunctionDeclaration",
+                    message: "Unexpected space before function parentheses.",
+                    line: 1,
+                    column: 13
+                }
+            ]
+        },
+        {
+            code: "function foo\n//\n() {}",
+            output: null,
+            options: ["never"],
+            errors: [
+                {
+                    type: "FunctionDeclaration",
+                    message: "Unexpected space before function parentheses.",
+                    line: 1,
+                    column: 13
+                }
+            ]
+        },
         {
             code: "var foo = function () {}",
             output: "var foo = function() {}",