Repository: eslint/eslint
Pull request #12395 (2019-10-09 18:04:03)

Update: measure plugin loading time and output in debug message
**What is the purpose of this pull request? (put an "X" next to item)**

[ ] Documentation update
[ ] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/bug-report.md))
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-proposal.md))
[ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/master/templates/rule-change-proposal.md))
[ ] Add autofixing 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.)
-->

**What changes did you make? (Give an overview)**
I've added measurement of loading time for each plugin. Times are shown in debug output.

The reason is in unexpectedly significant startup time for some plugins, even when there is nothing to check for them. One possible example:
- ESLint configuration has `typescript-eslint` plugin added
- pre-commit hook is configured to run ESLint on modified files
- the commit does not contain `.ts` files (only `.js`, so ESLint is still launched, but there is nothing for `typescript-eslint` to check)

In this example `typescript-eslint` plugin is still loaded and consumes more than half a second to load https://github.com/typescript-eslint/typescript-eslint/issues/1040

More examples:
- https://github.com/lo1tuma/eslint-plugin-mocha/issues/213
- eslint-plugin-react - adds about 250ms to ESLint startup time
- eslint-plugin-import - adds about 350ms

So in case you added these four plugins, ESLint will require 1.5s to start. It's significant for both CLI tools and for pre-commit hooks. I'd like to know exact timings in order to tune ESLint configuration (pre-commit hook may have the fastest one, CI configuration should have the slowest one).

**Is there anything you'd like reviewers to focus on?**


