Repository: eslint/eslint
Pull request #15850 (2022-05-07 19:49:50)

fix: function-paren-newline crash on "new new Foo();"
<!--
    Thank you for contributing!

    ESLint adheres to the [JS Foundation Code of Conduct](https://eslint.org/conduct).
-->

#### Prerequisites checklist

- [x] I have read the [contributing guidelines](https://github.com/eslint/eslint/blob/HEAD/CONTRIBUTING.md).

#### What is the purpose of this pull request? (put an "X" next to an item)

<!--
    The following template is intentionally not a markdown checkbox list for the reasons
    explained in https://github.com/eslint/eslint/pull/12848#issuecomment-580302888
-->

[ ] Documentation update
[x] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/HEAD/templates/bug-report.md))
[ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/HEAD/templates/rule-proposal.md))
[ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/HEAD/templates/rule-change-proposal.md))
[ ] Add autofix to a rule
[ ] Add a CLI option
[ ] Add something to the core
[ ] Other, please explain:

<!--
    If the item you've checked above has a template, please paste the template questions below and answer them. (If this pull request is addressing an issue, you can just paste a link to the issue here instead.)
-->

<!--
    Please ensure your pull request is ready:

    - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
    - Include tests for this change
    - Update documentation for this change (if appropriate)
-->

<!--
    The following is required for all pull requests:
-->

#### What changes did you make? (Give an overview)

`function-paren-newline` crashes when see the code like this:

```js
new new Boolean();
```

This code has no sense, but this is correct JavaScript:

<img width="446" alt="image" src="https://user-images.githubusercontent.com/1573141/167269417-436fc394-6456-4b0b-a773-264f1f24a034.png">

It throws [TypeError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError) when trying to execute first `new` after second one returns instance of an object.

```sh
coderaiser@cloudcmd:~/putout/packages/plugin-remove-useless-new$ eslint new-new.js

Oops! Something went wrong! :(

ESLint: 8.15.0

TypeError: Cannot read properties of null (reading 'range')
Occurred while linting /Users/coderaiser/putout/packages/plugin-remove-useless-new/new-new.js:1
Rule: "function-paren-newline"
    at SourceCode.getTokenAfter (/Users/coderaiser/putout/node_modules/eslint/lib/source-code/token-store/index.js:315:18)
    at validateParens (/Users/coderaiser/putout/node_modules/eslint/lib/rules/function-paren-newline.js:109:52)
    at ArrowFunctionExpression,CallExpression,FunctionDeclaration,FunctionExpression,ImportExpression,NewExpression (/Users/coderaiser/putout/node_modules/eslint/lib/rules/function-paren-newline.js:277:21)
    at ruleErrorHandler (/Users/coderaiser/putout/node_modules/eslint/lib/linter/linter.js:1114:28)
    at /Users/coderaiser/putout/node_modules/eslint/lib/linter/safe-emitter.js:45:58
    at Array.forEach (<anonymous>)
    at Object.emit (/Users/coderaiser/putout/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
    at NodeEventGenerator.applySelector (/Users/coderaiser/putout/node_modules/eslint/lib/linter/node-event-generator.js:297:26)
    at NodeEventGenerator.applySelectors (/Users/coderaiser/putout/node_modules/eslint/lib/linter/node-event-generator.js:326:22)
    at NodeEventGenerator.enterNode (/Users/coderaiser/putout/node_modules/eslint/lib/linter/node-event-generator.js:340:14)
coderaiser@cloudcmd:~/putout/packages/plugin-remove-useless-new$ cat new-new.js
new new Boolean();
```


#### Is there anything you'd like reviewers to focus on?

The problem occurs on `AwaitExpression` switch case when we fall through to `CallExpression` case 
https://github.com/eslint/eslint/blob/9b17d6fac6983d2fed4cd005acba17be0a183970/lib/rules/function-paren-newline.js#L192-L209

<!-- markdownlint-disable-file MD004 -->


linux-foundation-easycla[bot]:  <a href="https://api.easycla.lfx.linuxfoundation.org/v2/repository-provider/github/sign/19114526/11061773/15850/#/?version=2"><img src="https://s3.amazonaws.com/cla-project-logo-prod/cla-missing-id.svg" alt="CLA Missing ID" align="left" height="28" width="328"></a> <a href="https://api.easycla.lfx.linuxfoundation.org/v2/repository-provider/github/sign/19114526/11061773/15850/#/?version=2"><img src="https://s3.amazonaws.com/cla-project-logo-prod/cla-not-signed.svg" alt="CLA Not Signed" align="left" height="28" width="328"></a><br/><br /><ul><li> :x: The commit (786c05826b862f51062cb55f5efe65ad04c57127). This user is missing the User's ID, preventing the EasyCLA check. <a href='https://help.github.com/en/github/committing-changes-to-your-project/why-are-my-commits-linked-to-the-wrong-user' target='_blank'>Consult GitHub Help</a> to resolve.For further assistance with EasyCLA, <a href='https://jira.linuxfoundation.org/servicedesk/customer/portal/4' target='_blank'>please submit a support request ticket</a>.</li></ul>
netlify[bot]: ### <span aria-hidden="true">👷</span> Deploy Preview for *docs-eslint* processing.


