Repository: eslint/eslint (js)

Issue:
[no-extra-parens] Allow an exception for (new X()).y
**What rule do you want to change?** no-extra-parens

**Does this change cause the rule to produce more or fewer warnings?** Fewer, if configured

**How will the change be implemented? (New option, new default behavior, etc.)?** New option, similar to the existing ones like returnAssign, nestedBinaryExpressions, etc.

**Please provide some example code that this change will affect:**

```js
const doc = (new JSDOM()).window.document;

const { document } = (new JSDOM(`<!doctype html><html><head></head><body>
  <div></div><div title=""></div><div title="yes"></div>
</body></html>`)).window;
```

**What does the rule currently do for this code?**

It requires removing the parens, i.e. that I write


```js
const doc = new JSDOM().window.document;

const { document } = new JSDOM(`<!doctype html><html><head></head><body>
  <div></div><div title=""></div><div title="yes"></div>
</body></html>`).window;
```

This is equivalent, but *it feels really weird*. Although the `new` operator binds more closely than the `.` operator in JS, this is a somewhat-surprising feature of JS, as `.` otherwise binds very high, and most space-separated operators bind quite low.

**What will the rule do after it's changed?**

Allow the above code, when a new option is configured, e.g.`"newExpressions": false`.

**Are you willing to submit a pull request to implement this change?**

Yes, although a community volunteer would be much appreciated.

**Other note**

This changed in v6.5.0 as part of https://github.com/eslint/eslint/pull/12302.

Pull request description:
Update: enforceForNewInMemberExpressions no-extra-parens (fixes #12428)
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

**What is the purpose of this pull request? (put an "X" next to item)**

[X] Changes an existing rule #12428

<!--
    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 rule do you want to change?**

no-extra-parens

**Does this change cause the rule to produce more or fewer warnings?**

Fewer if the option is set to `false`. Default is `true`.

**How will the change be implemented? (New option, new default behavior, etc.)?**

new option `enforceForNewInMemberExpressions`

**Please provide some example code that this change will affect:**

```js
/* eslint no-extra-parens: "error" */

const foo = (new Bar()).baz; // error

const quux = (new Bar())[baz]; // error

(new Bar()).doSomething(); // error
```

**What does the rule currently do for this code?**

3 errors.

**What will the rule do after it's changed?**

No errors if the option is set to `false`:

```js
/* eslint no-extra-parens: ["error", "all", { "enforceForNewInMemberExpressions": false }] */

const foo = (new Bar()).baz; // ok

const quux = (new Bar())[baz]; // ok

(new Bar()).doSomething(); // ok
```

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

**What changes did you make? (Give an overview)**

New option.

**Is there anything you'd like reviewers to focus on?**

Patch:
diff --git a/README.md b/README.md
index c12264b9f..dd414f1d1 100644
--- a/README.md
+++ b/README.md
@@ -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://clay.global"><img src="https://images.opencollective.com/clayglobal/2468f34/logo.png" alt="clay" 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://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://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.minitool.com"><img src="https://images.opencollective.com/minitool-software-ltd/6d68e16/logo.png" alt="MiniTool Software Ltd" 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/lib/cli-engine/cli-engine.js b/lib/cli-engine/cli-engine.js
index e768da837..17ed8d9f0 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()];
diff --git a/lib/linter/linter.js b/lib/linter/linter.js
index 5b9ce07a5..8bd29b947 100644
--- a/lib/linter/linter.js
+++ b/lib/linter/linter.js
@@ -810,9 +810,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 +840,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 +987,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 +1021,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 +1160,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/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/dot-location.js b/lib/rules/dot-location.js
index c2e734a1a..812988efa 100644
--- a/lib/rules/dot-location.js
+++ b/lib/rules/dot-location.js
@@ -67,7 +67,7 @@ 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}`)
                     });
@@ -75,7 +75,7 @@ module.exports = {
             } else if (!astUtils.isTokenOnSameLine(dot, prop)) {
                 context.report({
                     node,
-                    loc: dot.loc.start,
+                    loc: dot.loc,
                     messageId: "expectedDotBeforeProperty",
                     fix: fixer => fixer.replaceTextRange([tokenBeforeDot.range[1], prop.range[0]], `${textBeforeDot}${textAfterDot}.`)
                 });
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-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-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-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/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/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..778365194 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",
@@ -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",


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/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/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/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-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-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/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],