Repository: eslint/eslint
Pull request #9718 (2017-12-13 04:23:28)

Chore: improve arrow-body-style error message (refs #5498)
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

**What is the purpose of this pull request? (put an "X" next to item)**

[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:
-->

**What changes did you make? (Give an overview)**

https://github.com/eslint/eslint/issues/5498 gets more than twice as much traffic as any of our other issues. My interpretation of this fact is that people are often confused by errors from the `arrow-body-style` rule, and end up searching and finding that issue. This commit updates the error message for `arrow-body-style` to be more specific about how to fix the problem.

**Is there anything you'd like reviewers to focus on?**

Any wording suggestions?



Patch:
diff --git a/docs/developer-guide/nodejs-api.md b/docs/developer-guide/nodejs-api.md
index 562e107ca..357b4ef67 100644
--- a/docs/developer-guide/nodejs-api.md
+++ b/docs/developer-guide/nodejs-api.md
@@ -839,4 +839,4 @@ ruleTester.run("my-rule", myRule, {
 ## Deprecated APIs
 
 * `cli` - the `cli` object has been deprecated in favor of `CLIEngine`. As of v1.0.0, `cli` is no longer exported and should not be used by external tools.
-* `linter` - the `linter` object has has been deprecated in favor of `Linter`, as of v4.0.0
+* `linter` - the `linter` object has been deprecated in favor of `Linter`, as of v4.0.0
diff --git a/docs/developer-guide/selectors.md b/docs/developer-guide/selectors.md
index c3a2f8cf8..ac1ae0d3f 100644
--- a/docs/developer-guide/selectors.md
+++ b/docs/developer-guide/selectors.md
@@ -32,7 +32,7 @@ The following selectors are supported:
 * attribute existence: `[attr]`
 * attribute value: `[attr="foo"]` or `[attr=123]`
 * attribute regex: `[attr=/foo.*/]`
-* attribute conditons: `[attr!="foo"]`, `[attr>2]`, `[attr<3]`, `[attr>=2]`, or `[attr<=3]`
+* attribute conditions: `[attr!="foo"]`, `[attr>2]`, `[attr<3]`, `[attr>=2]`, or `[attr<=3]`
 * nested attribute: `[attr.level2="foo"]`
 * field: `FunctionDeclaration > Identifier.id`
 * First or last child: `:first-child` or `:last-child`
diff --git a/docs/developer-guide/working-with-plugins.md b/docs/developer-guide/working-with-plugins.md
index da2573acc..cfd59db49 100644
--- a/docs/developer-guide/working-with-plugins.md
+++ b/docs/developer-guide/working-with-plugins.md
@@ -108,7 +108,7 @@ By default, ESLint will not perform autofixes when a processor is used, even whe
 
     The `range` property contains two indexes in the code, referring to the start and end location of a contiguous section of text that will be replaced. The `text` property refers to the text that will replace the given range.
 
-    In the initial list of problems, the `fix` property will refer refer to a fix in the processed JavaScript. The `postprocess` method should transform the object to refer to a fix in the original, unprocessed file.
+    In the initial list of problems, the `fix` property will refer to a fix in the processed JavaScript. The `postprocess` method should transform the object to refer to a fix in the original, unprocessed file.
 
 2. Add a `supportsAutofix: true` property to the processor.
 
@@ -168,7 +168,7 @@ Add these keywords into your `package.json` file to make it easy for others to f
 
 ## Working with Custom Parsers
 
-If you want to use your own parser and provide additional capabilities for your rules, you can specify your own custom parser. If a `parseForESLint` method is exposed on the parser, this method will be used to parse the code. Otherwise, the `parse` method will be used. Both methods should take in the the source code as the first argument, and an optional configuration object as the second argument (provided as `parserOptions` in a config file). The `parse` method should simply return the AST. The `parseForESLint` method should return an object that contains the required property `ast` and an optional `services` property. `ast` should contain the AST. The `services` property can contain any parser-dependent services (such as type checkers for nodes). The value of the `services` property is available to rules as `context.parserServices`.
+If you want to use your own parser and provide additional capabilities for your rules, you can specify your own custom parser. If a `parseForESLint` method is exposed on the parser, this method will be used to parse the code. Otherwise, the `parse` method will be used. Both methods should take in the source code as the first argument, and an optional configuration object as the second argument (provided as `parserOptions` in a config file). The `parse` method should simply return the AST. The `parseForESLint` method should return an object that contains the required property `ast` and an optional `services` property. `ast` should contain the AST. The `services` property can contain any parser-dependent services (such as type checkers for nodes). The value of the `services` property is available to rules as `context.parserServices`.
 
 You can find an ESLint parser project [here](https://github.com/eslint/typescript-eslint-parser).
 
diff --git a/docs/developer-guide/working-with-rules.md b/docs/developer-guide/working-with-rules.md
index 5edbd63b7..372deda2b 100644
--- a/docs/developer-guide/working-with-rules.md
+++ b/docs/developer-guide/working-with-rules.md
@@ -117,7 +117,7 @@ Additionally, the `context` object has the following methods:
 * `getDeclaredVariables(node)` - returns a list of [variables](https://estools.github.io/escope/Variable.html) declared by the given node. This information can be used to track references to variables.
     * If the node is a `VariableDeclaration`, all variables declared in the declaration are returned.
     * If the node is a `VariableDeclarator`, all variables declared in the declarator are returned.
-    * If the node is a `FunctionDeclaration` or `FunctionExpression`, the variable for the function name is returned,in addition to variables for the function parameters.
+    * If the node is a `FunctionDeclaration` or `FunctionExpression`, the variable for the function name is returned, in addition to variables for the function parameters.
     * If the node is an `ArrowFunctionExpression`, variables for the parameters are returned.
     * If the node is a `ClassDeclaration` or a `ClassExpression`, the variable for the class name is returned.
     * If the node is a `CatchClause`, the variable for the exception is returned.
diff --git a/docs/rules/lines-between-class-members.md b/docs/rules/lines-between-class-members.md
index 5196b6ad5..b3a67f42f 100644
--- a/docs/rules/lines-between-class-members.md
+++ b/docs/rules/lines-between-class-members.md
@@ -39,8 +39,8 @@ This rule has a string option and an object option.
 
 String option:
 
-* `"always"`(default) require an empty line after after class members
-* `"never"` disallows an empty line after after class members
+* `"always"`(default) require an empty line after class members
+* `"never"` disallows an empty line after class members
 
 Object option:
 
diff --git a/docs/rules/no-restricted-modules.md b/docs/rules/no-restricted-modules.md
index 6b8d18e3b..aa6c3e982 100644
--- a/docs/rules/no-restricted-modules.md
+++ b/docs/rules/no-restricted-modules.md
@@ -5,7 +5,7 @@ application. The keyword `require` is used in Node.js/CommonJS to import modules
 
 Why would you want to restrict a module?
 
-Disallowing usage of specific Node.js modules can be useful if you want to limit the available methods a developer can use. For example,You can block usage of the `fs` module if you want to disallow file system access.
+Disallowing usage of specific Node.js modules can be useful if you want to limit the available methods a developer can use. For example, you can block usage of the `fs` module if you want to disallow file system access.
 
 ## Rule Details
 
@@ -105,4 +105,4 @@ var crypto = require('crypto');
 
 var crypto = require('crypto');
 var pick = require('lodash/pick');
-```
\ No newline at end of file
+```
diff --git a/lib/rules/arrow-body-style.js b/lib/rules/arrow-body-style.js
index 78a391334..54e4e8d00 100644
--- a/lib/rules/arrow-body-style.js
+++ b/lib/rules/arrow-body-style.js
@@ -109,10 +109,22 @@ module.exports = {
                 }
 
                 if (never || asNeeded && blockBody[0].type === "ReturnStatement") {
+                    let message;
+
+                    if (blockBody.length === 0) {
+                        message = "Unexpected block statement surrounding arrow body; put a value of `undefined` immediately after the `=>`.";
+                    } else if (blockBody.length > 1) {
+                        message = "Unexpected block statement surrounding arrow body.";
+                    } else if (astUtils.isOpeningBraceToken(sourceCode.getFirstToken(blockBody[0], { skip: 1 }))) {
+                        message = "Unexpected block statement surrounding arrow body; parenthesize the returned value and move it immediately after the `=>`.";
+                    } else {
+                        message = "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`.";
+                    }
+
                     context.report({
                         node,
                         loc: arrowBody.loc.start,
-                        message: "Unexpected block statement surrounding arrow body.",
+                        message,
                         fix(fixer) {
                             const fixes = [];
 
diff --git a/lib/rules/lines-between-class-members.js b/lib/rules/lines-between-class-members.js
index 85e8c6935..ab87f5e84 100644
--- a/lib/rules/lines-between-class-members.js
+++ b/lib/rules/lines-between-class-members.js
@@ -55,7 +55,56 @@ module.exports = {
          * @returns {boolean} True if there is at least a line between the tokens
          */
         function isPaddingBetweenTokens(first, second) {
-            return second.loc.start.line - first.loc.end.line >= 2;
+            const comments = sourceCode.getCommentsBefore(second);
+            const len = comments.length;
+
+            // If there is no comments
+            if (len === 0) {
+                const linesBetweenFstAndSnd = second.loc.start.line - first.loc.end.line - 1;
+
+                return linesBetweenFstAndSnd >= 1;
+            }
+
+
+            // If there are comments
+            let sumOfCommentLines = 0; // the numbers of lines of comments
+            let prevCommentLineNum = -1; // line number of the end of the previous comment
+
+            for (let i = 0; i < len; i++) {
+                const commentLinesOfThisComment = comments[i].loc.end.line - comments[i].loc.start.line + 1;
+
+                sumOfCommentLines += commentLinesOfThisComment;
+
+                /*
+                 * If this comment and the previous comment are in the same line,
+                 * the count of comment lines is duplicated. So decrement sumOfCommentLines.
+                 */
+                if (prevCommentLineNum === comments[i].loc.start.line) {
+                    sumOfCommentLines -= 1;
+                }
+
+                prevCommentLineNum = comments[i].loc.end.line;
+            }
+
+            /*
+             * If the first block and the first comment are in the same line,
+             * the count of comment lines is duplicated. So decrement sumOfCommentLines.
+             */
+            if (first.loc.end.line === comments[0].loc.start.line) {
+                sumOfCommentLines -= 1;
+            }
+
+            /*
+             * If the last comment and the second block are in the same line,
+             * the count of comment lines is duplicated. So decrement sumOfCommentLines.
+             */
+            if (comments[len - 1].loc.end.line === second.loc.start.line) {
+                sumOfCommentLines -= 1;
+            }
+
+            const linesBetweenFstAndSnd = second.loc.start.line - first.loc.end.line - 1;
+
+            return linesBetweenFstAndSnd - sumOfCommentLines >= 1;
         }
 
         return {
@@ -65,8 +114,7 @@ module.exports = {
                 for (let i = 0; i < body.length - 1; i++) {
                     const curFirst = sourceCode.getFirstToken(body[i]);
                     const curLast = sourceCode.getLastToken(body[i]);
-                    const comments = sourceCode.getCommentsBefore(body[i + 1]);
-                    const nextFirst = comments.length ? comments[0] : sourceCode.getFirstToken(body[i + 1]);
+                    const nextFirst = sourceCode.getFirstToken(body[i + 1]);
                     const isPadded = isPaddingBetweenTokens(curLast, nextFirst);
                     const isMulti = !astUtils.isTokenOnSameLine(curFirst, curLast);
                     const skip = !isMulti && options[1].exceptAfterSingleLine;


Test patch:
diff --git a/tests/lib/rules/arrow-body-style.js b/tests/lib/rules/arrow-body-style.js
index eda9e23a6..b1b341093 100644
--- a/tests/lib/rules/arrow-body-style.js
+++ b/tests/lib/rules/arrow-body-style.js
@@ -50,7 +50,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => {return 0};",
             options: ["always"],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Expected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Expected block statement surrounding arrow body."
+                }
             ]
         },
         {
@@ -58,7 +63,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => {return {}};",
             options: ["always"],
             errors: [
-                { line: 1, column: 18, type: "ArrowFunctionExpression", message: "Expected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 18,
+                    type: "ArrowFunctionExpression",
+                    message: "Expected block statement surrounding arrow body."
+                }
             ]
         },
         {
@@ -66,7 +76,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => 0;",
             options: ["as-needed"],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
@@ -74,7 +89,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => 0;",
             options: ["as-needed"],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
@@ -82,7 +102,25 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => bar();",
             options: ["as-needed"],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
+            ]
+        },
+        {
+            code: "var foo = () => {};",
+            output: null,
+            options: ["never"],
+            errors: [
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; put a value of `undefined` immediately after the `=>`."
+                }
             ]
         },
         {
@@ -90,7 +128,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => 0;",
             options: ["never"],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
@@ -98,7 +141,25 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => ({ bar: 0 });",
             options: ["as-needed"],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; parenthesize the returned value and move it immediately after the `=>`."
+                }
+            ]
+        },
+        {
+            code: "var foo = () => { return ({ bar: 0 }); };",
+            output: "var foo = () => ({ bar: 0 });",
+            options: ["as-needed"],
+            errors: [
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
@@ -106,7 +167,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: null, // not fixed
             options: ["as-needed", { requireReturnForObjectLiteral: true }],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
@@ -114,7 +180,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => ( /* a */ {ok: true} /* b */ );",
             options: ["as-needed"],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
@@ -122,7 +193,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => '{';",
             options: ["as-needed"],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
@@ -130,7 +206,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => ({ bar: 0 }.bar);",
             options: ["as-needed"],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; parenthesize the returned value and move it immediately after the `=>`."
+                }
             ]
         },
         {
@@ -146,7 +227,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => 0;",
             options: ["as-needed", { requireReturnForObjectLiteral: true }],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
@@ -154,7 +240,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => bar();",
             options: ["as-needed", { requireReturnForObjectLiteral: true }],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
@@ -162,7 +253,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => {return {}};",
             options: ["as-needed", { requireReturnForObjectLiteral: true }],
             errors: [
-                { line: 1, column: 18, type: "ArrowFunctionExpression", message: "Expected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 18,
+                    type: "ArrowFunctionExpression",
+                    message: "Expected block statement surrounding arrow body."
+                }
             ]
         },
         {
@@ -170,7 +266,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => {return { bar: 0 }};",
             options: ["as-needed", { requireReturnForObjectLiteral: true }],
             errors: [
-                { line: 1, column: 18, type: "ArrowFunctionExpression", message: "Expected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 18,
+                    type: "ArrowFunctionExpression",
+                    message: "Expected block statement surrounding arrow body."
+                }
             ]
         },
         {
@@ -178,7 +279,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = () => {return (((((((5)))))))};",
             options: ["always"],
             errors: [
-                { line: 1, column: 24, type: "ArrowFunctionExpression", message: "Expected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 24,
+                    type: "ArrowFunctionExpression",
+                    message: "Expected block statement surrounding arrow body."
+                }
             ]
         },
         {
@@ -190,7 +296,7 @@ ruleTester.run("arrow-body-style", rule, {
             output: null,
             options: ["never"],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`." }
             ]
         },
         {
@@ -202,7 +308,7 @@ ruleTester.run("arrow-body-style", rule, {
             output: null,
             options: ["never"],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`." }
             ]
         },
         {
@@ -216,7 +322,12 @@ ruleTester.run("arrow-body-style", rule, {
             "[1, 2, 3].map(foo)",
             options: ["never"],
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
@@ -224,7 +335,12 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = /* a */ ( /* b */ ) /* c */ => /* d */  /* e */  /* f */ 5 /* g */  /* h */  /* i */ ;",
             options: ["as-needed"],
             errors: [
-                { line: 1, column: 50, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 50,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
@@ -232,28 +348,48 @@ ruleTester.run("arrow-body-style", rule, {
             output: "var foo = /* a */ ( /* b */ ) /* c */ => /* d */ {return ( /* e */ 5 /* f */ )} /* g */ ;",
             options: ["always"],
             errors: [
-                { line: 1, column: 60, type: "ArrowFunctionExpression", message: "Expected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 60,
+                    type: "ArrowFunctionExpression",
+                    message: "Expected block statement surrounding arrow body."
+                }
             ]
         },
         {
             code: "var foo = () => {\nreturn bar;\n};",
             output: "var foo = () => bar;",
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
             code: "var foo = () => {\nreturn bar;};",
             output: "var foo = () => bar;",
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
             code: "var foo = () => {return bar;\n};",
             output: "var foo = () => bar;",
             errors: [
-                { line: 1, column: 17, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 1,
+                    column: 17,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
@@ -268,7 +404,12 @@ ruleTester.run("arrow-body-style", rule, {
                   .bar;
             `,
             errors: [
-                { line: 2, column: 31, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 2,
+                    column: 31,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`."
+                }
             ]
         },
         {
@@ -287,7 +428,12 @@ ruleTester.run("arrow-body-style", rule, {
                 });
             `,
             errors: [
-                { line: 2, column: 31, type: "ArrowFunctionExpression", message: "Unexpected block statement surrounding arrow body." }
+                {
+                    line: 2,
+                    column: 31,
+                    type: "ArrowFunctionExpression",
+                    message: "Unexpected block statement surrounding arrow body; parenthesize the returned value and move it immediately after the `=>`."
+                }
             ]
         },
         {
diff --git a/tests/lib/rules/lines-between-class-members.js b/tests/lib/rules/lines-between-class-members.js
index 1304d719a..443a41f2f 100644
--- a/tests/lib/rules/lines-between-class-members.js
+++ b/tests/lib/rules/lines-between-class-members.js
@@ -36,6 +36,10 @@ ruleTester.run("lines-between-class-members", rule, {
         "class foo{ bar(){}\n\nbaz(){}}",
         "class foo{ bar(){}\n\n/*comments*/baz(){}}",
         "class foo{ bar(){}\n\n//comments\nbaz(){}}",
+        "class foo{ bar(){}\n//comments\n\nbaz(){}}",
+        "class A{ foo() {} // a comment\n\nbar() {}}",
+        "class A{ foo() {}\n/* a */ /* b */\n\nbar() {}}",
+        "class A{ foo() {}/* a */ \n\n /* b */bar() {}}",
 
         "class foo{ bar(){}\n\n;;baz(){}}",
         "class foo{ bar(){};\n\nbaz(){}}",
@@ -43,6 +47,9 @@ ruleTester.run("lines-between-class-members", rule, {
         { code: "class foo{ bar(){}\nbaz(){}}", options: ["never"] },
         { code: "class foo{ bar(){}\n/*comments*/baz(){}}", options: ["never"] },
         { code: "class foo{ bar(){}\n//comments\nbaz(){}}", options: ["never"] },
+        { code: "class foo{ bar(){}/* comments\n\n*/baz(){}}", options: ["never"] },
+        { code: "class foo{ bar(){}/* \ncomments\n*/baz(){}}", options: ["never"] },
+        { code: "class foo{ bar(){}\n/* \ncomments\n*/\nbaz(){}}", options: ["never"] },
 
         { code: "class foo{ bar(){}\n\nbaz(){}}", options: ["always"] },
         { code: "class foo{ bar(){}\n\n/*comments*/baz(){}}", options: ["always"] },