|  Name | Link |
|---------------------------------|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 786c05826b862f51062cb55f5efe65ad04c57127 |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/docs-eslint/deploys/6276cd607af2260008c909d3 |
aladdin-add: @coderaiser can you sign the cla?
coderaiser: > @coderaiser can you sign the cla?

Sure, I did it a couple times, but for some reason I always get redirected to https://github.com/eslint/eslint-visitor-keys/pull/32 after sign up.
snitin315: @coderaiser please make sure you are committing using the same email id which you used to sign the CLA. Please check your local git settings.
coderaiser: > @coderaiser please make sure you are committing using the same email id which you used to sign the CLA. Please check your local git settings.

I tried all my emails actually, and did it about 10 times 😅. Looks like something isn’t working properly, I can’t understand why I get redirected to already merged PR in other repo 🤷.
aladdin-add: > I can’t understand why I get redirected to already merged PR in other repo 🤷.

I guess it's another OpenJS project, and are using the easyCLA too. 😂
coderaiser: > I guess it's another OpenJS project, and is using the easyCLA too. 😂

But how this separate project related to `Missing ID on Commit` button I'm clicking opening the link https://api.easycla.lfx.linuxfoundation.org/v2/repository-provider/github/sign/19114526/11061773/15850/#/?version=2.

Does this `easyCLA` remember projects that was signed before? Maybe this link is misconfigured?
aladdin-add: https://github.com/openjs-foundation/EasyCLA#openjs-foundation-cla
Once a contributor is authorized for one OpenJS Foundation project, the signature is recognized for any other OpenJS Foundation repos that use EasyCLA.
aladdin-add: looks happy now. 👍 

Patch:
diff --git a/README.md b/README.md
index 4ad24079b..c21b6eaa7 100644
--- a/README.md
+++ b/README.md
@@ -297,7 +297,7 @@ The following companies, organizations, and individuals support ESLint's ongoing
 <!--sponsorsstart-->
 <h3>Platinum Sponsors</h3>
 <p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
-<p><a href="https://contra.com"><img src="https://images.opencollective.com/contra1/c70f93f/logo.png" alt="Contra" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" 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://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
+<p><a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" 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://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
 <p><a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3>
 <p><a href="https://launchdarkly.com"><img src="https://images.opencollective.com/launchdarkly/574bb9e/logo.png" alt="launchdarkly" height="32"></a> <a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a></p>
 <!--sponsorsend-->
diff --git a/lib/rules/function-paren-newline.js b/lib/rules/function-paren-newline.js
index 898e113ee..a5b8f0d70 100644
--- a/lib/rules/function-paren-newline.js
+++ b/lib/rules/function-paren-newline.js
@@ -191,10 +191,13 @@ module.exports = {
         function getParenTokens(node) {
             switch (node.type) {
                 case "NewExpression":
-                    if (!node.arguments.length && !(
-                        astUtils.isOpeningParenToken(sourceCode.getLastToken(node, { skip: 1 })) &&
-                        astUtils.isClosingParenToken(sourceCode.getLastToken(node))
-                    )) {
+                    if (!node.arguments.length &&
+                        !(
+                            astUtils.isOpeningParenToken(sourceCode.getLastToken(node, { skip: 1 })) &&
+                            astUtils.isClosingParenToken(sourceCode.getLastToken(node)) &&
+                            node.callee.range[1] < node.range[1]
+                        )
+                    ) {
 
                         // If the NewExpression does not have parens (e.g. `new Foo`), return null.
                         return null;


Test patch:
diff --git a/tests/lib/rules/function-paren-newline.js b/tests/lib/rules/function-paren-newline.js
index 048370f35..a8c7cc858 100644
--- a/tests/lib/rules/function-paren-newline.js
+++ b/tests/lib/rules/function-paren-newline.js
@@ -30,6 +30,7 @@ const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
 ruleTester.run("function-paren-newline", rule, {
 
     valid: [
+        "new new Foo();",
 
         // multiline option (default)
         "function baz(foo, bar) {}",
@@ -1174,6 +1175,18 @@ ruleTester.run("function-paren-newline", rule, {
             options: ["never"],
             errors: [LEFT_UNEXPECTED_ERROR]
         },
+        {
+            code: `
+                new new C()(
+                );
+            `,
+            output: `
+                new new C()();
+            `,
+            options: ["never"],
+            errors: [LEFT_UNEXPECTED_ERROR, RIGHT_UNEXPECTED_ERROR]
+        },
+
         {
             code: `
                 function baz(