Repository: eslint/eslint (js)

Issue:
Bug: max-lines-per-function changes in eslint 8.4.0
### Environment

Node version: 16.13.1
npm version: 8.1.2
Local ESLint version: 8.4.0
Global ESLint version: none
Operating System: Windows 10 21H1, Alpine Linux 3.14


### What parser are you using?

Default (Espree)

### What did you do?

With the changes to `max-lines-per-function` in v8.4.0 per https://github.com/eslint/eslint/pull/15140, this rule cannot be disabled at the start of the function with `// eslint-disable-next-line max-lines-per-function`, which did work in previous versions and has made this a breaking change. The rule now flags this disable as unused since no problems are reported for `max-lines-per-function` on this line, and flags an error on the first line that exceeds the line length limit.

<details>
<summary>Configuration</summary>

```
module.exports = {
    env: {
        es6: true,
        node: true
    },
    extends: ['eslint:recommended'],
    reportUnusedDisableDirectives: true,
    rules: {
        'max-lines-per-function': ['error', { 'max': 5}]
    }
};
```
</details>

```js
// eslint-disable-next-line max-lines-per-function -- flagged as unused
const foo = () => {
    const x = 1;
    console.log(x);
    console.log(x);
    console.log(x);
    console.log(x); // error is flagged here and subsequent lines
    console.log(x);
    console.log(x);
    console.log(x);
    console.log(x);
};
```


### What did you expect to happen?

`// eslint-disable-next-line max-lines-per-function` should disable the rule for a function exceeding the max lines, and should not be listed as unused

### What actually happened?

`// eslint-disable-next-line max-lines-per-function` before the function is listed as unused.  The only way to disable for the function appears to be wrapping it with `disable`/`enable` comments, as shown below. This limits the options to disable the rule, e.g. you might want to disable for a factory function, but enable the rule for any internally defined functions, which isn't an option with this disable.

```js
/* eslint-disable max-lines-per-function */
const foo = () => {
    const x = 1;
    console.log(x);
    console.log(x);
    console.log(x);
    console.log(x);
    console.log(x);
    console.log(x);
    console.log(x);
    console.log(x);
};
/* eslint-enable max-lines-per-function */
```

### Participation

- [ ] I am willing to submit a pull request for this issue.

### Additional comments

_No response_

Pull request:
fix: revert changes to reported locations in max-lines-per-function
<!--
    Thank you for contributing!

    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

#### Prerequisites checklist

- [x] I have read the [contributing guidelines](https://github.com/eslint/eslint/blob/HEAD/CONTRIBUTING.md).

#### What is the purpose of this pull request? (put an "X" next to an item)

<!--
    The following template is intentionally not a markdown checkbox list for the reasons
    explained in https://github.com/eslint/eslint/pull/12848#issuecomment-580302888
-->

[ ] Documentation update
[ ] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/HEAD/templates/bug-report.md))
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/HEAD/templates/rule-proposal.md))
[ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/HEAD/templates/rule-change-proposal.md))
[ ] Add autofix to a rule
[ ] Add a CLI option
[ ] Add something to the core
[x] Other, please explain:

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

Fixes #15390, reverts #15140

#### What changes did you make? (Give an overview)

Reverted 8f44cf505765b663e371412ab57f0f1dbbe78513.

#### Is there anything you'd like reviewers to focus on?


Patch:
diff --git a/lib/rules/max-lines-per-function.js b/lib/rules/max-lines-per-function.js
index c1b945ca1..5985a739e 100644
--- a/lib/rules/max-lines-per-function.js
+++ b/lib/rules/max-lines-per-function.js
@@ -80,7 +80,7 @@ module.exports = {
             OPTIONS_OR_INTEGER_SCHEMA
         ],
         messages: {
-            exceed: "{{name}} has exceeded the limit of lines allowed by {{linesExceed}}. Maximum allowed number of lines per function is {{maxLines}}."
+            exceed: "{{name}} has too many lines ({{lineCount}}). Maximum allowed is {{maxLines}}."
         }
     },
 
