Repository: eslint/eslint (js)

Issue:
indent treats nested function parameters incorrectly
**Tell us about your environment**

* **ESLint Version:** v4.1.1
* **Node Version:** v5.1.0
* **npm Version:** 3.3.12

**What parser (default, Babel-ESLint, etc.) are you using?** default

**Please show your full configuration:**

<details>
<summary>Configuration</summary>

<!-- Paste your configuration below: -->
```js
/*eslint indent: ["error", 2, { "FunctionDeclaration": {"body": 1, "parameters": 1} }]*/
```

</details>

**What did you do? Please include the actual source code causing the issue.**
I ran ESlint to check for validation issues.
<!-- Paste the source code below: -->
```js
/*eslint indent: ["error", 2, { "FunctionDeclaration": {"body": 1, "parameters": 1} }]*/

define([
  "bar",
  "baz",
  "qux"
],

function (
  bar,
  baz,
  qux
) {
  qux();
});
```

**What did you expect to happen?**
I expected no validation issues.

**What actually happened? Please include the actual, raw output from ESLint.**
It gave me validation errors:

```
  10:1  error  Expected indentation of 4 spaces but found 2  indent
  11:1  error  Expected indentation of 4 spaces but found 2  indent
  12:1  error  Expected indentation of 4 spaces but found 2  indent
  13:1  error  Expected indentation of 2 spaces but found 0  indent

✖ 4 problems (4 errors, 0 warnings)
  4 errors, 0 warnings potentially fixable with the `--fix` option.
```

If I run `--fix` it ends up looking like this, which to me is double the function parameter spacing that I want (it has 4 spaces instead of 2) and it adds 2 spaces before `) {`.

```js
define([
  "bar",
  "baz",
  "qux"
],

function (
    bar, // These three parameters should have 2 spaces instead of 4
    baz,
    qux
  ) { // This line should have 0 spaces instead of 2
  qux();
});
```

**Note**
Running without the `define` as a simple method works as expected from the [documentation examples](http://eslint.org/docs/rules/indent#functiondeclaration). I.e. this works as expected (no validation issues):

```js
/*eslint indent: ["error", 2, { "FunctionDeclaration": {"body": 1, "parameters": 1} }]*/

function foo(
  bar,
  baz,
  qux
) {
  qux();
}
```

Pull request description:
Update: fix indentation of nested function parameters (fixes #8892)
<!--
    ESLint adheres to the [JS Foundation Code of Conduct](https://js.foundation/community/code-of-conduct).
-->

**What is the purpose of this pull request? (put an "X" next to item)**

[x] Bug fix (https://github.com/eslint/eslint/issues/8892)

<!--
    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 (http://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)**

Previously, the `indent` rule would only offset the first token of an element in a list (e.g. an array). However, this was incorrect because the other tokens of the element might not depend on the indentation of the first token. For example, in a function expression, the indentation of the parens does not depend on the indentation of the `function` token. This commit updates the `indent` rule to correctly offset all of the tokens in the element.


**Is there anything you'd like reviewers to focus on?**

Nothing in particular

Patch:
diff --git a/lib/rules/indent.js b/lib/rules/indent.js
index 8739c58d0..727ecfaae 100644
--- a/lib/rules/indent.js
+++ b/lib/rules/indent.js
@@ -386,18 +386,6 @@ class OffsetStorage {
     getFirstDependency(token) {
         return this.desiredOffsets[token.range[0]].from;
     }
-
-    /**
-     * Increases the offset for a token from its parent by the given amount
-     * @param {Token} token The token whose offset should be increased
-     * @param {number} amount The number of indent levels that the offset should increase by
-     * @returns {void}
-     */
-    increaseOffset(token, amount) {
-        const currentOffsetInfo = this.desiredOffsets[token.range[0]];
-
-        this.desiredOffsets[token.range[0]] = { offset: currentOffsetInfo.offset + amount, from: currentOffsetInfo.from };
-    }
 }
 
 const ELEMENT_LIST_SCHEMA = {
@@ -750,7 +738,7 @@ module.exports = {
                     const firstTokenOfPreviousElement = previousElement && getFirstToken(previousElement);
 
                     if (previousElement && sourceCode.getLastToken(previousElement).loc.start.line > startToken.loc.end.line) {
-                        offsets.matchIndentOf(firstTokenOfPreviousElement, getFirstToken(element));
+                        offsets.setDesiredOffsets(getTokensAndComments(element), firstTokenOfPreviousElement, 0);
                     }
                 }
             });


Test patch:
diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js
index 0f6e05148..0001c76fd 100644
--- a/tests/lib/rules/indent.js
+++ b/tests/lib/rules/indent.js
@@ -1470,6 +1470,27 @@ ruleTester.run("indent", rule, {
             `,
             options: [4, { VariableDeclarator: 0, SwitchCase: 1 }]
         },
+        {
+            code: unIndent`
+                [[
+                ], function(
+                    foo
+                ) {}
+                ]
+            `
+        },
+        {
+            code: unIndent`
+                define([
+                    'foo'
+                ], function(
+                    bar
+                ) {
+                    baz;
+                }
+                )
+            `
+        },
         {
             code: unIndent`
                 const func = function (opts) {
@@ -5588,6 +5609,46 @@ ruleTester.run("indent", rule, {
                 [5, 0, 2, "Punctuator"]
             ])
         },
+        {
+            code: unIndent`
+                [[
+                ], function(
+                        foo
+                    ) {}
+                ]
+            `,
+            output: unIndent`
+                [[
+                ], function(
+                    foo
+                ) {}
+                ]
+            `,
+            errors: expectedErrors([[3, 4, 8, "Identifier"], [4, 0, 4, "Punctuator"]])
+        },
+        {
+            code: unIndent`
+                define([
+                    'foo'
+                ], function(
+                        bar
+                    ) {
+                    baz;
+                }
+                )
+            `,
+            output: unIndent`
+                define([
+                    'foo'
+                ], function(
+                    bar
+                ) {
+                    baz;
+                }
+                )
+            `,
+            errors: expectedErrors([[4, 4, 8, "Identifier"], [5, 0, 4, "Punctuator"]])
+        },
         {
             code: unIndent`
                 while (1 < 2)