Repository: eslint/eslint (js)

Issue:
no-obj-calls should report Atomics()
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).

    This template is for requesting a rule change. If you are here for another reason, please see below:

    1. To report a bug: https://eslint.org/docs/developer-guide/contributing/reporting-bugs
    2. To propose a new rule: https://eslint.org/docs/developer-guide/contributing/new-rules
    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.
-->

Similar to `Math`, `JSON` and `Reflect`, which the [no-obj-calls](https://eslint.org/docs/rules/no-obj-calls) rule already reports, `Atomics` is not a function.

[Atomics in ECMAScript 2017 spec](https://www.ecma-international.org/ecma-262/8.0/index.html#sec-atomics-object):

> The Atomics object does not have a [[Call]] internal method; it is not possible to invoke the Atomics object as a function.

**What rule do you want to change?**

`no-obj-calls`

**Does this change cause the rule to produce more or fewer warnings?**

more

**How will the change be implemented? (New option, new default behavior, etc.)?**

new default behavior

It would be also good to ensure that the reported variables are global.

**Please provide some example code that this change will affect:**

<!-- Put your code examples here -->
```js
/*eslint no-obj-calls: "error"*/
/*eslint-env es2017*/

Atomics();
```

**What does the rule currently do for this code?**

No errors

**What will the rule do after it's changed?**

Error: `'Atomics' is not a function.` 

**Are you willing to submit a pull request to implement this change?**

Yes. The idea is to add `Atomics` and also use `ReferenceTracker` to report only global variables (for all 4 targeted globals) in the same PR.

Would it be okay for a semver-minor? I think that when `Reflect` was added to this rule it was seen as a bug fix (#7710 #7700).


Pull request:
Update: Report global Atomics calls in no-obj-calls (fixes #12234)
<!--
    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] Bug fix
[X] Changes an existing rule #12234

<!--
    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.)
-->

This PR modifies the `no-obj-calls` to:

* Report `Atomics()` as described in #12234, which can produce **more** errors by default.
* Report only globals, which can produce fewer errors.

E.g., the rule will not report `Math()` if the `Math` is shadowed or turned `off`.

Also, the rule will not report `Reflect()` if an ES2015+ environment is not activated (and the variable isn't added manually as a global in the config file or `/*global*/`). The same applies to `Atomics` and ES2017+ environment.

<!--
    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)**

Added `Atomics` to the list of non-callable globals and modified the logic to report only references to defined global variables.

**Is there anything you'd like reviewers to focus on?**

Patch:
diff --git a/README.md b/README.md
index 4c02d619c..28f512920 100644
--- a/README.md
+++ b/README.md
@@ -262,7 +262,7 @@ The following companies, organizations, and individuals support ESLint's ongoing
 <!-- NOTE: This section is autogenerated. Do not manually edit.-->
 <!--sponsorsstart-->
 <h3>Gold Sponsors</h3>
-<p><a href="https://www.shopify.com"><img src="https://images.opencollective.com/shopify/eeb91aa/logo.png" alt="Shopify" height="96"></a> <a href="http://engineering.salesforce.com"><img src="https://images.opencollective.com/salesforce/d1b37c4/logo.png" alt="Salesforce" height="96"></a> <a href="https://badoo.com/team?utm_source=eslint"><img src="https://images.opencollective.com/badoo/2826a3b/logo.png" alt="Badoo" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/001a341/logo.png" alt="Airbnb" height="96"></a> <a href="https://code.facebook.com/projects/"><img src="https://images.opencollective.com/fbopensource/fbb8a5b/logo.png" alt="Facebook Open Source" height="96"></a></p><h3>Silver Sponsors</h3>
+<p><a href="https://www.shopify.com"><img src="https://images.opencollective.com/shopify/eeb91aa/logo.png" alt="Shopify" height="96"></a> <a href="http://engineering.salesforce.com"><img src="https://images.opencollective.com/salesforce/d1b37c4/logo.png" alt="Salesforce" height="96"></a> <a href="https://badoo.com/team?utm_source=eslint"><img src="https://images.opencollective.com/badoo/2826a3b/logo.png" alt="Badoo" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://code.facebook.com/projects/"><img src="https://images.opencollective.com/fbopensource/fbb8a5b/logo.png" alt="Facebook Open Source" height="96"></a></p><h3>Silver Sponsors</h3>
 <p><a href="https://www.ampproject.org/"><img src="https://images.opencollective.com/amp/c8a3b25/logo.png" alt="AMP Project" height="64"></a></p><h3>Bronze Sponsors</h3>
 <p><a href="https://discordapp.com"><img src="https://images.opencollective.com/discordapp/7e3d9a9/logo.png" alt="Discord" height="32"></a> <a href="https://moneypug.co.uk/"><img src="https://images.opencollective.com/moneypug/45f8d53/logo.png" alt="MONEYPUG" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/0b37d14/logo.png" alt="Free Icons by Icons8" height="32"></a> <a href="https://uxplanet.org/top-ui-ux-design-agencies-user-experience-firms-8c54697e290"><img src="https://images.opencollective.com/ui-ux-design-agencies/cae5dfe/logo.png" alt="UI UX Design Agencies" height="32"></a> <a href="https://clay.global"><img src="https://images.opencollective.com/clayglobal/2468f34/logo.png" alt="clay" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://tekhattan.com"><img src="https://images.opencollective.com/tekhattan/bc73c28/logo.png" alt="TekHattan" height="32"></a> <a href="https://www.marfeel.com/"><img src="https://images.opencollective.com/marfeel/4b88e30/logo.png" alt="Marfeel" height="32"></a> <a href="http://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a> <a href="https://jsheroes.io/"><img src="https://images.opencollective.com/jsheroes1/9fedf0b/logo.png" alt="JSHeroes " height="32"></a></p>
 <!--sponsorsend-->
diff --git a/docs/rules/no-obj-calls.md b/docs/rules/no-obj-calls.md
index 9484eb736..cfd5576ea 100644
--- a/docs/rules/no-obj-calls.md
+++ b/docs/rules/no-obj-calls.md
@@ -6,13 +6,17 @@ The [ECMAScript 5 specification](https://es5.github.io/#x15.8) makes it clear th
 
 > The Math object does not have a `[[Call]]` internal property; it is not possible to invoke the Math object as a function.
 
-And the [ECMAScript 2015 specification](https://www.ecma-international.org/ecma-262/6.0/index.html#sec-reflect-object) makes it clear that `Reflect` cannot be invoked:
+The [ECMAScript 2015 specification](https://www.ecma-international.org/ecma-262/6.0/index.html#sec-reflect-object) makes it clear that `Reflect` cannot be invoked:
 
 > The Reflect object also does not have a `[[Call]]` internal method; it is not possible to invoke the Reflect object as a function.
 
+And the [ECMAScript 2017 specification](https://www.ecma-international.org/ecma-262/8.0/index.html#sec-atomics-object) makes it clear that `Atomics` cannot be invoked:
+
+> The Atomics object does not have a [[Call]] internal method; it is not possible to invoke the Atomics object as a function.
+
 ## Rule Details
 
-This rule disallows calling the `Math`, `JSON` and `Reflect` objects as functions.
+This rule disallows calling the `Math`, `JSON`, `Reflect` and `Atomics` objects as functions.
 
 Examples of **incorrect** code for this rule:
 
@@ -22,6 +26,7 @@ Examples of **incorrect** code for this rule:
 var math = Math();
 var json = JSON();
 var reflect = Reflect();
+var atomics = Atomics();
 ```
 
 Examples of **correct** code for this rule:
@@ -34,6 +39,7 @@ function area(r) {
 }
 var object = JSON.parse("{}");
 var value = Reflect.get({ x: 1, y: 2 }, "x");
+var first = Atomics.load(foo, 0);
 ```
 
 ## Further Reading
diff --git a/docs/rules/no-sequences.md b/docs/rules/no-sequences.md
index f1f4afea0..602a412f1 100644
--- a/docs/rules/no-sequences.md
+++ b/docs/rules/no-sequences.md
@@ -60,7 +60,7 @@ switch ((val = foo(), val)) {}
 
 while ((val = foo(), val < 42));
 
-// with ((doSomething(), val)) {}
+with ((doSomething(), val)) {}
 ```
 
 ## When Not To Use It
diff --git a/docs/rules/no-useless-catch.md b/docs/rules/no-useless-catch.md
index d320e561d..0562063f6 100644
--- a/docs/rules/no-useless-catch.md
+++ b/docs/rules/no-useless-catch.md
@@ -43,6 +43,12 @@ try {
 } catch (e) {
   handleError(e);
 }
+
+try {
+  doSomethingThatMightThrow();
+} finally {
+  cleanUp();
+}
 ```
 
 ## When Not To Use It
diff --git a/lib/rules/eqeqeq.js b/lib/rules/eqeqeq.js
index 58ff9030d..57926dbed 100644
--- a/lib/rules/eqeqeq.js
+++ b/lib/rules/eqeqeq.js
@@ -116,18 +116,6 @@ module.exports = {
             return astUtils.isNullLiteral(node.right) || astUtils.isNullLiteral(node.left);
         }
 
-        /**
-         * Gets the location (line and column) of the binary expression's operator
-         * @param {ASTNode} node The binary expression node to check
-         * @returns {Object} { line, column } location of operator
-         * @private
-         */
-        function getOperatorLocation(node) {
-            const opToken = sourceCode.getTokenAfter(node.left);
-
-            return { line: opToken.loc.start.line, column: opToken.loc.start.column };
-        }
-
         /**
          * Reports a message for this rule.
          * @param {ASTNode} node The binary expression node that was checked
@@ -136,21 +124,21 @@ module.exports = {
          * @private
          */
         function report(node, expectedOperator) {
+            const operatorToken = sourceCode.getFirstTokenBetween(
+                node.left,
+                node.right,
+                token => token.value === node.operator
+            );
+
             context.report({
                 node,
-                loc: getOperatorLocation(node),
+                loc: operatorToken.loc,
                 messageId: "unexpected",
                 data: { expectedOperator, actualOperator: node.operator },
                 fix(fixer) {
 
                     // If the comparison is a `typeof` comparison or both sides are literals with the same type, then it's safe to fix.
                     if (isTypeOfBinary(node) || areLiteralsAndSameType(node)) {
-                        const operatorToken = sourceCode.getFirstTokenBetween(
-                            node.left,
-                            node.right,
-                            token => token.value === node.operator
-                        );
-
                         return fixer.replaceText(operatorToken, expectedOperator);
                     }
                     return null;
diff --git a/lib/rules/no-obj-calls.js b/lib/rules/no-obj-calls.js
index 92492b7a2..5102d5594 100644
--- a/lib/rules/no-obj-calls.js
+++ b/lib/rules/no-obj-calls.js
@@ -5,6 +5,18 @@
 
 "use strict";
 
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const { CALL, ReferenceTracker } = require("eslint-utils");
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+const nonCallableGlobals = ["Atomics", "JSON", "Math", "Reflect"];
+
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
@@ -20,23 +32,31 @@ module.exports = {
             url: "https://eslint.org/docs/rules/no-obj-calls"
         },
 
-        schema: []
+        schema: [],
+
+        messages: {
+            unexpectedCall: "'{{name}}' is not a function."
+        }
     },
 
     create(context) {
 
         return {
-            CallExpression(node) {
-
-                if (node.callee.type === "Identifier") {
-                    const name = node.callee.name;
+            Program() {
+                const scope = context.getScope();
+                const tracker = new ReferenceTracker(scope);
+                const traceMap = {};
+
+                for (const global of nonCallableGlobals) {
+                    traceMap[global] = {
+                        [CALL]: true
+                    };
+                }
 
-                    if (name === "Math" || name === "JSON" || name === "Reflect") {
-                        context.report({ node, message: "'{{name}}' is not a function.", data: { name } });
-                    }
+                for (const { node } of tracker.iterateGlobalReferences(traceMap)) {
+                    context.report({ node, messageId: "unexpectedCall", data: { name: node.callee.name } });
                 }
             }
         };
-
     }
 };
diff --git a/lib/rules/no-octal-escape.js b/lib/rules/no-octal-escape.js
index a2860ca5b..7f6845ec7 100644
--- a/lib/rules/no-octal-escape.js
+++ b/lib/rules/no-octal-escape.js
@@ -20,7 +20,11 @@ module.exports = {
             url: "https://eslint.org/docs/rules/no-octal-escape"
         },
 
-        schema: []
+        schema: [],
+
+        messages: {
+            octalEscapeSequence: "Don't use octal: '\\{{sequence}}'. Use '\\u....' instead."
+        }
     },
 
     create(context) {
@@ -32,15 +36,17 @@ module.exports = {
                     return;
                 }
 
-                const match = node.raw.match(/^([^\\]|\\[^0-7])*\\([0-3][0-7]{1,2}|[4-7][0-7]|[0-7])/u);
+                // \0 represents a valid NULL character if it isn't followed by a digit.
+                const match = node.raw.match(
+                    /^(?:[^\\]|\\.)*?\\([0-3][0-7]{1,2}|[4-7][0-7]|[1-7])/u
+                );
 
                 if (match) {
-                    const octalDigit = match[2];
-
-                    // \0 is actually not considered an octal
-                    if (match[2] !== "0" || typeof match[3] !== "undefined") {
-                        context.report({ node, message: "Don't use octal: '\\{{octalDigit}}'. Use '\\u....' instead.", data: { octalDigit } });
-                    }
+                    context.report({
+                        node,
+                        messageId: "octalEscapeSequence",
+                        data: { sequence: match[1] }
+                    });
                 }
             }
 
diff --git a/lib/rules/no-unsafe-negation.js b/lib/rules/no-unsafe-negation.js
index f394f6742..717e5f6be 100644
--- a/lib/rules/no-unsafe-negation.js
+++ b/lib/rules/no-unsafe-negation.js
@@ -51,7 +51,7 @@ module.exports = {
         },
 
         schema: [],
-        fixable: "code",
+        fixable: null,
         messages: {
             unexpected: "Unexpected negating the left operand of '{{operator}}' operator."
         }
@@ -70,15 +70,7 @@ module.exports = {
                         node,
                         loc: node.left.loc,
                         messageId: "unexpected",
-                        data: { operator: node.operator },
-
-                        fix(fixer) {
-                            const negationToken = sourceCode.getFirstToken(node.left);
-                            const fixRange = [negationToken.range[1], node.range[1]];
-                            const text = sourceCode.text.slice(fixRange[0], fixRange[1]);
-
-                            return fixer.replaceTextRange(fixRange, `(${text})`);
-                        }
+                        data: { operator: node.operator }
                     });
                 }
             }
diff --git a/lib/rules/space-before-function-paren.js b/lib/rules/space-before-function-paren.js
index ca20dbc4a..3a6d430f3 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/cli-engine/cli-engine.js b/tests/lib/cli-engine/cli-engine.js
index 0c6db3ff9..b3039e743 100644
--- a/tests/lib/cli-engine/cli-engine.js
+++ b/tests/lib/cli-engine/cli-engine.js
@@ -1641,6 +1641,8 @@ describe("CLIEngine", () => {
                             {
                                 column: 9,
                                 line: 2,
+                                endColumn: 11,
+                                endLine: 2,
                                 message: "Expected '===' and instead saw '=='.",
                                 messageId: "unexpected",
                                 nodeType: "BinaryExpression",
diff --git a/tests/lib/rules/eqeqeq.js b/tests/lib/rules/eqeqeq.js
index b74e9bc2c..05e33bbcf 100644
--- a/tests/lib/rules/eqeqeq.js
+++ b/tests/lib/rules/eqeqeq.js
@@ -105,6 +105,69 @@ ruleTester.run("eqeqeq", rule, {
                 { messageId: "unexpected", data: wantedNotEqEq, type: "BinaryExpression", line: 1 },
                 { messageId: "unexpected", data: wantedNotEqEq, type: "BinaryExpression", line: 1 }
             ]
+        },
+
+        // location tests
+        {
+            code: "a == b;",
+            errors: [
+                {
+                    messageId: "unexpected",
+                    data: wantedEqEqEq,
+                    type: "BinaryExpression",
+                    column: 3,
+                    endColumn: 5
+                }
+            ]
+        },
+        {
+            code: "a!=b;",
+            errors: [
+                {
+                    messageId: "unexpected",
+                    data: wantedNotEqEq,
+                    type: "BinaryExpression",
+                    column: 2,
+                    endColumn: 4
+                }
+            ]
+        },
+        {
+            code: "(a + b) == c;",
+            errors: [
+                {
+                    messageId: "unexpected",
+                    data: wantedEqEqEq,
+                    type: "BinaryExpression",
+                    column: 9,
+                    endColumn: 11
+                }
+            ]
+        },
+        {
+            code: "(a + b)  !=  c;",
+            errors: [
+                {
+                    messageId: "unexpected",
+                    data: wantedNotEqEq,
+                    type: "BinaryExpression",
+                    column: 10,
+                    endColumn: 12
+                }
+            ]
+        },
+        {
+            code: "((1) )  ==  (2);",
+            output: "((1) )  ===  (2);",
+            errors: [
+                {
+                    messageId: "unexpected",
+                    data: wantedEqEqEq,
+                    type: "BinaryExpression",
+                    column: 9,
+                    endColumn: 11
+                }
+            ]
         }
 
     // If no output is provided, assert that no output is produced.
diff --git a/tests/lib/rules/no-obj-calls.js b/tests/lib/rules/no-obj-calls.js
index 6f390ab45..d5bcf0638 100644
--- a/tests/lib/rules/no-obj-calls.js
+++ b/tests/lib/rules/no-obj-calls.js
@@ -20,11 +20,112 @@ const ruleTester = new RuleTester();
 
 ruleTester.run("no-obj-calls", rule, {
     valid: [
-        "var x = Math.random();"
+        "var x = Math;",
+        "var x = Math.random();",
+        "var x = Math.PI;",
+        "var x = foo.Math();",
+        "JSON.parse(foo)",
+        "Reflect.get(foo, 'x')",
+        "Atomics.load(foo, 0)",
+
+        // non-existing variables
+        "/*globals Math: off*/ Math();",
+        {
+            code: "JSON();",
+            globals: { JSON: "off" }
+        },
+        "Reflect();",
+        "Atomics();",
+        {
+            code: "Atomics();",
+            env: { es6: true }
+        },
+
+        // shadowed variables
+        "var Math; Math();",
+        {
+            code: "let JSON; JSON();",
+            parserOptions: { ecmaVersion: 2015 }
+        },
+        {
+            code: "if (foo) { const Reflect = 1; Reflect(); }",
+            parserOptions: { ecmaVersion: 2015 },
+            env: { es6: true }
+        },
+        "function foo(Math) { Math(); }",
+        {
+            code: "function foo(Atomics) { Atomics(); }",
+            env: { es2017: true }
+        },
+        "function foo() { var JSON; JSON(); }",
+        {
+            code: "function foo() { var Atomics = bar(); var baz = Atomics(5); }",
+            globals: { Atomics: false }
+        }
     ],
     invalid: [
-        { code: "var x = Math();", errors: [{ message: "'Math' is not a function.", type: "CallExpression" }] },
-        { code: "var x = JSON();", errors: [{ message: "'JSON' is not a function.", type: "CallExpression" }] },
-        { code: "var x = Reflect();", errors: [{ message: "'Reflect' is not a function.", type: "CallExpression" }] }
+
+        // test full message
+        {
+            code: "Math();",
+            errors: [{ message: "'Math' is not a function.", type: "CallExpression" }]
+        },
+
+        {
+            code: "var x = Math();",
+            errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "CallExpression" }]
+        },
+        {
+            code: "f(Math());",
+            errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "CallExpression", column: 3, endColumn: 9 }]
+        },
+        {
+            code: "Math().foo;",
+            errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "CallExpression", column: 1, endColumn: 7 }]
+        },
+        {
+            code: "var x = JSON();",
+            errors: [{ messageId: "unexpectedCall", data: { name: "JSON" }, type: "CallExpression" }]
+        },
+        {
+            code: "x = JSON(str);",
+            errors: [{ messageId: "unexpectedCall", data: { name: "JSON" }, type: "CallExpression" }]
+        },
+        {
+            code: "Math( JSON() );",
+            errors: [
+                { messageId: "unexpectedCall", data: { name: "Math" }, type: "CallExpression", column: 1, endColumn: 15 },
+                { messageId: "unexpectedCall", data: { name: "JSON" }, type: "CallExpression", column: 7, endColumn: 13 }
+            ]
+        },
+        {
+            code: "var x = Reflect();",
+            env: { es6: true },
+            errors: [{ messageId: "unexpectedCall", data: { name: "Reflect" }, type: "CallExpression" }]
+        },
+        {
+            code: "var x = Reflect();",
+            env: { es2017: true },
+            errors: [{ messageId: "unexpectedCall", data: { name: "Reflect" }, type: "CallExpression" }]
+        },
+        {
+            code: "/*globals Reflect: true*/ Reflect();",
+            errors: [{ messageId: "unexpectedCall", data: { name: "Reflect" }, type: "CallExpression" }]
+        },
+        {
+            code: "var x = Atomics();",
+            env: { es2017: true },
+            errors: [{ messageId: "unexpectedCall", data: { name: "Atomics" }, type: "CallExpression" }]
+        },
+        {
+            code: "var x = Atomics();",
+            env: { es2020: true },
+            errors: [{ messageId: "unexpectedCall", data: { name: "Atomics" }, type: "CallExpression" }]
+        },
+        {
+            code: "var x = Atomics();",
+            globals: { Atomics: false },
+            errors: [{ messageId: "unexpectedCall", data: { name: "Atomics" }, type: "CallExpression" }]
+        }
     ]
 });
diff --git a/tests/lib/rules/no-octal-escape.js b/tests/lib/rules/no-octal-escape.js
index b15416ebf..cd555ab60 100644
--- a/tests/lib/rules/no-octal-escape.js
+++ b/tests/lib/rules/no-octal-escape.js
@@ -24,13 +24,34 @@ ruleTester.run("no-octal-escape", rule, {
         "var foo = \"\\x51\";",
         "var foo = \"foo \\\\251 bar\";",
         "var foo = /([abc]) \\1/g;",
-        "var foo = '\\0';"
+        "var foo = '\\0';",
+        "'\\0 '",
+        "'\\0a'",
+        "'\\\\1'",
+        "'\\\\01'",
+        "'\\08'",
+        "'\\09'"
     ],
     invalid: [
+
+        // Test full message
         { code: "var foo = \"foo \\01 bar\";", errors: [{ message: "Don't use octal: '\\01'. Use '\\u....' instead.", type: "Literal" }] },
-        { code: "var foo = \"foo \\251 bar\";", errors: [{ message: "Don't use octal: '\\251'. Use '\\u....' instead.", type: "Literal" }] },
-        { code: "var foo = \"\\751\";", errors: [{ message: "Don't use octal: '\\75'. Use '\\u....' instead.", type: "Literal" }] },
-        { code: "var foo = \"\\3s51\";", errors: [{ message: "Don't use octal: '\\3'. Use '\\u....' instead.", type: "Literal" }] },
-        { code: "var foo = \"\\\\\\751\";", errors: [{ message: "Don't use octal: '\\75'. Use '\\u....' instead.", type: "Literal" }] }
+
+        { code: "var foo = \"foo \\251 bar\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "251" }, type: "Literal" }] },
+        { code: "var foo = \"\\751\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "75" }, type: "Literal" }] },
+        { code: "var foo = \"\\3s51\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "3" }, type: "Literal" }] },
+        { code: "var foo = \"\\\\\\751\";", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "75" }, type: "Literal" }] },
+        { code: "'\\0\\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
+        { code: "'\\0 \\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
+        { code: "'\\0\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+        { code: "'\\0 \\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+        { code: "'\\08\\1'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "1" }, type: "Literal" }] },
+        { code: "'\\08\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+
+        // Only the first one is reported
+        { code: "'\\01\\02'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+        { code: "'\\02\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "02" }, type: "Literal" }] },
+        { code: "'\\01\\2'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "01" }, type: "Literal" }] },
+        { code: "'\\2\\01'", errors: [{ messageId: "octalEscapeSequence", data: { sequence: "2" }, type: "Literal" }] }
     ]
 });
diff --git a/tests/lib/rules/no-unsafe-negation.js b/tests/lib/rules/no-unsafe-negation.js
index 8316aad02..6ac245412 100644
--- a/tests/lib/rules/no-unsafe-negation.js
+++ b/tests/lib/rules/no-unsafe-negation.js
@@ -34,32 +34,26 @@ ruleTester.run("no-unsafe-negation", rule, {
     invalid: [
         {
             code: "!a in b",
-            output: "!(a in b)",
             errors: [unexpectedInError]
         },
         {
             code: "(!a in b)",
-            output: "(!(a in b))",
             errors: [unexpectedInError]
         },
         {
             code: "!(a) in b",
-            output: "!((a) in b)",
             errors: [unexpectedInError]
         },
         {
             code: "!a instanceof b",
-            output: "!(a instanceof b)",
             errors: [unexpectedInstanceofError]
         },
         {
             code: "(!a instanceof b)",
-            output: "(!(a instanceof b))",
             errors: [unexpectedInstanceofError]
         },
         {
             code: "!(a) instanceof b",
-            output: "!((a) instanceof b)",
             errors: [unexpectedInstanceofError]
         }
     ]
diff --git a/tests/lib/rules/space-before-function-paren.js b/tests/lib/rules/space-before-function-paren.js
index 5bcfd7be1..961d6895a 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() {}",