@@ -170,26 +170,18 @@ module.exports = {
                 return;
             }
             let lineCount = 0;
-            let comments = 0;
-            let blankLines = 0;
 
             for (let i = node.loc.start.line - 1; i < node.loc.end.line; ++i) {
                 const line = lines[i];
 
                 if (skipComments) {
                     if (commentLineNumbers.has(i + 1) && isFullLineComment(line, i + 1, commentLineNumbers.get(i + 1))) {
-                        if (lineCount <= maxLines) {
-                            comments++;
-                        }
                         continue;
                     }
                 }
 
                 if (skipBlankLines) {
                     if (line.match(/^\s*$/u)) {
-                        if (lineCount <= maxLines) {
-                            blankLines++;
-                        }
                         continue;
                     }
                 }
@@ -199,21 +191,11 @@ module.exports = {
 
             if (lineCount > maxLines) {
                 const name = upperCaseFirst(astUtils.getFunctionNameWithKind(funcNode));
-                const linesExceed = lineCount - maxLines;
-
-                const loc = {
-                    start: {
-                        line: node.loc.start.line + maxLines + (comments + blankLines),
-                        column: 0
-                    },
-                    end: node.loc.end
-                };
 
                 context.report({
                     node,
-                    loc,
                     messageId: "exceed",
-                    data: { name, linesExceed, maxLines }
+                    data: { name, lineCount, maxLines }
                 });
             }
         }


Test patch:
diff --git a/tests/lib/rules/max-lines-per-function.js b/tests/lib/rules/max-lines-per-function.js
index 74acab2af..ba01206f4 100644
--- a/tests/lib/rules/max-lines-per-function.js
+++ b/tests/lib/rules/max-lines-per-function.js
@@ -199,14 +199,7 @@ if ( x === y ) {
             code: "function name() {\n}",
             options: [1],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function 'name'", linesExceed: 1, maxLines: 1 },
-                    line: 2,
-                    column: 1,
-                    endLine: 2,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 2, maxLines: 1 } }
             ]
         },
 
@@ -215,14 +208,7 @@ if ( x === y ) {
             code: "var func = function() {\n}",
             options: [1],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function", linesExceed: 1, maxLines: 1 },
-                    line: 2,
-                    column: 1,
-                    endLine: 2,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Function", lineCount: 2, maxLines: 1 } }
             ]
         },
 
@@ -231,14 +217,7 @@ if ( x === y ) {
             code: "const bar = () => {\nconst x = 2 + 1;\nreturn x;\n}",
             options: [3],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Arrow function", linesExceed: 1, maxLines: 3 },
-                    line: 4,
-                    column: 1,
-                    endLine: 4,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Arrow function", lineCount: 4, maxLines: 3 } }
             ]
         },
 
@@ -247,14 +226,7 @@ if ( x === y ) {
             code: "const bar = () =>\n 2",
             options: [1],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Arrow function", linesExceed: 1, maxLines: 1 },
-                    line: 2,
-                    column: 1,
-                    endLine: 2,
-                    endColumn: 3
-                }
+                { messageId: "exceed", data: { name: "Arrow function", lineCount: 2, maxLines: 1 } }
             ]
         },
 
@@ -263,14 +235,7 @@ if ( x === y ) {
             code: `() => {${"foo\n".repeat(60)}}`,
             options: [{}],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Arrow function", linesExceed: 11, maxLines: 50 },
-                    line: 51,
-                    column: 1,
-                    endLine: 61,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Arrow function", lineCount: 61, maxLines: 50 } }
             ]
         },
 
@@ -279,14 +244,7 @@ if ( x === y ) {
             code: "function name() {\nvar x = 5;\n\t\n \n\nvar x = 2;\n}",
             options: [{ max: 6, skipComments: false, skipBlankLines: false }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function 'name'", linesExceed: 1, maxLines: 6 },
-                    line: 7,
-                    column: 1,
-                    endLine: 7,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 7, maxLines: 6 } }
             ]
         },
 
