Repository: eslint/eslint (js)

Issue:
Class & Fatarrow allman curly indentation after --fix issue
Hello, first off, thanks for the great tool. I love it!

I tried to see if someone else had reported this, which I can't seem to find. So there is a good chance this is simply a config issue on my side. Sorry in advance if that is the case

**Tell us about your environment**

* **ESLint Version:** v4.0.0-alpha.1
* **Node Version:** v7.9.0
* **npm Version:** v4.2.0

**What parser (default, Babel-ESLint, etc.) are you using?**

Default

**Please show your full configuration:**

<!-- Paste your configuration below: -->
```js
{
    "env": {
        "es6": true,
        "browser": true,
        "node": true
    },
    "globals": {
        "global": false,
        "UTIL": false,
        "__version": false,
        "__theme": false,
        "__themeCode": false,
        "__isMobile": false,
        "__dpi": false,
        "__postfix": false,
        "__t": false,
        "PIXI": true
    },
    "parserOptions": {
        "ecmaVersion": 6,
        "sourceType": "module"
    },
    "rules": {
        // Possible Errors
        "comma-dangle": [1, "always-multiline"],
        "no-cond-assign": [1, "except-parens"],
        "no-console": 1,
        "no-constant-condition": 1,
        "no-control-regex": 1,
        "no-debugger": 1,
        "no-dupe-args": 1,
        "no-dupe-keys": 1,
        "no-duplicate-case": 1,
        "no-empty": 1,
        "no-empty-character-class": 1,
        "no-ex-assign": 1,
        "no-extra-boolean-cast": 1,
        "no-extra-parens": 0,
        "no-extra-semi": 1,
        "no-func-assign": 1,
        "no-inner-declarations": 1,
        "no-invalid-regexp": 1,
        "no-irregular-whitespace": 1,
        "no-negated-in-lhs": 1,
        "no-obj-calls": 1,
        "no-prototype-builtins": 1,
        "no-regex-spaces": 1,
        "no-sparse-arrays": 1,
        "no-unexpected-multiline": 1,
        "no-unreachable": 1,
        "no-unsafe-finally": 1,
        "use-isnan": 1,
        "valid-jsdoc": [1, { "requireReturn": false, "requireReturnType": true, "requireParamDescription": true, "requireReturnDescription": true }],
        "valid-typeof": 1,

        // Best Practices
        "accessor-pairs": 1,
        "array-callback-return": 1,
        "block-scoped-var": 1,
        "complexity": 0,
        "consistent-return": 1,
        "curly": [1, "multi-line"],
        "default-case": 0,
        "dot-location": [1, "property"],
        "dot-notation": 1,
        "eqeqeq": 1,
        "guard-for-in": 0,
        "no-alert": 1,
        "no-caller": 1,
        "no-case-declarations": 1,
        "no-div-regex": 1,
        "no-else-return": 1,
        "no-empty-function": 1,
        "no-empty-pattern": 1,
        "no-eq-null": 1,
        "no-eval": 1,
        "no-extend-native": 1,
        "no-extra-bind": 1,
        "no-extra-label": 1,
        "no-fallthrough": 1,
        "no-floating-decimal": 1,
        "no-implicit-coercion": [1, { "boolean": false, "number": true, "string": true, "allow": [] }],
        "no-implicit-globals": 1,
        "no-implied-eval": 1,
        "no-invalid-this": 0,
        "no-iterator": 1,
        "no-labels": 1,
        "no-lone-blocks": 1,
        "no-loop-func": 1,
        "no-magic-numbers": [0],
        "no-multi-spaces": [1, { "exceptions": { "VariableDeclarator": true, "ImportDeclaration": true, "Property": true } }],
        "no-multi-str": 1,
        "no-native-reassign": 1,
        "no-new": 1,
        "no-new-func": 1,
        "no-new-wrappers": 1,
        "no-octal": 1,
        "no-octal-escape": 1,
        "no-param-reassign": 0,
        "no-proto": 1,
        "no-redeclare": 1,
        "no-return-assign": 1,
        "no-script-url": 1,
        "no-self-assign": 1,
        "no-self-compare": 1,
        "no-sequences": 1,
        "no-throw-literal": 1,
        "no-unmodified-loop-condition": 1,
        "no-unused-expressions": 1,
        "no-unused-labels": 1,
        "no-useless-call": 1,
        "no-useless-concat": 1,
        "no-useless-escape": 0,
        "no-void": 1,
        "no-warning-comments": 0,
        "no-with": 1,
        "radix": 1,
        "vars-on-top": 0,
        "wrap-iife": [1, "inside"],
        "yoda": 1,

        // Strict Mode
        "strict": [1, "global"],

        // Variables
        "init-declarations": 0,
        "no-catch-shadow": 1,
        "no-delete-var": 1,
        "no-label-var": 1,
        "no-restricted-globals": 1,
        "no-shadow": 0,
        "no-shadow-restricted-names": 1,
        "no-undef": 1,
        "no-undef-init": 1,
        "no-undefined": 0,
        "no-unused-vars": 1,
        "no-use-before-define": [1, "nofunc"],

        // Node.js and CommonJS
        "callback-return": 0,
        "global-require": 1,
        "handle-callback-err": 1,
        "no-mixed-requires": 1,
        "no-new-require": 1,
        "no-path-concat": 1,
        "no-process-env": 0,
        "no-process-exit": 0,
        "no-restricted-modules": 0,
        "no-sync": 0,

        // Stylistic Issues
        "array-bracket-spacing": [1, "never"],
        "block-spacing": [1, "always"],
        "brace-style": [1, "allman", { "allowSingleLine": true }],
        "camelcase": [1, { "properties": "always" }],
        "comma-spacing": [1, { "before": false, "after": true }],
        "comma-style": [1, "last"],
        "computed-property-spacing": [1, "never"],
        "consistent-this": 0,
        "eol-last": [1, "unix"],
        "func-names": [1, "always"],
        "func-style": [1, "declaration", { "allowArrowFunctions": true }],
        "id-blacklist": 0,
        "id-length": 0,
        "id-match": 0,
        "indent": [1, 4, { "SwitchCase": 1, "VariableDeclarator": { "var": 1, "let": 1, "const": 1 } }],
        "jsx-quotes": [1, "prefer-double"],
        "key-spacing": [1, { "beforeColon": false, "afterColon": true, "mode": "minimum" }],
        "keyword-spacing": [1, { "before": true, "after": true }],
        "linebreak-style": [1, "unix"],
        "lines-around-comment": 0,
        "max-depth": [1, 6],
        "max-len": [1, { "code": 125, "tabWidth": 4 }],
        "max-lines": 0,
        "max-nested-callbacks": [1, { "max": 5 }],
        "max-params": [1, { "max": 10 }],
        "max-statements": 0,
        "max-statements-per-line": [1, { "max": 2 }],
        "new-cap": [1, { "newIsCap": true, "capIsNew": false, "properties": false }],
        "new-parens": 1,
        "newline-after-var": [1, "always"],
        "newline-before-return": 1,
        "newline-per-chained-call": [1, { "ignoreChainWithDepth": 4 }],
        "no-array-constructor": 1,
        "no-bitwise": 0,
        "no-continue": 0,
        "no-inline-comments": 0,
        "no-lonely-if": 1,
        "no-mixed-operators": 1,
        "no-mixed-spaces-and-tabs": 1,
        "no-multiple-empty-lines": [1, { "max": 1, "maxEOF": 1, "maxBOF": 0 }],
        "no-negated-condition": 0,
        "no-nested-ternary": 1,
        "no-new-object": 1,
        "no-plusplus": 0,
        "no-restricted-syntax": [1, "DebuggerStatement", "EmptyStatement", "LabeledStatement", "WithStatement"],
        "no-spaced-func": 1,
        "no-ternary": 0,
        "no-trailing-spaces": 1,
        "no-underscore-dangle": 0,
        "no-unneeded-ternary": 1,
        "no-whitespace-before-property": 1,
        "object-curly-newline": 0,
        "object-curly-spacing": [1, "always"],
        "object-property-newline": 0,
        "one-var": [1, "never"],
        "one-var-declaration-per-line": [1, "always"],
        "operator-assignment": 0,
        "operator-linebreak": [1, "before"],
        "padded-blocks": [1, "never"],
        "quote-props": [1, "as-needed"],
        "quotes": [1, "single", { "allowTemplateLiterals": true }],
        "require-jsdoc": [1, { "require": { "FunctionDeclaration": false, "ClassDeclaration": true, "MethodDefinition": true } }],
        "semi": [1, "always"],
        "semi-spacing": [1, { "before": false, "after": true }],
        "sort-vars": 0,
        "space-before-blocks": [1, "always"],
        "space-before-function-paren": [1, { "anonymous": "always", "named": "never" }],
        "space-in-parens": [1, "never"],
        "space-infix-ops": 1,
        "space-unary-ops": [1, { "words": true, "nonwords": false }],
        "spaced-comment": [1, "always"],
        "unicode-bom": [1, "never"],
        "wrap-regex": 1,

        // ECMAScript 6
        "arrow-body-style": [1, "as-needed"],
        "arrow-parens": 1,
        "arrow-spacing": [1, { "before": true, "after": true }],
        "constructor-super": 1,
        "generator-star-spacing": [1, {"before": true, "after": false}],
        "no-class-assign": 1,
        "no-confusing-arrow": [1, { "allowParens": true }],
        "no-const-assign": 1,
        "no-dupe-class-members": 1,
        "no-duplicate-imports": 1,
        "no-new-symbol": 1,
        "no-restricted-imports": 0,
        "no-this-before-super": 1,
        "no-useless-computed-key": 1,
        "no-useless-constructor": 1,
        "no-useless-rename": 1,
        "no-var": 1,
        "object-shorthand": 1,
        "prefer-arrow-callback": 0,
        "prefer-const": 1,
        "prefer-reflect": 0,
        "prefer-rest-params": 0,
        "prefer-spread": 0,
        "prefer-template": 1,
        "require-yield": 1,
        "rest-spread-spacing": [1, "never"],
        "sort-imports": 0,
        "template-curly-spacing": [1, "never"],
        "yield-star-spacing": [1, "before"]
    }
}




```