jsf-clabot: [![CLA assistant check](https://cla.js.foundation/pull/badge/not_signed)](https://cla.js.foundation/eslint/eslint?pullRequest=12395) <br/>Thank you for your submission, we really appreciate it. Like many open source projects, we ask that you sign our [Contributor License Agreement](https://cla.js.foundation/eslint/eslint?pullRequest=12395) before we can accept your contribution.<br/><hr/>**v-homyakov** seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please [add the email address used for this commit to your account](https://help.github.com/articles/why-are-my-commits-linked-to-the-wrong-user/#commits-are-not-linked-to-any-user).
platinumazure: I should qualify: This looks good, outside of the CLA check. Please let us know if you run into issues while fixing the commits to allow the CLA check to pass. Thanks!
platinumazure: Marking as "evaluating" for now, but we can change to "accept" if nobody from the team objects to this change.

Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0667729f8..0e7d5181c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -41,7 +41,7 @@ jobs:
     - uses: actions/checkout@v1
     - uses: actions/setup-node@v1
       with:
-        version: ${{ matrix.node }}
+        node-version: ${{ matrix.node }}
     - name: Install Packages
       run: npm install
     - name: Test
diff --git a/README.md b/README.md
index c12264b9f..fd0c14668 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ ESLint is a tool for identifying and reporting on patterns found in ECMAScript/J
 
 ## <a name="installation-and-usage"></a>Installation and Usage
 
-Prerequisites: [Node.js](https://nodejs.org/) (`^8.10.0`, `^10.13.0`, or `>=11.10.1`), npm version 3+.
+Prerequisites: [Node.js](https://nodejs.org/) (`^8.10.0`, `^10.13.0`, or `>=11.10.1`) built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.)
 
 You can install ESLint using npm:
 
@@ -156,8 +156,9 @@ ESLint follows [semantic versioning](https://semver.org). However, due to the na
     * A new CLI capability is created.
     * New capabilities to the public API are added (new classes, new methods, new arguments to existing methods, etc.).
     * A new formatter is created.
+    * `eslint:recommended` is updated and will result in strictly fewer errors (e.g., rule removals).
 * Major release (likely to break your lint build)
-    * `eslint:recommended` is updated.
+    * `eslint:recommended` is updated and may result in new errors (e.g., rule additions, most rule option updates).
     * A new option to an existing rule that results in ESLint reporting more errors by default.
     * An existing formatter is removed.
     * Part of the public API is removed or changed in an incompatible way.
@@ -264,7 +265,7 @@ The following companies, organizations, and individuals support ESLint's ongoing
 <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/ca8f997/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://opensource.facebook.com"><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://clay.global"><img src="https://images.opencollective.com/clayglobal/2468f34/logo.png" alt="clay" height="32"></a> <a href="https://www.minitool.com"><img src="https://images.opencollective.com/minitool-software-ltd/6d68e16/logo.png" alt="MiniTool Software Ltd" height="32"></a> <a href="https://mixpanel.com"><img src="https://images.opencollective.com/mixpanel/cd682f7/logo.png" alt="Mixpanel" 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://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://www.codacy.com/?utm_source=eslint&utm_medium=cpm&utm_campaign=eslint-sponsorship"><img src="https://images.opencollective.com/codacy/ed22716/logo.png" alt="Codacy" height="32"></a> <a href="https://discordapp.com"><img src="https://images.opencollective.com/discordapp/7e3d9a9/logo.png" alt="Discord" 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>
+<p><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://www.bugsnag.com/platforms?utm_source=Open Collective&utm_medium=Website&utm_content=open-source&utm_campaign=2019-community&utm_term="><img src="https://images.opencollective.com/bugsnag-stability-monitoring/c2cef36/logo.png" alt="Bugsnag Stability Monitoring" height="32"></a> <a href="https://www.minitool.com"><img src="https://images.opencollective.com/minitool-software-ltd/6d68e16/logo.png" alt="MiniTool Software Ltd" height="32"></a> <a href="https://www.codacy.com/?utm_source=eslint&utm_medium=cpm&utm_campaign=eslint-sponsorship"><img src="https://images.opencollective.com/codacy/ed22716/logo.png" alt="Codacy" height="32"></a> <a href="https://mixpanel.com"><img src="https://images.opencollective.com/mixpanel/cd682f7/logo.png" alt="Mixpanel" 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://icons8.com"><img src="https://images.opencollective.com/icons8/0b37d14/logo.png" alt="Free Icons by Icons8" height="32"></a> <a href="https://www.crosswordsolver.com"><img src="https://images.opencollective.com/crosswordsolver/d4481d6/logo.png" alt="Crosswordsolver" 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://discordapp.com"><img src="https://images.opencollective.com/discordapp/7e3d9a9/logo.png" alt="Discord" 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-->
 
 ## <a name="technology-sponsors"></a>Technology Sponsors
diff --git a/docs/developer-guide/nodejs-api.md b/docs/developer-guide/nodejs-api.md
index 464d6dbd1..f5ec84616 100644
--- a/docs/developer-guide/nodejs-api.md
+++ b/docs/developer-guide/nodejs-api.md
@@ -80,13 +80,22 @@ const codeLines = SourceCode.splitLines(code);
 
 ## Linter
 
-The `Linter` object does the actual evaluation of the JavaScript code. It doesn't do any filesystem operations, it simply parses and reports on the code. In particular, the `Linter` object does not process configuration objects or files. You can retrieve instances of `Linter` like this:
+The `Linter` object does the actual evaluation of the JavaScript code. It doesn't do any filesystem operations, it simply parses and reports on the code. In particular, the `Linter` object does not process configuration objects or files.
+The `Linter` is a constructor, and you can create a new instance by passing in the options you want to use. The available options are:
+
+* `cwd` - Path to a directory that should be considered as the current working directory. It is accessible to rules by calling `context.getCwd()` (see [The Context Object](./working-with-rules.md#The-Context-Object)). If `cwd` is `undefined`, it will be normalized to `process.cwd()` if the global `process` object is defined (for example, in the Node.js runtime) , or `undefined` otherwise.
+
+For example:
 
 ```js
 const Linter = require("eslint").Linter;
-const linter = new Linter();
+const linter1 = new Linter({ cwd: 'path/to/project' });
+const linter2 = new Linter();
 ```
 
+In this example, rules run on `linter1` will get `path/to/project` when calling `context.getCwd()`.
+Those run on `linter2` will get `process.cwd()` if the global `process` object is defined or `undefined` otherwise (e.g. on the browser https://eslint.org/demo).
+
 ### Linter#verify
 
 The most important method on `Linter` is `verify()`, which initiates linting of the given text. This method accepts three arguments:
diff --git a/docs/developer-guide/working-with-rules.md b/docs/developer-guide/working-with-rules.md
index 35f224b32..ef6cbd634 100644
--- a/docs/developer-guide/working-with-rules.md
+++ b/docs/developer-guide/working-with-rules.md
@@ -126,6 +126,7 @@ The `context` object contains additional functionality that is helpful for rules
 Additionally, the `context` object has the following methods:
 
 * `getAncestors()` - returns an array of the ancestors of the currently-traversed node, starting at the root of the AST and continuing through the direct parent of the current node. This array does not include the currently-traversed node itself.
+* `getCwd()` - returns the `cwd` passed to [Linter](./nodejs-api.md#Linter). It is a path to a directory that should be considered as the current working directory.
 * `getDeclaredVariables(node)` - returns a list of [variables](./scope-manager-interface.md#variable-interface) 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.
diff --git a/docs/rules/no-extra-parens.md b/docs/rules/no-extra-parens.md
index 1896d0a9e..4cadaa757 100644
--- a/docs/rules/no-extra-parens.md
+++ b/docs/rules/no-extra-parens.md
@@ -25,6 +25,7 @@ This rule has an object option for exceptions to the `"all"` option:
 * `"ignoreJSX": "none|all|multi-line|single-line"` allows extra parentheses around no/all/multi-line/single-line JSX components. Defaults to `none`.
 * `"enforceForArrowConditionals": false` allows extra parentheses around ternary expressions which are the body of an arrow function
 * `"enforceForSequenceExpressions": false` allows extra parentheses around sequence expressions
+* `"enforceForNewInMemberExpressions": false` allows extra parentheses around `new` expressions in member expressions
 
 ### all
 
@@ -207,6 +208,20 @@ if ((val = foo(), val < 10)) {}
 while ((val = foo(), val < 10));
 ```
 
+### enforceForNewInMemberExpressions
+
+Examples of **correct** code for this rule with the `"all"` and `{ "enforceForNewInMemberExpressions": false }` options:
+
+```js
+/* eslint no-extra-parens: ["error", "all", { "enforceForNewInMemberExpressions": false }] */
+
+const foo = (new Bar()).baz;
+
+const quux = (new Bar())[baz];
+
+(new Bar()).doSomething();
+```
+
 ### functions
 
 Examples of **incorrect** code for this rule with the `"functions"` option:
diff --git a/docs/rules/no-param-reassign.md b/docs/rules/no-param-reassign.md
index f88d211e2..2ee312c2b 100644
--- a/docs/rules/no-param-reassign.md
+++ b/docs/rules/no-param-reassign.md
@@ -42,7 +42,7 @@ function foo(bar) {
 
 ## Options
 
-This rule takes one option, an object, with a boolean property `"props"` and an array `"ignorePropertyModificationsFor"`. `"props"` is `false` by default. If `"props"` is set to `true`, this rule warns against the modification of parameter properties unless they're included in `"ignorePropertyModificationsFor"`, which is an empty array by default.
+This rule takes one option, an object, with a boolean property `"props"`, and  arrays `"ignorePropertyModificationsFor"` and `"ignorePropertyModificationsForRegex"`. `"props"` is `false` by default. If `"props"` is set to `true`, this rule warns against the modification of parameter properties unless they're included in `"ignorePropertyModificationsFor"` or `"ignorePropertyModificationsForRegex"`, which is an empty array by default.
 
 ### props
 
@@ -124,6 +124,24 @@ function foo(bar) {
 }
 ```
 
+Examples of **correct** code for the `{ "props": true }` option with `"ignorePropertyModificationsForRegex"` set:
+
+```js
+/*eslint no-param-reassign: ["error", { "props": true, "ignorePropertyModificationsForRegex": ["^bar"] }]*/
+
+function foo(bar) {
+    barVar.prop = "value";
+}
+
+function foo(bar) {
+    delete barrito.aaa;
+}
+
+function foo(bar) {
+    bar_.aaa++;
+}
+```
+
 
 ## When Not To Use It
 
diff --git a/docs/rules/no-unneeded-ternary.md b/docs/rules/no-unneeded-ternary.md
index b4caddf58..e5d4e8011 100644
--- a/docs/rules/no-unneeded-ternary.md
+++ b/docs/rules/no-unneeded-ternary.md
@@ -41,8 +41,6 @@ Examples of **incorrect** code for this rule:
 var a = x === 2 ? true : false;
 
 var a = x ? true : false;
-
-var a = f(x ? x : 1);
 ```
 
 Examples of **correct** code for this rule:
@@ -58,7 +56,7 @@ var a = x ? "Yes" : "No";
 
 var a = x ? y : x;
 
-var a = x ? x : 1;  // Note that this is only allowed as it on the right hand side of an assignment; this type of ternary is disallowed everywhere else. See defaultAssignment option below for more details.
+f(x ? x : 1); // default assignment - would be disallowed if defaultAssignment option set to false. See option details below.
 ```
 
 ## Options
@@ -70,7 +68,7 @@ This rule has an object option:
 
 ### defaultAssignment
 
-The defaultAssignment option allows expressions of the form `x ? x : expr` (where `x` is any identifier and `expr` is any expression) as the right hand side of assignments (but nowhere else).
+When set to `true`, which it is by default, The defaultAssignment option allows expressions of the form `x ? x : expr` (where `x` is any identifier and `expr` is any expression).
 
 Examples of additional **incorrect** code for this rule with the `{ "defaultAssignment": false }` option:
 
@@ -78,8 +76,12 @@ Examples of additional **incorrect** code for this rule with the `{ "defaultAssi
 /*eslint no-unneeded-ternary: ["error", { "defaultAssignment": false }]*/
 
 var a = x ? x : 1;
+
+f(x ? x : 1);
 ```
 
+Note that `defaultAssignment: false` still allows expressions of the form `x ? expr : x` (where the identifier is on the right hand side of the ternary).
+
 ## When Not To Use It
 
 You can turn this rule off if you are not concerned with unnecessary complexity in conditional expressions.
diff --git a/docs/rules/no-unsafe-negation.md b/docs/rules/no-unsafe-negation.md
index 880e9f644..38bb9b02f 100644
--- a/docs/rules/no-unsafe-negation.md
+++ b/docs/rules/no-unsafe-negation.md
@@ -4,12 +4,10 @@ Just as developers might type `-a + b` when they mean `-(a + b)` for the negativ
 
 ## Rule Details
 
-This rule disallows negating the left operand of [Relational Operators](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Expressions_and_Operators#Relational_operators).
+This rule disallows negating the left operand of the following relational operators:
 
-Relational Operators are:
-
-- `in` operator.
-- `instanceof` operator.
+- [`in` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in).
+- [`instanceof` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof).
 
 Examples of **incorrect** code for this rule:
 
@@ -72,6 +70,38 @@ if (!(foo) in object) {
 }
 ```
 
+## Options
+
+This rule has an object option:
+
+- `"enforceForOrderingRelations": false` (default) allows negation of the left-hand side of ordering relational operators (`<`, `>`, `<=`, `>=`)
+- `"enforceForOrderingRelations": true` disallows negation of the left-hand side of ordering relational operators
+
+### enforceForOrderingRelations
+
+With this option set to `true` the rule is additionally enforced for:
+
+- `<` operator.
+- `>` operator.
+- `<=` operator.
+- `>=` operator.
+
+The purpose is to avoid expressions such as `! a < b` (which is equivalent to `(a ? 0 : 1) < b`) when what is really intended is `!(a < b)`.
+
+Examples of additional **incorrect** code for this rule with the `{ "enforceForOrderingRelations": true }` option:
+
+```js
+/*eslint no-unsafe-negation: ["error", { "enforceForOrderingRelations": true }]*/
+
+if (! a < b) {}
+
+while (! a > b) {}
+
+foo = ! a <= b;
+
+foo = ! a >= b;
+```
+
 ## When Not To Use It
 
 If you don't want to notify unsafe logical negations, then it's safe to disable this rule.
diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md
index 172e79736..e68294205 100644
--- a/docs/user-guide/configuring.md
+++ b/docs/user-guide/configuring.md
@@ -376,11 +376,11 @@ For example:
         "plugin:@foo/foo/recommended",
         "plugin:@bar/recommended"
     ],
-    "rules": [
+    "rules": {
         "jquery/a-rule": "error",
         "@foo/foo/some-rule": "error",
         "@bar/another-rule": "error"
-    ],
+    },
     "env": {
         "jquery/jquery": true,
         "@foo/foo/env-foo": true,
diff --git a/docs/user-guide/getting-started.md b/docs/user-guide/getting-started.md
index 1bebf7d69..b457ea940 100644
--- a/docs/user-guide/getting-started.md
+++ b/docs/user-guide/getting-started.md
@@ -13,7 +13,7 @@ ESLint is a tool for identifying and reporting on patterns found in ECMAScript/J
 
 ## Installation and Usage
 
-Prerequisites: [Node.js](https://nodejs.org/en/) (>=8.10), npm version 3+.
+Prerequisites: [Node.js](https://nodejs.org/en/) (`^8.10.0`, `^10.13.0`, or `>=11.10.1`) built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.)
 
 You can install ESLint using npm:
 
diff --git a/docs/user-guide/migrating-to-6.0.0.md b/docs/user-guide/migrating-to-6.0.0.md
index 2cc1575a3..3baec19d9 100644
--- a/docs/user-guide/migrating-to-6.0.0.md
+++ b/docs/user-guide/migrating-to-6.0.0.md
@@ -247,7 +247,7 @@ With this change, any unknown values in a `globals` object result in a config va
 
 **To address:** If you see config validation errors related to globals after updating, ensure that all values configured for globals are either `readonly`, `writable`, or `off`. (ESLint also accepts some alternate spellings and variants for compatibility.)
 
-## <a name="experimental-object-rest-spread"></a> The depreacted `experimentalObjectRestSpread` option has been removed
+## <a name="experimental-object-rest-spread"></a> The deprecated `experimentalObjectRestSpread` option has been removed
 
 Previously, when using the default parser, a config could use the `experimentalObjectRestSpread` option to enable parsing support for object rest/spread properties:
 
diff --git a/lib/cli-engine/cascading-config-array-factory.js b/lib/cli-engine/cascading-config-array-factory.js
index ba5c03793..6c914ea49 100644
--- a/lib/cli-engine/cascading-config-array-factory.js
+++ b/lib/cli-engine/cascading-config-array-factory.js
@@ -152,6 +152,7 @@ function createCLIConfigArray({
  */
 class ConfigurationNotFoundError extends Error {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {string} directoryPath The directory path.
      */
diff --git a/lib/cli-engine/cli-engine.js b/lib/cli-engine/cli-engine.js
index e768da837..8afd26270 100644
--- a/lib/cli-engine/cli-engine.js
+++ b/lib/cli-engine/cli-engine.js
@@ -567,7 +567,7 @@ class CLIEngine {
         });
         const lintResultCache =
             options.cache ? new LintResultCache(cacheFilePath) : null;
-        const linter = new Linter();
+        const linter = new Linter({ cwd: options.cwd });
 
         /** @type {ConfigArray[]} */
         const lastConfigArrays = [configArrayFactory.getConfigArrayForFile()];
@@ -667,11 +667,14 @@ class CLIEngine {
     addPlugin(name, pluginObject) {
         const {
             additionalPluginPool,
-            configArrayFactory
+            configArrayFactory,
+            lastConfigArrays
         } = internalSlotsMap.get(this);
 
         additionalPluginPool.set(name, pluginObject);
         configArrayFactory.clearCache();
+        lastConfigArrays.length = 1;
+        lastConfigArrays[0] = configArrayFactory.getConfigArrayForFile();
     }
 
     /**
diff --git a/lib/cli-engine/config-array-factory.js b/lib/cli-engine/config-array-factory.js
index 6e1ba1e02..cf529b6ee 100644
--- a/lib/cli-engine/config-array-factory.js
+++ b/lib/cli-engine/config-array-factory.js
@@ -859,8 +859,14 @@ class ConfigArrayFactory {
         if (filePath) {
             try {
                 writeDebugLogForLoading(request, relativeTo, filePath);
+
+                const startTime = Date.now();
+                const pluginDefinition = require(filePath);
+
+                debug(`Plugin ${filePath} loaded in: ${Date.now() - startTime}ms`);
+
                 return new ConfigDependency({
-                    definition: normalizePlugin(require(filePath)),
+                    definition: normalizePlugin(pluginDefinition),
                     filePath,
                     id,
                     importerName,
diff --git a/lib/cli-engine/config-array/config-dependency.js b/lib/cli-engine/config-array/config-dependency.js
index 8db9ff00c..0d5f6f713 100644
--- a/lib/cli-engine/config-array/config-dependency.js
+++ b/lib/cli-engine/config-array/config-dependency.js
@@ -81,6 +81,7 @@ class ConfigDependency {
         this.importerPath = importerPath;
     }
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @returns {Object} a JSON compatible object.
      */
@@ -95,6 +96,7 @@ class ConfigDependency {
         return obj;
     }
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @returns {Object} an object to display by `console.log()`.
      */
diff --git a/lib/cli-engine/file-enumerator.js b/lib/cli-engine/file-enumerator.js
index 59083fc46..38f55de03 100644
--- a/lib/cli-engine/file-enumerator.js
+++ b/lib/cli-engine/file-enumerator.js
@@ -149,6 +149,7 @@ function readdirSafeSync(directoryPath) {
  */
 class NoFilesFoundError extends Error {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {string} pattern The glob pattern which was not found.
      * @param {boolean} globDisabled If `true` then the pattern was a glob pattern, but glob was disabled.
@@ -165,6 +166,7 @@ class NoFilesFoundError extends Error {
  */
 class AllFilesIgnoredError extends Error {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {string} pattern The glob pattern which was not found.
      */
diff --git a/lib/cli-engine/formatters/html.js b/lib/cli-engine/formatters/html.js
index 091eab1c4..69f739555 100644
--- a/lib/cli-engine/formatters/html.js
+++ b/lib/cli-engine/formatters/html.js
@@ -96,6 +96,7 @@ function renderMessages(messages, parentIndex, rulesMeta) {
     }).join("\n");
 }
 
+// eslint-disable-next-line jsdoc/require-description
 /**
  * @param {Array} results Test results.
  * @param {Object} rulesMeta Dictionary containing metadata for each rule executed by the analysis.
diff --git a/lib/cli-engine/ignored-paths.js b/lib/cli-engine/ignored-paths.js
index 12dfce066..dec8e1860 100644
--- a/lib/cli-engine/ignored-paths.js
+++ b/lib/cli-engine/ignored-paths.js
@@ -121,6 +121,7 @@ function relativize(globPattern, relativePathToOldBaseDir) {
  */
 class IgnoredPaths {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {Object} providedOptions object containing 'ignore', 'ignorePath' and 'patterns' properties
      */
diff --git a/lib/init/autoconfig.js b/lib/init/autoconfig.js
index 5b84df3bb..64be3d2a8 100644
--- a/lib/init/autoconfig.js
+++ b/lib/init/autoconfig.js
@@ -69,6 +69,7 @@ function makeRegistryItems(rulesConfig) {
  */
 class Registry {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {rulesConfig} [rulesConfig] Hash of rule names and arrays of possible configurations
      */
diff --git a/lib/init/config-rule.js b/lib/init/config-rule.js
index a93142b8a..7aec89c3d 100644
--- a/lib/init/config-rule.js
+++ b/lib/init/config-rule.js
@@ -174,6 +174,7 @@ function combinePropertyObjects(objArr1, objArr2) {
  */
 class RuleConfigSet {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {ruleConfig[]} configs Valid rule configurations
      */
diff --git a/lib/linter/code-path-analysis/code-path-analyzer.js b/lib/linter/code-path-analysis/code-path-analyzer.js
index 79d1cf193..6822ae2be 100644
--- a/lib/linter/code-path-analysis/code-path-analyzer.js
+++ b/lib/linter/code-path-analysis/code-path-analyzer.js
@@ -597,6 +597,7 @@ function postprocess(analyzer, node) {
  */
 class CodePathAnalyzer {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {EventGenerator} eventGenerator An event generator to wrap.
      */
diff --git a/lib/linter/code-path-analysis/code-path-segment.js b/lib/linter/code-path-analysis/code-path-segment.js
index 6fa5ff442..6b17b25c7 100644
--- a/lib/linter/code-path-analysis/code-path-segment.js
+++ b/lib/linter/code-path-analysis/code-path-segment.js
@@ -33,6 +33,7 @@ function isReachable(segment) {
  */
 class CodePathSegment {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {string} id An identifier.
      * @param {CodePathSegment[]} allPrevSegments An array of the previous segments.
diff --git a/lib/linter/code-path-analysis/code-path-state.js b/lib/linter/code-path-analysis/code-path-state.js
index f6eec93e0..75de1bc6c 100644
--- a/lib/linter/code-path-analysis/code-path-state.js
+++ b/lib/linter/code-path-analysis/code-path-state.js
@@ -218,6 +218,7 @@ function finalizeTestSegmentsOfFor(context, choiceContext, head) {
  */
 class CodePathState {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {IdGenerator} idGenerator An id generator to generate id for code
      *   path segments.
diff --git a/lib/linter/code-path-analysis/code-path.js b/lib/linter/code-path-analysis/code-path.js
index b9f72912f..49b37c6b2 100644
--- a/lib/linter/code-path-analysis/code-path.js
+++ b/lib/linter/code-path-analysis/code-path.js
@@ -21,6 +21,7 @@ const IdGenerator = require("./id-generator");
  */
 class CodePath {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {string} id An identifier.
      * @param {CodePath|null} upper The code path of the upper function scope.
diff --git a/lib/linter/code-path-analysis/fork-context.js b/lib/linter/code-path-analysis/fork-context.js
index 76a64f876..eb1d2de5a 100644
--- a/lib/linter/code-path-analysis/fork-context.js
+++ b/lib/linter/code-path-analysis/fork-context.js
@@ -97,6 +97,7 @@ function mergeExtraSegments(context, segments) {
  */
 class ForkContext {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {IdGenerator} idGenerator An identifier generator for segments.
      * @param {ForkContext|null} upper An upper fork context.
diff --git a/lib/linter/code-path-analysis/id-generator.js b/lib/linter/code-path-analysis/id-generator.js
index 83787a4ea..4cb2e0e3d 100644
--- a/lib/linter/code-path-analysis/id-generator.js
+++ b/lib/linter/code-path-analysis/id-generator.js
@@ -18,6 +18,7 @@
  */
 class IdGenerator {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {string} prefix Optional. A prefix of generated ids.
      */
diff --git a/lib/linter/linter.js b/lib/linter/linter.js
index 5b9ce07a5..6d88cb5aa 100644
--- a/lib/linter/linter.js
+++ b/lib/linter/linter.js
@@ -666,6 +666,8 @@ function parse(text, parser, providedParserOptions, filePath) {
         // If the message includes a leading line number, strip it:
         const message = `Parsing error: ${ex.message.replace(/^line \d+:/iu, "").trim()}`;
 
+        debug("%s\n%s", message, ex.stack);
+
         return {
             success: false,
             error: {
@@ -810,9 +812,10 @@ const BASE_TRAVERSAL_CONTEXT = Object.freeze(
  * @param {Object} settings The settings that were enabled in the config
  * @param {string} filename The reported filename of the code
  * @param {boolean} disableFixes If true, it doesn't make `fix` properties.
+ * @param {string | undefined} cwd cwd of the cli
  * @returns {Problem[]} An array of reported problems
  */
-function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parserName, settings, filename, disableFixes) {
+function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parserName, settings, filename, disableFixes, cwd) {
     const emitter = createEmitter();
     const nodeQueue = [];
     let currentNode = sourceCode.ast;
@@ -839,6 +842,7 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parser
             {
                 getAncestors: () => getAncestors(currentNode),
                 getDeclaredVariables: sourceCode.scopeManager.getDeclaredVariables.bind(sourceCode.scopeManager),
+                getCwd: () => cwd,
                 getFilename: () => filename,
                 getScope: () => getScope(sourceCode.scopeManager, currentNode),
                 getSourceCode: () => sourceCode,
@@ -985,6 +989,24 @@ function getRule(slots, ruleId) {
     );
 }
 
+/**
+ * Normalize the value of the cwd
+ * @param {string | undefined} cwd raw value of the cwd, path to a directory that should be considered as the current working directory, can be undefined.
+ * @returns {string | undefined} normalized cwd
+ */
+function normalizeCwd(cwd) {
+    if (cwd) {
+        return cwd;
+    }
+    if (typeof process === "object") {
+        return process.cwd();
+    }
+
+    // It's more explicit to assign the undefined
+    // eslint-disable-next-line no-undefined
+    return undefined;
+}
+
 /**
  * The map to store private data.
  * @type {WeakMap<Linter, LinterInternalSlots>}
@@ -1001,8 +1023,14 @@ const internalSlotsMap = new WeakMap();
  */
 class Linter {
 
-    constructor() {
+    /**
+     * Initialize the Linter.
+     * @param {Object} [config] the config object
+     * @param {string} [config.cwd]  path to a directory that should be considered as the current working directory, can be undefined.
+     */
+    constructor({ cwd } = {}) {
         internalSlotsMap.set(this, {
+            cwd: normalizeCwd(cwd),
             lastConfigArray: null,
             lastSourceCode: null,
             parserMap: new Map([["espree", espree]]),
@@ -1134,7 +1162,8 @@ class Linter {
                 parserName,
                 settings,
                 options.filename,
-                options.disableFixes
+                options.disableFixes,
+                slots.cwd
             );
         } catch (err) {
             err.message += `\nOccurred while linting ${options.filename}`;
diff --git a/lib/linter/node-event-generator.js b/lib/linter/node-event-generator.js
index ece44a102..fc7b879f6 100644
--- a/lib/linter/node-event-generator.js
+++ b/lib/linter/node-event-generator.js
@@ -202,6 +202,7 @@ const parseSelector = lodash.memoize(rawSelector => {
  */
 class NodeEventGenerator {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {SafeEmitter} emitter
      * An SafeEmitter which is the destination of events. This emitter must already
diff --git a/lib/rules/array-bracket-newline.js b/lib/rules/array-bracket-newline.js
index 214631777..b4b4dd430 100644
--- a/lib/rules/array-bracket-newline.js
+++ b/lib/rules/array-bracket-newline.js
@@ -216,7 +216,7 @@ module.exports = {
                 ) ||
                 (
                     options.consistent &&
-                    firstIncComment.loc.start.line !== openBracket.loc.end.line
+                    openBracket.loc.end.line !== first.loc.start.line
                 )
             );
 
diff --git a/lib/rules/comma-dangle.js b/lib/rules/comma-dangle.js
index 0c177296e..fb2d167c7 100644
--- a/lib/rules/comma-dangle.js
+++ b/lib/rules/comma-dangle.js
@@ -41,18 +41,17 @@ function isTrailingCommaAllowed(lastItem) {
 /**
  * Normalize option value.
  * @param {string|Object|undefined} optionValue The 1st option value to normalize.
+ * @param {number} ecmaVersion The normalized ECMAScript version.
  * @returns {Object} The normalized option value.
  */
-function normalizeOptions(optionValue) {
+function normalizeOptions(optionValue, ecmaVersion) {
     if (typeof optionValue === "string") {
         return {
             arrays: optionValue,
             objects: optionValue,
             imports: optionValue,
             exports: optionValue,
-
-            // For backward compatibility, always ignore functions.
-            functions: "ignore"
+            functions: (!ecmaVersion || ecmaVersion < 8) ? "ignore" : optionValue
         };
     }
     if (typeof optionValue === "object" && optionValue !== null) {
@@ -135,7 +134,8 @@ module.exports = {
     },
 
     create(context) {
-        const options = normalizeOptions(context.options[0]);
+        const options = normalizeOptions(context.options[0], context.parserOptions.ecmaVersion);
+
         const sourceCode = context.getSourceCode();
 
         /**
diff --git a/lib/rules/default-param-last.js b/lib/rules/default-param-last.js
index ee73aaf32..12e0b5950 100644
--- a/lib/rules/default-param-last.js
+++ b/lib/rules/default-param-last.js
@@ -25,6 +25,7 @@ module.exports = {
 
     create(context) {
 
+        // eslint-disable-next-line jsdoc/require-description
         /**
          * @param {ASTNode} node function node
          * @returns {void}
diff --git a/lib/rules/dot-location.js b/lib/rules/dot-location.js
index c2e734a1a..d483e217a 100644
--- a/lib/rules/dot-location.js
+++ b/lib/rules/dot-location.js
@@ -47,19 +47,18 @@ module.exports = {
 
         /**
          * Reports if the dot between object and property is on the correct loccation.
-         * @param {ASTNode} obj The object owning the property.
-         * @param {ASTNode} prop The property of the object.
-         * @param {ASTNode} node The corresponding node of the token.
+         * @param {ASTNode} node The `MemberExpression` node.
          * @returns {void}
          */
-        function checkDotLocation(obj, prop, node) {
-            const dot = sourceCode.getTokenBefore(prop);
+        function checkDotLocation(node) {
+            const property = node.property;
+            const dot = sourceCode.getTokenBefore(property);
 
             // `obj` expression can be parenthesized, but those paren tokens are not a part of the `obj` node.
             const tokenBeforeDot = sourceCode.getTokenBefore(dot);
 
             const textBeforeDot = sourceCode.getText().slice(tokenBeforeDot.range[1], dot.range[0]);
-            const textAfterDot = sourceCode.getText().slice(dot.range[1], prop.range[0]);
+            const textAfterDot = sourceCode.getText().slice(dot.range[1], property.range[0]);
 
             if (onObject) {
                 if (!astUtils.isTokenOnSameLine(tokenBeforeDot, dot)) {
@@ -67,17 +66,17 @@ module.exports = {
 
                     context.report({
                         node,
-                        loc: dot.loc.start,
+                        loc: dot.loc,
                         messageId: "expectedDotAfterObject",
-                        fix: fixer => fixer.replaceTextRange([tokenBeforeDot.range[1], prop.range[0]], `${neededTextAfterToken}.${textBeforeDot}${textAfterDot}`)
+                        fix: fixer => fixer.replaceTextRange([tokenBeforeDot.range[1], property.range[0]], `${neededTextAfterToken}.${textBeforeDot}${textAfterDot}`)
                     });
                 }
-            } else if (!astUtils.isTokenOnSameLine(dot, prop)) {
+            } else if (!astUtils.isTokenOnSameLine(dot, property)) {
                 context.report({
                     node,
-                    loc: dot.loc.start,
+                    loc: dot.loc,
                     messageId: "expectedDotBeforeProperty",
-                    fix: fixer => fixer.replaceTextRange([tokenBeforeDot.range[1], prop.range[0]], `${textBeforeDot}${textAfterDot}.`)
+                    fix: fixer => fixer.replaceTextRange([tokenBeforeDot.range[1], property.range[0]], `${textBeforeDot}${textAfterDot}.`)
                 });
             }
         }
@@ -89,7 +88,7 @@ module.exports = {
          */
         function checkNode(node) {
             if (!node.computed) {
-                checkDotLocation(node.object, node.property, node);
+                checkDotLocation(node);
             }
         }
 
diff --git a/lib/rules/indent.js b/lib/rules/indent.js
index 1aeac12d1..94c83692b 100644
--- a/lib/rules/indent.js
+++ b/lib/rules/indent.js
@@ -187,6 +187,7 @@ class BinarySearchTree {
  */
 class TokenInfo {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {SourceCode} sourceCode A SourceCode object
      */
@@ -236,6 +237,7 @@ class TokenInfo {
  */
 class OffsetStorage {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {TokenInfo} tokenInfo a TokenInfo instance
      * @param {number} indentSize The desired size of each indentation level
diff --git a/lib/rules/keyword-spacing.js b/lib/rules/keyword-spacing.js
index ef619aa77..2b3fef33b 100644
--- a/lib/rules/keyword-spacing.js
+++ b/lib/rules/keyword-spacing.js
@@ -86,8 +86,8 @@ module.exports = {
                             retv[key] = {
                                 type: "object",
                                 properties: {
-                                    before: { type: "boolean", default: true },
-                                    after: { type: "boolean", default: true }
+                                    before: { type: "boolean" },
+                                    after: { type: "boolean" }
                                 },
                                 additionalProperties: false
                             };
diff --git a/lib/rules/no-dupe-keys.js b/lib/rules/no-dupe-keys.js
index cfddde476..89e1f2de6 100644
--- a/lib/rules/no-dupe-keys.js
+++ b/lib/rules/no-dupe-keys.js
@@ -23,6 +23,7 @@ const SET_KIND = /^(?:init|set)$/u;
  */
 class ObjectInfo {
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @param {ObjectInfo|null} upper The information of the outer object.
      * @param {ASTNode} node The ObjectExpression node of this information.
diff --git a/lib/rules/no-extra-parens.js b/lib/rules/no-extra-parens.js
index 677cde56b..f96e572bf 100644
--- a/lib/rules/no-extra-parens.js
+++ b/lib/rules/no-extra-parens.js
@@ -50,7 +50,8 @@ module.exports = {
                                 returnAssign: { type: "boolean" },
                                 ignoreJSX: { enum: ["none", "all", "single-line", "multi-line"] },
                                 enforceForArrowConditionals: { type: "boolean" },
-                                enforceForSequenceExpressions: { type: "boolean" }
+                                enforceForSequenceExpressions: { type: "boolean" },
+                                enforceForNewInMemberExpressions: { type: "boolean" }
                             },
                             additionalProperties: false
                         }
@@ -80,6 +81,8 @@ module.exports = {
             context.options[1].enforceForArrowConditionals === false;
         const IGNORE_SEQUENCE_EXPRESSIONS = ALL_NODES && context.options[1] &&
             context.options[1].enforceForSequenceExpressions === false;
+        const IGNORE_NEW_IN_MEMBER_EXPR = ALL_NODES && context.options[1] &&
+            context.options[1].enforceForNewInMemberExpressions === false;
 
         const PRECEDENCE_OF_ASSIGNMENT_EXPR = precedence({ type: "AssignmentExpression" });
         const PRECEDENCE_OF_UPDATE_EXPR = precedence({ type: "UpdateExpression" });
@@ -893,6 +896,7 @@ module.exports = {
                 }
 
                 if (nodeObjHasExcessParens &&
+                  !IGNORE_NEW_IN_MEMBER_EXPR &&
                   node.object.type === "NewExpression" &&
                   isNewExpressionWithParens(node.object)) {
                     report(node.object);
diff --git a/lib/rules/no-mixed-operators.js b/lib/rules/no-mixed-operators.js
index 9e4cbd6e2..80fac79af 100644
--- a/lib/rules/no-mixed-operators.js
+++ b/lib/rules/no-mixed-operators.js
@@ -197,13 +197,13 @@ module.exports = {
 
             context.report({
                 node: left,
-                loc: getOperatorToken(left).loc.start,
+                loc: getOperatorToken(left).loc,
                 message,
                 data
             });
             context.report({
                 node: right,
-                loc: getOperatorToken(right).loc.start,
+                loc: getOperatorToken(right).loc,
                 message,
                 data
             });
diff --git a/lib/rules/no-multi-spaces.js b/lib/rules/no-multi-spaces.js
index 64a04c5cc..403d04da9 100644
--- a/lib/rules/no-multi-spaces.js
+++ b/lib/rules/no-multi-spaces.js
@@ -121,7 +121,7 @@ module.exports = {
 
                     context.report({
                         node: rightToken,
-                        loc: rightToken.loc.start,
+                        loc: { start: leftToken.loc.end, end: rightToken.loc.start },
                         message: "Multiple spaces found before '{{displayValue}}'.",
                         data: { displayValue },
                         fix: fixer => fixer.replaceTextRange([leftToken.range[1], rightToken.range[0]], " ")
diff --git a/lib/rules/no-param-reassign.js b/lib/rules/no-param-reassign.js
index edaaef537..d65eb3476 100644
--- a/lib/rules/no-param-reassign.js
+++ b/lib/rules/no-param-reassign.js
@@ -45,6 +45,13 @@ module.exports = {
                                     type: "string"
                                 },
                                 uniqueItems: true
+                            },
+                            ignorePropertyModificationsForRegex: {
+                                type: "array",
+                                items: {
+                                    type: "string"
+                                },
+                                uniqueItems: true
                             }
                         },
                         additionalProperties: false
@@ -57,6 +64,7 @@ module.exports = {
     create(context) {
         const props = context.options[0] && context.options[0].props;
         const ignoredPropertyAssignmentsFor = context.options[0] && context.options[0].ignorePropertyModificationsFor || [];
+        const ignoredPropertyAssignmentsForRegex = context.options[0] && context.options[0].ignorePropertyModificationsForRegex || [];
 
         /**
          * Checks whether or not the reference modifies properties of its variable.
@@ -136,6 +144,19 @@ module.exports = {
             return false;
         }
 
+        /**
+         * Tests that an identifier name matches any of the ignored property assignments.
+         * First we test strings in ignoredPropertyAssignmentsFor.
+         * Then we instantiate and test RegExp objects from ignoredPropertyAssignmentsForRegex strings.
+         * @param {string} identifierName A string that describes the name of an identifier to
+         * ignore property assignments for.
+         * @returns {boolean} Whether the string matches an ignored property assignment regular expression or not.
+         */
+        function isIgnoredPropertyAssignment(identifierName) {
+            return ignoredPropertyAssignmentsFor.includes(identifierName) ||
+                ignoredPropertyAssignmentsForRegex.some(ignored => new RegExp(ignored, "u").test(identifierName));
+        }
+
         /**
          * Reports a reference if is non initializer and writable.
          * @param {Reference} reference A reference to check.
@@ -157,7 +178,7 @@ module.exports = {
             ) {
                 if (reference.isWrite()) {
                     context.report({ node: identifier, message: "Assignment to function parameter '{{name}}'.", data: { name: identifier.name } });
-                } else if (props && isModifyingProp(reference) && ignoredPropertyAssignmentsFor.indexOf(identifier.name) === -1) {
+                } else if (props && isModifyingProp(reference) && !isIgnoredPropertyAssignment(identifier.name)) {
                     context.report({ node: identifier, message: "Assignment to property of function parameter '{{name}}'.", data: { name: identifier.name } });
                 }
             }
diff --git a/lib/rules/no-self-assign.js b/lib/rules/no-self-assign.js
index 9a06ebba6..705d0f409 100644
--- a/lib/rules/no-self-assign.js
+++ b/lib/rules/no-self-assign.js
@@ -61,6 +61,9 @@ function isSameMember(left, right) {
     if (lobj.type === "MemberExpression") {
         return isSameMember(lobj, robj);
     }
+    if (lobj.type === "ThisExpression") {
+        return true;
+    }
     return lobj.type === "Identifier" && lobj.name === robj.name;
 }
 
diff --git a/lib/rules/no-tabs.js b/lib/rules/no-tabs.js
index 0c0a22011..3fc0b78b6 100644
--- a/lib/rules/no-tabs.js
+++ b/lib/rules/no-tabs.js
@@ -55,8 +55,14 @@ module.exports = {
                         context.report({
                             node,
                             loc: {
-                                line: index + 1,
-                                column: match.index
+                                start: {
+                                    line: index + 1,
+                                    column: match.index
+                                },
+                                end: {
+                                    line: index + 1,
+                                    column: match.index + match[0].length
+                                }
                             },
                             message: "Unexpected tab character."
                         });
diff --git a/lib/rules/no-unsafe-negation.js b/lib/rules/no-unsafe-negation.js
index 5226b367d..5c8f569d7 100644
--- a/lib/rules/no-unsafe-negation.js
+++ b/lib/rules/no-unsafe-negation.js
@@ -16,14 +16,23 @@ const astUtils = require("./utils/ast-utils");
 //------------------------------------------------------------------------------
 
 /**
- * Checks whether the given operator is a relational operator or not.
+ * Checks whether the given operator is `in` or `instanceof`
  * @param {string} op The operator type to check.
- * @returns {boolean} `true` if the operator is a relational operator.
+ * @returns {boolean} `true` if the operator is `in` or `instanceof`
  */
-function isRelationalOperator(op) {
+function isInOrInstanceOfOperator(op) {
     return op === "in" || op === "instanceof";
 }
 
+/**
+ * Checks whether the given operator is an ordering relational operator or not.
+ * @param {string} op The operator type to check.
+ * @returns {boolean} `true` if the operator is an ordering relational operator.
+ */
+function isOrderingRelationalOperator(op) {
+    return op === "<" || op === ">" || op === ">=" || op === "<=";
+}
+
 /**
  * Checks whether the given node is a logical negation expression or not.
  * @param {ASTNode} node The node to check.
@@ -48,7 +57,18 @@ module.exports = {
             url: "https://eslint.org/docs/rules/no-unsafe-negation"
         },
 
-        schema: [],
+        schema: [
+            {
+                type: "object",
+                properties: {
+                    enforceForOrderingRelations: {
+                        type: "boolean",
+                        default: false
+                    }
+                },
+                additionalProperties: false
+            }
+        ],
         fixable: null,
         messages: {
             unexpected: "Unexpected negating the left operand of '{{operator}}' operator."
@@ -57,10 +77,15 @@ module.exports = {
 
     create(context) {
         const sourceCode = context.getSourceCode();
+        const options = context.options[0] || {};
+        const enforceForOrderingRelations = options.enforceForOrderingRelations === true;
 
         return {
             BinaryExpression(node) {
-                if (isRelationalOperator(node.operator) &&
+                const orderingRelationRuleApplies = enforceForOrderingRelations && isOrderingRelationalOperator(node.operator);
+
+                if (
+                    (isInOrInstanceOfOperator(node.operator) || orderingRelationRuleApplies) &&
                     isNegation(node.left) &&
                     !astUtils.isParenthesised(sourceCode, node.left)
                 ) {
diff --git a/lib/rules/no-unused-expressions.js b/lib/rules/no-unused-expressions.js
index 191dd7c58..fd0440256 100644
--- a/lib/rules/no-unused-expressions.js
+++ b/lib/rules/no-unused-expressions.js
@@ -47,6 +47,7 @@ module.exports = {
             allowTernary = config.allowTernary || false,
             allowTaggedTemplates = config.allowTaggedTemplates || false;
 
+        // eslint-disable-next-line jsdoc/require-description
         /**
          * @param {ASTNode} node any node
          * @returns {boolean} whether the given node structurally represents a directive
@@ -56,6 +57,7 @@ module.exports = {
                 node.expression.type === "Literal" && typeof node.expression.value === "string";
         }
 
+        // eslint-disable-next-line jsdoc/require-description
         /**
          * @param {Function} predicate ([a] -> Boolean) the function used to make the determination
          * @param {a[]} list the input list
@@ -70,6 +72,7 @@ module.exports = {
             return list.slice();
         }
 
+        // eslint-disable-next-line jsdoc/require-description
         /**
          * @param {ASTNode} node a Program or BlockStatement node
          * @returns {ASTNode[]} the leading sequence of directive nodes in the given node's body
@@ -78,6 +81,7 @@ module.exports = {
             return takeWhile(looksLikeDirective, node.body);
         }
 
+        // eslint-disable-next-line jsdoc/require-description
         /**
          * @param {ASTNode} node any node
          * @param {ASTNode[]} ancestors the given node's ancestors
diff --git a/lib/rules/operator-assignment.js b/lib/rules/operator-assignment.js
index 63982cf39..e294668b4 100644
--- a/lib/rules/operator-assignment.js
+++ b/lib/rules/operator-assignment.js
@@ -150,6 +150,11 @@ module.exports = {
                                 const leftText = sourceCode.getText().slice(node.range[0], equalsToken.range[0]);
                                 const rightText = sourceCode.getText().slice(operatorToken.range[1], node.right.range[1]);
 
+                                // Check for comments that would be removed.
+                                if (sourceCode.commentsExistBetween(equalsToken, operatorToken)) {
+                                    return null;
+                                }
+
                                 return fixer.replaceText(node, `${leftText}${expr.operator}=${rightText}`);
                             }
                             return null;
@@ -182,11 +187,17 @@ module.exports = {
                     messageId: "unexpected",
                     fix(fixer) {
                         if (canBeFixed(node.left)) {
+                            const firstToken = sourceCode.getFirstToken(node);
                             const operatorToken = getOperatorToken(node);
                             const leftText = sourceCode.getText().slice(node.range[0], operatorToken.range[0]);
                             const newOperator = node.operator.slice(0, -1);
                             let rightText;
 
+                            // Check for comments that would be duplicated.
+                            if (sourceCode.commentsExistBetween(firstToken, operatorToken)) {
+                                return null;
+                            }
+
                             // If this change would modify precedence (e.g. `foo *= bar + 1` => `foo = foo * (bar + 1)`), parenthesize the right side.
                             if (
                                 astUtils.getPrecedence(node.right) <= astUtils.getPrecedence({ type: "BinaryExpression", operator: newOperator }) &&
@@ -194,7 +205,17 @@ module.exports = {
                             ) {
                                 rightText = `${sourceCode.text.slice(operatorToken.range[1], node.right.range[0])}(${sourceCode.getText(node.right)})`;
                             } else {
-                                rightText = sourceCode.text.slice(operatorToken.range[1], node.range[1]);
+                                const firstRightToken = sourceCode.getFirstToken(node.right);
+                                let rightTextPrefix = "";
+
+                                if (
+                                    operatorToken.range[1] === firstRightToken.range[0] &&
+                                    !astUtils.canTokensBeAdjacent(newOperator, firstRightToken)
+                                ) {
+                                    rightTextPrefix = " "; // foo+=+bar -> foo= foo+ +bar
+                                }
+
+                                rightText = `${rightTextPrefix}${sourceCode.text.slice(operatorToken.range[1], node.range[1])}`;
                             }
 
                             return fixer.replaceText(node, `${leftText}= ${leftText}${newOperator}${rightText}`);
diff --git a/lib/rules/prefer-destructuring.js b/lib/rules/prefer-destructuring.js
index 6fc9128b9..eff37294a 100644
--- a/lib/rules/prefer-destructuring.js
+++ b/lib/rules/prefer-destructuring.js
@@ -103,6 +103,7 @@ module.exports = {
         // Helpers
         //--------------------------------------------------------------------------
 
+        // eslint-disable-next-line jsdoc/require-description
         /**
          * @param {string} nodeType "AssignmentExpression" or "VariableDeclarator"
          * @param {string} destructuringType "array" or "object"
diff --git a/lib/rules/prefer-numeric-literals.js b/lib/rules/prefer-numeric-literals.js
index b4113a3b3..672d9bcaa 100644
--- a/lib/rules/prefer-numeric-literals.js
+++ b/lib/rules/prefer-numeric-literals.js
@@ -5,6 +5,12 @@
 
 "use strict";
 
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const astUtils = require("./utils/ast-utils");
+
 //------------------------------------------------------------------------------
 // Helpers
 //------------------------------------------------------------------------------
@@ -94,13 +100,13 @@ module.exports = {
                             functionName: sourceCode.getText(node.callee)
                         },
                         fix(fixer) {
-                            const newPrefix = prefixMap[node.arguments[1].value];
-
                             if (sourceCode.getCommentsInside(node).length) {
                                 return null;
                             }
 
-                            if (+(newPrefix + node.arguments[0].value) !== parseInt(node.arguments[0].value, node.arguments[1].value)) {
+                            const replacement = `${prefixMap[node.arguments[1].value]}${node.arguments[0].value}`;
+
+                            if (+replacement !== parseInt(node.arguments[0].value, node.arguments[1].value)) {
 
                                 /*
                                  * If the newly-produced literal would be invalid, (e.g. 0b1234),
@@ -108,7 +114,29 @@ module.exports = {
                                  */
                                 return null;
                             }
-                            return fixer.replaceText(node, prefixMap[node.arguments[1].value] + node.arguments[0].value);
+
+                            const tokenBefore = sourceCode.getTokenBefore(node),
+                                tokenAfter = sourceCode.getTokenAfter(node);
+                            let prefix = "",
+                                suffix = "";
+
+                            if (
+                                tokenBefore &&
+                                tokenBefore.range[1] === node.range[0] &&
+                                !astUtils.canTokensBeAdjacent(tokenBefore, replacement)
+                            ) {
+                                prefix = " ";
+                            }
+
+                            if (
+                                tokenAfter &&
+                                node.range[1] === tokenAfter.range[0] &&
+                                !astUtils.canTokensBeAdjacent(replacement, tokenAfter)
+                            ) {
+                                suffix = " ";
+                            }
+
+                            return fixer.replaceText(node, `${prefix}${replacement}${suffix}`);
                         }
                     });
                 }
diff --git a/lib/rules/space-in-parens.js b/lib/rules/space-in-parens.js
index 35ded5e78..85ee74210 100644
--- a/lib/rules/space-in-parens.js
+++ b/lib/rules/space-in-parens.js
@@ -232,7 +232,7 @@ module.exports = {
                     if (token.value === "(" && openerMissingSpace(token, nextToken)) {
                         context.report({
                             node,
-                            loc: token.loc.start,
+                            loc: token.loc,
                             messageId: "missingOpeningSpace",
                             fix(fixer) {
                                 return fixer.insertTextAfter(token, " ");
@@ -244,7 +244,7 @@ module.exports = {
                     if (token.value === "(" && openerRejectsSpace(token, nextToken)) {
                         context.report({
                             node,
-                            loc: token.loc.start,
+                            loc: { start: token.loc.end, end: nextToken.loc.start },
                             messageId: "rejectedOpeningSpace",
                             fix(fixer) {
                                 return fixer.removeRange([token.range[1], nextToken.range[0]]);
@@ -256,7 +256,7 @@ module.exports = {
                     if (token.value === ")" && closerMissingSpace(prevToken, token)) {
                         context.report({
                             node,
-                            loc: token.loc.start,
+                            loc: token.loc,
                             messageId: "missingClosingSpace",
                             fix(fixer) {
                                 return fixer.insertTextBefore(token, " ");
@@ -268,7 +268,7 @@ module.exports = {
                     if (token.value === ")" && closerRejectsSpace(prevToken, token)) {
                         context.report({
                             node,
-                            loc: token.loc.start,
+                            loc: { start: prevToken.loc.end, end: token.loc.start },
                             messageId: "rejectedClosingSpace",
                             fix(fixer) {
                                 return fixer.removeRange([prevToken.range[1], token.range[0]]);
diff --git a/lib/rules/vars-on-top.js b/lib/rules/vars-on-top.js
index 6974cb224..28ddae442 100644
--- a/lib/rules/vars-on-top.js
+++ b/lib/rules/vars-on-top.js
@@ -32,6 +32,7 @@ module.exports = {
         // Helpers
         //--------------------------------------------------------------------------
 
+        // eslint-disable-next-line jsdoc/require-description
         /**
          * @param {ASTNode} node any node
          * @returns {boolean} whether the given node structurally represents a directive
diff --git a/lib/shared/traverser.js b/lib/shared/traverser.js
index 79fb32faf..32f767795 100644
--- a/lib/shared/traverser.js
+++ b/lib/shared/traverser.js
@@ -65,6 +65,7 @@ class Traverser {
         this._leave = null;
     }
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @returns {ASTNode} The current node.
      */
@@ -72,6 +73,7 @@ class Traverser {
         return this._current;
     }
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @returns {ASTNode[]} The ancestor nodes.
      */
diff --git a/lib/source-code/source-code.js b/lib/source-code/source-code.js
index 450dc24a1..86a56803e 100644
--- a/lib/source-code/source-code.js
+++ b/lib/source-code/source-code.js
@@ -423,7 +423,7 @@ class SourceCode extends TokenStore {
     isSpaceBetweenTokens(first, second) {
         const text = this.text.slice(first.range[1], second.range[0]);
 
-        return /\s/u.test(text.replace(/\/\*.*?\*\//gu, ""));
+        return /\s/u.test(text.replace(/\/\*.*?\*\//gus, ""));
     }
 
     /**
diff --git a/package.json b/package.json
index 39d8967d7..94a10b969 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
   "main": "./lib/api.js",
   "scripts": {
     "test": "node Makefile.js test",
+    "test:cli": "mocha",
     "lint": "node Makefile.js lint",
     "fix": "node Makefile.js lint -- fix",
     "fuzz": "node Makefile.js fuzz",
@@ -51,9 +52,9 @@
     "debug": "^4.0.1",
     "doctrine": "^3.0.0",
     "eslint-scope": "^5.0.0",
-    "eslint-utils": "^1.4.2",
+    "eslint-utils": "^1.4.3",
     "eslint-visitor-keys": "^1.1.0",
-    "espree": "^6.1.1",
+    "espree": "^6.1.2",
     "esquery": "^1.0.1",
     "esutils": "^2.0.2",
     "file-entry-cache": "^5.0.1",
@@ -63,7 +64,7 @@
     "ignore": "^4.0.6",
     "import-fresh": "^3.0.0",
     "imurmurhash": "^0.1.4",
-    "inquirer": "^6.4.1",
+    "inquirer": "^7.0.0",
     "is-glob": "^4.0.0",
     "js-yaml": "^3.13.1",
     "json-stable-stringify-without-jsonify": "^1.0.1",
@@ -85,7 +86,7 @@
   "devDependencies": {
     "@babel/core": "^7.4.3",
     "@babel/preset-env": "^7.4.3",
-    "acorn": "^7.0.0",
+    "acorn": "^7.1.0",
     "babel-loader": "^8.0.5",
     "chai": "^4.0.1",
     "cheerio": "^0.22.0",
diff --git a/packages/eslint-config-eslint/default.yml b/packages/eslint-config-eslint/default.yml
index 9fcd1dcf4..a1fd92ff9 100644
--- a/packages/eslint-config-eslint/default.yml
+++ b/packages/eslint-config-eslint/default.yml
@@ -48,6 +48,7 @@ rules:
     jsdoc/check-types: "error"
     jsdoc/implements-on-classes: "error"
     jsdoc/newline-after-description: ["error", "never"]
+    jsdoc/require-description: "error"
     jsdoc/require-hyphen-before-param-description: ["error", "never"]
     jsdoc/require-jsdoc: "error"
     jsdoc/require-param: "error"


Test patch:
diff --git a/docs/developer-guide/unit-tests.md b/docs/developer-guide/unit-tests.md
index 3c45d67a4..9b9bd4407 100644
--- a/docs/developer-guide/unit-tests.md
+++ b/docs/developer-guide/unit-tests.md
@@ -12,6 +12,10 @@ This automatically starts Mocha and runs all tests in the `tests` directory. You
 
 If you want to quickly run just one test, you can do so by running Mocha directly and passing in the filename. For example:
 
-    ./node_modules/.bin/mocha tests/lib/rules/no-wrap-func.js
+    npm test:cli tests/lib/rules/no-wrap-func.js
 
 Running individual tests is useful when you're working on a specific bug and iterating on the solution. You should be sure to run `npm test` before submitting a pull request.
+
+## More Control on Unit Testing
+
+`npm test:cli` is an alias of the Mocha cli in `./node_modules/.bin/mocha`. [Options](https://mochajs.org/#command-line-usage) are available to be provided to help to better control the test to run.
diff --git a/lib/cli-engine/config-array/override-tester.js b/lib/cli-engine/config-array/override-tester.js
index d6695423e..67c8a6ed8 100644
--- a/lib/cli-engine/config-array/override-tester.js
+++ b/lib/cli-engine/config-array/override-tester.js
@@ -166,6 +166,7 @@ class OverrideTester {
         ));
     }
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @returns {Object} a JSON compatible object.
      */
@@ -182,6 +183,7 @@ class OverrideTester {
         };
     }
 
+    // eslint-disable-next-line jsdoc/require-description
     /**
      * @returns {Object} an object to display by `console.log()`.
      */
diff --git a/tests/lib/cli-engine/cli-engine.js b/tests/lib/cli-engine/cli-engine.js
index 7c2ce871c..2cdc81301 100644
--- a/tests/lib/cli-engine/cli-engine.js
+++ b/tests/lib/cli-engine/cli-engine.js
@@ -4022,6 +4022,14 @@ describe("CLIEngine", () => {
 
             assert(engine.getRules().has("node/no-deprecated-api"), "node/no-deprecated-api is present");
         });
+
+        it("should expose the rules of the plugin that is added by 'addPlugin'.", () => {
+            const engine = new CLIEngine({ plugins: ["foo"] });
+
+            engine.addPlugin("foo", require("eslint-plugin-node"));
+
+            assert(engine.getRules().has("foo/no-deprecated-api"), "foo/no-deprecated-api is present");
+        });
     });
 
     describe("resolveFileGlobPatterns", () => {
diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js
index e4e4e163e..4d04eb34d 100644
--- a/tests/lib/linter/linter.js
+++ b/tests/lib/linter/linter.js
@@ -3195,6 +3195,58 @@ describe("Linter", () => {
         });
     });
 
+    describe("when receiving cwd in options during instantiation", () => {
+        const code = "a;\nb;";
+        const config = { rules: { checker: "error" } };
+
+        it("should get cwd correctly in the context", () => {
+            const cwd = "cwd";
+            const linterWithOption = new Linter({ cwd });
+            let spy;
+
+            linterWithOption.defineRule("checker", context => {
+                spy = sinon.spy(() => {
+                    assert.strictEqual(context.getCwd(), cwd);
+                });
+                return { Program: spy };
+            });
+
+            linterWithOption.verify(code, config);
+            assert(spy && spy.calledOnce);
+        });
+
+        it("should assign process.cwd() to it if cwd is undefined", () => {
+            let spy;
+            const linterWithOption = new Linter({ });
+
+            linterWithOption.defineRule("checker", context => {
+
+                spy = sinon.spy(() => {
+                    assert.strictEqual(context.getCwd(), process.cwd());
+                });
+                return { Program: spy };
+            });
+
+            linterWithOption.verify(code, config);
+            assert(spy && spy.calledOnce);
+        });
+
+        it("should assign process.cwd() to it if the option is undefined", () => {
+            let spy;
+
+            linter.defineRule("checker", context => {
+
+                spy = sinon.spy(() => {
+                    assert.strictEqual(context.getCwd(), process.cwd());
+                });
+                return { Program: spy };
+            });
+
+            linter.verify(code, config);
+            assert(spy && spy.calledOnce);
+        });
+    });
+
     describe("reportUnusedDisable option", () => {
         it("reports problems for unused eslint-disable comments", () => {
             assert.deepStrictEqual(
diff --git a/tests/lib/rule-tester/rule-tester.js b/tests/lib/rule-tester/rule-tester.js
index 5c1dc0178..71e381c70 100644
--- a/tests/lib/rule-tester/rule-tester.js
+++ b/tests/lib/rule-tester/rule-tester.js
@@ -67,7 +67,7 @@ describe("RuleTester", () => {
     let ruleTester;
 
     /**
-     * @description A helper function to verify Node.js core error messages.
+     * A helper function to verify Node.js core error messages.
      * @param {string} actual The actual input
      * @param {string} expected The expected input
      * @returns {Function} Error callback to verify that the message is correct
diff --git a/tests/lib/rules/array-bracket-newline.js b/tests/lib/rules/array-bracket-newline.js
index b1603fcd5..d20c365db 100644
--- a/tests/lib/rules/array-bracket-newline.js
+++ b/tests/lib/rules/array-bracket-newline.js
@@ -65,6 +65,10 @@ ruleTester.run("array-bracket-newline", rule, {
         { code: "var a = [\n]", options: ["consistent"] },
         { code: "var a = [1]", options: ["consistent"] },
         { code: "var a = [\n1\n]", options: ["consistent"] },
+        { code: "var a = [//\n1\n]", options: ["consistent"] },
+        { code: "var a = [/**/\n1\n]", options: ["consistent"] },
+        { code: "var a = [/*\n*/1\n]", options: ["consistent"] },
+        { code: "var a = [//\n]", options: ["consistent"] },
 
         // { multiline: true }
         { code: "var foo = [];", options: [{ multiline: true }] },
@@ -156,6 +160,10 @@ ruleTester.run("array-bracket-newline", rule, {
         { code: "var [\n] = foo", options: ["consistent"], parserOptions: { ecmaVersion: 6 } },
         { code: "var [a] = foo", options: ["consistent"], parserOptions: { ecmaVersion: 6 } },
         { code: "var [\na\n] = foo", options: ["consistent"], parserOptions: { ecmaVersion: 6 } },
+        { code: "var [//\na\n] = foo", options: ["consistent"], parserOptions: { ecmaVersion: 6 } },
+        { code: "var [/**/\na\n] = foo", options: ["consistent"], parserOptions: { ecmaVersion: 6 } },
+        { code: "var [/*\n*/a\n] = foo", options: ["consistent"], parserOptions: { ecmaVersion: 6 } },
+        { code: "var [//\n] = foo", options: ["consistent"], parserOptions: { ecmaVersion: 6 } },
 
         // { multiline: true }
         { code: "var [] = foo;", options: [{ multiline: true }], parserOptions: { ecmaVersion: 6 } },
@@ -529,6 +537,21 @@ ruleTester.run("array-bracket-newline", rule, {
                 }
             ]
         },
+        {
+            code: "var foo = [//\n1]",
+            output: "var foo = [//\n1\n]",
+            options: ["consistent"],
+            errors: [
+                {
+                    messageId: "missingClosingLinebreak",
+                    type: "ArrayExpression",
+                    line: 2,
+                    column: 2,
+                    endLine: 2,
+                    endColumn: 3
+                }
+            ]
+        },
 
         // { multiline: true }
         {
@@ -1459,6 +1482,22 @@ ruleTester.run("array-bracket-newline", rule, {
                 }
             ]
         },
+        {
+            code: "var [//\na] = foo",
+            output: "var [//\na\n] = foo",
+            options: ["consistent"],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [
+                {
+                    messageId: "missingClosingLinebreak",
+                    type: "ArrayPattern",
+                    line: 2,
+                    column: 2,
+                    endLine: 2,
+                    endColumn: 3
+                }
+            ]
+        },
 
         // { minItems: 2 }
         {
diff --git a/tests/lib/rules/comma-dangle.js b/tests/lib/rules/comma-dangle.js
index 573c0c2bd..6d51825eb 100644
--- a/tests/lib/rules/comma-dangle.js
+++ b/tests/lib/rules/comma-dangle.js
@@ -235,31 +235,100 @@ ruleTester.run("comma-dangle", rule, {
             options: ["only-multiline"],
             parserOptions: { ecmaVersion: 6, sourceType: "module" }
         },
-
-
-        // trailing comma in functions -- ignore by default
         {
-            code: "function foo(a,) {}",
+            code: "function foo(a) {}",
+            options: ["always"]
+        },
+        {
+            code: "foo(a)",
+            options: ["always"]
+        },
+        {
+            code: "function foo(a) {}",
+            options: ["never"]
+        },
+        {
+            code: "foo(a)",
+            options: ["never"]
+        },
+        {
+            code: "function foo(a,\nb) {}",
+            options: ["always-multiline"]
+        },
+        {
+            code: "foo(a,\nb)",
+            options: ["always-multiline"]
+        },
+        {
+            code: "function foo(a,\nb) {}",
+            options: ["only-multiline"]
+        },
+        {
+            code: "foo(a,\nb)",
+            options: ["only-multiline"]
+        },
+        {
+            code: "function foo(a) {}",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 7 }
+        },
+        {
+            code: "foo(a)",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 7 }
+        },
+        {
+            code: "function foo(a) {}",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 7 }
+        },
+        {
+            code: "foo(a)",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 7 }
+        },
+        {
+            code: "function foo(a,\nb) {}",
+            options: ["always-multiline"],
+            parserOptions: { ecmaVersion: 7 }
+        },
+        {
+            code: "foo(a,\nb)",
+            options: ["always-multiline"],
+            parserOptions: { ecmaVersion: 7 }
+        },
+        {
+            code: "function foo(a,\nb) {}",
+            options: ["only-multiline"],
+            parserOptions: { ecmaVersion: 7 }
+        },
+        {
+            code: "foo(a,\nb)",
+            options: ["only-multiline"],
+            parserOptions: { ecmaVersion: 7 }
+        },
+        {
+            code: "function foo(a) {}",
             options: ["never"],
             parserOptions: { ecmaVersion: 8 }
         },
         {
-            code: "foo(a,)",
+            code: "foo(a)",
             options: ["never"],
             parserOptions: { ecmaVersion: 8 }
         },
         {
-            code: "function foo(a) {}",
+            code: "function foo(a,) {}",
             options: ["always"],
             parserOptions: { ecmaVersion: 8 }
         },
         {
-            code: "foo(a)",
+            code: "foo(a,)",
             options: ["always"],
             parserOptions: { ecmaVersion: 8 }
         },
         {
-            code: "function foo(\na,\nb\n) {}",
+            code: "function foo(\na,\nb,\n) {}",
             options: ["always-multiline"],
             parserOptions: { ecmaVersion: 8 }
         },
@@ -269,22 +338,22 @@ ruleTester.run("comma-dangle", rule, {
             parserOptions: { ecmaVersion: 8 }
         },
         {
-            code: "function foo(a,b,) {}",
+            code: "function foo(a,b) {}",
             options: ["always-multiline"],
             parserOptions: { ecmaVersion: 8 }
         },
         {
-            code: "foo(a,b,)",
+            code: "foo(a,b)",
             options: ["always-multiline"],
             parserOptions: { ecmaVersion: 8 }
         },
         {
-            code: "function foo(a,b,) {}",
+            code: "function foo(a,b) {}",
             options: ["only-multiline"],
             parserOptions: { ecmaVersion: 8 }
         },
         {
-            code: "foo(a,b,)",
+            code: "foo(a,b)",
             options: ["only-multiline"],
             parserOptions: { ecmaVersion: 8 }
         },
@@ -315,6 +384,11 @@ ruleTester.run("comma-dangle", rule, {
             options: [{ functions: "always" }],
             parserOptions: { ecmaVersion: 8 }
         },
+        {
+            code: "foo(a,)",
+            options: [{ functions: "always" }],
+            parserOptions: { ecmaVersion: 9 }
+        },
         {
             code: "bar(...a,)",
             options: [{ functions: "always" }],
@@ -1283,6 +1357,208 @@ ruleTester.run("comma-dangle", rule, {
             parserOptions: { ecmaVersion: 8 },
             errors: [{ messageId: "unexpected", type: "SpreadElement" }]
         },
+        {
+            code: "function foo(a,) {}",
+            output: "function foo(a) {}",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "Identifier" }]
+        },
+        {
+            code: "(function foo(a,) {})",
+            output: "(function foo(a) {})",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "Identifier" }]
+        },
+        {
+            code: "(a,) => a",
+            output: "(a) => a",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "Identifier" }]
+        },
+        {
+            code: "(a,) => (a)",
+            output: "(a) => (a)",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "Identifier" }]
+        },
+        {
+            code: "({foo(a,) {}})",
+            output: "({foo(a) {}})",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "Identifier" }]
+        },
+        {
+            code: "class A {foo(a,) {}}",
+            output: "class A {foo(a) {}}",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "Identifier" }]
+        },
+        {
+            code: "foo(a,)",
+            output: "foo(a)",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "Identifier" }]
+        },
+        {
+            code: "foo(...a,)",
+            output: "foo(...a)",
+            options: ["never"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "SpreadElement" }]
+        },
+
+        {
+            code: "function foo(a) {}",
+            output: "function foo(a,) {}",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "missing", type: "Identifier" }]
+        },
+        {
+            code: "(function foo(a) {})",
+            output: "(function foo(a,) {})",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "missing", type: "Identifier" }]
+        },
+        {
+            code: "(a) => a",
+            output: "(a,) => a",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "missing", type: "Identifier" }]
+        },
+        {
+            code: "(a) => (a)",
+            output: "(a,) => (a)",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "missing", type: "Identifier" }]
+        },
+        {
+            code: "({foo(a) {}})",
+            output: "({foo(a,) {},})",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [
+                { messageId: "missing", type: "Identifier" },
+                { messageId: "missing", type: "Property" }
+            ]
+        },
+        {
+            code: "class A {foo(a) {}}",
+            output: "class A {foo(a,) {}}",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "missing", type: "Identifier" }]
+        },
+        {
+            code: "foo(a)",
+            output: "foo(a,)",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "missing", type: "Identifier" }]
+        },
+        {
+            code: "foo(...a)",
+            output: "foo(...a,)",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "missing", type: "SpreadElement" }]
+        },
+
+        {
+            code: "function foo(a,) {}",
+            output: "function foo(a) {}",
+            options: ["always-multiline"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "Identifier" }]
+        },
+        {
+            code: "(function foo(a,) {})",
+            output: "(function foo(a) {})",
+            options: ["always-multiline"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "Identifier" }]
+        },
+        {
+            code: "foo(a,)",
+            output: "foo(a)",
+            options: ["always-multiline"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "Identifier" }]
+        },
+        {
+            code: "foo(...a,)",
+            output: "foo(...a)",
+            options: ["always-multiline"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "SpreadElement" }]
+        },
+        {
+            code: "function foo(\na,\nb\n) {}",
+            output: "function foo(\na,\nb,\n) {}",
+            options: ["always-multiline"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "missing", type: "Identifier" }]
+        },
+        {
+            code: "foo(\na,\nb\n)",
+            output: "foo(\na,\nb,\n)",
+            options: ["always-multiline"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "missing", type: "Identifier" }]
+        },
+        {
+            code: "foo(\n...a,\n...b\n)",
+            output: "foo(\n...a,\n...b,\n)",
+            options: ["always-multiline"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "missing", type: "SpreadElement" }]
+        },
+
+        {
+            code: "function foo(a,) {}",
+            output: "function foo(a) {}",
+            options: ["only-multiline"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "Identifier" }]
+        },
+        {
+            code: "(function foo(a,) {})",
+            output: "(function foo(a) {})",
+            options: ["only-multiline"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "Identifier" }]
+        },
+        {
+            code: "foo(a,)",
+            output: "foo(a)",
+            options: ["only-multiline"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "Identifier" }]
+        },
+        {
+            code: "foo(...a,)",
+            output: "foo(...a)",
+            options: ["only-multiline"],
+            parserOptions: { ecmaVersion: 8 },
+            errors: [{ messageId: "unexpected", type: "SpreadElement" }]
+        },
+        {
+            code: "function foo(a) {}",
+            output: "function foo(a,) {}",
+            options: ["always"],
+            parserOptions: { ecmaVersion: 9 },
+            errors: [{ messageId: "missing", type: "Identifier" }]
+        },
 
         // separated options
         {
diff --git a/tests/lib/rules/dot-location.js b/tests/lib/rules/dot-location.js
index 3f6caea60..1a6ea37a7 100644
--- a/tests/lib/rules/dot-location.js
+++ b/tests/lib/rules/dot-location.js
@@ -143,13 +143,13 @@ ruleTester.run("dot-location", rule, {
             code: "obj\n.property",
             output: "obj.\nproperty",
             options: ["object"],
-            errors: [{ messageId: "expectedDotAfterObject", type: "MemberExpression", line: 2, column: 1 }]
+            errors: [{ messageId: "expectedDotAfterObject", type: "MemberExpression", line: 2, column: 1, endLine: 2, endColumn: 2 }]
         },
         {
             code: "obj.\nproperty",
             output: "obj\n.property",
             options: ["property"],
-            errors: [{ messageId: "expectedDotBeforeProperty", type: "MemberExpression", line: 1, column: 4 }]
+            errors: [{ messageId: "expectedDotBeforeProperty", type: "MemberExpression", line: 1, column: 4, endLine: 1, endColumn: 5 }]
         },
         {
             code: "(obj).\nproperty",
diff --git a/tests/lib/rules/keyword-spacing.js b/tests/lib/rules/keyword-spacing.js
index 9c0bf8d0a..9971facf1 100644
--- a/tests/lib/rules/keyword-spacing.js
+++ b/tests/lib/rules/keyword-spacing.js
@@ -545,6 +545,8 @@ ruleTester.run("keyword-spacing", rule, {
         { code: "if (a) {}else{}", options: [override("else", NEITHER)] },
         "if (a) {}\nelse\n{}",
         { code: "if(a) {}\nelse\n{}", options: [NEITHER] },
+        { code: "if(a){ }else{ }", options: [{ before: false, after: true, overrides: { else: { after: false }, if: { after: false } } }] },
+        { code: "if(a){ }else{ }", options: [{ before: true, after: false, overrides: { else: { before: false }, if: { before: false } } }] },
 
         // not conflict with `semi-spacing`
         "if (a);else;",
diff --git a/tests/lib/rules/no-extra-parens.js b/tests/lib/rules/no-extra-parens.js
index e42b5eadc..2cda39104 100644
--- a/tests/lib/rules/no-extra-parens.js
+++ b/tests/lib/rules/no-extra-parens.js
@@ -456,6 +456,14 @@ ruleTester.run("no-extra-parens", rule, {
         { code: "if((a, b)){}", options: ["all", { enforceForSequenceExpressions: false }] },
         { code: "while ((val = foo(), val < 10));", options: ["all", { enforceForSequenceExpressions: false }] },
 
+        // ["all", { enforceForNewInMemberExpressions: false }]
+        { code: "(new foo()).bar", options: ["all", { enforceForNewInMemberExpressions: false }] },
+        { code: "(new foo())[bar]", options: ["all", { enforceForNewInMemberExpressions: false }] },
+        { code: "(new foo()).bar()", options: ["all", { enforceForNewInMemberExpressions: false }] },
+        { code: "(new foo(bar)).baz", options: ["all", { enforceForNewInMemberExpressions: false }] },
+        { code: "(new foo.bar()).baz", options: ["all", { enforceForNewInMemberExpressions: false }] },
+        { code: "(new foo.bar()).baz()", options: ["all", { enforceForNewInMemberExpressions: false }] },
+
         "let a = [ ...b ]",
         "let a = { ...b }",
         {
@@ -659,6 +667,7 @@ ruleTester.run("no-extra-parens", rule, {
         invalid("(foo.bar()).baz", "foo.bar().baz", "CallExpression"),
         invalid("(foo\n.bar())\n.baz", "foo\n.bar()\n.baz", "CallExpression"),
         invalid("(new foo()).bar", "new foo().bar", "NewExpression"),
+        invalid("(new foo())[bar]", "new foo()[bar]", "NewExpression"),
         invalid("(new foo()).bar()", "new foo().bar()", "NewExpression"),
         invalid("(new foo(bar)).baz", "new foo(bar).baz", "NewExpression"),
         invalid("(new foo.bar()).baz", "new foo.bar().baz", "NewExpression"),
@@ -1165,6 +1174,63 @@ ruleTester.run("no-extra-parens", rule, {
             ]
         },
 
+        // ["all", { enforceForNewInMemberExpressions: true }]
+        {
+            code: "(new foo()).bar",
+            output: "new foo().bar",
+            options: ["all"],
+            errors: [
+                {
+                    messageId: "unexpected",
+                    type: "NewExpression"
+                }
+            ]
+        },
+        {
+            code: "(new foo()).bar",
+            output: "new foo().bar",
+            options: ["all", {}],
+            errors: [
+                {
+                    messageId: "unexpected",
+                    type: "NewExpression"
+                }
+            ]
+        },
+        {
+            code: "(new foo()).bar",
+            output: "new foo().bar",
+            options: ["all", { enforceForNewInMemberExpressions: true }],
+            errors: [
+                {
+                    messageId: "unexpected",
+                    type: "NewExpression"
+                }
+            ]
+        },
+        {
+            code: "(new foo())[bar]",
+            output: "new foo()[bar]",
+            options: ["all", { enforceForNewInMemberExpressions: true }],
+            errors: [
+                {
+                    messageId: "unexpected",
+                    type: "NewExpression"
+                }
+            ]
+        },
+        {
+            code: "(new foo.bar()).baz",
+            output: "new foo.bar().baz",
+            options: ["all", { enforceForNewInMemberExpressions: true }],
+            errors: [
+                {
+                    messageId: "unexpected",
+                    type: "NewExpression"
+                }
+            ]
+        },
+
         // https://github.com/eslint/eslint/issues/8175
         invalid(
             "let a = [...(b)]",
diff --git a/tests/lib/rules/no-mixed-operators.js b/tests/lib/rules/no-mixed-operators.js
index 4e822181f..efc93bf79 100644
--- a/tests/lib/rules/no-mixed-operators.js
+++ b/tests/lib/rules/no-mixed-operators.js
@@ -64,8 +64,8 @@ ruleTester.run("no-mixed-operators", rule, {
         {
             code: "a && b || c",
             errors: [
-                { column: 3, message: "Unexpected mix of '&&' and '||'." },
-                { column: 8, message: "Unexpected mix of '&&' and '||'." }
+                { column: 3, endColumn: 5, message: "Unexpected mix of '&&' and '||'." },
+                { column: 8, endColumn: 10, message: "Unexpected mix of '&&' and '||'." }
             ]
         },
         {
@@ -110,48 +110,48 @@ ruleTester.run("no-mixed-operators", rule, {
             code: "a + b - c",
             options: [{ allowSamePrecedence: false }],
             errors: [
-                { column: 3, message: "Unexpected mix of '+' and '-'." },
-                { column: 7, message: "Unexpected mix of '+' and '-'." }
+                { column: 3, endColumn: 4, message: "Unexpected mix of '+' and '-'." },
+                { column: 7, endColumn: 8, message: "Unexpected mix of '+' and '-'." }
             ]
         },
         {
             code: "a * b / c",
             options: [{ allowSamePrecedence: false }],
             errors: [
-                { column: 3, message: "Unexpected mix of '*' and '/'." },
-                { column: 7, message: "Unexpected mix of '*' and '/'." }
+                { column: 3, endColumn: 4, message: "Unexpected mix of '*' and '/'." },
+                { column: 7, endColumn: 8, message: "Unexpected mix of '*' and '/'." }
             ]
         },
         {
             code: "a || b ? c : d",
             options: [{ groups: [["&&", "||", "?:"]] }],
             errors: [
-                { column: 3, message: "Unexpected mix of '||' and '?:'." },
-                { column: 8, message: "Unexpected mix of '||' and '?:'." }
+                { column: 3, endColumn: 5, message: "Unexpected mix of '||' and '?:'." },
+                { column: 8, endColumn: 9, message: "Unexpected mix of '||' and '?:'." }
             ]
         },
         {
             code: "a && b ? 1 : 2",
             options: [{ groups: [["&&", "||", "?:"]] }],
             errors: [
-                { column: 3, message: "Unexpected mix of '&&' and '?:'." },
-                { column: 8, message: "Unexpected mix of '&&' and '?:'." }
+                { column: 3, endColumn: 5, message: "Unexpected mix of '&&' and '?:'." },
+                { column: 8, endColumn: 9, message: "Unexpected mix of '&&' and '?:'." }
             ]
         },
         {
             code: "x ? a && b : 0",
             options: [{ groups: [["&&", "||", "?:"]] }],
             errors: [
-                { column: 3, message: "Unexpected mix of '?:' and '&&'." },
-                { column: 7, message: "Unexpected mix of '?:' and '&&'." }
+                { column: 3, endColumn: 4, message: "Unexpected mix of '?:' and '&&'." },
+                { column: 7, endColumn: 9, message: "Unexpected mix of '?:' and '&&'." }
             ]
         },
         {
             code: "x ? 0 : a && b",
             options: [{ groups: [["&&", "||", "?:"]] }],
             errors: [
-                { column: 3, message: "Unexpected mix of '?:' and '&&'." },
-                { column: 11, message: "Unexpected mix of '?:' and '&&'." }
+                { column: 3, endColumn: 4, message: "Unexpected mix of '?:' and '&&'." },
+                { column: 11, endColumn: 13, message: "Unexpected mix of '?:' and '&&'." }
             ]
         }
     ]
diff --git a/tests/lib/rules/no-multi-spaces.js b/tests/lib/rules/no-multi-spaces.js
index db77ff391..4a8e6034e 100644
--- a/tests/lib/rules/no-multi-spaces.js
+++ b/tests/lib/rules/no-multi-spaces.js
@@ -112,7 +112,9 @@ ruleTester.run("no-multi-spaces", rule, {
             output: "function foo(a, b) {}",
             errors: [{
                 message: "Multiple spaces found before 'b'.",
-                type: "Identifier"
+                type: "Identifier",
+                column: 16,
+                endColumn: 18
             }]
         },
         {
@@ -121,7 +123,9 @@ ruleTester.run("no-multi-spaces", rule, {
             parserOptions: { ecmaVersion: 6 },
             errors: [{
                 message: "Multiple spaces found before 'b'.",
-                type: "Identifier"
+                type: "Identifier",
+                column: 14,
+                endColumn: 16
             }]
         },
         {
@@ -129,7 +133,9 @@ ruleTester.run("no-multi-spaces", rule, {
             output: "var a = 1",
             errors: [{
                 message: "Multiple spaces found before '1'.",
-                type: "Numeric"
+                type: "Numeric",
+                column: 8,
+                endColumn: 10
             }]
         },
         {
@@ -153,7 +159,9 @@ ruleTester.run("no-multi-spaces", rule, {
             output: "var arr = {'a': 1, 'b': 2};",
             errors: [{
                 message: "Multiple spaces found before ''b''.",
-                type: "String"
+                type: "String",
+                column: 19,
+                endColumn: 21
             }]
         },
         {
@@ -213,16 +221,24 @@ ruleTester.run("no-multi-spaces", rule, {
             output: "[ , 1, , 3, , ]",
             errors: [{
                 message: "Multiple spaces found before ','.",
-                type: "Punctuator"
+                type: "Punctuator",
+                column: 2,
+                endColumn: 4
             }, {
                 message: "Multiple spaces found before ','.",
-                type: "Punctuator"
+                type: "Punctuator",
+                column: 8,
+                endColumn: 10
             }, {
                 message: "Multiple spaces found before ','.",
-                type: "Punctuator"
+                type: "Punctuator",
+                column: 14,
+                endColumn: 16
             }, {
                 message: "Multiple spaces found before ']'.",
-                type: "Punctuator"
+                type: "Punctuator",
+                column: 17,
+                endColumn: 19
             }]
         },
         {
@@ -273,7 +289,9 @@ ruleTester.run("no-multi-spaces", rule, {
             output: "function foo () {}",
             errors: [{
                 message: "Multiple spaces found before '('.",
-                type: "Punctuator"
+                type: "Punctuator",
+                column: 13,
+                endColumn: 19
             }]
         },
         {
@@ -389,7 +407,9 @@ ruleTester.run("no-multi-spaces", rule, {
             output: "var x = 5;",
             errors: [{
                 message: "Multiple spaces found before '5'.",
-                type: "Numeric"
+                type: "Numeric",
+                column: 8,
+                endColumn: 11
             }]
         },
 
@@ -415,7 +435,9 @@ ruleTester.run("no-multi-spaces", rule, {
             output: "var x = 5; // comment",
             errors: [{
                 message: "Multiple spaces found before '// comment'.",
-                type: "Line"
+                type: "Line",
+                column: 11,
+                endColumn: 13
             }]
         },
         {
@@ -582,7 +604,9 @@ ruleTester.run("no-multi-spaces", rule, {
             options: [{ ignoreEOLComments: false }],
             errors: [{
                 message: "Multiple spaces found before '/*comment...*/'.",
-                type: "Block"
+                type: "Block",
+                column: 11,
+                endColumn: 13
             }]
         },
         {
diff --git a/tests/lib/rules/no-obj-calls.js b/tests/lib/rules/no-obj-calls.js
index d5bcf0638..db7261568 100644
--- a/tests/lib/rules/no-obj-calls.js
+++ b/tests/lib/rules/no-obj-calls.js
@@ -61,6 +61,10 @@ ruleTester.run("no-obj-calls", rule, {
         {
             code: "function foo() { var Atomics = bar(); var baz = Atomics(5); }",
             globals: { Atomics: false }
+        },
+        {
+            code: "var construct = typeof Reflect !== \"undefined\" ? Reflect.construct : undefined; construct();",
+            globals: { Reflect: false }
         }
     ],
     invalid: [
diff --git a/tests/lib/rules/no-param-reassign.js b/tests/lib/rules/no-param-reassign.js
index fec1e4168..5bb70e6aa 100644
--- a/tests/lib/rules/no-param-reassign.js
+++ b/tests/lib/rules/no-param-reassign.js
@@ -45,6 +45,11 @@ ruleTester.run("no-param-reassign", rule, {
         { code: "function foo(a) { for (a.b of arr); }", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }], parserOptions: { ecmaVersion: 6 } },
         { code: "function foo(a, z) { a.b = 0; x.y = 0; }", options: [{ props: true, ignorePropertyModificationsFor: ["a", "x"] }] },
         { code: "function foo(a) { a.b.c = 0;}", options: [{ props: true, ignorePropertyModificationsFor: ["a"] }] },
+        { code: "function foo(aFoo) { aFoo.b = 0; }", options: [{ props: true, ignorePropertyModificationsForRegex: ["^a.*$"] }] },
+        { code: "function foo(aFoo) { ++aFoo.b; }", options: [{ props: true, ignorePropertyModificationsForRegex: ["^a.*$"] }] },
+        { code: "function foo(aFoo) { delete aFoo.b; }", options: [{ props: true, ignorePropertyModificationsForRegex: ["^a.*$"] }] },
+        { code: "function foo(a, z) { aFoo.b = 0; x.y = 0; }", options: [{ props: true, ignorePropertyModificationsForRegex: ["^a.*$", "^x.*$"] }] },
+        { code: "function foo(aFoo) { aFoo.b.c = 0;}", options: [{ props: true, ignorePropertyModificationsForRegex: ["^a.*$"] }] },
         {
             code: "function foo(a) { ({ [a]: variable } = value) }",
             options: [{ props: true }],
@@ -152,6 +157,18 @@ ruleTester.run("no-param-reassign", rule, {
             parserOptions: { ecmaVersion: 6 },
             errors: [{ message: "Assignment to property of function parameter 'bar'." }]
         },
+        {
+            code: "function foo(bar) { [bar.a] = []; }",
+            options: [{ props: true, ignorePropertyModificationsForRegex: ["^a.*$"] }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Assignment to property of function parameter 'bar'." }]
+        },
+        {
+            code: "function foo(bar) { [bar.a] = []; }",
+            options: [{ props: true, ignorePropertyModificationsForRegex: ["^B.*$"] }],
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Assignment to property of function parameter 'bar'." }]
+        },
         {
             code: "function foo(bar) { ({foo: bar.a} = {}); }",
             options: [{ props: true }],
diff --git a/tests/lib/rules/no-self-assign.js b/tests/lib/rules/no-self-assign.js
index 4e168a897..eaa0d02d1 100644
--- a/tests/lib/rules/no-self-assign.js
+++ b/tests/lib/rules/no-self-assign.js
@@ -70,6 +70,14 @@ ruleTester.run("no-self-assign", rule, {
         {
             code: "a[\n    'b'\n] = a[\n    'b'\n]",
             options: [{ props: false }]
+        },
+        {
+            code: "this.x = this.y",
+            options: [{ props: true }]
+        },
+        {
+            code: "this.x = this.x",
+            options: [{ props: false }]
         }
     ],
     invalid: [
@@ -120,6 +128,11 @@ ruleTester.run("no-self-assign", rule, {
         { code: "a.b.c = a.b.c", options: [{ props: true }], errors: ["'a.b.c' is assigned to itself."] },
         { code: "a[b] = a[b]", options: [{ props: true }], errors: ["'a[b]' is assigned to itself."] },
         { code: "a['b'] = a['b']", options: [{ props: true }], errors: ["'a['b']' is assigned to itself."] },
-        { code: "a[\n    'b'\n] = a[\n    'b'\n]", options: [{ props: true }], errors: ["'a['b']' is assigned to itself."] }
+        { code: "a[\n    'b'\n] = a[\n    'b'\n]", options: [{ props: true }], errors: ["'a['b']' is assigned to itself."] },
+        {
+            code: "this.x = this.x",
+            options: [{ props: true }],
+            errors: ["'this.x' is assigned to itself."]
+        }
     ]
 });
diff --git a/tests/lib/rules/no-tabs.js b/tests/lib/rules/no-tabs.js
index ac0ad9e74..637f49051 100644
--- a/tests/lib/rules/no-tabs.js
+++ b/tests/lib/rules/no-tabs.js
@@ -40,7 +40,9 @@ ruleTester.run("no-tabs", rule, {
             errors: [{
                 message: ERROR_MESSAGE,
                 line: 1,
-                column: 17
+                column: 17,
+                endLine: 1,
+                endColumn: 18
             }]
         },
         {
@@ -48,7 +50,9 @@ ruleTester.run("no-tabs", rule, {
             errors: [{
                 message: ERROR_MESSAGE,
                 line: 1,
-                column: 5
+                column: 5,
+                endLine: 1,
+                endColumn: 6
             }]
         },
         {
@@ -59,7 +63,9 @@ ruleTester.run("no-tabs", rule, {
             errors: [{
                 message: ERROR_MESSAGE,
                 line: 2,
-                column: 5
+                column: 5,
+                endLine: 2,
+                endColumn: 6
             }]
         },
         {
@@ -70,7 +76,9 @@ ruleTester.run("no-tabs", rule, {
             errors: [{
                 message: ERROR_MESSAGE,
                 line: 1,
-                column: 9
+                column: 9,
+                endLine: 1,
+                endColumn: 10
             }]
         },
         {
@@ -82,12 +90,16 @@ ruleTester.run("no-tabs", rule, {
                 {
                     message: ERROR_MESSAGE,
                     line: 2,
-                    column: 5
+                    column: 5,
+                    endLine: 2,
+                    endColumn: 6
                 },
                 {
                     message: ERROR_MESSAGE,
                     line: 3,
-                    column: 1
+                    column: 1,
+                    endLine: 3,
+                    endColumn: 2
                 }
             ]
         },
@@ -97,8 +109,50 @@ ruleTester.run("no-tabs", rule, {
             errors: [{
                 message: ERROR_MESSAGE,
                 line: 1,
-                column: 30
+                column: 30,
+                endLine: 1,
+                endColumn: 31
             }]
+        },
+        {
+            code: "\t\ta =\t\t\tb +\tc\t\t;\t\t",
+            errors: [
+                {
+                    message: ERROR_MESSAGE,
+                    line: 1,
+                    column: 1,
+                    endLine: 1,
+                    endColumn: 3
+                },
+                {
+                    message: ERROR_MESSAGE,
+                    line: 1,
+                    column: 6,
+                    endLine: 1,
+                    endColumn: 9
+                },
+                {
+                    message: ERROR_MESSAGE,
+                    line: 1,
+                    column: 12,
+                    endLine: 1,
+                    endColumn: 13
+                },
+                {
+                    message: ERROR_MESSAGE,
+                    line: 1,
+                    column: 14,
+                    endLine: 1,
+                    endColumn: 16
+                },
+                {
+                    message: ERROR_MESSAGE,
+                    line: 1,
+                    column: 17,
+                    endLine: 1,
+                    endColumn: 19
+                }
+            ]
         }
     ]
 });
diff --git a/tests/lib/rules/no-unneeded-ternary.js b/tests/lib/rules/no-unneeded-ternary.js
index 243526c22..a297b211b 100644
--- a/tests/lib/rules/no-unneeded-ternary.js
+++ b/tests/lib/rules/no-unneeded-ternary.js
@@ -27,6 +27,12 @@ ruleTester.run("no-unneeded-ternary", rule, {
         "var a = x === 2 ? 'true' : 'false';",
         "var a = foo ? foo : bar;",
         "var value = 'a';var canSet = true;var result = value || (canSet ? 'unset' : 'can not set')",
+        "var a = foo ? bar : foo;",
+        "foo ? bar : foo;",
+        "var a = f(x ? x : 1)",
+        "f(x ? x : 1);",
+        "foo ? foo : bar;",
+        "var a = foo ? 'Yes' : foo;",
         {
             code: "var a = foo ? 'Yes' : foo;",
             options: [{ defaultAssignment: false }]
@@ -34,6 +40,10 @@ ruleTester.run("no-unneeded-ternary", rule, {
         {
             code: "var a = foo ? bar : foo;",
             options: [{ defaultAssignment: false }]
+        },
+        {
+            code: "foo ? bar : foo;",
+            options: [{ defaultAssignment: false }]
         }
     ],
     invalid: [
@@ -314,6 +324,39 @@ ruleTester.run("no-unneeded-ternary", rule, {
                 line: 1,
                 column: 13
             }]
+        },
+        {
+            code: "f(x ? x : 1);",
+            output: "f(x || 1);",
+            options: [{ defaultAssignment: false }],
+            errors: [{
+                message: "Unnecessary use of conditional expression for default assignment.",
+                type: "ConditionalExpression",
+                line: 1,
+                column: 7
+            }]
+        },
+        {
+            code: "x ? x : 1;",
+            output: "x || 1;",
+            options: [{ defaultAssignment: false }],
+            errors: [{
+                message: "Unnecessary use of conditional expression for default assignment.",
+                type: "ConditionalExpression",
+                line: 1,
+                column: 5
+            }]
+        },
+        {
+            code: "var a = foo ? foo : bar;",
+            output: "var a = foo || bar;",
+            options: [{ defaultAssignment: false }],
+            errors: [{
+                message: "Unnecessary use of conditional expression for default assignment.",
+                type: "ConditionalExpression",
+                line: 1,
+                column: 15
+            }]
         }
     ]
 });
diff --git a/tests/lib/rules/no-unsafe-negation.js b/tests/lib/rules/no-unsafe-negation.js
index 6ac245412..9493bbb72 100644
--- a/tests/lib/rules/no-unsafe-negation.js
+++ b/tests/lib/rules/no-unsafe-negation.js
@@ -18,7 +18,26 @@ const rule = require("../../../lib/rules/no-unsafe-negation"),
 
 const ruleTester = new RuleTester();
 const unexpectedInError = { messageId: "unexpected", data: { operator: "in" } };
-const unexpectedInstanceofError = { messageId: "unexpected", data: { operator: "instanceof" } };
+const unexpectedInstanceofError = {
+    messageId: "unexpected",
+    data: { operator: "instanceof" }
+};
+const unexpectedLessThanOperatorError = {
+    messageId: "unexpected",
+    data: { operator: "<" }
+};
+const unexpectedMoreThanOperatorError = {
+    messageId: "unexpected",
+    data: { operator: ">" }
+};
+const unexpectedMoreThanOrEqualOperatorError = {
+    messageId: "unexpected",
+    data: { operator: ">=" }
+};
+const unexpectedLessThanOrEqualOperatorError = {
+    messageId: "unexpected",
+    data: { operator: "<=" }
+};
 
 ruleTester.run("no-unsafe-negation", rule, {
     valid: [
@@ -29,7 +48,37 @@ ruleTester.run("no-unsafe-negation", rule, {
         "a instanceof b",
         "a instanceof b === false",
         "!(a instanceof b)",
-        "(!a) instanceof b"
+        "(!a) instanceof b",
+
+        // tests cases for enforceForOrderingRelations option:
+        "if (! a < b) {}",
+        "while (! a > b) {}",
+        "foo = ! a <= b;",
+        "foo = ! a >= b;",
+        {
+            code: "! a <= b",
+            options: [{}]
+        },
+        {
+            code: "foo = ! a >= b;",
+            options: [{ enforceForOrderingRelations: false }]
+        },
+        {
+            code: "foo = (!a) >= b;",
+            options: [{ enforceForOrderingRelations: true }]
+        },
+        {
+            code: "a <= b",
+            options: [{ enforceForOrderingRelations: true }]
+        },
+        {
+            code: "!(a < b)",
+            options: [{ enforceForOrderingRelations: true }]
+        },
+        {
+            code: "foo = a > b;",
+            options: [{ enforceForOrderingRelations: true }]
+        }
     ],
     invalid: [
         {
@@ -55,6 +104,31 @@ ruleTester.run("no-unsafe-negation", rule, {
         {
             code: "!(a) instanceof b",
             errors: [unexpectedInstanceofError]
+        },
+        {
+            code: "if (! a < b) {}",
+            options: [{ enforceForOrderingRelations: true }],
+            errors: [unexpectedLessThanOperatorError]
+        },
+        {
+            code: "while (! a > b) {}",
+            options: [{ enforceForOrderingRelations: true }],
+            errors: [unexpectedMoreThanOperatorError]
+        },
+        {
+            code: "foo = ! a <= b;",
+            options: [{ enforceForOrderingRelations: true }],
+            errors: [unexpectedLessThanOrEqualOperatorError]
+        },
+        {
+            code: "foo = ! a >= b;",
+            options: [{ enforceForOrderingRelations: true }],
+            errors: [unexpectedMoreThanOrEqualOperatorError]
+        },
+        {
+            code: "! a <= b",
+            options: [{ enforceForOrderingRelations: true }],
+            errors: [unexpectedLessThanOrEqualOperatorError]
         }
     ]
 });
diff --git a/tests/lib/rules/operator-assignment.js b/tests/lib/rules/operator-assignment.js
index fe7b326a1..2f8753253 100644
--- a/tests/lib/rules/operator-assignment.js
+++ b/tests/lib/rules/operator-assignment.js
@@ -191,6 +191,86 @@ ruleTester.run("operator-assignment", rule, {
         code: "foo[5] = foo[5] / baz",
         output: "foo[5] /= baz", // this is ok because 5 is a literal, so toString won't get called
         errors: EXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "/*1*/x/*2*/./*3*/y/*4*/= x.y +/*5*/z/*6*/./*7*/w/*8*/;",
+        output: "/*1*/x/*2*/./*3*/y/*4*/+=/*5*/z/*6*/./*7*/w/*8*/;", // these comments are preserved
+        options: ["always"],
+        errors: EXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "x // 1\n . // 2\n y // 3\n = x.y + //4\n z //5\n . //6\n w;",
+        output: "x // 1\n . // 2\n y // 3\n += //4\n z //5\n . //6\n w;", // these comments are preserved
+        options: ["always"],
+        errors: EXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "x = /*1*/ x + y",
+        output: null, // not fixed; fixing would remove this comment
+        options: ["always"],
+        errors: EXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "x = //1\n x + y",
+        output: null, // not fixed; fixing would remove this comment
+        options: ["always"],
+        errors: EXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "x.y = x/*1*/.y + z",
+        output: null, // not fixed; fixing would remove this comment
+        options: ["always"],
+        errors: EXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "x.y = x. //1\n y + z",
+        output: null, // not fixed; fixing would remove this comment
+        options: ["always"],
+        errors: EXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "x = x /*1*/ + y",
+        output: null, // not fixed; fixing would remove this comment
+        options: ["always"],
+        errors: EXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "x = x //1\n + y",
+        output: null, // not fixed; fixing would remove this comment
+        options: ["always"],
+        errors: EXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "/*1*/x +=/*2*/y/*3*/;",
+        output: "/*1*/x = x +/*2*/y/*3*/;", // these comments are preserved and not duplicated
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "x +=//1\n y",
+        output: "x = x +//1\n y", // this comment is preserved and not duplicated
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "(/*1*/x += y)",
+        output: "(/*1*/x = x + y)", // this comment is preserved and not duplicated
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "x/*1*/+=  y",
+        output: null, // not fixed; fixing would duplicate this comment
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "x //1\n +=  y",
+        output: null, // not fixed; fixing would duplicate this comment
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "(/*1*/x) +=  y",
+        output: null, // not fixed; fixing would duplicate this comment
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "x/*1*/.y +=  z",
+        output: null, // not fixed; fixing would duplicate this comment
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "x.//1\n y +=  z",
+        output: null, // not fixed; fixing would duplicate this comment
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
     }, {
         code: "(foo.bar) ^= ((((((((((((((((baz))))))))))))))))",
         output: "(foo.bar) = (foo.bar) ^ ((((((((((((((((baz))))))))))))))))",
@@ -230,6 +310,31 @@ ruleTester.run("operator-assignment", rule, {
         output: "foo = foo * (bar + 1)",
         options: ["never"],
         errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo+=-bar",
+        output: "foo= foo+-bar", // tokens can be adjacent
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo+=+bar",
+        output: "foo= foo+ +bar", // tokens cannot be adjacent, insert a space between
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo+= +bar",
+        output: "foo= foo+ +bar", // tokens cannot be adjacent, but there is already a space between
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo+=/**/+bar",
+        output: "foo= foo+/**/+bar", // tokens cannot be adjacent, but there is a comment between
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
+    }, {
+        code: "foo+=+bar===baz",
+        output: "foo= foo+(+bar===baz)", // tokens cannot be adjacent, but the right side will be parenthesised
+        options: ["never"],
+        errors: UNEXPECTED_OPERATOR_ASSIGNMENT
     }]
 
 });
diff --git a/tests/lib/rules/prefer-numeric-literals.js b/tests/lib/rules/prefer-numeric-literals.js
index 800047051..ddd6e36c8 100644
--- a/tests/lib/rules/prefer-numeric-literals.js
+++ b/tests/lib/rules/prefer-numeric-literals.js
@@ -92,6 +92,104 @@ ruleTester.run("prefer-numeric-literals", rule, {
             errors: [{ message: "Use hexadecimal literals instead of Number.parseInt()." }]
         },
 
+        // Adjacent tokens tests
+        {
+            code: "parseInt('11', 2)",
+            output: "0b11",
+            errors: [{ message: "Use binary literals instead of parseInt()." }]
+        },
+        {
+            code: "Number.parseInt('67', 8)",
+            output: "0o67",
+            errors: [{ message: "Use octal literals instead of Number.parseInt()." }]
+        },
+        {
+            code: "5+parseInt('A', 16)",
+            output: "5+0xA",
+            errors: [{ message: "Use hexadecimal literals instead of parseInt()." }]
+        },
+        {
+            code: "function *f(){ yield(Number).parseInt('11', 2) }",
+            output: "function *f(){ yield 0b11 }",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Use binary literals instead of (Number).parseInt()." }]
+        },
+        {
+            code: "function *f(){ yield(Number.parseInt)('67', 8) }",
+            output: "function *f(){ yield 0o67 }",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Use octal literals instead of Number.parseInt()." }]
+        },
+        {
+            code: "function *f(){ yield(parseInt)('A', 16) }",
+            output: "function *f(){ yield 0xA }",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Use hexadecimal literals instead of parseInt()." }]
+        },
+        {
+            code: "function *f(){ yield Number.parseInt('11', 2) }",
+            output: "function *f(){ yield 0b11 }",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Use binary literals instead of Number.parseInt()." }]
+        },
+        {
+            code: "function *f(){ yield/**/Number.parseInt('67', 8) }",
+            output: "function *f(){ yield/**/0o67 }",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Use octal literals instead of Number.parseInt()." }]
+        },
+        {
+            code: "function *f(){ yield(parseInt('A', 16)) }",
+            output: "function *f(){ yield(0xA) }",
+            parserOptions: { ecmaVersion: 6 },
+            errors: [{ message: "Use hexadecimal literals instead of parseInt()." }]
+        },
+        {
+            code: "parseInt('11', 2)+5",
+            output: "0b11+5",
+            errors: [{ message: "Use binary literals instead of parseInt()." }]
+        },
+        {
+            code: "Number.parseInt('17', 8)+5",
+            output: "0o17+5",
+            errors: [{ message: "Use octal literals instead of Number.parseInt()." }]
+        },
+        {
+            code: "parseInt('A', 16)+5",
+            output: "0xA+5",
+            errors: [{ message: "Use hexadecimal literals instead of parseInt()." }]
+        },
+        {
+            code: "parseInt('11', 2)in foo",
+            output: "0b11 in foo",
+            errors: [{ message: "Use binary literals instead of parseInt()." }]
+        },
+        {
+            code: "Number.parseInt('17', 8)in foo",
+            output: "0o17 in foo",
+            errors: [{ message: "Use octal literals instead of Number.parseInt()." }]
+        },
+        {
+            code: "parseInt('A', 16)in foo",
+            output: "0xA in foo",
+            errors: [{ message: "Use hexadecimal literals instead of parseInt()." }]
+        },
+        {
+            code: "parseInt('11', 2) in foo",
+            output: "0b11 in foo",
+            errors: [{ message: "Use binary literals instead of parseInt()." }]
+        },
+        {
+            code: "Number.parseInt('17', 8)/**/in foo",
+            output: "0o17/**/in foo",
+            errors: [{ message: "Use octal literals instead of Number.parseInt()." }]
+        },
+        {
+            code: "(parseInt('A', 16))in foo",
+            output: "(0xA)in foo",
+            errors: [{ message: "Use hexadecimal literals instead of parseInt()." }]
+        },
+
         // Should not autofix if it would remove comments
         {
             code: "/* comment */Number.parseInt('11', 2);",
diff --git a/tests/lib/rules/space-in-parens.js b/tests/lib/rules/space-in-parens.js
index 6f90da52b..a68c6bae7 100644
--- a/tests/lib/rules/space-in-parens.js
+++ b/tests/lib/rules/space-in-parens.js
@@ -128,8 +128,17 @@ ruleTester.run("space-in-parens", rule, {
             output: "bar(baz)",
             options: ["never"],
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 4 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 10 }
+                { messageId: "rejectedOpeningSpace", line: 1, column: 5, endColumn: 6 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 9, endColumn: 10 }
+            ]
+        },
+        {
+            code: "bar(  baz  )",
+            output: "bar(baz)",
+            options: ["never"],
+            errors: [
+                { messageId: "rejectedOpeningSpace", line: 1, column: 5, endColumn: 7 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 10, endColumn: 12 }
             ]
         },
         {
@@ -137,8 +146,17 @@ ruleTester.run("space-in-parens", rule, {
             output: "foo()",
             options: ["never"],
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 4 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 6 }
+                { messageId: "rejectedOpeningSpace", line: 1, column: 5, endColumn: 6 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 5, endColumn: 6 }
+            ]
+        },
+        {
+            code: "foo(  )",
+            output: "foo()",
+            options: ["never"],
+            errors: [
+                { messageId: "rejectedOpeningSpace", line: 1, column: 5, endColumn: 7 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 5, endColumn: 7 }
             ]
         },
         {
@@ -151,7 +169,7 @@ ruleTester.run("space-in-parens", rule, {
             code: "foo\n(\nbar )",
             output: "foo\n(\nbar)",
             options: ["never"],
-            errors: [{ messageId: "rejectedClosingSpace", line: 3, column: 5 }]
+            errors: [{ messageId: "rejectedClosingSpace", line: 3, column: 4 }]
         },
         {
             code: "foo\n(bar\n)\n",
@@ -170,8 +188,8 @@ ruleTester.run("space-in-parens", rule, {
             output: "foo( bar )",
             options: ["always"],
             errors: [
-                { messageId: "missingOpeningSpace", line: 1, column: 4 },
-                { messageId: "missingClosingSpace", line: 1, column: 8 }
+                { messageId: "missingOpeningSpace", line: 1, column: 4, endColumn: 5 },
+                { messageId: "missingClosingSpace", line: 1, column: 8, endColumn: 9 }
             ]
         },
 
@@ -248,7 +266,7 @@ ruleTester.run("space-in-parens", rule, {
             code: "foo( /* bar */ baz)",
             output: "foo(/* bar */ baz)",
             options: ["never"],
-            errors: [{ messageId: "rejectedOpeningSpace", line: 1, column: 4 }]
+            errors: [{ messageId: "rejectedOpeningSpace", line: 1, column: 5 }]
         },
 
         // exceptions
@@ -266,8 +284,8 @@ ruleTester.run("space-in-parens", rule, {
             output: "foo()",
             options: ["always", { exceptions: ["()", "empty"] }],
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 4 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 6 }
+                { messageId: "rejectedOpeningSpace", line: 1, column: 5 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 5 }
             ]
         },
         {
@@ -275,8 +293,8 @@ ruleTester.run("space-in-parens", rule, {
             output: "foo()",
             options: ["always", { exceptions: ["empty"] }],
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 4 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 6 }
+                { messageId: "rejectedOpeningSpace", line: 1, column: 5 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 5 }
             ]
         },
         {
@@ -284,7 +302,7 @@ ruleTester.run("space-in-parens", rule, {
             output: "foo( bar())",
             options: ["always", { exceptions: ["()", "empty"] }],
             errors: [
-                { messageId: "rejectedClosingSpace", line: 1, column: 12 }
+                { messageId: "rejectedClosingSpace", line: 1, column: 11 }
             ]
         },
         {
@@ -300,10 +318,10 @@ ruleTester.run("space-in-parens", rule, {
             output: "foo(bar( ))",
             options: ["never", { exceptions: ["empty"] }],
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 4 },
+                { messageId: "rejectedOpeningSpace", line: 1, column: 5 },
                 { messageId: "missingOpeningSpace", line: 1, column: 9 },
                 { messageId: "missingClosingSpace", line: 1, column: 10 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 12 }
+                { messageId: "rejectedClosingSpace", line: 1, column: 11 }
             ]
         },
         {
@@ -312,7 +330,7 @@ ruleTester.run("space-in-parens", rule, {
             options: ["never", { exceptions: ["[]"] }],
             errors: [
                 { messageId: "missingOpeningSpace", line: 1, column: 4 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 18 }
+                { messageId: "rejectedClosingSpace", line: 1, column: 17 }
             ]
         },
         {
@@ -449,8 +467,8 @@ ruleTester.run("space-in-parens", rule, {
             output: "(( 1 + 2 ))",
             options: ["always", { exceptions: ["()"] }],
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 1 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 13 }
+                { messageId: "rejectedOpeningSpace", line: 1, column: 2 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 12 }
             ]
         },
         {
@@ -458,10 +476,10 @@ ruleTester.run("space-in-parens", rule, {
             output: "((1 + 2))",
             options: ["never"],
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 1 },
-                { messageId: "rejectedOpeningSpace", line: 1, column: 3 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 11 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 13 }
+                { messageId: "rejectedOpeningSpace", line: 1, column: 2 },
+                { messageId: "rejectedOpeningSpace", line: 1, column: 4 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 10 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 12 }
             ]
         },
         {
@@ -506,7 +524,7 @@ ruleTester.run("space-in-parens", rule, {
             output: "var result = ( 1 / ( 1 + 2 )) + 3",
             options: ["always", { exceptions: ["()"] }],
             errors: [
-                { messageId: "rejectedClosingSpace", line: 1, column: 30 }
+                { messageId: "rejectedClosingSpace", line: 1, column: 29 }
             ]
         },
         {
@@ -524,7 +542,7 @@ ruleTester.run("space-in-parens", rule, {
             errors: [
                 { messageId: "missingOpeningSpace", line: 1, column: 14 },
                 { messageId: "missingClosingSpace", line: 1, column: 26 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 28 }
+                { messageId: "rejectedClosingSpace", line: 1, column: 27 }
             ]
         },
 
@@ -535,8 +553,8 @@ ruleTester.run("space-in-parens", rule, {
             options: ["never"],
             parserOptions: { ecmaVersion: 6 },
             errors: [
-                { messageId: "rejectedOpeningSpace", line: 1, column: 19 },
-                { messageId: "rejectedClosingSpace", line: 1, column: 27 }
+                { messageId: "rejectedOpeningSpace", line: 1, column: 20 },
+                { messageId: "rejectedClosingSpace", line: 1, column: 26 }
             ]
         },
         {
diff --git a/tests/lib/source-code/source-code.js b/tests/lib/source-code/source-code.js
index 57cc960d2..9e8da4844 100644
--- a/tests/lib/source-code/source-code.js
+++ b/tests/lib/source-code/source-code.js
@@ -1796,6 +1796,7 @@ describe("SourceCode", () => {
             ["let  foo = bar;", true],
             ["let /**/ foo = bar;", true],
             ["let/**/foo = bar;", false],
+            ["let/*\n*/foo = bar", false],
             ["a+b", false],
             ["a/**/+b", false],
             ["a/* */+b", false],