@@ -295,14 +253,7 @@ if ( x === y ) {
             code: "function name() {\r\nvar x = 5;\r\n\t\r\n \r\n\r\nvar x = 2;\r\n}",
             options: [{ max: 6, skipComments: true, skipBlankLines: false }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function 'name'", linesExceed: 1, maxLines: 6 },
-                    line: 7,
-                    column: 1,
-                    endLine: 7,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 7, maxLines: 6 } }
             ]
         },
 
@@ -311,14 +262,7 @@ if ( x === y ) {
             code: "function name() {\nvar x = 5;\n\t\n \n\nvar x = 2;\n}",
             options: [{ max: 2, skipComments: true, skipBlankLines: true }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function 'name'", linesExceed: 2, maxLines: 2 },
-                    line: 6,
-                    column: 1,
-                    endLine: 7,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 4, maxLines: 2 } }
             ]
         },
 
@@ -327,14 +271,7 @@ if ( x === y ) {
             code: "function name() {\r\nvar x = 5;\r\n\t\r\n \r\n\r\nvar x = 2;\r\n}",
             options: [{ max: 2, skipComments: true, skipBlankLines: true }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function 'name'", linesExceed: 2, maxLines: 2 },
-                    line: 6,
-                    column: 1,
-                    endLine: 7,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 4, maxLines: 2 } }
             ]
         },
 
@@ -343,14 +280,7 @@ if ( x === y ) {
             code: "function name() { // end of line comment\nvar x = 5; /* mid line comment */\n\t// single line comment taking up whole line\n\t\n \n\nvar x = 2;\n}",
             options: [{ max: 6, skipComments: true, skipBlankLines: false }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function 'name'", linesExceed: 1, maxLines: 6 },
-                    line: 8,
-                    column: 1,
-                    endLine: 8,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 7, maxLines: 6 } }
             ]
         },
 
@@ -359,14 +289,7 @@ if ( x === y ) {
             code: "function name() { // end of line comment\nvar x = 5; /* mid line comment */\n\t// single line comment taking up whole line\n\t\n \n\nvar x = 2;\n}",
             options: [{ max: 1, skipComments: true, skipBlankLines: true }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function 'name'", linesExceed: 3, maxLines: 1 },
-                    line: 2,
-                    column: 1,
-                    endLine: 8,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 4, maxLines: 1 } }
             ]
         },
 
@@ -375,14 +298,7 @@ if ( x === y ) {
             code: "function name() { // end of line comment\nvar x = 5; /* mid line comment */\n\t// single line comment taking up whole line\n\t\n \n\nvar x = 2;\n}",
             options: [{ max: 1, skipComments: false, skipBlankLines: true }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function 'name'", linesExceed: 4, maxLines: 1 },
-                    line: 2,
-                    column: 1,
-                    endLine: 8,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 5, maxLines: 1 } }
             ]
         },
 
@@ -397,14 +313,7 @@ if ( x === y ) {
 }`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function 'foo'", linesExceed: 5, maxLines: 2 },
-                    line: 3,
-                    column: 1,
-                    endLine: 7,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Function 'foo'", lineCount: 7, maxLines: 2 } }
             ]
         },
 
@@ -419,14 +328,7 @@ function
 ()`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false, IIFEs: true }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function", linesExceed: 2, maxLines: 2 },
-                    line: 4,
-                    column: 1,
-                    endLine: 5,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Function", lineCount: 4, maxLines: 2 } }
             ]
         },
 
@@ -444,14 +346,7 @@ if ( x === y ) {
 }`,
             options: [{ max: 9, skipComments: true, skipBlankLines: false }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function 'parent'", linesExceed: 1, maxLines: 9 },
-                    line: 10,
-                    column: 1,
-                    endLine: 10,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Function 'parent'", lineCount: 10, maxLines: 9 } }
             ]
         },
 
@@ -469,22 +364,8 @@ if ( x === y ) {
 }`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function 'parent'", linesExceed: 8, maxLines: 2 },