**What did you do? Please include the actual source code causing the issue.**

This is the code before running `eslint src --fix`

<!-- Paste the source code below: -->
```js
class Klass {
    constructor() {
        const nameKlass = (name) => {
            this.name = name;
        };
        nameKlass('Klass');
    }
}
```

**What did you expect to happen?**

I expected the *Allman* style curly brace placement

```js
class Klass
{
    constructor()
    {
        const nameKlass = (name) =>
        {
            this.name = name;
        };

        nameKlass('Klass');
    }
}
```

**What actually happened? Please include the actual, raw output from ESLint.**

The braces are indented after class and after the fat arrow.

```js
class Klass
    { // shouldn't be indented
    constructor()
    {
        const nameKlass = (name) =>
            {                    // shouldn't be indented
                this.name = name; // shouldn't be indented
            };                   // shouldn't be indented

        nameKlass('Klass');
    }
}
```

Pull request description:
Update: check allman-style blocks correctly in indent rule (fixes #8493)
**What is the purpose of this pull request? (put an "X" next to item)**

[x] Bug fix (https://github.com/eslint/eslint/issues/8493)

<!--
    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, there was a bug in the indent rule where allman-style blocks with function bodies would be indented by one too many levels. This commit fixes the issue and updates the BlockStatement indentation handler to use the same logic as other lists of nodes (e.g. arrays).

**Is there anything you'd like reviewers to focus on?**

Nothing in particular

Patch:
diff --git a/docs/user-guide/configuring.md b/docs/user-guide/configuring.md
index 34a69b569..00fccdf4e 100644
--- a/docs/user-guide/configuring.md
+++ b/docs/user-guide/configuring.md
@@ -76,6 +76,7 @@ The following parsers are compatible with ESLint:
 
 * [Esprima](https://npmjs.com/package/esprima)
 * [Babel-ESLint](https://npmjs.com/package/babel-eslint) - A wrapper around the [Babel](http://babeljs.io) parser that makes it compatible with ESLint.
+* [typescript-eslint-parser(Experimental)](https://npmjs.com/package/typescript-eslint-parser) - A parser that converts TypeScript into an ESTree-compatible form so it can be used in ESLint. The goal is to allow TypeScript files to be parsed by ESLint (though not necessarily pass all ESLint rules).
 
 Note when using a custom parser, the `parserOptions` configuration property is still required for ESLint to work properly with features not in ECMAScript 5 by default. Parsers are all passed `parserOptions` and may or may not use them to determine which features to enable.
 
diff --git a/lib/rules/indent.js b/lib/rules/indent.js
index 56ce2e13e..b7597e57b 100644
--- a/lib/rules/indent.js
+++ b/lib/rules/indent.js
@@ -555,49 +555,6 @@ module.exports = {
             return sourceCode.getTokens(node, { includeComments: true });
         }
 
-        /**
-         * Check indentation for blocks
-         * @param {ASTNode} node node to check
-         * @returns {void}
-         */
-        function addBlockIndent(node) {
-
-            let blockIndentLevel;
-
-            if (node.parent && isOuterIIFE(node.parent)) {
-                blockIndentLevel = options.outerIIFEBody;
-            } else if (node.parent && (node.parent.type === "FunctionExpression" || node.parent.type === "ArrowFunctionExpression")) {
-                blockIndentLevel = options.FunctionExpression.body;
-            } else if (node.parent && node.parent.type === "FunctionDeclaration") {
-                blockIndentLevel = options.FunctionDeclaration.body;
-            } else {
-                blockIndentLevel = 1;
-            }
-
-            /*
-             * If the block starts on its own line, then match the tokens in the block against the opening curly of the block.
-             * Otherwise, match the token in the block against the tokens in the block's parent.
-             *
-             * For example:
-             * function foo() {
-             *   {
-             *      // (random block, tokens should get matched against the { that opens the block)
-             *      foo;
-             *   }
-             *
-             * if (foo &&
-             *     bar) {
-             *     baz(); // Tokens in the block should get matched against the `if` statement, even though the opening curly is indented.
-             * }
-             */
-            const tokens = getTokensAndComments(node);
-            const tokenToMatchAgainst = tokenInfo.isFirstTokenOfLine(tokens[0]) ? tokens[0] : sourceCode.getFirstToken(node.parent);
-
-            offsets.matchIndentOf(tokenToMatchAgainst, tokens[0]);
-            offsets.setDesiredOffsets(tokens, tokens[0], blockIndentLevel);
-            offsets.matchIndentOf(tokenToMatchAgainst, tokens[tokens.length - 1]);
-        }
-
         /**
         * Check indentation for lists of elements (arrays, objects, function params)
         * @param {Token[]} tokens list of tokens
@@ -652,6 +609,37 @@ module.exports = {
             });
         }
 
+        /**
+         * Check indentation for blocks
+         * @param {ASTNode} node node to check
+         * @returns {void}
+         */
+        function addBlockIndent(node) {
+
+            let blockIndentLevel;
+
+            if (node.parent && isOuterIIFE(node.parent)) {
+                blockIndentLevel = options.outerIIFEBody;
+            } else if (node.parent && (node.parent.type === "FunctionExpression" || node.parent.type === "ArrowFunctionExpression")) {
+                blockIndentLevel = options.FunctionExpression.body;
+            } else if (node.parent && node.parent.type === "FunctionDeclaration") {
+                blockIndentLevel = options.FunctionDeclaration.body;
+            } else {
+                blockIndentLevel = 1;
+            }
+
+            const tokens = getTokensAndComments(node);
+
+            /*
+             * For blocks that aren't lone statements, ensure that the opening curly brace
+             * is aligned with the parent.
+             */
+            if (!astUtils.STATEMENT_LIST_PARENTS.has(node.parent.type)) {
+                offsets.matchIndentOf(sourceCode.getFirstToken(node.parent), tokens[0]);
+            }
+            addElementListIndent(tokens, node.body, blockIndentLevel);
+        }
+
         /**
          * Check indent for array block content or object block content
          * @param {ASTNode} node node to examine
diff --git a/lib/rules/no-extend-native.js b/lib/rules/no-extend-native.js
index 547770d8f..c550cf5da 100644
--- a/lib/rules/no-extend-native.js
+++ b/lib/rules/no-extend-native.js
@@ -9,8 +9,15 @@
 // Requirements
 //------------------------------------------------------------------------------
 
+const astUtils = require("../ast-utils");
 const globals = require("globals");
 
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+const propertyDefinitionMethods = new Set(["defineProperty", "defineProperties"]);
+
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
@@ -43,73 +50,123 @@ module.exports = {
     create(context) {
 
         const config = context.options[0] || {};
-        const exceptions = config.exceptions || [];
-        let modifiedBuiltins = Object.keys(globals.builtin).filter(builtin => builtin[0].toUpperCase() === builtin[0]);
+        const exceptions = new Set(config.exceptions || []);
+        const modifiedBuiltins = new Set(
+            Object.keys(globals.builtin)
+                .filter(builtin => builtin[0].toUpperCase() === builtin[0])
+                .filter(builtin => !exceptions.has(builtin))
+        );
+
+        /**
+         * Reports a lint error for the given node.
+         * @param {ASTNode} node The node to report.
+         * @param {string} builtin The name of the native builtin being extended.
+         * @returns {void}
+         */
+        function reportNode(node, builtin) {
+            context.report({
+                node,
+                message: "{{builtin}} prototype is read only, properties should not be added.",
+                data: {
+                    builtin
+                }
+            });
+        }
 
-        if (exceptions.length) {
-            modifiedBuiltins = modifiedBuiltins.filter(builtIn => exceptions.indexOf(builtIn) === -1);
+        /**
+         * Check to see if the `prototype` property of the given object
+         * identifier node is being accessed.
+         * @param {ASTNode} identifierNode The Identifier representing the object
+         * to check.
+         * @returns {boolean} True if the identifier is the object of a
+         * MemberExpression and its `prototype` property is being accessed,
+         * false otherwise.
+         */
+        function isPrototypePropertyAccessed(identifierNode) {
+            return Boolean(
+                identifierNode &&
+                identifierNode.parent &&
+                identifierNode.parent.type === "MemberExpression" &&
+                identifierNode.parent.object === identifierNode &&
+                astUtils.getStaticPropertyName(identifierNode.parent) === "prototype"
+            );
         }
 
-        return {
+        /**
+         * Checks that an identifier is an object of a prototype whose member
+         * is being assigned in an AssignmentExpression.
+         * Example: Object.prototype.foo = "bar"
+         * @param {ASTNode} identifierNode The identifier to check.
+         * @returns {boolean} True if the identifier's prototype is modified.
+         */
+        function isInPrototypePropertyAssignment(identifierNode) {
+            return Boolean(
+                isPrototypePropertyAccessed(identifierNode) &&
+                identifierNode.parent.parent.type === "MemberExpression" &&
+                identifierNode.parent.parent.parent.type === "AssignmentExpression" &&
+                identifierNode.parent.parent.parent.left === identifierNode.parent.parent
+            );
+        }
 
-            // handle the Array.prototype.extra style case
-            AssignmentExpression(node) {
-                const lhs = node.left;
+        /**
+         * Checks that an identifier is an object of a prototype whose member
+         * is being extended via the Object.defineProperty() or
+         * Object.defineProperties() methods.
+         * Example: Object.defineProperty(Array.prototype, "foo", ...)
+         * Example: Object.defineProperties(Array.prototype, ...)
+         * @param {ASTNode} identifierNode The identifier to check.
+         * @returns {boolean} True if the identifier's prototype is modified.
+         */
+        function isInDefinePropertyCall(identifierNode) {
+            return Boolean(
+                isPrototypePropertyAccessed(identifierNode) &&
+                identifierNode.parent.parent.type === "CallExpression" &&
+                identifierNode.parent.parent.arguments[0] === identifierNode.parent &&
+                identifierNode.parent.parent.callee.type === "MemberExpression" &&
+                identifierNode.parent.parent.callee.object.type === "Identifier" &&
+                identifierNode.parent.parent.callee.object.name === "Object" &&
+                identifierNode.parent.parent.callee.property.type === "Identifier" &&
+                propertyDefinitionMethods.has(identifierNode.parent.parent.callee.property.name)
+            );
+        }
 
-                if (lhs.type !== "MemberExpression" || lhs.object.type !== "MemberExpression") {
-                    return;
-                }
+        /**
+         * Check to see if object prototype access is part of a prototype
+         * extension. There are three ways a prototype can be extended:
+         * 1. Assignment to prototype property (Object.prototype.foo = 1)
+         * 2. Object.defineProperty()/Object.defineProperties() on a prototype
+         * If prototype extension is detected, report the AssignmentExpression
+         * or CallExpression node.
+         * @param {ASTNode} identifierNode The Identifier representing the object
+         * which prototype is being accessed and possibly extended.
+         * @returns {void}
+         */
+        function checkAndReportPrototypeExtension(identifierNode) {
+            if (isInPrototypePropertyAssignment(identifierNode)) {
+
+                // Identifier --> MemberExpression --> MemberExpression --> AssignmentExpression
+                reportNode(identifierNode.parent.parent.parent, identifierNode.name);
+            } else if (isInDefinePropertyCall(identifierNode)) {
+
+                // Identifier --> MemberExpression --> CallExpression
+                reportNode(identifierNode.parent.parent, identifierNode.name);
+            }
+        }
 
-                const affectsProto = lhs.object.computed
-                    ? lhs.object.property.type === "Literal" && lhs.object.property.value === "prototype"
-                    : lhs.object.property.name === "prototype";
+        return {
 
-                if (!affectsProto) {
-                    return;
-                }
+            "Program:exit"() {
+                const globalScope = context.getScope();
 
                 modifiedBuiltins.forEach(builtin => {
-                    if (lhs.object.object.name === builtin) {
-                        context.report({
-                            node,
-                            message: "{{builtin}} prototype is read only, properties should not be added.",
-                            data: {
-                                builtin
-                            }
-                        });
+                    const builtinVar = globalScope.set.get(builtin);
+
+                    if (builtinVar && builtinVar.references) {
+                        builtinVar.references
+                            .map(ref => ref.identifier)
+                            .forEach(checkAndReportPrototypeExtension);
                     }
                 });
-            },
-
-            // handle the Object.definePropert[y|ies](Array.prototype) case
-            CallExpression(node) {
-
-                const callee = node.callee;
-
-                // only worry about Object.definePropert[y|ies]
-                if (callee.type === "MemberExpression" &&
-                    callee.object.name === "Object" &&
-                    (callee.property.name === "defineProperty" || callee.property.name === "defineProperties")) {
-
-                    // verify the object being added to is a native prototype
-                    const subject = node.arguments[0];
-                    const object = subject && subject.object;
-
-                    if (object &&
-                        object.type === "Identifier" &&
-                        (modifiedBuiltins.indexOf(object.name) > -1) &&
-                        subject.property.name === "prototype") {
-
-                        context.report({
-                            node,
-                            message: "{{objectName}} prototype is read only, properties should not be added.",
-                            data: {
-                                objectName: object.name
-                            }
-                        });
-                    }
-                }
-
             }
         };
 


Test patch:
diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js
index 7d04e50a3..9d19c6b23 100644
--- a/tests/lib/rules/indent.js
+++ b/tests/lib/rules/indent.js
@@ -3111,6 +3111,22 @@ ruleTester.run("indent", rule, {
                 );
             `
         },
+        {
+            code: unIndent`
+                if (foo)
+                {
+                    bar();
+                }
+            `
+        },
+        {
+            code: unIndent`
+                function foo(bar)
+                {
+                    baz();
+                }
+            `
+        },
         {
             code: unIndent`
                 () =>
@@ -3133,6 +3149,23 @@ ruleTester.run("indent", rule, {
                 )
             `,
             parserOptions: { ecmaVersion: 6 }
+        },
+        {
+            code: unIndent`
+                var x = function foop(bar)
+                {
+                    baz();
+                }
+            `
+        },
+        {
+            code: unIndent`
+                var x = (bar) =>
+                {
+                    baz();
+                }
+            `,
+            parserOptions: { ecmaVersion: 6 }
         }
     ],
 
diff --git a/tests/lib/rules/no-extend-native.js b/tests/lib/rules/no-extend-native.js
index 9293a9399..ec5449a87 100644
--- a/tests/lib/rules/no-extend-native.js
+++ b/tests/lib/rules/no-extend-native.js
@@ -40,7 +40,14 @@ ruleTester.run("no-extend-native", rule, {
 
         // https://github.com/eslint/eslint/issues/4438
         "Object.defineProperty()",
-        "Object.defineProperties()"
+        "Object.defineProperties()",
+
+        // https://github.com/eslint/eslint/issues/8461
+        "function foo() { var Object = function() {}; Object.prototype.p = 0 }",
+        {
+            code: "{ let Object = function() {}; Object.prototype.p = 0 }",
+            parserOptions: { ecmaVersion: 6 }
+        }
     ],
     invalid: [{
         code: "Object.prototype.p = 0",
@@ -78,6 +85,12 @@ ruleTester.run("no-extend-native", rule, {
             message: "Array prototype is read only, properties should not be added.",
             type: "CallExpression"
         }]
+    }, {
+        code: "Object.defineProperties(Array.prototype, {p: {value: 0}, q: {value: 0}})",
+        errors: [{
+            message: "Array prototype is read only, properties should not be added.",
+            type: "CallExpression"
+        }]
     },
     {
         code: "Number['prototype']['p'] = 0",
@@ -86,5 +99,24 @@ ruleTester.run("no-extend-native", rule, {
             message: "Number prototype is read only, properties should not be added.",
             type: "AssignmentExpression"
         }]
+    },
+    {
+        code: "Object.prototype.p = 0; Object.prototype.q = 0",
+        errors: [{
+            message: "Object prototype is read only, properties should not be added.",
+            type: "AssignmentExpression",
+            column: 1
+        }, {
+            message: "Object prototype is read only, properties should not be added.",
+            type: "AssignmentExpression",
+            column: 25
+        }]
+    },
+    {
+        code: "function foo() { Object.prototype.p = 0 }",
+        errors: [{
+            message: "Object prototype is read only, properties should not be added.",
+            type: "AssignmentExpression"
+        }]
     }]
 });