-                    line: 3,
-                    column: 1,
-                    endLine: 10,
-                    endColumn: 2
-                },
-                {
-                    messageId: "exceed",
-                    data: { name: "Function 'nested'", linesExceed: 2, maxLines: 2 },
-                    line: 5,
-                    column: 1,
-                    endLine: 6,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Function 'parent'", lineCount: 10, maxLines: 2 } },
+                { messageId: "exceed", data: { name: "Function 'nested'", lineCount: 4, maxLines: 2 } }
             ]
         },
 
@@ -499,14 +380,7 @@ if ( x === y ) {
 }`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Method 'method'", linesExceed: 3, maxLines: 2 },
-                    line: 4,
-                    column: 1,
-                    endLine: 6,
-                    endColumn: 6
-                }
+                { messageId: "exceed", data: { name: "Method 'method'", lineCount: 5, maxLines: 2 } }
             ]
         },
 
@@ -521,14 +395,7 @@ if ( x === y ) {
 }`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Static method 'foo'", linesExceed: 3, maxLines: 2 },
-                    line: 4,
-                    column: 1,
-                    endLine: 6,
-                    endColumn: 6
-                }
+                { messageId: "exceed", data: { name: "Static method 'foo'", lineCount: 5, maxLines: 2 } }
             ]
         },
 
@@ -541,16 +408,9 @@ if ( x === y ) {
         return 1
     }
 }`,
-            options: [{ max: 4, skipComments: true, skipBlankLines: false }],
+            options: [{ max: 2, skipComments: true, skipBlankLines: false }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Getter 'foo'", linesExceed: 1, maxLines: 4 },
-                    line: 6,
-                    column: 1,
-                    endLine: 6,
-                    endColumn: 6
-                }
+                { messageId: "exceed", data: { name: "Getter 'foo'", lineCount: 5, maxLines: 2 } }
             ]
         },
 
@@ -565,14 +425,7 @@ if ( x === y ) {
 }`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Setter 'foo'", linesExceed: 3, maxLines: 2 },
-                    line: 4,
-                    column: 1,
-                    endLine: 6,
-                    endColumn: 6
-                }
+                { messageId: "exceed", data: { name: "Setter 'foo'", lineCount: 5, maxLines: 2 } }
             ]
         },
 
@@ -590,14 +443,7 @@ if ( x === y ) {
 }`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Static method", linesExceed: 6, maxLines: 2 },
-                    line: 4,
-                    column: 1,
-                    endLine: 9,
-                    endColumn: 6
-                }
+                { messageId: "exceed", data: { name: "Static method", lineCount: 8, maxLines: 2 } }
             ]
         },
 
@@ -612,14 +458,7 @@ if ( x === y ) {
 }());`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false, IIFEs: true }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function", linesExceed: 5, maxLines: 2 },
-                    line: 3,
-                    column: 1,
-                    endLine: 7,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Function", lineCount: 7, maxLines: 2 } }
             ]
         },
 
@@ -634,28 +473,7 @@ if ( x === y ) {
 })();`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false, IIFEs: true }],
             errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Arrow function", linesExceed: 5, maxLines: 2 },
-                    line: 3,
-                    column: 1,
-                    endLine: 7,
-                    endColumn: 2
-                }
-            ]
-        },
-        {
-            code: "\nfoo();\nbar();\nbaz();\nfunction name() {\nvar x = 5;\n/* comment 1 */\n/* comment 2 */\n\t\n \n\nvar x = 2;\n}\nquz();",
-            options: [{ max: 2, skipComments: true, skipBlankLines: true }],
-            errors: [
-                {
-                    messageId: "exceed",
-                    data: { name: "Function 'name'", linesExceed: 2, maxLines: 2 },
-                    line: 12,
-                    column: 1,
-                    endLine: 13,
-                    endColumn: 2
-                }
+                { messageId: "exceed", data: { name: "Arrow function", lineCount: 7, maxLines: 2 } }
             ]
         }
     ]